You look to be a little overloaded.
Remember to keep stuff separated. It helps to keep a self-cheat-sheet of sorts to remember what is what.
(1)
You need to keep track of
circles: you should have a circle type:
1 2 3 4
|
struct circle
{
int x, y, r; // center x, center y, radius
};
|
(2)
You need to keep track of
more than one circle, and your code is not permitted to forget about any circles: you should have a global list of them:
|
std::vector <circle> circles;
|
(3)
You need to have a stacking order: some circles are on top (draw last, select first), other circles are on bottom (draw first, select last):
1 2
|
std::vector <circle> circles;
// stacking order is first → bottom-most to last → top-most
|
(4)
Click event handler to add a circle needs to add a circle to the top of the list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
case WM_LBUTTONDOWN:
last_x = x; // what kind of variable should last_x and last_y be?
last_y = y; // local or global?
break;
// (because we are done with them for now... but we need their values when
// the user finally lets go of the mouse button)
case WM_LBUTTONUP:
{
// notice how r is a local variable -- it only exists inside of the enclosing { and } braces
int r = std::sqrt( (x - last_x) * (x - last_x) + (y - last_y) * (y - last_y) );
circles.push_back( { x, y, r } );
// (we don't need r any more. rest in peace, r.)
}
break;
|
(5)
You need to draw the circles, bottom to top. (You
do have a function specifically for painting, right?)
1 2 3
|
case WM_PAINT:
PaintProc( ... );
break;
|
1 2 3 4 5 6 7 8 9 10
|
void PaintProc( ... )
{
// repaint the background here
// repaint all the circles
for (auto c : circles)
// draw the circle c here
//...
}
|
(6)
You need to be able to
select a circle. A function will help:
1 2 3 4 5
|
bool is_point_in_circle( const point& p, const circle& c )
{
int d = std::sqrt( (c.x - p.x) * (c.x - p.x) + (c.y - p.y) * (c.y - p.y) );
return d <= c.r;
}
|
Hmm... I have written the same 'distance' code twice now...
This is a good candidate for a
function! ;^)
Rewrite:
1 2 3 4 5 6 7 8 9
|
int distance( int x1, int y1, int x2, int y2 )
{
return std::sqrt( ... );
}
bool is_point_in_circle( const point& p, const circle& c )
{
return distance( c.x, c.y, p.x, p.y ) <= c.r;
}
|
Nice! Don't forget to fix the LMB up code to use the new distance() function too.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
case WM_RBUTTONUP:
{
// Remember, top-most to bottom-most
int n = circles.size();
while (n--)
if (is_point_in_circle( point{ x, y }, circles[n] ))
{
// invalidate the region where the circle is
...
// erase the found circle
circles.erase( std::next( circles.begin(), n ) );
// done
break;
}
}
break;
|
Et cetera. Remember, one thing at a time.
What happens when you are asked to track
other shapes besides circles?
You might have to change your vector to hold a different kind of structure than just a circle.
|
std::vector <shape> shapes;
|
For your assignment, a simple, hand-made discriminated union will do:
1 2 3 4 5 6 7 8 9 10 11
|
struct shape
{
typedef enum { CIRCLE, RECTANGLE, ... } shape_type;
shape_type type;
union
{
circle c;
rectangle r;
...
};
};
|
Hope this helps.