From: Shamus Hammons Date: Fri, 14 Jan 2022 01:20:08 +0000 (-0600) Subject: Further progress on Polylines: Polylines can be selected and moved. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=architektonas;a=commitdiff_plain;h=10cf4c797bed05831e976068b7504908279dc997 Further progress on Polylines: Polylines can be selected and moved. This required a bit of shuffling under the hood to support this, but the short version is that now Polylines will properly respond to mouse movement near their contours and control points. They still can't be modified or created as of yet, but that's coming. :-) Also, slight change to Circle and Arc handling: now clicking on their contours will translate them instead of changing their radii. Holding SHIFT will allow changing their radii. --- diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 39196a7..e65bbe9 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -459,31 +459,18 @@ void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool { painter->SetBrush(QBrush(Qt::NoBrush)); Polyline * pl = (Polyline *)obj; - Point lastp; - double lastbump; - for(VPVectorIter i=pl->points.begin(); i!=pl->points.end(); i++) + for(long unsigned int i=0; i<(pl->points.size()-1); i++) { - if (i != pl->points.begin()) - { - Point p = ((Object *)(*i))->p[0]; - double bump = ((Object *)(*i))->length; - - if (lastbump == 0) - painter->DrawLine(lastp, p); - else - { - Arc a = Geometry::Unpack(lastp, p, lastbump); - painter->DrawArc(a.p[0], a.radius[0], a.angle[0], a.angle[1]); - } + Point p1 = pl->points[i]; + Point p2 = pl->points[i + 1]; - lastp = p; - lastbump = bump; - } + if (p1.b == 0) + painter->DrawLine(p1, p2); else { - lastp = ((Object *)(*i))->p[0]; - lastbump = ((Object *)(*i))->length; + Arc a = Geometry::Unpack(p1, p2, p1.b); + painter->DrawArc(a.p[0], a.radius[0], a.angle[0], a.angle[1]); } } @@ -2397,6 +2384,7 @@ Point DrawingView::SnapPointToGrid(Point point) point.y = floor(point.y); point.z = 0; // Make *sure* Z doesn't go anywhere!!! point *= Global::gridSpacing; + return point; } @@ -2441,68 +2429,14 @@ Rect DrawingView::GetObjectExtents(Object * obj) case OTArc: { Arc * a = (Arc *)obj; + rect = a->Bounds(); + break; + } - double start = a->angle[0]; - double end = start + a->angle[1]; - - // Swap 'em if the span is negative... - if (a->angle[1] < 0) - { - end = a->angle[0]; - start = end + a->angle[1]; - } - - rect = Rect(Point(cos(start), sin(start)), Point(cos(end), sin(end))); - - // 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°. -*/ -#if 1 - int quadStart = (int)(a->angle[0] / QTR_TAU); - double qsRemain = a->angle[0] - ((double)quadStart * QTR_TAU); - int numAxes = (int)((a->angle[1] + qsRemain) / QTR_TAU); - - double axis[4] = { 0, 0, 0, 0 }; - axis[0] = rect.t, axis[1] = rect.l, axis[2] = rect.b, axis[3] = rect.r; - double box[4] = { 1.0, -1.0, -1.0, 1.0 }; - - for(int i=0; i QTR_TAU)) - rect.t = 1.0; - - if ((start < HALF_TAU) && (end > HALF_TAU)) - rect.l = -1.0; - - if ((start < THREE_QTR_TAU) && (end > THREE_QTR_TAU)) - rect.b = -1.0; - - if ((start < TAU) && (end > TAU)) - rect.r = 1.0; - - if ((start < (TAU + QTR_TAU)) && (end > (TAU + QTR_TAU))) - rect.t = 1.0; - - if ((start < (TAU + HALF_TAU)) && (end > (TAU + HALF_TAU))) - rect.l = -1.0; - - if ((start < (TAU + THREE_QTR_TAU)) && (end > (TAU + THREE_QTR_TAU))) - rect.b = -1.0; -#endif - - rect *= a->radius[0]; - rect.Translate(a->p[0]); + case OTPolyline: + { + Polyline * p = (Polyline *)obj; + rect = p->Bounds(); break; } @@ -2569,58 +2503,7 @@ void DrawingView::CheckObjectBounds(void) case OTArc: { Arc * a = (Arc *)obj; - - double start = a->angle[0]; - double end = start + a->angle[1]; - - // Swap 'em if the span is negative... - if (a->angle[1] < 0) - { - end = a->angle[0]; - start = end + a->angle[1]; - } - - // If the end of the arc is before the beginning, add 360 degrees - // to it - if (end < start) - end += TAU; - -#if 1 - int quadStart = (int)(a->angle[0] / QTR_TAU); - double qsRemain = a->angle[0] - ((double)quadStart * QTR_TAU); - int numAxes = (int)((a->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 QTR_TAU)) - bounds.t = 1.0; - - if ((start < HALF_TAU) && (end > HALF_TAU)) - bounds.l = -1.0; - - if ((start < THREE_QTR_TAU) && (end > THREE_QTR_TAU)) - bounds.b = -1.0; - - if ((start < TAU) && (end > TAU)) - bounds.r = 1.0; - - if ((start < (TAU + QTR_TAU)) && (end > (TAU + QTR_TAU))) - bounds.t = 1.0; - - if ((start < (TAU + HALF_TAU)) && (end > (TAU + HALF_TAU))) - bounds.l = -1.0; - - if ((start < (TAU + THREE_QTR_TAU)) && (end > (TAU + THREE_QTR_TAU))) - bounds.b = -1.0; -#endif - - bounds *= a->radius[0]; - bounds.Translate(a->p[0]); + Rect bounds = a->Bounds(); if (selection.Contains(bounds)) a->selected = true; @@ -2631,15 +2514,9 @@ void DrawingView::CheckObjectBounds(void) case OTPolyline: { Polyline * pl = (Polyline *)obj; - Rect r(((Object *)(pl->points[0]))->p[0]); + Rect bounds = pl->Bounds(); - for(int i=0; i<(pl->points.size()-1); i++) - { - r += ((Object *)(pl->points[i]))->p[0]; - r += ((Object *)(pl->points[i + 1]))->p[0]; - } - - if (selection.Contains(r)) + if (selection.Contains(bounds)) pl->selected = true; break; @@ -2745,7 +2622,7 @@ bool DrawingView::HitTest(Object * obj, Point point) else if ((distance * Global::zoom) < 5.0) obj->hitObject = true; - obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitObject ? true : false); + obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitObject); if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHO != obj->hitObject)) needUpdate = true; @@ -2768,7 +2645,7 @@ bool DrawingView::HitTest(Object * obj, Point point) else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) obj->hitObject = true; - obj->hovered = (obj->hitPoint[0] || obj->hitObject ? true : false); + obj->hovered = (obj->hitPoint[0] || obj->hitObject); if ((oldHP != obj->hitPoint[0]) || (oldHO != obj->hitObject)) needUpdate = true; @@ -2790,7 +2667,7 @@ bool DrawingView::HitTest(Object * obj, Point point) // Get the span that we're pointing at... double span = angle - obj->angle[0]; - // N.B.: Still need to hit test the arc start & arc span handles... + // N.B.: Still need to hit test the arc start & arc span handles... [looks like it's DONE?] double spanAngle = obj->angle[0] + obj->angle[1]; Point handle1 = obj->p[0] + (Vector(cos(obj->angle[0]), sin(obj->angle[0])) * obj->radius[0]); Point handle2 = obj->p[0] + (Vector(cos(spanAngle), sin(spanAngle)) * obj->radius[0]); @@ -2818,7 +2695,7 @@ bool DrawingView::HitTest(Object * obj, Point point) else if (((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) && (span < obj->angle[1])) obj->hitObject = true; - obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitObject ? true : false); + obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitObject); if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHO != obj->hitObject)) needUpdate = true; @@ -2826,6 +2703,86 @@ bool DrawingView::HitTest(Object * obj, Point point) break; } + case OTPolyline: + { + Polyline * pl = (Polyline *)obj; + bool oldHP0 = pl->hitPoint[0], oldHO = pl->hitObject; + pl->hitPoint[0] = pl->hitObject = false; + + for(long unsigned int i=0; i<(pl->points.size()-1); i++) + { + Point p1 = pl->points[i]; + Point p2 = pl->points[i + 1]; + + double dist1 = Vector::Magnitude(p1, point) * Global::zoom; + double dist2 = Vector::Magnitude(p2, point) * Global::zoom; + + // Check for endpoints of lines and/or arcs first + if (dist1 < 8.0) + { + pl->hitPoint[0] = true; + hoverPoint = p1; + hoverPointValid = true; + pl->ptNum = i; + } + else if (dist2 < 8.0) + { + pl->hitPoint[0] = true; + hoverPoint = p2; + hoverPointValid = true; + pl->ptNum = i + 1; + } + // Check for object (line/arc) last + else if (p1.b == 0) + { + double t = Geometry::ParameterOfLineAndPoint(p1, p2, point); + double objDist; + + // No bump == check for line proximity + if (t < 0.0) + objDist = dist1; + else if (t > 1.0) + objDist = dist2; + else + { + Line l(p1, p2); + Vector v1 = l.Vect(); + Vector v2(p1, point); + objDist = fabs((v1.x * v2.y - v2.x * v1.y) / l.Length()) * Global::zoom; + } + + if (objDist < 5.0) + pl->hitObject = true; + } + else + { + // We have a bump == check for arc proximity + Arc a = Geometry::Unpack(p1, p2, p1.b); + double length = Vector::Magnitude(a.p[0], point); + double angle = Vector::Angle(a.p[0], point); + double span = angle - a.angle[0]; + + // Ensure point span is positive if we have a positive arc span + if (span < 0 && a.angle[1] > 0) + span += TAU; + + // Ensure point span is negative if we have a negative arc span + if (span > 0 && a.angle[1] < 0) + span -= TAU; + + if (((fabs(length - a.radius[0]) * Global::zoom) < 2.5) && (fabs(span) < fabs(a.angle[1]))) + pl->hitObject = true; + } + } + + pl->hovered = (pl->hitPoint[0] || pl->hitObject); + + if ((oldHP0 != pl->hitPoint[0]) || (oldHO != pl->hitObject)) + needUpdate = true; + + break; + } + case OTDimension: { bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHP3 = obj->hitPoint[3], oldHP4 = obj->hitPoint[4], oldHO = obj->hitObject; @@ -2878,7 +2835,7 @@ bool DrawingView::HitTest(Object * obj, Point point) else if ((hCS2Point.Magnitude() * Global::zoom) < 8.0) obj->hitPoint[4] = true; - obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitPoint[3] || obj->hitPoint[4] || obj->hitObject ? true : false); + obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitPoint[3] || obj->hitPoint[4] || obj->hitObject); if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHP3 != obj->hitPoint[3]) || (oldHP4 != obj->hitPoint[4]) || (oldHO != obj->hitObject)) needUpdate = true; @@ -2898,7 +2855,7 @@ bool DrawingView::HitTest(Object * obj, Point point) if (r.Contains(point)) obj->hitObject = true; - obj->hovered = (obj->hitObject ? true : false); + obj->hovered = obj->hitObject; if (oldHO != obj->hitObject) needUpdate = true; @@ -3096,11 +3053,16 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not* obj->p[0] = point; else if (obj->hitObject) { - double oldRadius = obj->length; - obj->radius[0] = Vector::Magnitude(obj->p[0], point); + if (shiftDown) + { + double oldRadius = obj->length; + obj->radius[0] = Vector::Magnitude(obj->p[0], point); - QString text = QObject::tr("Radius: %1\nScale: %2%"); - informativeText = text.arg(obj->radius[0], 0, 'f', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'f', 0); + QString text = QObject::tr("Radius: %1\nScale: %2%"); + informativeText = text.arg(obj->radius[0], 0, 'f', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'f', 0); + } + else + obj->p[0] += delta; } break; @@ -3169,16 +3131,34 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not* { if (shiftDown) { - return; + obj->radius[0] = Vector::Magnitude(obj->p[0], point); + QString text = QObject::tr("Radius: %1"); + informativeText = text.arg(obj->radius[0], 0, 'f', 4); } - - obj->radius[0] = Vector::Magnitude(obj->p[0], point); - QString text = QObject::tr("Radius: %1"); - informativeText = text.arg(obj->radius[0], 0, 'f', 4); + else + obj->p[0] += delta; } break; + case OTPolyline: + { +#if 1 + // Do this for now... + ((Polyline *)obj)->Translate(delta); +// Polyline * pl = (Polyline *)obj; + +// for(long unsigned int i=0; ipoints.size(); i++) +// pl->points[i] += delta; +#else + Polyline * pl = (Polyline *)obj; + + for(long unsigned int i=0; i<(pl->points.size()-1); i++) +#endif + + break; + } + case OTDimension: if (obj->hitPoint[0]) obj->p[0] = point; diff --git a/src/fileio.cpp b/src/fileio.cpp index ad303f4..8058a41 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -413,16 +413,22 @@ if (errno) else if (strcmp(buffer, "POLYLINE") == 0) { long int size; - obj = (Object *)new Polyline(); + std::vector pts; + uint32_t color; + float thickness; + int style; + fscanf(file, "(%li)", &size); - fscanf(file, " (%i, %f, %i)\n", &obj->color, &obj->thickness, &obj->style); + fscanf(file, " (%i, %f, %i)\n", &color, &thickness, &style); for(int i=0; ip[0].x, &po->p[0].y, &po->length); - ((Polyline *)obj)->Add(po); + Point p; + fscanf(file, "(%lf,%lf,%lf)\n", &p.x, &p.y, &p.b); + pts.push_back(p); } + + obj = (Object *)new Polyline(pts, thickness, color, style); } else if (strcmp(buffer, "TEXT") == 0) { @@ -496,10 +502,9 @@ if (errno) fprintf(file, "POLYLINE %i (%li)", p->layer, p->points.size()); fprintf(file, " (%i, %f, %i)\n", obj->color, obj->thickness, obj->style); - for(VPVectorIter i=p->points.begin(); i!=p->points.end(); i++) + for(long unsigned int i=0; ipoints.size(); i++) { - Object * po = (Object *)(*i); - fprintf(file, "(%.16lf,%.16lf,%.16lf)\n", po->p[0].x, po->p[0].y, po->length); + fprintf(file, "(%.16lf,%.16lf,%.16lf)\n", p->points[i].x, p->points[i].y, p->points[i].b); } } break; diff --git a/src/geometry.cpp b/src/geometry.cpp index 6b3935d..f491856 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -593,7 +593,7 @@ Arc Geometry::Unpack(Point tail, Point head, double bump) { double length = Vector::Magnitude(tail, head) / 2.0; double bumpLen = length * fabs(bump); - Point midpoint = Vector::Midpoint(tail, head); + Point midpoint = (tail + head) / 2.0; Vector mpNormal = Vector::Normal(tail, head); // Normal points to the left // Flip the normal if the bump is pointing left diff --git a/src/objectwidget.cpp b/src/objectwidget.cpp index f31e4f5..739d1c1 100644 --- a/src/objectwidget.cpp +++ b/src/objectwidget.cpp @@ -81,9 +81,6 @@ void ObjectWidget::ShowInfo(Object * obj) s += QString("Center: <%1, %2>
Radius: %3
Start: %4°
Span: %5°
").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->radius[0]).arg(obj->angle[0] * RADIANS_TO_DEGREES).arg(obj->angle[1] * RADIANS_TO_DEGREES); break; - case OTPolygon: - break; - case OTDimension: { Dimension * d = (Dimension *)obj; @@ -91,6 +88,9 @@ void ObjectWidget::ShowInfo(Object * obj) break; } + case OTPolyline: + break; + case OTSpline: break; diff --git a/src/structs.cpp b/src/structs.cpp new file mode 100644 index 0000000..b731fae --- /dev/null +++ b/src/structs.cpp @@ -0,0 +1,254 @@ +// +// 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 +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 01/13/2022 Created this file + +#include "structs.h" +#include +#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 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 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::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; + } + }*/ diff --git a/src/structs.h b/src/structs.h index 8250a00..e7e7b30 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2,13 +2,13 @@ #define __STRUCTS_H__ #include -#include #include +#include #include "global.h" #include "rect.h" #include "vector.h" -enum ObjectType { OTNone = 0, OTLine, OTCircle, OTEllipse, OTArc, OTPolygon, OTDimension, OTSpline, OTText, OTContainer, OTPolyline, OTCount }; +enum ObjectType { OTNone = 0, OTLine, OTCircle, OTEllipse, OTArc, OTDimension, OTPolyline, OTSpline, OTText, OTContainer, OTCount }; enum DimensionType { DTLinear = 0, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric, DTCircumferential, DTAngular, DTLeader, DTCount }; @@ -18,20 +18,10 @@ enum ToolState { TSNone, TSPoint1, TSPoint2, TSPoint3, TSPoint4, TSDone }; enum BasicUnit { BUInch = 0, BUFoot, BUYard, BUMile, BUMM, BUCM, BUM, BUKM, BUCount }; -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 }; +extern const char objName[OTCount][16]; +extern const char dimName[DTCount][32]; +extern const char buShortName[BUCount][8]; +extern const double buInInches[BUCount]; #define OBJECT_COMMON \ int type; \ @@ -56,43 +46,33 @@ struct Object { struct Line { OBJECT_COMMON; - Line(): type(OTLine), id(Global::objectID++), selected(false), hovered(false), hitObject(false) { hitPoint[0] = hitPoint[1] = false; } - 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 Vect(void) { return Vector(p[0], p[1]); } - Vector Unit(void) { return Vector(p[0], p[1]).Unit(); } - double Length(void) { return Vector(p[0], p[1]).Magnitude(); } + Line(); + Line(Vector pt1, Vector pt2, float th = 1.0, uint32_t c = 0, int l = LSSolid); + Vector Vect(void); + Vector Unit(void); + double Length(void); }; struct Circle { OBJECT_COMMON; - Circle(): type(OTCircle), id(Global::objectID++) {} - 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; } + Circle(); + Circle(Vector pt1, double r, float th = 1.0, uint32_t c = 0, int l = LSSolid); }; struct Ellipse { OBJECT_COMMON; - Ellipse(): type(OTEllipse), id(Global::objectID++) {} - 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; } + Ellipse(); + Ellipse(Vector pt1, Vector pt2, double r1, double r2, float th = 1.0, uint32_t c = 0, int l = LSSolid); }; struct Arc { OBJECT_COMMON; - Arc(): type(OTArc), id(Global::objectID++) {} - 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; } + Arc(); + Arc(Vector pt1, double r, double a1, double a2, float th = 1.0, uint32_t c = 0, int l = LSSolid); + Rect Bounds(void); }; struct Dimension { @@ -102,14 +82,8 @@ struct Dimension { Point lp[2]; // Line point, the actual dimension line Object * obj[2]; // Pointer to attached objects (circle, lines for angle) - Dimension(): type(OTDimension), id(Global::objectID++), selected(false), - hovered(false), hitObject(false) - { hitPoint[0] = hitPoint[1] = hitPoint[2] = hitPoint[3] = hitPoint[4] = false; } - 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; } + Dimension(); + Dimension(Vector pt1, Vector pt2, DimensionType dt = DTLinear, double offs = 0, float th = 1.0, uint32_t c = 0x0000FF, int l = LSSolid); }; struct Text { @@ -118,37 +92,29 @@ struct Text { bool measured; std::string s; - Text(): type(OTText), id(Global::objectID++) {} - 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... -struct Polygon { - OBJECT_COMMON; - int sides; - - Polygon(): type(OTPolygon), id(Global::objectID++) {} + Text(); + Text(Vector pt1, const char * str, float th = 10.0, uint32_t c = 0); }; struct Polyline { OBJECT_COMMON; - VPVector points; -//need this? could just repeat the endpoint as well... -// bool closed; - Object * clicked; - - Polyline(): type(OTPolyline), id(Global::objectID++), selected(false), hovered(false), hitObject(false), clicked(NULL) {} - void Add(void * obj) { points.push_back(obj); } - void Add(VPVector objs) { points.insert(points.end(), objs.begin(), objs.end()); } + std::vector points; +// bool closed; //need this? could just repeat the endpoint as well... +// Object * clicked; + int ptNum; + + Polyline(float th = 1.0, uint32_t c = 0, int l = LSSolid); + Polyline(std::vector, float th = 1.0, uint32_t c = 0, int l = LSSolid); + void Add(Point); + void Add(std::vector); + Rect Bounds(void); + void Translate(Point); }; struct Spline { OBJECT_COMMON; - Spline(): type(OTSpline), id(Global::objectID++) {} + Spline(); }; struct Container { @@ -163,24 +129,9 @@ struct Container { int decimalPrecision; // 0-5, which, +1, is # of decimal places int fractionalPrecision; // 0-5, which, +1, is 1/(2^n) - 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 Add(void * obj) { objects.push_back(obj); } - void Add(VPVector objs) { objects.insert(objects.end(), objs.begin(), objs.end()); } -// void DeleteContents(void) {} -/* void DeleteContents(Container * c) - { - std::vector::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; - } - }*/ + Container(bool tl = false); + void Add(void * obj); + void Add(VPVector objs); }; #endif // __STRUCTS_H__ diff --git a/src/utils.cpp b/src/utils.cpp index c038f36..cd05ba7 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -73,6 +73,11 @@ Object * CopyObject(Object * obj) newObject = new Dimension(); memcpy(newObject, obj, sizeof(Dimension)); break; + case OTPolyline: + newObject = new Polyline(); + memcpy(newObject, obj, sizeof(Polyline)); + ((Polyline *)newObject)->points = ((Polyline *)obj)->points; + break; case OTSpline: newObject = new Spline(); memcpy(newObject, obj, sizeof(Spline)); @@ -137,6 +142,12 @@ Object * CopyObject2(Object * obj) memcpy(newObject, obj, sizeof(Dimension)); break; + case OTPolyline: + newObject = new Polyline(); + memcpy(newObject, obj, sizeof(Polyline)); + ((Polyline *)newObject)->points = ((Polyline *)obj)->points; + break; + case OTSpline: newObject = new Spline(); memcpy(newObject, obj, sizeof(Spline)); @@ -399,6 +410,8 @@ void TranslateObject(Object * obj, Point delta) for(VPVectorIter i=c->objects.begin(); i!=c->objects.end(); i++) TranslateObject((Object *)*i, delta); } + else if (obj->type == OTPolyline) + ((Polyline *)obj)->Translate(delta); obj->p[0] += delta; obj->p[1] += delta; @@ -482,6 +495,10 @@ void TranslateObjects(VPVector & v, Point delta) Container * c = (Container *)obj; TranslateObjects(c->objects, delta); } + else if (obj->type == OTPolyline) + { + ((Polyline *)obj)->Translate(delta); + } } } diff --git a/src/vector.cpp b/src/vector.cpp index 8b2dda2..fbe45ff 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -16,20 +16,20 @@ #include "vector.h" -#include // For sqrt() +#include // For sqrt() #include "mathconstants.h" // Vector implementation -Vector::Vector(double xx/*= 0*/, double yy/*= 0*/, double zz/*= 0*/): x(xx), y(yy), z(zz) +Vector::Vector(double xx/*= 0*/, double yy/*= 0*/, double zz/*= 0*/): x(xx), y(yy), z(zz), b(0) { } -Vector::Vector(Vector tail, Vector head): x(head.x - tail.x), y(head.y - tail.y), z(head.z - tail.z) +Vector::Vector(Vector tail, Vector head): x(head.x - tail.x), y(head.y - tail.y), z(head.z - tail.z), b(0) { } -Vector::Vector(const Vector &v): x(v.x), y(v.y), z(v.z) +Vector::Vector(const Vector &v): x(v.x), y(v.y), z(v.z), b(v.b) { } @@ -43,7 +43,7 @@ void Vector::SetAngleAndLength(double angle, double length) Vector Vector::operator=(Vector const v) { - x = v.x, y = v.y, z = v.z; + x = v.x, y = v.y, z = v.z, b = v.b; return *this; } @@ -267,7 +267,7 @@ bool Vector::isZero(double epsilon/*= 1e-6*/) return Vector(-v.y, v.x); } -/*static*/ double Vector::AngleBetween(Vector a, Vector b) +/*static*/ double Vector::AngleBetween(Vector a1, Vector a2) { // This is done using the following formula: // (a . b) = ||a|| ||b|| cos(theta) @@ -276,10 +276,10 @@ bool Vector::isZero(double epsilon/*= 1e-6*/) // Also, the vectors a & b have to be non-zero. // Also, have to check using an epsilon because acos will not return an // exact value if the vectors are orthogonal. - if (a.isZero() || b.isZero()) + if (a1.isZero() || a2.isZero()) return 0; - return acos(a.Dot(b) / (a.Magnitude() * b.Magnitude())); + return acos(a1.Dot(a2) / (a1.Magnitude() * a2.Magnitude())); } /*static*/ Point Vector::Midpoint(Point p1, Point p2) diff --git a/src/vector.h b/src/vector.h index 97985c5..b6292ab 100644 --- a/src/vector.h +++ b/src/vector.h @@ -57,11 +57,11 @@ class Vector static double Angle(Point p1, Point p2); static double Parameter(Vector v1, Vector v2, Vector p); static Vector Normal(Vector v1, Vector v2); - static double AngleBetween(Vector a, Vector b); + static double AngleBetween(Vector a1, Vector a2); static Point Midpoint(Point p1, Point p2); public: - double x, y, z; + double x, y, z, b; // "b" is an extra used mainly for arc bumps }; #endif // __VECTOR_H__