Die Klasse Rectangle

1. Aufgabe

Definieren und implementieren Sie eine Klasse Rectangle, die ein Rechteck im Sinne des kartesischen Koordinatensystems verwaltet. Das Rechteck soll dabei durch zwei Punkte (x1, y1) und (x2, y2) festgelegt werden, die die linke obere und rechte untere Ecke markieren.

Folgende Anforderungen an die Klasse Rectangle sind mit geeigneten programmiersprachlichen Konstrukten umzusetzen:

  • Bei der Erzeugung eines Rectangle-Objekts mit dem Standard-Konstruktor werden beide Koordinaten auf den Wert (0, 0) gesetzt.

  • Bei der Erzeugung eines Rectangle-Objekts mit einem benutzerdefinierten Konstruktor werden die Koordinaten entsprechend der Parameter des Konstruktors gesetzt. Dabei soll für zwei Punkte (x1, y1) und (x2, y2) im Objekt stets gelten: x1x2 und y1y2. Erfüllen die als Parameter übergebenen Koordinaten diese Eigenschaft nicht, so sind im Objekt zwei modifizierte Punkte an Hand der Original-Punkte abzuleiten. Mit dieser Forderung soll erreicht werden, dass die beiden Punkte im Objekt stets die linke obere und rechte untere Ecke des Rechtecks beschreiben. Die Implementierung der nachfolgend beschriebenen Methoden vereinfacht sich auf diese Weise nicht unerheblich!

  • Ergänzen Sie die Klasse um getter- und setter-Methoden zum Lesen und Schreiben der Koordinaten des Rechtecks. Achten Sie darauf, dass beim Ändern einer Koordinate die Regel „x1x2 und y1y2“ beibehalten bleibt.

  • Überladen Sie den Operator operator<< geeignet, um Rectangle-Objekt in der Konsole ausgeben zu können.

  • Schreiben Sie eine Methode Circumference zur Berechnung des Umfangs eines Rechtecks.

  • Die Methode Diagonal berechnet die Länge der Diagonalen des Rechtecks.

  • Schreiben Sie eine Methode Area zur Berechnung der Fläche eines Rechtecks.

  • Die Methode IsSquare überprüft, ob das Rechteck ein Quadrat ist oder nicht.

  • Schreiben Sie eine Methode Center, die den Punkt im Zentrum des Rechtecks berechnet. Übergeben Sie zu diesem Zweck die Adressen zweier int-Variablen an die Methode, um dort das Resultat ablegen zu können. Alternativ können Sie eine Klasse Point definieren, die von der Center-Methode als Rückgabetyp verwendet wird.

  • Schreiben Sie eine Methode AdjustWidth, die die Breite eines Rechtecks ändert: x2 = x1 + width.

    Beispiel: Für ein Rechteck mit den Koordinaten (1, 1) und (4, 5) besitzt nach dem Aufruf

    AdjustWidth(10);

    die Koordinate x2 den Wert 11.

  • Schreiben Sie eine Methode AdjustHeight, die die Höhe eines Rechtecks ändert:

    y2 = y1 - height.

  • Ergänzen Sie den Operator operator<< um weitere Angaben wie zum Beispiel Informationen zur Fläche und zum Umfang, zur Diagonalen und darüber, ob das Rechteck ein Quadrat ist.

  • Schreiben Sie eine Methode Intersection, die ein zweites Rectangle-Objekt als Parameter übergeben bekommt und dasjenige Rechteck berechnet, das die beiden Rechtecke gemeinsam haben. Das Resultat-Rechteck ist als Rückgabewert der Intersection-Methode zurückzuliefern.

    Beispiel:

    Rectangle rect1(1, 4, 4, 1);
    Rectangle rect2(2, 5, 6, 2);
    Rectangle rect = rect1.Intersection(rect2);

    liefert ein Rechtecht rect mit den Eckpunkten (2, 4) und (4, 2) zurück.

  • Schreiben Sie eine Methode Move, die ein Rechteck in x- und/oder y-Richtung verschieben kann:

    Beispiel:

    Rectangle rect(1,1,4,5);
    rect.MoveTo(3, 6);

    Das Rechteck rect wird um 3 in x- und 6 in y-Richtung verschoben.

Teilen Sie die Implementierung geeignet auf mehrere Dateien auf!

Testen Sie die geforderte Funktionalität durch entsprechende Testfunktionen im Hauptprogramm.

2. Lösung

