]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Add ability to add Arcs to document.
[architektonas] / src / drawingview.cpp
index aeb764cc5781ff38364f7a99eb154c4898c360bd..9e1b56c784e02698733c85cd205c1bc913db372f 100644 (file)
@@ -323,6 +323,9 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
                painter.SetBrush(QBrush(QColor(255, 127, 0, 100)));
                painter.DrawRect(Global::selection);
        }
+
+       if (!informativeText.isEmpty())
+               painter.DrawInformativeText(informativeText);
 }
 
 
@@ -354,31 +357,26 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v)
                switch (obj->type)
                {
                case OTLine:
-               {
-                       Line * l = (Line *)obj;
-                       painter->DrawLine(l->p[0], l->p[1]);
+                       painter->DrawLine(obj->p[0], obj->p[1]);
 
-                       if (l->hitPoint[0])
-                               painter->DrawHandle(l->p[0]);
+                       if (obj->hitPoint[0])
+                               painter->DrawHandle(obj->p[0]);
 
-                       if (l->hitPoint[1])
-                               painter->DrawHandle(l->p[1]);
+                       if (obj->hitPoint[1])
+                               painter->DrawHandle(obj->p[1]);
 
                        break;
-               }
                case OTCircle:
-               {
-                       Circle * ci = (Circle *)obj;
                        painter->SetBrush(QBrush(Qt::NoBrush));
-                       painter->DrawEllipse(ci->p[0], ci->radius, ci->radius);
+                       painter->DrawEllipse(obj->p[0], obj->radius[0], obj->radius[0]);
+
+                       if (obj->hitPoint[0])
+                               painter->DrawHandle(obj->p[0]);
+
                        break;
-               }
                case OTArc:
-               {
-                       Arc * a = (Arc *)obj;
-                       painter->DrawArc(a->p[0], a->radius, a->angle1, a->angle2);
+                       painter->DrawArc(obj->p[0], obj->radius[0], obj->angle[0], obj->angle[1]);
                        break;
-               }
                case OTDimension:
                {
                        Dimension * d = (Dimension *)obj;
@@ -571,6 +569,10 @@ void DrawingView::ToolHandler(int mode, Point p)
 {
        if (Global::tool == TTLine)
                LineHandler(mode, p);
+       else if (Global::tool == TTCircle)
+               CircleHandler(mode, p);
+       else if (Global::tool == TTArc)
+               ArcHandler(mode, p);
        else if (Global::tool == TTRotate)
                RotateHandler(mode, p);
 }
@@ -597,8 +599,72 @@ void DrawingView::ToolDraw(Painter * painter)
                        double absAngle = v.Angle() * RADIANS_TO_DEGREES;
                        double absLength = v.Magnitude();
                        QString text = tr("Length: %1 in.\n") + QChar(0x2221) + tr(": %2");
-                       text = text.arg(absLength).arg(absAngle);
-                       painter->DrawInformativeText(text);
+                       informativeText = text.arg(absLength).arg(absAngle);
+               }
+       }
+       else if (Global::tool == TTCircle)
+       {
+               if (Global::toolState == TSNone)
+               {
+                       painter->DrawHandle(toolPoint[0]);
+               }
+               else if ((Global::toolState == TSPoint2) && shiftDown)
+               {
+                       painter->DrawHandle(toolPoint[1]);
+               }
+               else
+               {
+                       double length = Vector::Magnitude(toolPoint[0], toolPoint[1]);
+//                     painter->DrawLine(toolPoint[0], toolPoint[1]);
+//                     painter->DrawHandle(toolPoint[1]);
+                       painter->SetBrush(QBrush(Qt::NoBrush));
+                       painter->DrawEllipse(toolPoint[0], length, length);
+                       QString text = tr("Radius: %1 in.");//\n") + QChar(0x2221) + tr(": %2");
+                       informativeText = text.arg(length);//.arg(absAngle);
+               }
+       }
+       else if (Global::tool == TTArc)
+       {
+               if (Global::toolState == TSNone)
+               {
+                       painter->DrawHandle(toolPoint[0]);
+               }
+               else if (Global::toolState == TSPoint2)
+               {
+                       double length = Vector::Magnitude(toolPoint[0], toolPoint[1]);
+                       painter->SetBrush(QBrush(Qt::NoBrush));
+                       painter->DrawEllipse(toolPoint[0], length, length);
+                       painter->DrawLine(toolPoint[0], toolPoint[1]);
+                       painter->DrawHandle(toolPoint[1]);
+                       QString text = tr("Radius: %1 in.");
+                       informativeText = text.arg(length);
+               }
+               else if (Global::toolState == TSPoint3)
+               {
+                       double angle = Vector::Angle(toolPoint[0], toolPoint[2]);
+                       painter->DrawLine(toolPoint[0], toolPoint[2]);
+                       painter->SetBrush(QBrush(Qt::NoBrush));
+                       painter->DrawEllipse(toolPoint[0], toolPoint[1].x, toolPoint[1].x);
+                       painter->DrawHandle(toolPoint[0] + (Vector(cos(angle), sin(angle)) * toolPoint[1].x));
+                       QString text = tr("Angle start: %1") + QChar(0x00B0);
+                       informativeText = text.arg(RADIANS_TO_DEGREES * angle);
+               }
+               else
+               {
+                       double angle = Vector::Angle(toolPoint[0], toolPoint[3]);
+                       double span = angle - toolPoint[2].x;
+
+                       if (span < 0)
+                               span += PI_TIMES_2;
+
+                       painter->DrawLine(toolPoint[0], toolPoint[3]);
+                       painter->SetBrush(QBrush(Qt::NoBrush));
+                       painter->DrawEllipse(toolPoint[0], toolPoint[1].x, toolPoint[1].x);
+                       painter->SetPen(0xFF00FF, 2.0, LSSolid);
+                       painter->DrawArc(toolPoint[0], toolPoint[1].x, toolPoint[2].x, span);
+                       painter->DrawHandle(toolPoint[0] + (Vector(cos(angle), sin(angle)) * toolPoint[1].x));
+                       QString text = tr("Arc span: %1") + QChar(0x00B0);
+                       informativeText = text.arg(RADIANS_TO_DEGREES * span);
                }
        }
        else if (Global::tool == TTRotate)
