]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Preliminary support for Polylines.
[architektonas] / src / drawingview.cpp
index 3b6f92c6663c363bba9b1cf68e006793f101a7e0..39196a753646a9eb7929e8d699b9e21f89c8fce3 100644 (file)
@@ -133,7 +133,7 @@ void DrawingView::DrawBackground(Painter * painter)
 
        painter->SetBrush(0xF0F0F0);
        painter->SetPen(0xF0F0F0, 1, 1);
-       painter->DrawRect(QRectF(QPointF(ul.x, ul.y), QPointF(br.x, br.y)));
+       painter->DrawRect(Rect(ul, br));
 
        double spacing = Global::gridSpacing;
 
@@ -455,6 +455,41 @@ void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool
 
                        break;
 
+               case OTPolyline:
+               {
+                       painter->SetBrush(QBrush(Qt::NoBrush));
+                       Polyline * pl = (Polyline *)obj;
+                       Point lastp;
+                       double lastbump;
+
+                       for(VPVectorIter i=pl->points.begin(); i!=pl->points.end(); 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]);
+                                       }
+
+                                       lastp = p;
+                                       lastbump = bump;
+                               }
+                               else
+                               {
+                                       lastp = ((Object *)(*i))->p[0];
+                                       lastbump = ((Object *)(*i))->length;
+                               }
+                       }
+
+                       break;
+               }
+
                case OTDimension:
                {
                        Dimension * d = (Dimension *)obj;
@@ -632,15 +667,12 @@ Where is the text offset?  It looks like it's drawing in the center, but obvious
                        break;
                }
 
+#if 0
                case OTPolygon:
                {
                        break;
                }
-
-               case OTPolyline:
-               {
-                       break;
-               }
+#endif
 
                case OTContainer:
                {
@@ -1975,8 +2007,8 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                // Didn't hit any object and not using a tool, so do a selection
                // rectangle
                Global::selectionInProgress = true;
-               Global::selection.setTopLeft(QPointF(point.x, point.y));
-               Global::selection.setBottomRight(QPointF(point.x, point.y));
+               Global::selection.l = Global::selection.r = point.x;
+               Global::selection.t = Global::selection.b = point.y;
                select = GetSelection();
        }
        else if (event->button() == Qt::MiddleButton)
@@ -1998,7 +2030,8 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
        }
 
        Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
-       Global::selection.setBottomRight(QPointF(point.x, point.y));
+       Global::selection.r = point.x;
+       Global::selection.b = point.y;
        // Only needs to be done here, as mouse down is always preceded by movement
        Global::snapPointIsValid = false;
        hoveringIntersection = false;
@@ -2411,12 +2444,40 @@ Rect DrawingView::GetObjectExtents(Object * 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];
+               }
+
                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<numAxes; i++)
+                       axis[(quadStart + i) % 4] = box[(quadStart + i) % 4];
+
+               // The rect is constructed the same way we traverse the axes: TLBR
+               Rect r2(axis[0], axis[1], axis[2], axis[3]);
+
+               rect |= r2;
+#else
                // Adjust the bounds depending on which axes are crossed
                if ((start < QTR_TAU) && (end > QTR_TAU))
                        rect.t = 1.0;
@@ -2438,6 +2499,7 @@ Rect DrawingView::GetObjectExtents(Object * obj)
 
                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]);