Quellcode: Siehe auch https://github.com/peterloos/Cpp_Rectangle.git.

Wir stellen dieses Mal gleich zwei Lösungen zu dieser Aufgabe vor. Eine erste Lösung setzt die Anforderungen der Aufgabenstellung direkt in eine Klasse Rectangle um. In einer zweiten Lösung erstellen wir zwei Klassen Point und Rectangle. Dabei müssen wir in C++ die Aspekte einer Aggregation beachten bzw. umsetzen, da ein Objekt des Typs Rectangle dann zwei Unterobjekte des Typs Point für die beiden Eckpunkte besitzt. Da – zumindest in diesem Beispiel – Point-Objekte prinzipiell auch ohne umgebendes Rectangle-Objekt in Erscheinung treten können, haben wir es nicht mit einer Komposition als Sonderfall der Aggregation zu tun.

In Listing 1 und Listing 2 finden Sie meinen Lösungsvorschlag zur ersten Variante vor:

01: class Rectangle
02: {
03: private:
04:     double m_x1;
05:     double m_y1;
06:     double m_x2;
07:     double m_y2;
08: 
09: public:
10:     // c'tors
11:     Rectangle();
12:     Rectangle(double x1, double y1, double x2, double y2);
13: 
14:     // getter/setter
15:     double GetX1() { return m_x1; };
16:     double GetY1() { return m_y1; };
17:     double GetX2() { return m_x2; };
18:     double GetY2() { return m_y2; };
19:     void SetX1(double x1);
20:     void SetY1(double y1);
21:     void SetX2(double x2);
22:     void SetY2(double y2);
23: 
24:     // public interface
25:     double Circumference() const;
26:     double Diagonal() const;
27:     double Area() const;
28:     bool IsSquare() const;
29:     void Center(double& x, double& y) const;
30:     void AdjustWidth(double width);
31:     void AdjustHeight(double height);
32:     void Move(double x, double y);
33:     Rectangle Intersection(const Rectangle& rect) const;
34: 
35: private:
36:     // private helper methods
37:     void Normalize();
38: 
39:     // output
40:     friend ostream& operator << (ostream& os, const Rectangle& r);
41: };

Beispiel 1. Klasse Rectangle: Schnittstelle Variante 1.