@@ -628,12 +694,12 @@ void DrawingView::ToolDraw(Painter * painter)
                        double absAngle = (Vector(toolPoint[1] - toolPoint[0]).Angle()) * RADIANS_TO_DEGREES;
 
                        QString text = QChar(0x2221) + QObject::tr(": %1");
-                       text = text.arg(absAngle);
+                       informativeText = text.arg(absAngle);
 
                        if (ctrlDown)
-                               text += " (Copy)";
+                               informativeText += " (Copy)";
 
-                       painter->DrawInformativeText(text);
+//                     painter->DrawInformativeText(text);
                }
        }
 }
@@ -680,6 +746,118 @@ void DrawingView::LineHandler(int mode, Point p)
 }
 
 
+void DrawingView::CircleHandler(int mode, Point p)
+{
+       switch (mode)
+       {
+       case ToolMouseDown:
+               if (Global::toolState == TSNone)
+                       toolPoint[0] = p;
+               else
+                       toolPoint[1] = p;
+
+               break;
+       case ToolMouseMove:
+               if (Global::toolState == TSNone)
+                       toolPoint[0] = p;
+               else
+                       toolPoint[1] = p;
+
+               break;
+       case ToolMouseUp:
+               if (Global::toolState == TSNone)
+               {
+                       Global::toolState = TSPoint2;
+                       // Prevent spurious line from drawing...
+                       toolPoint[1] = toolPoint[0];
+               }
+               else if ((Global::toolState == TSPoint2) && shiftDown)
+               {
+                       // Key override is telling us to make a new line, not continue the
+                       // previous one.
+                       toolPoint[0] = toolPoint[1];
+               }
+               else
+               {
+                       double length = Vector::Magnitude(toolPoint[0], toolPoint[1]);
+                       Circle * c = new Circle(toolPoint[0], length);
+                       document.objects.push_back(c);
+                       toolPoint[0] = toolPoint[1];
+                       Global::toolState = TSNone;
+               }
+       }
+}
+
+
+void DrawingView::ArcHandler(int mode, Point p)
+{
+       switch (mode)
+       {
+       case ToolMouseDown:
+               if (Global::toolState == TSNone)
+                       toolPoint[0] = p;
+               else if (Global::toolState == TSPoint2)
+                       toolPoint[1] = p;
+               else if (Global::toolState == TSPoint3)
+                       toolPoint[2] = p;
+               else
+                       toolPoint[3] = p;
+
+               break;
+       case ToolMouseMove:
+               if (Global::toolState == TSNone)
+                       toolPoint[0] = p;
+               else if (Global::toolState == TSPoint2)
+                       toolPoint[1] = p;
+               else if (Global::toolState == TSPoint3)
+                       toolPoint[2] = p;
+               else
+                       toolPoint[3] = p;
+
+               break;
+       case ToolMouseUp:
+               if (Global::toolState == TSNone)
+               {
+                       // Prevent spurious line from drawing...
+                       toolPoint[1] = toolPoint[0];
+                       Global::toolState = TSPoint2;
+               }
+               else if (Global::toolState == TSPoint2)
+               {
+                       if (shiftDown)
+                       {
+                               // Key override is telling us to start circle at new center, not
+                               // continue the current one.
+                               toolPoint[0] = toolPoint[1];
+                               return;
+                       }
+
+                       // Set the radius in toolPoint[1].x
+                       toolPoint[1].x = Vector::Magnitude(toolPoint[0], toolPoint[1]);
+                       Global::toolState = TSPoint3;
+               }
+               else if (Global::toolState == TSPoint3)
+               {
+                       // Set the angle in toolPoint[2].x
+                       toolPoint[2].x = Vector::Angle(toolPoint[0], toolPoint[2]);
+                       Global::toolState = TSPoint4;
+               }
+               else
+               {
+                       double endAngle = Vector::Angle(toolPoint[0], toolPoint[3]);
+                       double span = endAngle - toolPoint[2].x;
+
+                       if (span < 0)
+                               span += PI_TIMES_2;
+
+                       Arc * arc = new Arc(toolPoint[0], toolPoint[1].x, toolPoint[2].x, span);
+                       document.objects.push_back(arc);
+                       Global::toolState = TSNone;
+               }
+       }
+}
+
+
 void DrawingView::RotateHandler(int mode, Point p)
 {
        switch (mode)
@@ -707,7 +885,7 @@ void DrawingView::RotateHandler(int mode, Point p)
                        if (shiftDown)
                                return;
 
-                       double angle = Vector(toolPoint[1], toolPoint[0]).Angle();
+                       double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
                        std::vector<void *>::iterator j = select.begin();
                        std::vector<Object>::iterator i = toolScratch.begin();
 
@@ -719,6 +897,14 @@ void DrawingView::RotateHandler(int mode, Point p)
                                Object * obj2 = (Object *)(*j);
                                obj2->p[0] = p1;
                                obj2->p[1] = p2;
+
+                               if (obj.type == OTArc)
+                               {
+                                       obj2->angle[0] = obj.angle[0] + angle;
+
+                                       if (obj2->angle[0] > PI_TIMES_2)
+                                               obj2->angle[0] -= PI_TIMES_2;
+                               }
                        }
                }
 
