LAB 1 SOLUTION, Part II -- Color

Unsophisticated solution

There are many ways to add color to the rectangle. The most straightforward way is to add three integer members to myRect, and, for convenience of creating a rectangle, extend the constructor with arguments.

Then the methods for drawing the rectangle will change the current color to the the color of the rectangle right before drawing.

The functions that make new myRects, such as BoundingRectangle(..) and IntersectingRectangle(..) will make a rectangle of a particular color.

struct myRect
{
  int left;  
  int top;
  int right;  
  int bottom;
  
  int red;
  int green;
  int blue;

  myRect() { left = 0; top = 0; right = 0; bottom = 0;}

  myRect(int, int, int, int, int, int, int);
  
  bool IsPointInside( const myDot& );

  void DrawSolid();
  void DrawFrame();
};

myRect::myRect(int x1, int y1, int x2, int y2, int r, int g, int b)
{
  left   = min(x1,x2);
  top    = min(y1,y2);
  right  = max(x1,x2);
  bottom = max(y1,y2);
  red    = r;
  green  = g;
  blue   = b;
}

void myRect::DrawSolid()
{
  SetForeColor( red, green, blue );
  PaintRect(left, top, right, bottom);
}

void myRect::DrawFrame()
{
  SetForeColor( red, green, blue );
  FrameRect(left, top, right, bottom);
}
Here is the changed BoundingRectangle:
myRect BoundingRectangle( const myRect& R1, const myRect& R2 ){

  myRect r;
  // Find the min and max x-coordinates of both rectangles
  r.left  =  min( R1.left,   R2.left );
  r.right =  max( R1.right,  R2.right );
  // Find the min and max y-coordinates of both rectangles
  r.top   =  min( R1.top,    R2.top );
  r.bottom = max( R1.bottom, R2.bottom );

  // make it a _blue_ rectangle
  r.red = r.green = 0;
  r.blue = 255;

  return r;
}
In the test code the need for SetForeColor(..) is thus eliminated, which is much better than what we had before:
void main()
{
  // .... skipped

  for( int j=0; j < 10; j++ ){

    // make a _red_ random myRect
    myRect rect1 ( RandomLong(0,400),
		   RandomLong(0,400),
		   RandomLong(0,400),
		   RandomLong(0,400),
		   255, 0, 0 );

    // make a _green_ random myRect
    myRect rect2 ( RandomLong(0,400),
		   RandomLong(0,400), 
		   RandomLong(0,400),
		   RandomLong(0,400),
		   0, 255, 0 );
    
    rect1.DrawFrame();  // in red
    rect2.DrawFrame();  // in green
    
    BoundingRectangle(rect2, rect1).DrawFrame();
    IntersectingRectangle(rect2, rect1).DrawSolid();

    PressReturn();
    ClearDrawing();
  }

  PressReturn("Done");
}

Better Solution

A better solution is to keep the three components of the color in a special struct myRGB created for that purpose. The code below adheres to the new C++ standard of class initialization, under which all initial assigments of members are done in the initialization list that precedes the body of the constructor. If all necessary initialization work is done in that list, the body of the constructor is left empty, "{ }", which is considered to be good style.

struct myRGB {
  int red;
  int green;
  int blue;

  myRGB() : red(0), green(0), blue(0) {} 
  myRGB( int r, int g, int b ) : red(r), green(g), blue(b) { }
};

Then you can re-write myRect as

struct myRect
{
  int left;  
  int top;
  int right;  
  int bottom;
  
  myRGB color; 

  myRect() : left(0), top(0), right(0), bottom(0), color(0,0,0) {}

  myRect(int x1, int y1, int x2, int y2, const myRGB& col) :
    left   ( min(x1, x2) ),
    top    ( min(y1, y2) ),
    right  ( max(x1, x2) ),
    bottom ( max(y1, y2) ),
    color  ( col )
    { }
  
  bool IsPointInside( const myDot& );

  void DrawSolid();
  void DrawFrame();
};
Notice that the default constructor myRect() initializes the color to black, by calling ("color(0,0,0)") the three argument constructor myRGB(int, int, int). More complicated things, like calling a function, can also be done on the initialization list, e.g. "left( min(x1, x2) )".

With these definitions you can set the color of a myRect by something like

// create a red rectangle
myRect rect1( 100, 100, 300, 300, myRGB( 255, 0, 0 ) );  
or, in BoundingRectangle(..), for example:
  
// returns a _blue_ bounding rectangle
myRect BoundingRectangle( const myRect& R1, const myRect& R2 ){

  myRect r;

  r.left   = min( R1.left,   R2.left   );
  r.right  = max( R1.right,  R2.right  );
  r.top    = min( R1.top,    R2.top    );
  r.bottom = max( R1.bottom, R2.bottom );

  r.color.red   = 0;
  r.color.green = 0;
  r.color.blue  = 255;

  return r;
}
Finally, this approach gives an unexpected bonus. You can create several objects for standard colors, and then refer to them by names. For example:
// globals, declared before main()

myRGB red  ( 255, 0, 0 );  
myRGB green( 0, 255, 0 );  
myRGB blue ( 0, 0, 255 );  

// ...

void main(){
 
  // ...

  myRect rect1( 100, 100, 200, 200, red ); 
  myRect rect2( 200, 200, 300, 300, green ); 

  // ...

}
Such global objects are better made const, but then a few more issues specific to C++ semantics will arise. We will discuss those later.