001: #include <iostream>
002: #include <cmath>
003: using namespace std;
004: 
005: #include "Rectangle.h"
006: 
007: // c'tor(s)
008: Rectangle::Rectangle()
009: {
010:     m_x1 = 0;
011:     m_y1 = 0;
012:     m_x2 = 0;
013:     m_y2 = 0;
014: }
015: 
016: Rectangle::Rectangle(double x1, double y1, double x2, double y2)
017: {
018:     m_x1 = x1;
019:     m_y1 = y1;
020:     m_x2 = x2;
021:     m_y2 = y2;
022:     this->Normalize();
023: }
024: 
025: // getter/setter
026: void Rectangle::SetX1(double x1)
027: {
028:     m_x1 = x1;
029:     this->Normalize();
030: }
031: 
032: void Rectangle::SetY1(double y1)
033: {
034:     m_y1 = y1;
035:     this->Normalize();
036: }
037: 
038: void Rectangle::SetX2(double x2)
039: {
040:     m_x2 = x2;
041:     this->Normalize();
042: }
043: 
044: void Rectangle::SetY2(double y2)
045: {
046:     m_y2 = y2;
047:     this->Normalize();
048: }
049: 
050: // methods
051: double Rectangle::Circumference() const
052: {
053:     return 2 * ((m_x2 - m_x1) + (m_y1 - m_y2));
054: }
055: 
056: double Rectangle::Diagonal() const
057: {
058:     return sqrt((double)((m_x2 - m_x1) * (m_x2 - m_x1) +
059:         (m_y1 - m_y2) * (m_y1 - m_y2)));
060: }
061: 
062: double Rectangle::Area() const
063: {
064:     return (m_x2 - m_x1) * (m_y1 - m_y2);
065: }
066: 
067: bool Rectangle::IsSquare() const
068: {
069:     return (m_x2 - m_x1) == (m_y1 - m_y2);
070: }
071: 
072: void Rectangle::Center(double& x, double& y) const
073: {
074:     x = m_x1 + (m_x2 - m_x1) / 2.0;
075:     y = m_y2 + (m_y1 - m_y2) / 2.0;
076: }
077: 
078: void Rectangle::AdjustWidth(double width)
079: {
080:     m_x2 = m_x1 + width;
081:     this->Normalize();
082: }
083: 
084: void Rectangle::AdjustHeight(double height)
085: {
086:     m_y2 = m_y1 - height;
087:     this->Normalize();
088: }
089: 
090: void Rectangle::Move(double x, double y)
091: {
092:     m_x1 += x;
093:     m_y1 += y;
094:     m_x2 += x;
095:     m_y2 += y;
096: }
097: 
098: Rectangle Rectangle::Intersection(const Rectangle& r) const
099: {
100:     double x1, y1, x2, y2;
101: 
102:     if (m_x2 <= r.m_x1 || m_x1 >= r.m_x2 ||
103:         m_y1 <= r.m_y2 || m_y2 >= r.m_y1)
104:     {
105:         return Rectangle();
106:     }
107: 
108:     if (m_x1 < r.m_x1)
109:     {
110:         x1 = r.m_x1;
111:     }
112:     else
113:     {
114:         x1 = m_x1;
115:     }
116: 
117:     if (m_x2 < r.m_x2)
118:     {
119:         x2 = m_x2;
120:     }
121:     else
122:     {
123:         x2 = r.m_x2;
124:     }
125: 
126:     if (m_y1 > r.m_y1)
127:     {
128:         y1 = r.m_y1;
129:     }
130:     else
131:     {
132:         y1 = m_y1;
133:     }
134: 
135:     if (m_y2 > r.m_y2)
136:     {
137:         y2 = m_y2;
138:     }
139:     else
140:     {
141:         y2 = r.m_y2;
142:     }
143: 
144:     return Rectangle(x1, y1, x2, y2);
145: }
146: 
147: // output
148: ostream& operator << (ostream& os, const Rectangle& r)
149: {
150:     os << "Rectangle: (" << r.m_x1 << ',' << r.m_y1 << "),("
151:         << r.m_x2 << ',' << r.m_y2 << ") ";
152:     os << "[Area=" << r.Area() << ", Circumference=" << r.Circumference()
153:         << ", Diagonal=" << r.Diagonal() << ", IsSquare=" << r.IsSquare() << ']';
154: 
155:     return os;
156: }
157: 
158: // private helper methods
159: void Rectangle::Normalize()
160: {
161:     if (m_x1 > m_x2)
162:     {
163:         double tmp = m_x1;
164:         m_x1 = m_x2;
165:         m_x2 = tmp;
166:     }
167: 
168:     if (m_y1 < m_y2)
169:     {
170:         double tmp = m_y1;
171:         m_y1 = m_y2;
172:         m_y2 = tmp;
173:     }
174: }

Beispiel 2. Klasse Rectangle: Implementierung Variante 1.


Es folgt ein zweiter Lösungsvorschlag auf Basis zweier Klassen Klassen Point und Rectangle (Listing 3, Listing 4, Listing 5 und Listing 6):

01: class Point
02: {
03: private:
04:     double m_x;
05:     double m_y;
06: 
07: public:
08:     // c'tor(s)
09:     Point();
10:     Point(double x, double y);
11: 
12:     // getter/setter
13:     double GetX() const { return m_x; }
14:     double GetY() const { return m_y; }
15:     void SetX(double x) { m_x = x; };
16:     void SetY(double y) { m_y = y; };
17: 
18:     // output
19:     friend ostream& operator << (ostream& os, const Point& p);
20: };

Beispiel 3. Klasse Point: Schnittstelle Variante 2.


01: #include <iostream>
02: using namespace std;
03: 
04: #include "Point.h"
05: 
06: // c'tor(s)
07: Point::Point()
08: {
09:     m_x = 0;
10:     m_y = 0;
11: }
12: 
13: Point::Point(double x, double y)
14: {
15:     m_x = x;
16:     m_y = y;
17: }
18: 
19: // output
20: ostream& operator << (ostream& os, const Point& p)
21: {
22:     os << '(' << p.m_x << ',' << p.m_y << ')';
23:     return os;
24: }

Beispiel 4. Klasse Point: Implementierung Variante 2.


