Below some examples of models for geometrical shapes are given.
In certain cases constructors are defined which allow for implicit conversions between some of these types, such as from Square to Rectangle. This represents the fact that every Square value is a Rectangle value.
Note that CEDA models and variants don't support member functions, instead there is an emphasis on defining free functions on value types.
$model Point
{
float32 x;
float32 y;
};
inline float32 Perim(const Point& p)
{
return 0;
}
inline float32 Area(const Point& p)
{
return 0;
}
inline float32 Dist(const Point& p1, const Point& p2)
{
float32 dx = p2.x - p1.x;
float32 dy = p2.y - p1.y;
return sqrt(dx*dx + dy*dy);
}
$model Line
{
Point p1;
Point p2;
};
inline float32 Length(const Line& l)
{
return Dist(l.p1, l.p2);
}
inline float32 Perim(const Line& l)
{
return 2*Length(l);
}
inline float32 Area(const Line& l)
{
return 0;
}
$model Square
{
Point p1; // bottom left corner
float32 w; // width and height
};
inline float32 Width(const Square& s)
{
return s.w;
}
inline float32 Height(const Square& s)
{
return s.w;
}
inline Point TopLeft(const Square& s)
{
return Point(s.p1.x, s.p1.y + s.w);
}
inline Point TopRight(const Square& s)
{
return Point(s.p1.x + s.w, s.p1.y + s.w);
}
inline Point BotLeft(const Square& s)
{
return s.p1;
}
inline Point BotRight(const Square& s)
{
return Point(s.p1.x + s.w, s.p1.y);
}
float32 Perim(const Square& s)
{
return 4 * s.w;
}
inline float32 Area(const Square& s)
{
return s.w * s.w;
}
$model Rect
{
Point p1; // bottom left corner
Point p2; // top right corner
// Note that this single argument constructor is not declared 'explicit' and therefore
// allows for implicit conversion from Square to Rect.
$$(const Square& s) : p1(s.p1), p2(p1.x+s.w, p1.y+s.w) {}
};
inline float32 Width(const Rect& r)
{
return r.p2.x - r.p1.x;
}
inline float32 Height(const Rect& r)
{
return r.p2.y - r.p1.y;
}
inline float32 Perim(const Rect& r)
{
return 2*(Width(r) + Height(r));
}
inline float32 Area(const Rect& r)
{
return Width(r) * Height(r);
}
inline Point TopLeft(const Rect& r)
{
return Point(r.p1.x, r.p2.y);
}
inline Point TopRight(const Rect& r)
{
return r.p2;
}
inline Point BotLeft(const Rect& r)
{
return r.p1;
}
inline Point BotRight(const Rect& r)
{
return Point(r.p2.x, r.p1.y);
}
inline const Rect& BoundingRect(const Line& l)
{
return (const Rect&) l;
}
const float32 PI = 3.14159f;
$model Circle
{
Point c;
float32 r;
};
inline float32 Width(const Circle& c)
{
return 2*c.r;
}
inline float32 Height(const Circle& c)
{
return 2*c.r;
}
float32 Perim(const Circle& c)
{
return 2*PI*c.r;
}
float32 Area(const Circle& c)
{
return PI*c.r*c.r;
}
$model Polygon
{
xvector<Point> V;
// Unfortunately C++ doesn't take transitive closure on implicit conversion.
// So even though have implicit conversion from Square to Rect, and Rect to Polygon
// we don't automatically get the conversion from Square to Polygon.
$$(const Square& s)
{
V.push_back(TopLeft(s));
V.push_back(TopRight(s));
V.push_back(BotRight(s));
V.push_back(BotLeft(s));
}
$$(const Rect& r)
{
V.push_back(TopLeft(r));
V.push_back(TopRight(r));
V.push_back(BotRight(r));
V.push_back(BotLeft(r));
}
};
// Returns segment from vertex i-1 to i
inline Line Segment(const Polygon& p, ssize_t i)
{
ssize_t previ = (i == 0 ? p.V.size() : i) - 1;
return Line(p.V[previ], p.V[i]);
}
inline ssize_t NumVertices(const Polygon& p)
{
return p.V.size();
}
inline ssize_t NumSegments(const Polygon& p)
{
return p.V.size();
}
float32 Perim(const Polygon& p)
{
float32 P = 0;
for (ssize_t i=0 ; i < NumSegments(p) ; ++i)
{
P += Length(Segment(p,i));
}
return P;
}
float32 Area(const Polygon& p)
{
float32 A = 0;
for (ssize_t i=0 ; i < NumSegments(p) ; ++i)
{
Line l = Segment(p,i);
A += (l.p2.x - l.p1.x) * (l.p1.y + l.p2.y);
}
return A/2;
}