Assignment
2 Geometry
The
program is called Geometry. Name
the project Geometry so the .exe file
will come out to be Geometry.exe as
the submission system wants. But, as
always, modify
the title bar text so it says Geometry2345
(using your own 4-digit student ID number
instead of 2345).
The
purpose of the program is to let users make simple geometrical
constructions. You will build this
program as a C#
Windows Application. To
create the project, choose File | New
and then choose Visual C# Projects on
the left and Windows Application on
the right.
Here
are the specifications and some hints for the program design.
1. The background color of the window should be
white. When you left-click a blank area
of the screen, a
“point” is created. The user
sees a small circle (say 10 pixels in diameter) located at the point where the
mouse was clicked. The circle is drawn
with a pen whose default width is 3.
2. The maximum number of points that the
program must manage in any one session will not be more than 50. Some points may be created, later destroyed, and new points
created, but the total number of points ever created in any one session (that
is, any session run by the grader) will
not exceed 50.
3. When you left-click an already-existing point
(more precisely, when you left-click inside the 10-by-10 rectangle containing
that point), that point becomes “selected” (unless it is already
selected). Selected points are drawn
with a red circle instead of a black circle.
If you left-click a point that is already selected, it becomes
unselected. In this program you cannot
drag anything, so we ignore MouseUp entirely and “click” here means MouseDown. What happens if two points are so close
together that their 10-by-10 rectangles overlap? Then the click selects or deselects only one of the two points, namely the first
one that was created.
4. There is an item Draw on the menu
bar. The menu underneath it contains the
following items:
Connect
Selected Points
Bisect
Selected Segments
Delete
Selected Segments
Select
All
Unselect
All
5. When at least two points are selected and Connect
Selected Points is chosen, then all pairs of selected points are connected
by line segments. Examples: you can select two points, and they will be
connected by a line segment. Or you can
select three points, and a triangle will be drawn. If you select four points, a quadrilateral
and its diagonals will be drawn. The
lines are drawn with a pen whose width is by default 3. Note that you shouldn’t use the same point for both ends of a
segment—in other words, a segment must have
distinct endpoints.
6. When at least two points are selected and Bisect
Selected Segments is chosen, then all segments that currently exist whose endpoints are both selected will be
bisected. That means that a new point
will be created at the midpoint of the existing segment. The newly created points are not selected. (The new segments (the halves of the
bisected segments) should be added to the array m_Segments.) Note that the endpoints of a segment must be
distinct, so be careful that you don’t mistakenly create points that
bisect a “segment” whose two “endpoints” are identical. This bug has mystified some students in the
past. [Note: Bisecting a segment does create two new
segments, as mentioned, but does NOT delete the previously existing
segment. This makes sense because in an
extended version of this program (not this version) you would be able to drag
points and the whole construction would follow along. So you could drag the bisection point to make
a triangle—the old segment would still form one of the sides.]
7. The items Delete Selected Points and Delete
Selected Segments remove the selected items from the diagram. A segment is considered
“selected” when both its endpoints are selected. Selected segments are drawn in red;
non-selected segments are drawn in black.
Delete Selected Segments does not delete the endpoints of the
segments. [Note: When you delete one
or both endpoints of a segment, that automatically
deletes the segment, since segments can’t exist without endpoints, at
least in this program. But of course you can delete a segment without deleting
its endpoints.]
8. The item Select All results
in making all existing points “selected”. The item Unselect All makes all
existing points not “selected”.
Screen Shots:
|
After clicking three times
to create three points : |
After “Select
All” or clicking on each of the
three points:
|
After “Connect
Selected Points”:
|
|
After “Bisect
Selected Segments”:
|
After “Select
All”:
|
After “Connect
Selected Points”:
|
Notice
that in the fourth shot, after “Bisect Selected Segments”, the six short black
segments have overwritten the three long red segments. There are actually 9 segments present at
that time. Three long, selected segments
are not visible because six short, non-selected segments cover them up.
Programming Hints.
1. You can select the background color of your form in its property sheet in the form design editor. You can also change the Text property there to Geometry2345 instead of Form1.
2. The first step is to properly define the
data for the program. Your
program’s data should include an array m_Points whose elements are of type Point
, and an integer m_nPoints to keep track of how many points have been
created. Now, you need to know which of
these points is selected. You could keep
an array of Booleans called m_Selected for that purpose. You’ll also have to keep track of
which points actually exist. Since
points can be deleted, the existing points won’t always be numbered 0 to m_nPoints-1. For example, you could create points 0,1,2, and then delete point 1, so only points 0 and 2 would
exist at that time. I suggest an array
of Booleans, say m_Exists, to keep track of which points
exist. Another approach would be to
define your own class myPoint and give a myPoint object properties selected and exists,
and use an array of myPoints. The easiest
way to add member variables is just to type the code, for example:
public Point[] m_Points;
Note
that arrays are declared differently in C# than in C or C++. Just as in Java, you have to initialize an
array using new; this should be done in the constructor
of your form, something like this:
m_maxPoints = 50;
// just ONE occurrence of the hard-coded number 50
m_Diameter = 10; //
also just ONE occurrence of this hard-coded number
m_Points = new Point[m_maxPoints];// since the
array is allocated at run time its dimension can be specified by a variable.
m_Exists = new Boolean[m_maxPoints];
m_Selected = new Boolean[m_maxPoints];
m_nPoints = 0;
How will you keep track of segments? You should just specify a segment by a pair
of integers, e.g. (3,2)
means the segment whose endpoints are point 3 and point 2, that is m_Points[3] and m_Points[2]. There are several ways you could do
this, but the one the probably leads to
the easiest programming is to keep a two-dimensional array of Booleans such that m_Segments[i][j] is true if and only if m_Points[i] and m_Points[j]
are the endpoints of a segment.
public Boolean[,] m_Segments;
// this is how you declare a
two-dimensional array in C#
m_Segments = new
Boolean[m_maxPoints,m_maxPoints]; //
put this line in the constructor.
// (These two lines
don’t go next to each other in your code.)
You
don’t need to keep track of selected segments directly since a segment is
selected exactly when both its endpoints are selected.
To
draw the points or to hit-test the points, you need a rectangle around each
point. You could construct these as
needed, but I suggest that you construct these rectangles at the same time as
you create points, and keep them in an array m_theRectangles of Rectangle.
You will need these when you are hit-testing to see whether the user
has clicked on an existing point or not.
3. From the property sheet of the form, use the lightning-bolt icon to map events. Map the MouseDown event (not the Click event, which only tells you that a click has occurred, but not where).
Map the Paint event also. Those are the only two events you’ll need in this program. Remember, to map an event you just double-click its name.
4. Write the code for the event-handler for MouseDown. You will need to test whether the user has clicked on an existing point. Explicitly, did the click (more precisely the MouseDown) come inside a rectangle in the m_theRectangles array that corresponds to an existing point ? If so then an existing point is being selected (if it wasn’t already selected) or deselected (if it was already selected). If the click was not in any rectangle corresponding to an existing point, then a new point is being created. To create a new point, you enter the coordinates into m_Points[m_nPoints], and the appropriate rectangle into m_theRectangles, and then you increment m_nPoints. Just as in MFC, you don’t draw in this event handler! You only change data and call Invalidate(). The name Invalidate is still the same in .NET.
5. Your paint event handler should just do drawing—you don’t need calculations there. (Look Ma, no math in this assignment!) It should use a for-loop to go through the m_Rectangles array and draw a circle in each rectangle m_theRectangles[i] for which m_Exists[i] is nonzero. The color of the circle should be black if m_Selected[i] is zero and red otherwise. Of course, you won’t see anything until you’ve also written the MouseDown handler, because there are no points until someone clicks. Then, it should use a double for-loop to draw the segments. The second index j should start from i+1, not from 0. (What will go wrong if it started from 0? More than just drawing each segment twice.)
6. OnMouseDown checks to see if the point clicked on is in the rectangle associated with an existing point. If so it just toggles the selected status of that point. If not, it creates a new point, putting it into the m_Points array at some unused place. If you’re using m_Rects, set the rectangle of the new point now. At this point, you should be able to test points 1, 2, and 3 of the grading criteria below.
To do this hit-testing, use the Contains method of the Rectangle class.
7. Now add a menu to your program. Here is how: First, if the Toolbox isn’t visible, select View | Toolbox to make it visible. Then drag a Main Menu onto your form, and put menu items on it just as you’ve done all semester. Right-click each menu item to see its property sheet, and give it a name such as ConnectAll rather than menuItem3. After renaming all the menu items, then double-click them to create handler functions.
8. Now, one by one, implement the menu item handlers. These just change the data and then call Invalidate(). For example SelectAll loops through the array m_Selected and sets all the entries m_Selected[i] to 1 if m_Exists[i] is nonzero and i < m_nPoints. Test that they work—when they do, you’re done.
Grading Criteria (100 points total for the
program. 90 is an A-, 80 is a B-, 70 is a C-)
1. Background color of main window is white (5 points).
2. Can create visible points by left-clicking. Points are drawn correctly as small black circles, and remain in the same place when the window is resized. (15 points)
3. Can select
existing points by left-clicking.
Selected points turn red. Can unselect selected points
by left-clicking. (They turn
black again.) (15 points)
4. Menu shows up as
specified. (10 points)
5. Can use menu item Select All to select all points, and menu item Unselect All to unselect all points. (5 points)
6. Can use menu item Connect Selected Points to join two selected points with a line segment. (10 points)
7. Can use menu item Connect Selected Points when three points are selected to make a triangle, or when more points are selected, to make a more complicated figure. (10 points)
8. Menu item Delete Selected Segments works correctly. (5 points)
9. Menu item Delete Selected Points works correctly. (5 points)
10. Menu item Bisect Selected Segments works correctly, in that the new midpoints of the selected segments appear on the screen and are not selected. (10 points)
11. Select the two endpoints of a segment, choose Bisect Selected Segment, unselect one of the old endpoints and select the new midpoint, then choose Bisect Selected Segment. The selected segment should be bisected, showing that the operation of bisection correctly created the two new segments.) (10 points).
For an A+: Implement a new menu item, Circle from Point and Radius. For this to work, the user has to have selected exactly two points. The first one selected will be the center, and the other point will lie on the circle. The reason this is worth an A+ is that you will have to keep track of the order in which the points were selected.