]> Shamusworld >> Repos - architektonas/commitdiff
More polyline upgrading: points and arcs are now editable with the GUI.
authorShamus Hammons <jlhamm@acm.org>
Sat, 15 Jan 2022 18:05:22 +0000 (12:05 -0600)
committerShamus Hammons <jlhamm@acm.org>
Sat, 15 Jan 2022 18:05:22 +0000 (12:05 -0600)
architektonas.pro
src/applicationwindow.cpp
src/drawingview.cpp
src/geometry.cpp
src/geometry.h
src/structs.cpp
src/structs.h

index 5f68a703718f537e2aa4a1761863ff0942db433a..9e1679349f0b76ecf16652e176634d4d85383191 100644 (file)
@@ -98,6 +98,7 @@ SOURCES = \
        src/promptlineedit.cpp \
        src/rect.cpp \
        src/settingsdialog.cpp \
+       src/structs.cpp \
        src/units.cpp \
        src/utils.cpp \
        src/vector.cpp
index 8bbdbc1c5646c8c996fdf33244b0f0995f711fa7..b91177de80d0454b718c94bd51ce39ddf5d559a2 100644 (file)
@@ -1140,7 +1140,8 @@ void ApplicationWindow::ReadSettings(void)
        QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
        QSize size = settings.value("size", QSize(400, 400)).toSize();
        drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
-       snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
+       Global::snapToGrid = settings.value("snapToGrid", true).toBool();
+       snapToGridAct->setChecked(Global::snapToGrid);
        resize(size);
        move(pos);
        restoreState(settings.value("windowState").toByteArray());
index e65bbe92de99f12d47f6f2e12596c25d33485c1d..78fe9619a4a37d64e4de014971e8112b9defa7f9 100644 (file)
@@ -2752,7 +2752,10 @@ bool DrawingView::HitTest(Object * obj, Point point)
                                }
 
                                if (objDist < 5.0)
+                               {
                                        pl->hitObject = true;
+                                       pl->ptNum = i;
+                               }
                        }
                        else
                        {
@@ -2771,7 +2774,10 @@ bool DrawingView::HitTest(Object * obj, Point point)
                                        span -= TAU;
 
                                if (((fabs(length - a.radius[0]) * Global::zoom) < 2.5) && (fabs(span) < fabs(a.angle[1])))
+                               {
                                        pl->hitObject = true;
+                                       pl->ptNum = i;
+                               }
                        }
                }
 
@@ -3143,18 +3149,30 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not*
 
        case OTPolyline:
        {
-#if 1
-               // Do this for now...
-               ((Polyline *)obj)->Translate(delta);
-//             Polyline * pl = (Polyline *)obj;
-
-//             for(long unsigned int i=0; i<pl->points.size(); i++)
-//                     pl->points[i] += delta;
-#else
                Polyline * pl = (Polyline *)obj;
 
-               for(long unsigned int i=0; i<(pl->points.size()-1); i++)
-#endif
+               if (!shiftDown)
+                       pl->Translate(delta);
+               else
+               {
+                       // Move selected point by itself (if hit)
+                       if (pl->hitPoint[0])
+                       {
+                               point.b = pl->points[pl->ptNum].b;
+                               pl->points[pl->ptNum] = point;
+                       }
+                       else if (pl->hitObject)
+                       {
+                               // move arc radius, or maybe move line segment?  :-/
+                               int ptNum = pl->ptNum;
+                               Arc a = Geometry::FindArcForThreePoints(pl->points[ptNum], pl->points[ptNum + 1], point);
+                               pl->points[ptNum].b = Geometry::Pack(&a);
+
+                               // This doesn't quite get there... Maybe < 0.001?
+                               if (fabs(pl->points[ptNum].b) < EPSILON)
+                                       pl->points[ptNum].b = 0;
+                       }
+               }
 
                break;
        }