01: class Rectangle
02: {
03: private:
04:     Point m_p1;
05:     Point m_p2;
06: 
07: public:
08:     // c'tors
09:     Rectangle();
10:     Rectangle(Point p1, Point p2);
11:     Rectangle(double x1, double y1, double x2, double y2);
12: 
13:     // getter/setter
14:     double GetX1() const { return m_p1.GetX(); };
15:     double GetY1() const { return m_p1.GetY(); };
16:     double GetX2() const { return m_p2.GetX(); };
17:     double GetY2() const { return m_p2.GetY(); };
18:     Point GetLeftUpper() const { return m_p1; };
19:     Point GetRightLower() const { return m_p2; };
20:     void SetX1(double x);
21:     void SetY1(double y);
22:     void SetX2(double x);
23:     void SetY2(double y);
24:     void SetLeftUpper(Point p);
25:     void SetRightLower(Point p);
26: 
27:     // public interface
28:     double Circumference() const;
29:     double Diagonal() const;
30:     double Area() const;
31:     bool IsSquare() const;
32:     Point Center() const;
33:     void AdjustWidth(double width);
34:     void AdjustHeight(double height);
35:     void Move(double x, double y);
36:     Rectangle Intersection(const Rectangle& rect) const;
37: 
38: private:
39:     // private helper methods
40:     void Normalize();
41: 
42:     // output
43:     friend ostream& operator << (ostream& os, const Rectangle& r);
44: };

Beispiel 5. Klasse Rectangle: Schnittstelle Variante 2.


001: #include <iostream>
002: #include <cmath>
003: using namespace std;
004: 
005: #include "Point.h"
006: #include "Rectangle.h"
007: 
008: // c'tor(s)
009: Rectangle::Rectangle() : m_p1(0, 0), m_p2(0, 0)
010: {
011: }
012: 
013: Rectangle::Rectangle(Point p1, Point p2) : m_p1(p1), m_p2(p2)
014: {
015:     this->Normalize();
016: }
017: 
018: Rectangle::Rectangle(double x1, double y1, double x2, double y2)
019:     : m_p1(x1, y1), m_p2(x2, y2)
020: {
021:     this->Normalize();
022: }
023: 
024: // getter/setter
025: void Rectangle::SetX1(double x)
026: {
027:     m_p1.SetX(x);
028:     this->Normalize();
029: }
030: 
031: void Rectangle::SetY1(double y)
032: {
033:     m_p1.SetY(y);
034:     this->Normalize();
035: }
036: 
037: void Rectangle::SetX2(double x)
038: {
039:     m_p2.SetX(x);
040:     this->Normalize();
041: }
042: 
043: void Rectangle::SetY2(double y)
044: {
045:     m_p2.SetY(y);
046:     this->Normalize();
047: }
048: 
049: void Rectangle::SetLeftUpper(Point p)
050: {
051:     m_p1 = p;
052:     this->Normalize();
053: }
054: 
055: void Rectangle::SetRightLower(Point p)
056: {
057:     m_p2 = p;
058:     this->Normalize();
059: }
060: 
061: // methods
062: double Rectangle::Circumference() const
063: {
064:     return 2 * ((m_p2.GetX() - m_p1.GetX()) + (m_p1.GetY() - m_p2.GetY()));
065: }
066: 
067: double Rectangle::Diagonal() const
068: {
069:     return sqrt((
070:         (m_p2.GetX() - m_p1.GetX()) * (m_p2.GetX() - m_p1.GetX()) +
071:         (m_p1.GetY() - m_p2.GetY()) * (m_p1.GetY() - m_p2.GetY()))
072:         );
073: }
074: 
075: double Rectangle::Area() const
076: {
077:     return (m_p2.GetX() - m_p1.GetX()) * (m_p1.GetY() - m_p2.GetY());
078: }
079: 
080: bool Rectangle::IsSquare() const
081: {
082:     return (m_p2.GetX() - m_p1.GetX()) == (m_p1.GetY() - m_p2.GetY());
083: }
084: 
085: Point Rectangle::Center() const
086: {
087:     return Point(
088:         m_p1.GetX() + (m_p2.GetX() - m_p1.GetX()) / 2.0,
089:         m_p2.GetY() + (m_p1.GetY() - m_p2.GetY()) / 2.0);
090: }
091: 
092: void Rectangle::AdjustWidth(double width)
093: {
094:     m_p2.SetX(m_p1.GetX() + width);
095:     this->Normalize();
096: }
097: 
098: void Rectangle::AdjustHeight(double height)
099: {
100:     m_p2.SetY(m_p1.GetY() - height);
101:     this->Normalize();
102: }
103: 
104: void Rectangle::Move(double x, double y)
105: {
106:     m_p1.SetX(m_p1.GetX() + x);
107:     m_p1.SetY(m_p1.GetY() + y);
108:     m_p2.SetX(m_p2.GetX() + x);
109:     m_p2.SetY(m_p2.GetY() + y);
110: }
111: 
112: Rectangle Rectangle::Intersection(const Rectangle& r) const
113: {
114:     double x1, y1, x2, y2;
115: 
116:     if (m_p2.GetX() <= r.m_p1.GetX() || m_p1.GetX() >= r.m_p2.GetX() ||
117:         m_p1.GetY() <= r.m_p2.GetY() || m_p2.GetY() >= r.m_p1.GetY())
118:     {
119:         return Rectangle();
120:     }
121: 
122:     if (m_p1.GetX() < r.m_p1.GetX())
123:     {
124:         x1 = r.m_p1.GetX();
125:     }
126:     else
127:     {
128:         x1 = m_p1.GetX();
129:     }
130: 
131:     if (m_p2.GetX() < r.m_p2.GetX())
132:     {
133:         x2 = m_p2.GetX();
134:     }
135:     else
136:     {
137:         x2 = r.m_p2.GetX();
138:     }
139: 
140:     if (m_p1.GetY() > r.m_p1.GetY())
141:     {
142:         y1 = r.m_p1.GetY();
143:     }
144:     else
145:     {
146:         y1 = m_p1.GetY();
147:     }
148: 
149:     if (m_p2.GetY() > r.m_p2.GetY())
150:     {
151:         y2 = m_p2.GetY();
152:     }
153:     else
154:     {
155:         y2 = r.m_p2.GetY();
156:     }
157: 
158:     return Rectangle(x1, y1, x2, y2);
159: }
160: 
161: // output
162: ostream& operator << (ostream& os, const Rectangle& r)
163: {
164:     os << "Rectangle: " << r.GetLeftUpper() << ',' << r.GetRightLower() << ' ';
165:     os << "[Area=" << r.Area() << ", Circumference=" << r.Circumference()
166:         << ", Diagonal=" << r.Diagonal() << ", IsSquare=" << r.IsSquare() << ']';
167: 
168:     return os;
169: }
170: 
171: // private helper methods
172: void Rectangle::Normalize()
173: {
174:     if (m_p1.GetX() > m_p2.GetX())
175:     {
176:         double tmp = m_p1.GetX();
177:         m_p1.SetX(m_p2.GetX());
178:         m_p2.SetX(tmp);
179:     }
180: 
181:     if (m_p1.GetY() < m_p2.GetY())
182:     {
183:         double tmp = m_p1.GetY();
184:         m_p1.SetY(m_p2.GetY());
185:         m_p2.SetY(tmp);
186:     }
187: }