@@ -810,6 +996,7 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                        GetHovered(hover);      // prolly needed
 
                        // Needed for grab & moving objects
+                       // We do it *after*... why? (doesn't seem to confer any advantage...)
                        if (Global::snapToGrid)
                                oldPoint = SnapPointToGrid(point);
 
@@ -867,6 +1054,9 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
        // Handle object movement (left button down & over an object)
        if ((event->buttons() & Qt::LeftButton) && numHovered && !Global::tool)
        {
+               if (Global::snapToGrid)
+                       point = SnapPointToGrid(point);
+
                HandleObjectMovement(point);
                update();
                oldPoint = point;
@@ -913,26 +1103,25 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event)
                }
 
                if (Global::selectionInProgress)
-               {
-                       // Select all the stuff inside of selection
                        Global::selectionInProgress = false;
 
-                       // Clear our vectors
-                       select.clear();
-                       hover.clear();
+               informativeText.clear();
+// Should we be doing this automagically? Hmm...
+               // Clear our vectors
+               select.clear();
+               hover.clear();
 
-                       // Scoop 'em up
-                       std::vector<void *>::iterator i;
+               // Scoop 'em up
+               std::vector<void *>::iterator i;
 
-                       for(i=document.objects.begin(); i!=document.objects.end(); i++)
-                       {
-                               if (((Object *)(*i))->selected)
-                                       select.push_back(*i);
+               for(i=document.objects.begin(); i!=document.objects.end(); i++)
+               {
+                       if (((Object *)(*i))->selected)
+                               select.push_back(*i);
 
 //hmm, this is no good, too late to do any good :-P
-//                             if ((*i)->hovered)
-//                                     hover.push_back(*i);
-                       }
+//                     if ((*i)->hovered)
+//                             hover.push_back(*i);
                }
        }
        else if (event->button() == Qt::MiddleButton)