@@ -3166,7 +3184,7 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not*
                        obj->p[1] = point;
                else if (obj->hitObject)
                {
-                       // Move measurement lines in/out
+                       // Move extension lines in/out
                        if (shiftDown)
                        {
                                Dimension * d = (Dimension *)obj;
index f4918560990d8ddcd61709daf54aae49c6b4fadc..82d24e84c492ca81e2f116b23b1d84d14fc53d1a 100644 (file)
@@ -525,6 +525,21 @@ Vector Geometry::GetNormalOfPointAndLine(Point p, Line * l)
        return normal;
 }
 
+//
+// Returns the orientation of the points when traversed in order (from p1 to
+// p2 to p3).  +1 = CCW, -1 = CW, 0 = colinear
+//
+int Geometry::Orientation(Point p1, Point p2, Point p3)
+{
+       double xx = p2.x - p1.x, yy = p2.y - p1.y;
+       double aa = p3.x - p1.x, bb = p3.y - p1.y;
+
+       // Mult by -1 if screen coords already transformed
+       double zz = (xx * bb) - (yy * aa);
+
+       return (zz < 0 ? -1 : (zz == 0 ? 0 : 1));
+}
+
 Circle Geometry::FindCircleForThreePoints(Point p1, Point p2, Point p3)
 {
        // We use matrices and determinants to find the center and radius of the
@@ -582,6 +597,27 @@ Circle Geometry::FindCircleForThreePoints(Point p1, Point p2, Point p3)
        return c;
 }
 
+Arc Geometry::FindArcForThreePoints(Point p1, Point p2, Point p3)
+{
+       int orientation = Orientation(p1, p2, p3);
+
+       // Sanity check: if points are colinear, there is no arc
+       if (orientation == 0)
+               return Arc();
+
+       Circle c = FindCircleForThreePoints(p1, p2, p3);
+       double a1 = Vector::Angle(c.p[0], p1);
+       double a2 = Vector::Angle(c.p[0], p2);
+       double span = a2 - a1;
+
+       if (orientation < 0 && span > 0)
+               span -= TAU;
+       else if (orientation > 0 && span < 0)
+               span += TAU;
+
+       return Arc(c.p[0], c.radius[0], a1, span);
+}
+
 double Geometry::Determinant3x3(double a11, double a12, double a13, double a21, double a22, double a23, double a31, double a32, double a33)
 {
        return (a11 * ((a22 * a33) - (a32 * a23)))
@@ -602,7 +638,6 @@ Arc Geometry::Unpack(Point tail, Point head, double bump)
 
        // N.B.: The radius can also be found with r = (a² + h²) / 2h where a is
        // the 1/2 length of the line segment and h is the bump length.
-//     double radius = (length + (1.0 / length)) / 2.0;
        double radius = 0.5 * (((length * length) + (bumpLen * bumpLen)) / bumpLen);
        Vector ctrVec = mpNormal * (radius - bumpLen);
        Point center = midpoint + ctrVec;
@@ -621,3 +656,19 @@ Arc Geometry::Unpack(Point tail, Point head, double bump)
 
        return Arc(center, radius, angle1, span);
 }
+
+double Geometry::Pack(Arc * a)
+{
+       Point p1 = a->p[0] + (Vector(cos(a->angle[0]), sin(a->angle[0])) * a->radius[0]);
+       Point p2 = a->p[0] + (Vector(cos(a->angle[0] + a->angle[1]), sin(a->angle[0] + a->angle[1])) * a->radius[0]);
+       double endpointLen = Vector::Magnitude(p1, p2) / 2.0;
+
+       // Bump height can be found with h = r ± sqr(r² - a²) where r is the
+       // radius, and a is the 1/2 length of the endpoint's line segment.  The
+       // plus/minus term is positive if the arc span is less than 1/2 TAU,
+       // negative if the arc span is greater than 1/2 TAU.
+       double discriminant = sqrt((a->radius[0] * a->radius[0]) - (endpointLen * endpointLen));
+       double bumpLen = a->radius[0] + (discriminant * (fabs(a->angle[1]) < HALF_TAU ? 1.0 : -1.0));
+
+       return (bumpLen / endpointLen) * (a->angle[1] > 0 ? -1.0 : 1.0);
+}
index 0a05b373460224f2a1e12d39463ccacbc12a57a6..d657db6d986e5c454d66ec27c4ce921278070e7e 100644 (file)
@@ -24,9 +24,12 @@ class Geometry
                static void FindTangents(Object *, Object *);
                static Point NearestTo(Point, Point, Point);
                static Vector GetNormalOfPointAndLine(Point, Line *);
+               static int Orientation(Point, Point, Point);
                static Circle FindCircleForThreePoints(Point, Point, Point);
+               static Arc FindArcForThreePoints(Point, Point, Point);
                static double Determinant3x3(double, double, double, double, double, double, double, double, double);
                static Arc Unpack(Point, Point, double);
+               static double Pack(Arc *);
 };
 
 #endif         // __GEOMETRY_H__
index b731fae75a767c99d05962e639190ff863875caa..883e934e20e0d5629b7f664649721ecd8fbdf78f 100644 (file)
@@ -97,9 +97,30 @@ 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)
+Arc::Arc(Vector ctr, 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;
+       p[0] = ctr;
+       radius[0] = r;
+       angle[0] = a1;
+       angle[1] = a2;
+       hitPoint[0] = hitPoint[1] = hitPoint[2] = false;
+}
+
+Arc::Arc(Vector ctr, double r, Point p1, Point p2, 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] = ctr;
+       radius[0] = r;
+       angle[0] = Vector::Angle(ctr, p1);
+/*
+s =  10, e =  20, span = 10 (why not -350?)
+s =  20, e =  10, span = -10 (why not 350?)
+s =  10, e = 350, span = 340 (why not -20?)
+s = 350, e =  10, span = -340 (why not 20?)
+
+below is still not right, we need one more point to disambiguate this...
+*/
+       angle[1] = Vector::Angle(ctr, p2) - angle[0];
+       hitPoint[0] = hitPoint[1] = hitPoint[2] = false;
 }
 
 Rect Arc::Bounds(void)
index e7e7b30643ffa82465922fe2fdc3fead7d6a61cb..ea2245f65197b537945ff5a99edc7121a3344e96 100644 (file)
@@ -71,7 +71,8 @@ struct Arc {
        OBJECT_COMMON;
 
        Arc();
-       Arc(Vector pt1, double r, double a1, double a2, float th = 1.0, uint32_t c = 0, int l = LSSolid);
+       Arc(Vector ctr, double r, double a1, double a2, float th = 1.0, uint32_t c = 0, int l = LSSolid);
+       Arc(Vector ctr, double r, Point p1, Point p2, float th = 1.0, uint32_t c = 0, int l = LSSolid);
        Rect Bounds(void);
 };