Beispiel 6. Klasse Rectangle: Implementierung Variante 2.


Da wir die Klasse Point auch an der öffentlichen Schnittstelle der Klasse Rectangle in Erscheinung treten lassen, unterscheiden sich die beiden Testrahmen geringfügig. In Listing 7 finden Sie den Testrahmen für die Klasse Rectangle in der ersten Variante vor, der zweite Testrahmen weicht davon nur minimal ab:

001: #include <iostream>
002: using namespace std;
003: 
004: #include "Rectangle.h"
005: 
006: // testing function prototypes
007: void test01_ctors();
008: void test02_methods();
009: void test03_center();
010: void test04_adjust();
011: void test05_move();
012: void test06_intersection();
013: void test07();
014: 
015: void main()
016: {
017:     test01_ctors();
018:     test02_methods();
019:     test03_center();
020:     test04_adjust();
021:     test05_move();
022:     test06_intersection();
023:     getchar();
024: }
025: 
026: void test01_ctors()
027: {
028:     Rectangle rect1;
029:     cout << rect1 << endl;
030:     Rectangle rect2(3, 3, 5, 5);
031:     cout << rect2 << endl;
032:     Rectangle rect3(3, 3, 5, 1);
033:     cout << rect3 << endl;
034:     Rectangle rect4(3, 3, 1, 1);
035:     cout << rect4 << endl;
036:     Rectangle rect5(3, 3, 1, 5);
037:     cout << rect5 << endl;
038: }
039: 
040: void test02_methods()
041: {
042:     Rectangle rect(3, 4, 9, 10);
043:     cout << rect << endl;
044:     cout << "Circumference: " << rect.Circumference() << endl;
045:     cout << "Diagonal:      " << rect.Diagonal() << endl;
046:     cout << "Area:          " << rect.Area() << endl;
047:     cout << "IsSquare:      " << rect.IsSquare() << endl;
048: }
049: 
050: void test03_center()
051: {
052:     double x, y;
053:     Rectangle rect1(1, 3, 3, 1);
054:     cout << rect1 << endl;
055:     rect1.Center(x, y);
056:     cout << "Center: (" << x << "," << y << ')' << endl;
057: 
058:     Rectangle rect2(1, 4, 4, 1);
059:     cout << rect2 << endl;
060:     rect2.Center(x, y);
061:     cout << "Center: (" << x << "," << y << ')' << endl;
062: }
063: 
064: void test04_adjust()
065: {
066:     Rectangle rect(3, 3, 1, 1);
067:     cout << rect << endl;
068:     rect.AdjustWidth(3);
069:     cout << rect << endl;
070:     rect.AdjustWidth(-1);
071:     cout << rect << endl;
072:     rect.AdjustHeight(3);
073:     cout << rect << endl;
074:     rect.AdjustHeight(-1);
075:     cout << rect << endl;
076: }
077: 
078: void test05_move()
079: {
080:     Rectangle rect(1, 1, 4, 5);
081:     cout << rect << endl;
082:     rect.Move(5, -5);
083:     cout << rect << endl;
084: }
085: 
086: void test06_intersection()
087: {
088:     Rectangle rect1(4, 8, 9, 5);
089:     Rectangle rect2(2, 10, 8, 6);
090:     Rectangle rect = rect1.Intersection(rect2);
091:     cout << rect << endl;
092: 
093:     Rectangle rect3(7, 9, 9, 4);
094:     rect = rect1.Intersection(rect3);
095:     cout << rect << endl;
096: 
097:     rect = rect3.Intersection(rect3);
098:     cout << rect << endl;
099: 
100:     Rectangle rect4(6, 7, 10, 5);
101:     rect = rect1.Intersection(rect4);
102:     cout << rect << endl;
103: }