@@ -964,13 +1153,11 @@ void DrawingView::wheelEvent(QWheelEvent * event)
                Global::zoom /= zoomFactor;
        }
 
-#if 1
 //     Global::gridSpacing = gridPixels / Painter::zoom;
 //     UpdateGridBackground();
        SetGridSize(Global::gridSpacing * Global::zoom);
        update();
 //     zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
-#endif
 }
 
 
@@ -1013,6 +1200,7 @@ void DrawingView::keyReleaseEvent(QKeyEvent * event)
        }
 }
 
+
 //
 // This looks strange, but it's really quite simple: We want a point that's
 // more than half-way to the next grid point to snap there while conversely we
@@ -1058,7 +1246,7 @@ void DrawingView::CheckObjectBounds(void)
                {
                        Circle * c = (Circle *)obj;
 
-                       if (Global::selection.contains(c->p[0].x - c->radius, c->p[0].y - c->radius) && Global::selection.contains(c->p[0].x + c->radius, c->p[0].y + c->radius))
+                       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]))
                                c->selected = true;
 
                        break;
@@ -1067,8 +1255,8 @@ void DrawingView::CheckObjectBounds(void)
                {
                        Arc * a = (Arc *)obj;
 
-                       double start = a->angle1;
-                       double end = start + a->angle2;
+                       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);
@@ -1119,8 +1307,8 @@ void DrawingView::CheckObjectBounds(void)
                        if ((start < ((3.0 * PI) + PI_OVER_2)) && (end > ((3.0 * PI) + PI_OVER_2)))
                                bounds.setBottom(-1.0);
 
-                       bounds.setTopLeft(QPointF(bounds.left() * a->radius, bounds.top() * a->radius));
-                       bounds.setBottomRight(QPointF(bounds.right() * a->radius, bounds.bottom() * a->radius));
+                       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);
 
                        if (Global::selection.contains(bounds))
@@ -1152,13 +1340,12 @@ bool DrawingView::HitTestObjects(Point point)
                {
                case OTLine:
                {
-                       Line * l = (Line *)obj;
-                       bool oldHP0 = l->hitPoint[0], oldHP1 = l->hitPoint[1], oldHO = l->hitObject;
-                       l->hitPoint[0] = l->hitPoint[1] = l->hitObject = false;
-                       Vector lineSegment = l->p[1] - l->p[0];
-                       Vector v1 = point - l->p[0];
-                       Vector v2 = point - l->p[1];
-                       double t = Geometry::ParameterOfLineAndPoint(l->p[0], l->p[1], point);
+                       bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHO = obj->hitObject;
+                       obj->hitPoint[0] = obj->hitPoint[1] = obj->hitObject = false;
+                       Vector lineSegment = obj->p[1] - obj->p[0];
+                       Vector v1 = point - obj->p[0];
+                       Vector v2 = point - obj->p[1];
+                       double t = Geometry::ParameterOfLineAndPoint(obj->p[0], obj->p[1], point);
                        double distance;
 
                        if (t < 0.0)
@@ -1171,34 +1358,62 @@ bool DrawingView::HitTestObjects(Point point)
                                        / lineSegment.Magnitude());
 
                        if ((v1.Magnitude() * Global::zoom) < 8.0)
-                       {
-                               l->hitPoint[0] = true;
-//             snapPoint = l->p1;
-//             snapPointIsValid = true;
-                       }
+                               obj->hitPoint[0] = true;
                        else if ((v2.Magnitude() * Global::zoom) < 8.0)
-                       {
-                               l->hitPoint[1] = true;
-//             snapPoint = l->p2;
-//             snapPointIsValid = true;
-                       }
+                               obj->hitPoint[1] = true;
                        else if ((distance * Global::zoom) < 5.0)
-                               l->hitObject = true;
+                               obj->hitObject = true;
 
-//                     bool oldHovered = l->hovered;
-                       l->hovered = (l->hitPoint[0] || l->hitPoint[1] || l->hitObject ? true : false);
-//                     l->hovered = l->hitObject;
+                       obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitObject ? true : false);
 
