From 84fc4387b9a6051819da5c9ed688de1ec372c7f7 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Mon, 11 May 2015 07:46:28 -0500 Subject: [PATCH] Add ability to add Arcs to document. --- src/drawingview.cpp | 143 ++++++++++++++++++++++++++++++++++++++++++++ src/drawingview.h | 1 + src/structs.h | 2 +- src/vector.cpp | 9 +++ src/vector.h | 6 +- 5 files changed, 158 insertions(+), 3 deletions(-) diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 16280d6..9e1b56c 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -571,6 +571,8 @@ void DrawingView::ToolHandler(int mode, Point p) 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); } @@ -621,6 +623,50 @@ void DrawingView::ToolDraw(Painter * painter) 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) { if ((Global::toolState == TSNone) || (Global::toolState == TSPoint1)) @@ -743,6 +789,75 @@ void DrawingView::CircleHandler(int mode, Point p) } +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) @@ -1274,6 +1389,34 @@ bool DrawingView::HitTestObjects(Point point) 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; + } default: break; } diff --git a/src/drawingview.h b/src/drawingview.h index c8e46ff..e22634c 100644 --- a/src/drawingview.h +++ b/src/drawingview.h @@ -28,6 +28,7 @@ class DrawingView: public QWidget void ToolDraw(Painter *); void LineHandler(int, Point); void CircleHandler(int, Point); + void ArcHandler(int, Point); void RotateHandler(int, Point); void CheckObjectBounds(void); bool HitTestObjects(Point); diff --git a/src/structs.h b/src/structs.h index e0e17c8..6920e49 100644 --- a/src/structs.h +++ b/src/structs.h @@ -13,7 +13,7 @@ enum DimensionType { DTLinear, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric enum ToolType { TTNone, TTLine, TTCircle, TTEllipse, TTArc, TTDimension, TTText, TTPolygon, TTSpline, TTRotate, TTMirror, TTTrim, TTTriangulate, TTDelete }; -enum ToolState { TSNone, TSPoint1, TSPoint2, TSDone }; +enum ToolState { TSNone, TSPoint1, TSPoint2, TSPoint3, TSPoint4, TSDone }; #define OBJECT_COMMON \ int type; \ diff --git a/src/vector.cpp b/src/vector.cpp index a60c133..23b4299 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -243,6 +243,15 @@ bool Vector::isZero(double epsilon/*= 1e-6*/) } +// +// Convenience function +// +/*static*/ double Vector::Angle(Point p1, Point p2) +{ + return Vector(p1, p2).Angle(); +} + + // Returns the parameter of a point in space to this vector. If the parameter // is between 0 and 1, the normal of the vector to the point is on the vector. // Note: v1 is the tail, v2 is the head of the line (vector). diff --git a/src/vector.h b/src/vector.h index 6243898..4bcb461 100644 --- a/src/vector.h +++ b/src/vector.h @@ -13,6 +13,9 @@ // What we'll do here is create the vector type and use typedef to alias Point // to it. Yeah, that's it. +class Vector; +typedef Vector Point; + class Vector { public: @@ -49,6 +52,7 @@ class Vector static double Dot(Vector v1, Vector v2); static double Magnitude(Vector v1, Vector v2); + 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); @@ -57,6 +61,4 @@ class Vector double x, y, z; }; -typedef Vector Point; - #endif // __VECTOR_H__ -- 2.37.2