--- /dev/null
+//
+// structs.cpp: Useful structs to describe objects
+//
+// Part of the Architektonas Project
+// (C) 2022 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 01/13/2022 Created this file
+
+#include "structs.h"
+#include <math.h>
+#include "mathconstants.h"
+
+const char objName[OTCount][16] = {
+ "None", "Line", "Circle", "Ellipse", "Arc", "Polygon", "Dimension",
+ "Spline", "Text", "Container"
+};
+const char dimName[DTCount][32] = {
+ "Linear", "Vertical", "Horizontal", "Radial", "Diametric",
+ "Circumferential", "Angular", "Leader"
+};
+
+const char buShortName[BUCount][8] = {
+ "in", "ft", "yd", "mi", "mm", "cm", "m", "km"
+};
+
+const double buInInches[BUCount] = { 1.0, 12.0, 36.0, 1.0/25.4, 1.0/2.54, 1.0/0.0254, 1.0/0.0000254 };
+
+//
+// struct Line
+//
+Line::Line(): type(OTLine), id(Global::objectID++), selected(false), hovered(false), hitObject(false)
+{
+ hitPoint[0] = hitPoint[1] = false;
+}
+
+Line::Line(Vector pt1, Vector pt2, float th/*= 1.0*/, uint32_t c/* = 0*/, int l/*= LSSolid*/): type(OTLine), id(Global::objectID++), layer(0), color(c), thickness(th), style(l), selected(false), hovered(false), hitObject(false)
+{
+ p[0] = pt1;
+ p[1] = pt2;
+ hitPoint[0] = hitPoint[1] = false;
+}
+
+Vector Line::Vect(void)
+{
+ return Vector(p[0], p[1]);
+}
+
+Vector Line::Unit(void)
+{
+ return Vector(p[0], p[1]).Unit();
+}
+
+double Line::Length(void)
+{
+ return Vector(p[0], p[1]).Magnitude();
+}
+
+//
+// struct Circle
+//
+Circle::Circle(): type(OTCircle), id(Global::objectID++)
+{
+}
+
+Circle::Circle(Vector pt1, double r, float th/*= 1.0*/, uint32_t c/*= 0*/, int l/*= LSSolid*/): type(OTCircle), id(Global::objectID++), layer(0), color(c), thickness(th), style(l), selected(false), hovered(false), hitObject(false)
+{
+ p[0] = pt1;
+ radius[0] = r;
+ hitPoint[0] = hitPoint[1] = false;
+}
+
+//
+// struct Ellipse
+//
+Ellipse::Ellipse(): type(OTEllipse), id(Global::objectID++)
+{
+}
+
+Ellipse::Ellipse(Vector pt1, Vector pt2, double r1, double r2, float th/*= 1.0*/, uint32_t c/*= 0*/, int l/*= LSSolid*/): type(OTEllipse), id(Global::objectID++), layer(0), color(c), thickness(th), style(l), selected(false), hovered(false), hitObject(false)
+{
+ p[0] = pt1;
+ p[1] = pt2;
+ radius[0] = r1;
+ radius[1] = r2;
+ hitPoint[0] = hitPoint[1] = false;
+}
+
+//
+// struct Arc
+//
+Arc::Arc(): type(OTArc), id(Global::objectID++)
+{
+}
+
+Arc::Arc(Vector pt1, double r, double a1, double a2, float th/*= 1.0*/, uint32_t c/*= 0*/, int l/*= LSSolid*/): type(OTArc), id(Global::objectID++), layer(0), color(c), thickness(th), style(l), selected(false), hovered(false), hitObject(false)
+{
+ p[0] = pt1; radius[0] = r; angle[0] = a1, angle[1] = a2; hitPoint[0] = hitPoint[1] = hitPoint[2] = false;
+}
+
+Rect Arc::Bounds(void)
+{
+ // Swap start & end angles if the span is negative...
+ double start = (angle[1] > 0 ? angle[0] : angle[0] + angle[1]);
+ double end = (angle[1] > 0 ? angle[0] + angle[1] : angle[0]);
+
+ // If the end of the arc is before the beginning, add 360 degrees
+ // to it
+ if (end < start)
+ end += TAU;
+
+ // Find which quadrant the start angle is in (consider the beginning of
+ // the 90° angle to be in the quadrant, the end to be in the next
+ // quadrant). Then, divide the span into 90° segments. The integer
+ // portion is the definite axis crossings; the remainder needs more
+ // scrutiny. There will be an additional axis crossing if the the sum of
+ // the start angle and the remainder is > 90°.
+ int quadStart = (int)(start / QTR_TAU);
+ double qsRemain = start - ((double)quadStart * QTR_TAU);
+ int numAxes = (int)((fabs(angle[1]) + qsRemain) / QTR_TAU);
+
+ Rect bounds(sin(start), cos(start), sin(end), cos(end));
+ const double box[4] = { 1.0, -1.0, -1.0, 1.0 };
+
+ for(int i=0; i<numAxes; i++)
+ bounds[(quadStart + i) % 4] = box[(quadStart + i) % 4];
+
+ bounds *= radius[0];
+ bounds.Translate(p[0]);
+
+ return bounds;
+}
+
+//
+// struct Dimension
+//
+Dimension::Dimension(): type(OTDimension), id(Global::objectID++), selected(false), hovered(false), hitObject(false)
+{
+ hitPoint[0] = hitPoint[1] = hitPoint[2] = hitPoint[3] = hitPoint[4] = false;
+}
+
+Dimension::Dimension(Vector pt1, Vector pt2, DimensionType dt/*= DTLinear*/, double offs/*= 0*/, float th/*= 1.0*/, uint32_t c/*= 0x0000FF*/, int l/*= LSSolid*/): type(OTDimension), id(Global::objectID++), layer(0), color(c), thickness(th), style(l), selected(false), hovered(false), hitObject(false), subtype(dt), offset(offs)
+{
+ p[0] = pt1;
+ p[1] = pt2;
+ hitPoint[0] = hitPoint[1] = hitPoint[2] = hitPoint[3] = hitPoint[4] = false;
+}
+
+//
+// struct Text
+//
+Text::Text(): type(OTText), id(Global::objectID++)
+{
+}
+
+Text::Text(Vector pt1, const char * str, float th/*= 10.0*/, uint32_t c/*= 0*/): type(OTText), id(Global::objectID++), layer(0), color(c), thickness(th), style(LSSolid), selected(false), hovered(false), hitObject(false), measured(false), s(str)
+{
+ p[0] = pt1;
+ angle[0] = 0;
+}
+
+//prolly don't need this, as this just a special case of a polyline...
+#if 0
+//struct Polygon {
+ Polygon(): type(OTPolygon), id(Global::objectID++) {}
+#endif
+
+//
+// struct Polyline
+//
+Polyline::Polyline(float th/*= 1.0*/, uint32_t c/*= 0*/, int l/*= LSSolid*/): type(OTPolyline), id(Global::objectID++), layer(0), color(c), thickness(th), style(l), selected(false), hovered(false), hitObject(false)
+{
+}
+
+Polyline::Polyline(std::vector<Point> pts, float th/*= 1.0*/, uint32_t c/*= 0*/, int l/*= LSSolid*/): type(OTPolyline), id(Global::objectID++), layer(0), color(c), thickness(th), style(l), selected(false), hovered(false), hitObject(false)
+{
+ points = pts;
+}
+
+void Polyline::Add(Point p)
+{
+ points.push_back(p);
+}
+
+void Polyline::Add(std::vector<Point> pts)
+{
+ points.insert(points.end(), pts.begin(), pts.end());
+}
+
+Rect Polyline::Bounds(void)
+{
+ Rect bounds(points[0]);
+
+ for(long unsigned int i=0; i<(points.size()-1); i++)
+ {
+/*
+Need to check for arc bounds as well here...
+*/
+// bounds += points[i];
+ bounds += points[i + 1];
+ }
+
+ return bounds;
+}
+
+void Polyline::Translate(Point delta)
+{
+ for(long unsigned int i=0; i<points.size(); i++)
+ points[i] += delta;
+}
+
+//
+// struct Spline
+//
+Spline::Spline(): type(OTSpline), id(Global::objectID++)
+{
+}
+
+//
+// struct Container
+//
+Container::Container(bool tl/*= false*/): type(OTContainer), id(Global::objectID++), selected(false), hovered(false), hitObject(false), topLevel(tl), clicked(NULL), baseUnit(0), unitStyle(0), decimalPrecision(3), fractionalPrecision(4)
+{
+}
+
+void Container::Add(void * obj)
+{
+ objects.push_back(obj);
+}
+
+void Container::Add(VPVector objs)
+{
+ objects.insert(objects.end(), objs.begin(), objs.end());
+}
+
+// void DeleteContents(void) {}
+/* void DeleteContents(Container * c)
+ {
+ std::vector<void *>::iterator i;
+
+ for(i=c->objects.begin(); i!=c->objects.end(); i++)
+ {
+ Object * obj = (Object *)(*i);
+
+ if (obj->type == OTContainer)
+ DeleteContainer((Container *)obj);
+
+ delete *i;
+ }
+ }*/