@@ -2477,6 +2539,8 @@ void DrawingView::CheckObjectBounds(void)
        {
                Object * obj = (Object *)(*i);
                obj->selected = false;
+               Rect selection = Global::selection;
+               selection.Normalize();
 
                switch (obj->type)
                {
@@ -2485,7 +2549,7 @@ void DrawingView::CheckObjectBounds(void)
                {
                        Line * l = (Line *)obj;
 
-                       if (Global::selection.contains(l->p[0].x, l->p[0].y) && Global::selection.contains(l->p[1].x, l->p[1].y))
+                       if (selection.Contains(l->p[0]) && selection.Contains(l->p[1]))
                                l->selected = true;
 
                        break;
@@ -2494,8 +2558,9 @@ void DrawingView::CheckObjectBounds(void)
                case OTCircle:
                {
                        Circle * c = (Circle *)obj;
+                       Vector radVec(c->radius[0], c->radius[0]);
 
-                       if (Global::selection.contains(c->p[0].x - c->radius[0], c->p[0].y - c->radius[0]) && Global::selection.contains(c->p[0].x + c->radius[0], c->p[0].y + c->radius[0]))
+                       if (selection.Contains(c->p[0] - radVec) && selection.Contains(c->p[0] + radVec))
                                c->selected = true;
 
                        break;
@@ -2507,73 +2572,85 @@ void DrawingView::CheckObjectBounds(void)
 
                        double start = a->angle[0];
                        double end = start + a->angle[1];
-                       QPointF p1(cos(start), sin(start));
-                       QPointF p2(cos(end), sin(end));
-                       QRectF bounds(p1, p2);
 
-#if 1
-                       // Swap X/Y coordinates if they're backwards...
-                       if (bounds.left() > bounds.right())
-                       {
-                               double temp = bounds.left();
-                               bounds.setLeft(bounds.right());
-                               bounds.setRight(temp);
-                       }
-
-                       if (bounds.bottom() > bounds.top())
+                       // Swap 'em if the span is negative...
+                       if (a->angle[1] < 0)
                        {
-                               double temp = bounds.bottom();
-                               bounds.setBottom(bounds.top());
-                               bounds.setTop(temp);
+                               end = a->angle[0];
+                               start = end + a->angle[1];
                        }
-#else
-                       // Doesn't work as advertised! For shame!
-                       bounds = bounds.normalized();
-#endif
 
                        // 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<numAxes; i++)
+                               bounds[(quadStart + i) % 4] = box[(quadStart + i) % 4];
+#else
                        // Adjust the bounds depending on which axes are crossed
                        if ((start < QTR_TAU) && (end > QTR_TAU))
-                               bounds.setTop(1.0);
+                               bounds.t = 1.0;
 
                        if ((start < HALF_TAU) && (end > HALF_TAU))
-                               bounds.setLeft(-1.0);
+                               bounds.l = -1.0;
 
                        if ((start < THREE_QTR_TAU) && (end > THREE_QTR_TAU))
-                               bounds.setBottom(-1.0);
+                               bounds.b = -1.0;
 
                        if ((start < TAU) && (end > TAU))
-                               bounds.setRight(1.0);
+                               bounds.r = 1.0;
 
                        if ((start < (TAU + QTR_TAU)) && (end > (TAU + QTR_TAU)))
-                               bounds.setTop(1.0);
+                               bounds.t = 1.0;
 
                        if ((start < (TAU + HALF_TAU)) && (end > (TAU + HALF_TAU)))
-                               bounds.setLeft(-1.0);
+                               bounds.l = -1.0;
 
                        if ((start < (TAU + THREE_QTR_TAU)) && (end > (TAU + THREE_QTR_TAU)))
-                               bounds.setBottom(-1.0);
+                               bounds.b = -1.0;
+#endif
 
-                       bounds.setTopLeft(QPointF(bounds.left() * a->radius[0], bounds.top() * a->radius[0]));
-                       bounds.setBottomRight(QPointF(bounds.right() * a->radius[0], bounds.bottom() * a->radius[0]));
-                       bounds.translate(a->p[0].x, a->p[0].y);
+                       bounds *= a->radius[0];
+                       bounds.Translate(a->p[0]);
 
-                       if (Global::selection.contains(bounds))
+                       if (selection.Contains(bounds))
                                a->selected = true;
 
                        break;
                }
 
+               case OTPolyline:
+               {
+                       Polyline * pl = (Polyline *)obj;
+                       Rect r(((Object *)(pl->points[0]))->p[0]);
+
+                       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))
+                               pl->selected = true;
+
+                       break;
+               }
+
                case OTText:
                {
                        Text * t = (Text *)obj;
                        Rect r(obj->p[0], Point(t->p[0].x + t->extents.Width(), t->p[0].y - t->extents.Height()));
 
-                       if (Global::selection.contains(r.l, r.t) && Global::selection.contains(r.r, r.b))
+                       if (selection.Contains(r))
                                t->selected = true;
 
                        break;
@@ -2583,7 +2660,7 @@ void DrawingView::CheckObjectBounds(void)
                {
                        Container * c = (Container *)obj;
 
-                       if (Global::selection.contains(c->p[0].x, c->p[0].y) && Global::selection.contains(c->p[1].x, c->p[1].y))
+                       if (selection.Contains(c->p[0]) && selection.Contains(c->p[1]))
                                c->selected = true;
 
                        break;
@@ -3049,14 +3126,14 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not*
                                        obj->angle[1] += TAU;
 
                                QString text = QObject::tr("Span: %1") + QChar(0x00B0) + QObject::tr("\n%2") + QChar(0x00B0) + QObject::tr(" - %3") + QChar(0x00B0);
-                               informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'd', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 2);
+                               informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'f', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'f', 2);
                                return;
                        }
 
                        double angle = Vector::Angle(obj->p[0], point);
                        obj->angle[0] = angle;
                        QString text = QObject::tr("Start angle: %1") + QChar(0x00B0);
-                       informativeText = text.arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 4);
+                       informativeText = text.arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 4);
                }
                else if (obj->hitPoint[2])
                {
@@ -3070,7 +3147,7 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not*
                                        obj->angle[1] += TAU;
 
                                QString text = QObject::tr("Span: %1") + QChar(0x00B0) + QObject::tr("\n%2") + QChar(0x00B0) + QObject::tr(" - %3") + QChar(0x00B0);
-                               informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'd', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 2);
+                               informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'f', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'f', 2);
                                return;
                        }
 
@@ -3080,8 +3157,13 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not*
                        if (obj->angle[0] < 0)
                                obj->angle[0] += TAU;
 
+                       double endAngle = obj->angle[0] + obj->angle[1];
+
+                       if (endAngle > TAU)
+                               endAngle -= TAU;
+
                        QString text = QObject::tr("End angle: %1") + QChar(0x00B0);
-                       informativeText = text.arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 4);
+                       informativeText = text.arg(endAngle * RADIANS_TO_DEGREES, 0, 'f', 4);
                }
                else if (obj->hitObject)
                {
@@ -3092,7 +3174,7 @@ N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not*
 
                        obj->radius[0] = Vector::Magnitude(obj->p[0], point);
                        QString text = QObject::tr("Radius: %1");
-                       informativeText = text.arg(obj->radius[0], 0, 'd', 4);
+                       informativeText = text.arg(obj->radius[0], 0, 'f', 4);
                }
 
                break;