Beispiel 7. Testrahmen für Variante 1.


Bei der Ausführung des Programms aus Listing 7 sollten Sie folgendes Resultat erhalten:

Rectangle: (0,0),(0,0) [Area=0, Circumference=0, Diagonal=0, IsSquare=1]
Rectangle: (3,5),(5,3) [Area=4, Circumference=8, Diagonal=2.82843, IsSquare=1]
Rectangle: (3,3),(5,1) [Area=4, Circumference=8, Diagonal=2.82843, IsSquare=1]
Rectangle: (1,3),(3,1) [Area=4, Circumference=8, Diagonal=2.82843, IsSquare=1]
Rectangle: (1,5),(3,3) [Area=4, Circumference=8, Diagonal=2.82843, IsSquare=1]
Rectangle: (3,10),(9,4) [Area=36, Circumference=24, Diagonal=8.48528, IsSquare=1]
Circumference: 24
Diagonal:      8.48528
Area:          36
IsSquare:      1
Rectangle: (1,3),(3,1) [Area=4, Circumference=8, Diagonal=2.82843, IsSquare=1]
Center: (2,2)
Rectangle: (1,4),(4,1) [Area=9, Circumference=12, Diagonal=4.24264, IsSquare=1]
Center: (2.5,2.5)
Rectangle: (1,3),(3,1) [Area=4, Circumference=8, Diagonal=2.82843, IsSquare=1]
Rectangle: (1,3),(4,1) [Area=6, Circumference=10, Diagonal=3.60555, IsSquare=0]
Rectangle: (0,3),(1,1) [Area=2, Circumference=6, Diagonal=2.23607, IsSquare=0]
Rectangle: (0,3),(1,0) [Area=3, Circumference=8, Diagonal=3.16228, IsSquare=0]
Rectangle: (0,4),(1,3) [Area=1, Circumference=4, Diagonal=1.41421, IsSquare=1]
Rectangle: (1,5),(4,1) [Area=12, Circumference=14, Diagonal=5, IsSquare=0]
Rectangle: (6,0),(9,-4) [Area=12, Circumference=14, Diagonal=5, IsSquare=0]
Rectangle: (4,8),(8,6) [Area=8, Circumference=12, Diagonal=4.47214, IsSquare=0]
Rectangle: (7,8),(9,5) [Area=6, Circumference=10, Diagonal=3.60555, IsSquare=0]
Rectangle: (7,9),(9,4) [Area=10, Circumference=14, Diagonal=5.38516, IsSquare=0]
Rectangle: (6,7),(9,5) [Area=6, Circumference=10, Diagonal=3.60555, IsSquare=0]