-//                     if (oldHovered != l->hovered)
-                       if ((oldHP0 != l->hitPoint[0]) || (oldHP1 != l->hitPoint[1]) || (oldHO != l->hitObject))
+                       if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHO != obj->hitObject))
                                needUpdate = true;
 
                        break;
                }
                case OTCircle:
                {
-                       Circle * c = (Circle *)obj;
+                       bool oldHP = obj->hitPoint[0], oldHO = obj->hitObject;
+                       obj->hitPoint[0] = obj->hitObject = false;
+                       double length = Vector::Magnitude(obj->p[0], point);
+
+                       if ((length * Global::zoom) < 8.0)
+                               obj->hitPoint[0] = true;
+                       else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0)
+                               obj->hitObject = true;
 
+                       obj->hovered = (obj->hitPoint[0] || obj->hitObject ? true : false);
+
+                       if ((oldHP != obj->hitPoint[0]) || (oldHO != obj->hitObject))
+                               needUpdate = true;
+
+                       break;
+               }
+               case OTArc:
+               {
+                       bool oldHP = obj->hitPoint[0], oldHO = obj->hitObject;
+                       obj->hitPoint[0] = obj->hitObject = false;
+                       double length = Vector::Magnitude(obj->p[0], point);
+                       double angle = Vector::Angle(obj->p[0], point);
+
+                       // Make sure we get the angle in the correct spot
+                       if (angle < obj->angle[0])
+                               angle += PI_TIMES_2;
+
+                       // 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...
+
+                       if ((length * Global::zoom) < 8.0)
+                               obj->hitPoint[0] = true;
+                       else if (((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) && (span < obj->angle[1]))
+                               obj->hitObject = true;
+
+                       obj->hovered = (obj->hitPoint[0] || obj->hitObject ? true : false);
+
+                       if ((oldHP != obj->hitPoint[0]) || (oldHO != obj->hitObject))
+                               needUpdate = true;
 
                        break;
                }
@@ -1219,10 +1434,8 @@ bool DrawingView::HitTestObjects(Point point)
 
 void DrawingView::HandleObjectMovement(Point point)
 {
-       if (Global::snapToGrid)
-               point = SnapPointToGrid(point);
-
        Point delta = point - oldPoint;
+//printf("HOM: old = (%f,%f), new = (%f, %f), delta = (%f, %f)\n", oldPoint.x, oldPoint.y, point.x, point.y, delta.x, delta.y);
        Object * obj = (Object *)hover[0];
 //printf("Object type = %i (size=%i), ", obj->type, hover.size());
 //printf("Object (%X) move: hp1=%s, hp2=%s, hl=%s\n", obj, (obj->hitPoint[0] ? "true" : "false"), (obj->hitPoint[1] ? "true" : "false"), (obj->hitObject ? "true" : "false"));
@@ -1230,21 +1443,31 @@ void DrawingView::HandleObjectMovement(Point point)
        switch (obj->type)
        {
        case OTLine:
-       {
-               Line * l = (Line *)obj;
+               if (obj->hitPoint[0])
+                       obj->p[0] = point;
+               else if (obj->hitPoint[1])
+                       obj->p[1] = point;
+               else if (obj->hitObject)
+               {
+                       obj->p[0] += delta;
+                       obj->p[1] += delta;
+               }
 
-               if (l->hitPoint[0])
-                       l->p[0] = point;
-               else if (l->hitPoint[1])
-                       l->p[1] = point;
-               else if (l->hitObject)
+               break;
+       case OTCircle:
+               if (obj->hitPoint[0])
+                       obj->p[0] = point;
+               else if (obj->hitObject)
                {
-                       l->p[0] += delta;
-                       l->p[1] += delta;
+//this doesn't work. we need to save this on mouse down for this to work correctly!
+//                     double oldRadius = obj->radius[0];
+                       obj->radius[0] = Vector::Magnitude(obj->p[0], point);
+
+                       QString text = QObject::tr("Radius: %1");//\nScale: %2%");
+                       informativeText = text.arg(obj->radius[0], 0, 'd', 4);//.arg(obj->radius[0] / oldRadius * 100.0, 0, 'd', 0);
                }
 
                break;
-       }
        default:
                break;
        }