From c51c02d23ddd4423882da2c54b76f8f2c90c1c99 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Tue, 12 Apr 2011 00:36:32 +0000 Subject: [PATCH] Fixed Line rendering to keep attached Dimensions correct length with 'Fix Len' --- src/dimension.cpp | 53 +++++++++----------- src/dimension.h | 4 +- src/drawingview.cpp | 8 ++- src/line.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++-- src/line.h | 6 ++- src/object.cpp | 9 +++- src/object.h | 5 +- 7 files changed, 158 insertions(+), 42 deletions(-) diff --git a/src/dimension.cpp b/src/dimension.cpp index d049fc3..381196b 100644 --- a/src/dimension.cpp +++ b/src/dimension.cpp @@ -34,34 +34,6 @@ Dimension::~Dimension() else painter->setPen(QPen(Qt::blue, 1.0, Qt::SolidLine)); -#if 0 -// if (draggingHandle1) - if (state == OSSelected) - painter->drawEllipse(QPointF(position.x, position.y), 4.0, 4.0); - -// if (draggingHandle2) - if (state == OSSelected) - painter->drawEllipse(QPointF(endpoint.x, endpoint.y), 4.0, 4.0); - - if (Object::fixedLength && (draggingHandle1 || draggingHandle2)) - { - Vector point1 = (draggingHandle1 ? endpoint : position); - Vector point2 = (draggingHandle1 ? position : endpoint); - - Vector current(point2 - point1); - Vector v = current.Unit() * length; - Vector v2 = point1 + v; - painter->drawLine((int)point1.x, (int)point1.y, (int)v2.x, (int)v2.y); - - if (current.Magnitude() > length) - { - painter->setPen(QPen(QColor(128, 0, 0), 1.0, Qt::DashLine)); - painter->drawLine((int)v2.x, (int)v2.y, (int)point2.x, (int)point2.y); - } - } - else - painter->drawLine((int)position.x, (int)position.y, (int)endpoint.x, (int)endpoint.y); -#endif // Draw an aligned dimension line double angle = Vector(endpoint - position).Angle(); double orthoAngle = angle + (PI / 2.0); @@ -90,17 +62,28 @@ Dimension::~Dimension() Point ctr = p2 + v1; QString dimText = QString("%1\"").arg(Vector(endpoint - position).Magnitude()); int textWidth = QFontMetrics(painter->font()).width(dimText); + int textHeight = QFontMetrics(painter->font()).height(); //We have to do transformation voodoo to make the text come out readable and in correct orientation... //Some things to note here: if angle > 90 degrees, then we need to take the negative of the angle //for our text. painter->save(); painter->translate(ctr.x, ctr.y); +int yOffset = -8; +//16 : printf("textHeight: %d\n", textHeight); + +//Fix text so it isn't upside down... +if ((angle > PI * 0.5) && (angle < PI * 1.5)) +{ + angle += PI; + yOffset = 18; +} + painter->rotate(angle * RADIANS_TO_DEGREES); painter->scale(1.0, -1.0); //painter->translate(-textWidth / 2, -24); // painter->drawText(0, 0, textWidth, 20, Qt::AlignCenter, dimText); // This version draws the y-coord from the baseline of the font - painter->drawText(-textWidth / 2, -8, dimText); + painter->drawText(-textWidth / 2, yOffset, dimText); //painter->setPen(QPen(QColor(0xFF, 0x20, 0x20), 1.0, Qt::SolidLine)); //painter->drawLine(20, 0, -20, 0); //painter->drawLine(0, 20, 0, -20); @@ -295,3 +278,15 @@ about keeping track of old states... if (objectWasDragged) state = oldState; } + +void Dimension::SetPoint1(Vector v) +{ + position = v; + needUpdate = true; +} + +void Dimension::SetPoint2(Vector v) +{ + endpoint = v; + needUpdate = true; +} diff --git a/src/dimension.h b/src/dimension.h index 26fc588..34084c2 100644 --- a/src/dimension.h +++ b/src/dimension.h @@ -14,7 +14,8 @@ class Dimension: public Object virtual bool Collided(Vector); virtual void PointerMoved(Vector); virtual void PointerReleased(void); -// virtual bool NeedsUpdate(void); + void SetPoint1(Vector); + void SetPoint2(Vector); protected: Vector endpoint; // Starting point is Object::position @@ -24,7 +25,6 @@ class Dimension: public Object bool dragging; bool draggingHandle1; bool draggingHandle2; -// bool needUpdate; bool objectWasDragged; double length; }; diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 911b2ba..55b56e7 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -50,14 +50,18 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent), // setCursor(cur[TOOLSelect]); // setMouseTracking(true); - document.Add(new Line(Vector(5, 5), Vector(50, 40), &document)); + Line * line = new Line(Vector(5, 5), Vector(50, 40), &document); + document.Add(line); document.Add(new Line(Vector(50, 40), Vector(10, 83), &document)); document.Add(new Line(Vector(10, 83), Vector(17, 2), &document)); document.Add(new Circle(Vector(100, 100), 36, &document)); document.Add(new Circle(Vector(50, 150), 49, &document)); document.Add(new Arc(Vector(300, 300), 32, PI / 4.0, PI * 1.3, &document)), document.Add(new Arc(Vector(200, 200), 60, PI / 2.0, PI * 1.5, &document)); - document.Add(new Dimension(Vector(5, 5), Vector(50, 40), &document)); + Dimension * dimension = new Dimension(Vector(0, 0), Vector(0, 0), &document); + line->SetDimensionOnPoint1(dimension); + line->SetDimensionOnPoint2(dimension); + document.Add(dimension); } QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event) diff --git a/src/line.cpp b/src/line.cpp index b78a9dc..b7a11fb 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -9,11 +9,14 @@ // WHO WHEN WHAT // --- ---------- ------------------------------------------------------------ // JLH 03/22/2011 Created this file +// JLH 04/11/2011 Fixed attached dimensions to stay at correct length when +// "Fixed Length" button is down // #include "line.h" #include +#include "dimension.h" Line::Line(Vector p1, Vector p2, Object * p/*= NULL*/): Object(p1, p), endpoint(p2), dragging(false), draggingHandle1(false), draggingHandle2(false), //needUpdate(false), @@ -203,6 +206,23 @@ Like so: } else needUpdate = false; + + if (needUpdate) + { +// should only do this if "Fixed Length" is set... !!! FIX !!! + Vector point1 = (draggingHandle1 ? endpoint : position); + Vector point2 = (draggingHandle1 ? position : endpoint); + + Vector current(point2 - point1); + Vector v = current.Unit() * length; + Vector v2 = point1 + v; + + if (dimPoint1) + dimPoint1->SetPoint1(draggingHandle1 ? v2 : position); + + if (dimPoint2) + dimPoint2->SetPoint2(draggingHandle2 ? v2 : endpoint); + } } /*virtual*/ void Line::PointerReleased(void) @@ -247,9 +267,96 @@ about keeping track of old states... state = oldState; } -#if 0 -/*virtual*/ bool Line::NeedsUpdate(void) +void Line::SetDimensionOnPoint1(Dimension * dimension) +{ + dimPoint1 = dimension; + + if (dimension) + dimension->SetPoint1(position); +} + +void Line::SetDimensionOnPoint2(Dimension * dimension) { - return needUpdate; + dimPoint2 = dimension; + + if (dimension) + dimension->SetPoint2(endpoint); } -#endif + +/* +Intersection of two lines: + +Find where the lines with equations r = i + j + t (3i - j) and r = -i + s (j) intersect. + +When they intersect, we can set the equations equal to one another: + +i + j + t (3i - j) = -i + s (j) + +Equating coefficients: +1 + 3t = -1 and 1 - t = s +So t = -2/3 and s = 5/3 + +The position vector of the intersection point is therefore given by putting t = -2/3 or s = 5/3 into one of the above equations. This gives -i +5j/3 . + + +so, let's say we have two lines, l1 and l2. Points are v0(p0x, p0y), v1(p1x, p1y) for l1 +and v2(p2x, p2y), v3(p3x, p3y) for l2. + +d1 = v1 - v0, d2 = v3 - v2 + +Our parametric equations for the line then are: + +r1 = v0 + t(d1) +r2 = v2 + s(d2) + +Set r1 = r2, thus we have: + +v0 + t(d1) = v2 + s(d2) + +Taking coefficients, we have: + +p0x + t(d1x) = p2x + s(d2x) +p0y + t(d1y) = p2y + s(d2y) + +rearranging we get: + +t(d1x) - s(d2x) = p2x - p0x +t(d1y) - s(d2y) = p2y - p0y + +Determinant D is ad - bc where the matrix look like: + +a b +c d + +so D = (d1x)(d2y) - (d2x)(d1y) +if D = 0, the lines are parallel. +Dx = (p2x - p0x)(d2y) - (d2x)(p2y - p0y) +Dy = (d1x)(p2y - p0y) - (p2x - p0x)(d1y) +t = Dx/D, s = Dy/D + +We only need to calculate t, as we can then multiply it by d1 to get the intersection point. + +--------------------------------------------------------------------------------------------------- + +The first and most preferred method for intersection calculation is the perp-product calculation. There are two vectors, v1 and v2. Create a third vector vector between the starting points of these vectors, and calculate the perp product of v2 and the two other vectors. These two scalars have to be divided to get the mulitplication ratio of v1 to reach intersection point. So: + +v1 ( bx1 , by1 ); +v2 ( bx2 , by2 ); +v3 ( bx3 , by3 ); + +Perp product is equal with dot product of normal of first vector and the second vector, so we need normals: + +n1 ( -by1 , bx1 ); +n3 ( -by3 , bx3 ); + +Dot products: + +dp1 = n3.v2 = -by3*bx2 + bx3*by2; +dp2 = n1.v2 = -by1*bx2 + bx1*by2; + +ratio = dp1/dp2; +crossing vector = v1*rat; + +And that's it. +*/ + diff --git a/src/line.h b/src/line.h index 1a38fa3..8d79c1f 100644 --- a/src/line.h +++ b/src/line.h @@ -3,6 +3,8 @@ #include "object.h" +class Dimension; + class Line: public Object { public: @@ -14,7 +16,8 @@ class Line: public Object virtual bool Collided(Vector); virtual void PointerMoved(Vector); virtual void PointerReleased(void); -// virtual bool NeedsUpdate(void); + void SetDimensionOnPoint1(Dimension *); + void SetDimensionOnPoint2(Dimension *); protected: Vector endpoint; // Starting point is Object::position @@ -24,7 +27,6 @@ class Line: public Object bool dragging; bool draggingHandle1; bool draggingHandle2; -// bool needUpdate; bool objectWasDragged; double length; }; diff --git a/src/object.cpp b/src/object.cpp index c2e874c..eaef4d4 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -24,12 +24,12 @@ int Object::viewportHeight = 0; Object::Object(): position(Vector(0, 0)), parent(0), state(OSInactive), oldState(OSInactive), - needUpdate(false) + needUpdate(false), dimPoint1(0), dimPoint2(0) { } Object::Object(Vector v, Object * passedInParent/*= 0*/): position(v), parent(passedInParent), - state(OSInactive), oldState(OSInactive), needUpdate(false) + state(OSInactive), oldState(OSInactive), needUpdate(false), dimPoint1(0), dimPoint2(0) { } @@ -64,6 +64,11 @@ Object::~Object() return needUpdate; } +// This is intended to be overridden by the Container class, for object morphing +/*virtual*/ void Object::Transmute(Object *, Object *) +{ +} + ObjectState Object::GetState(void) { return state; diff --git a/src/object.h b/src/object.h index e0ea740..deaa91f 100644 --- a/src/object.h +++ b/src/object.h @@ -5,6 +5,7 @@ class QPainter; class QFont; +class Dimension; enum ObjectState { OSInactive, OSSelected }; @@ -21,7 +22,7 @@ class Object virtual void PointerMoved(Vector); virtual void PointerReleased(void); virtual bool NeedsUpdate(void); - + virtual void Transmute(Object *, Object *); ObjectState GetState(void); // Class methods @@ -38,6 +39,8 @@ class Object ObjectState state; ObjectState oldState; bool needUpdate; + Dimension * dimPoint1; + Dimension * dimPoint2; // Class variables static QFont * font; -- 2.37.2