]> Shamusworld >> Repos - architektonas/blobdiff - src/line.cpp
Fixed loading code, added "Base Unit" dialog.
[architektonas] / src / line.cpp
index da9717c1af65810bbe2975e33b9c8048c3798610..a3d745aa3da32908a53b3f45c47d6076af07ef24 100644 (file)
@@ -19,7 +19,9 @@
 #include "line.h"
 
 #include <QtGui>
+#include "container.h"
 #include "dimension.h"
+#include "mathconstants.h"
 #include "painter.h"
 
 
@@ -88,6 +90,35 @@ Line::~Line()
        else
 //             painter->DrawLine((int)position.x, (int)position.y, (int)endpoint.x, (int)endpoint.y);
                painter->DrawLine(position, endpoint);
+
+       // If we're rotating or setting the span, draw an information panel
+       // showing both absolute and relative angles being set.
+       if (draggingHandle1 || draggingHandle2)
+       {
+               double absAngle = (Vector(endpoint - position).Angle()) * RADIANS_TO_DEGREES;
+//             double relAngle = (startAngle >= oldAngle ? startAngle - oldAngle :
+//                     startAngle - oldAngle + (2.0 * PI)) * RADIANS_TO_DEGREES;
+               double absLength = Vector(position - endpoint).Magnitude();
+
+               QString text;
+
+               text = QObject::tr("Length: %1 in.\n") + QChar(0x2221) + QObject::tr(": %2");
+               text = text.arg(absLength).arg(absAngle);
+
+               QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
+               painter->SetPen(pen);
+               painter->SetBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
+               QRectF textRect(10.0, 10.0, 270.0, 70.0);       // x, y, w, h
+               painter->DrawRoundedRect(textRect, 7.0, 7.0);
+
+               textRect.setLeft(textRect.left() + 14);
+               painter->SetFont(*Object::font);
+//                     pen = QPen(QColor(0xDF, 0x5F, 0x00), 1.0, Qt::SolidLine);
+               pen = QPen(QColor(0x00, 0x5F, 0xDF));
+               painter->SetPen(pen);
+               painter->DrawText(textRect, Qt::AlignVCenter, text);
+//             painter->SetPen(QPen(QColor(0xDF, 0x5F, 0x00)));
+       }
 }
 
 /*virtual*/ Vector Line::Center(void)
@@ -101,7 +132,18 @@ Line::~Line()
 {
        // We can assume this, since this is a mouse down event here.
        objectWasDragged = false;
+       SaveState();
        HitTest(point);
+//     return StateChanged();
+
+// this is shite. this should be checked for in the Container, not here!
+       // If we're part of a non-top-level container, send this signal to it
+       if (parent->type == OTContainer && !((Container *)parent)->isTopLevelContainer
+               && (hitLine || hitPoint1 || hitPoint2))
+       {
+               parent->state = OSSelected;
+               return true;
+       }
 
 /*
 There's a small problem here with the implementation: You can have a dimension tied
@@ -255,9 +297,29 @@ Like so:
 
 /*virtual*/ void Line::PointerMoved(Vector point)
 {
-       // Hit test tells us what we hit (if anything) through boolean variables. It
-       // also tells us whether or not the state changed.
-       needUpdate = HitTest(point);
+       if (selectionInProgress)
+       {
+               // Check for whether or not the rect contains this line
+#if 0
+               if (selection.normalized().contains(Extents()))
+#else
+//             if (selection.normalized().contains(position.x, position.y)
+//                     && selection.normalized().contains(endpoint.x, endpoint.y))
+               if (selection.contains(position.x, position.y)
+                       && selection.contains(endpoint.x, endpoint.y))
+#endif
+                       state = OSSelected;
+               else
+                       state = OSInactive;
+
+               return;
+       }
+
+       // Hit test tells us what we hit (if anything) through boolean variables. (It
+       // also tells us whether or not the state changed. --not any more)
+       SaveState();
+       HitTest(point);
+       needUpdate = StateChanged();
 
        objectWasDragged = (draggingLine | draggingHandle1 | draggingHandle2);
 
@@ -308,16 +370,6 @@ try to do the right thing, most of the time. :-)
                Vector point1 = (draggingHandle1 ? endpoint : position);
                Vector point2 = (draggingHandle1 ? position : endpoint);
 
-#if 0
-               Vector current(point2, point1);
-               Vector v = current.Unit() * length;
-               Vector v2 = point1 + v;
-
-               //bleh
-               if (!Object::fixedLength)
-                       v2 = point2;
-#endif
-
                if (Object::fixedAngle)
                {
                        // Here we calculate the component of the current vector along the fixed angle.
@@ -369,22 +421,21 @@ the horizontal line or vertical line that intersects from the current mouse posi
                        }
                        else                                    // endpoint
                        {
-//                             Vector v1 = endpoint - position;
                                Vector v = Vector(endpoint - position).Unit() * length;
                                endpoint = position + v;
                        }
                }
                else
                {
-                       // Otherwise, we calculate the new length, just in case on the next move
-                       // it turns out to have a fixed length. :-)
+                       // Otherwise, we calculate the new length, just in case on the next
+                       // move it turns out to have a fixed length. :-)
                        length = Vector(endpoint - position).Magnitude();
                }
 
                if (!Object::fixedAngle)
                {
-                       // Calculate the new angle, just in case on the next move it turns out to
-                       // be fixed. :-)
+                       // Calculate the new angle, just in case on the next move it turns
+                       // out to be fixed. :-)
                        angle = Vector(endpoint - position).Unit();
                }
        }
@@ -393,19 +444,68 @@ the horizontal line or vertical line that intersects from the current mouse posi
        draggingHandle1 = false;
        draggingHandle2 = false;
 
-//     hitPoint1 = hitPoint2 = hitLine = false;
-
-       // Here we check for just a click: If object was clicked and dragged, then
-       // revert to the old state (OSInactive). Otherwise, keep the new state that
-       // we set.
-/*Maybe it would be better to just check for "object was dragged" state and not have to worry
-about keeping track of old states...
-*/
        if (objectWasDragged)
                state = oldState;
 }
 
 
+/*virtual*/ bool Line::HitTest(Point point)
+{
+//     SaveState();
+
+       hitPoint1 = hitPoint2 = hitLine = false;
+       Vector lineSegment = endpoint - position;
+       Vector v1 = point - position;
+       Vector v2 = point - endpoint;
+       double t = Vector::Parameter(position, endpoint, point);
+       double distance;
+
+       // Geometric interpretation:
+       // The parameter "t" on the vector lineSegment is where the normal of
+       // lineSegment coincides with point. If t < 0, the normal lies beyond the
+       // 1st endpoint. If t > 1, then the normal lies beyond the 2nd endpoint. We
+       // only calculate the length of the normal between the point and the
+       // lineSegment when the parameter is between 0 and 1.
+
+       // Geometric interpretation of "distance = ?Det?(ls, v1) / |ls|":
+       // If the segment endpoints are s and e, and the point is p, then the test
+       // for the perpendicular intercepting the segment is equivalent to insisting
+       // that the two dot products {s-e}.{s-p} and {e-s}.{e-p} are both non-negative.
+       // Perpendicular distance from the point to the segment is computed by first
+       // computing the area of the triangle the three points form, then dividing by
+       // the length of the segment.  Distances are done just by the Pythagorean
+       // theorem. Twice the area of the triangle formed by three points is the
+       // determinant of the following matrix:
+       //
+       // sx sy 1       0  0  1       0  0  0
+       // ex ey 1  ==>  ex ey 1  ==>  ex ey 0
+       // px py 1       px py 1       px py 0
+       //
+       // By translating the start point to the origin, and subtracting row 1 from
+       // all other rows, we end up with the matrix on the right which greatly
+       // simplifies the calculation of the determinant.
+
+       if (t < 0.0)
+               distance = v1.Magnitude();
+       else if (t > 1.0)
+               distance = v2.Magnitude();
+       else
+               // distance = ?Det?(ls, v1) / |ls|
+               distance = fabs((lineSegment.x * v1.y - v1.x * lineSegment.y)
+                       / lineSegment.Magnitude());
+
+       if ((v1.Magnitude() * Painter::zoom) < 8.0)
+               hitPoint1 = true;
+       else if ((v2.Magnitude() * Painter::zoom) < 8.0)
+               hitPoint2 = true;
+       else if ((distance * Painter::zoom) < 5.0)
+               hitLine = true;
+
+       return (hitPoint1 | hitPoint2 | hitLine ? true : false);
+//     return StateChanged();
+}
+
+
 // Check to see if the point passed in coincides with any we have. If so, return a
 // pointer to it; otherwise, return NULL.
 /*virtual*/ Vector * Line::GetPointAt(Vector v)
@@ -429,12 +529,13 @@ about keeping track of old states...
 {
 #warning "!!! This doesn't take care of attached Dimensions !!!"
 /*
-This is a real problem. While having a pointer in the Dimension to this line's points is fast & easy,
-it creates a huge problem when trying to replicate an object like this.
+This is a real problem. While having a pointer in the Dimension to this line's points
+is fast & easy, it creates a huge problem when trying to replicate an object like this.
 
-Maybe a way to fix that then, is to have reference numbers instead of pointers. That way, if you copy
-them, ... you might still have problems. Because you can't be sure if a copy will be persistant or not,
-you then *definitely* do not want them to have the same reference number.
+Maybe a way to fix that then, is to have reference numbers instead of pointers. That
+way, if you copy them, ... you might still have problems. Because you can't be sure if
+a copy will be persistant or not, you then *definitely* do not want them to have the
+same reference number.
 */
        return new Line(position, endpoint, parent);
 }
@@ -469,12 +570,21 @@ you then *definitely* do not want them to have the same reference number.
 }
 
 
-#if 0
-/*virtual*/ ObjectType Line::Type(void)
+/*virtual*/ void Line::Translate(Vector amount)
+{
+       position += amount;
+       endpoint += amount;
+}
+
+
+/*virtual*/ void Line::Rotate(Vector point, double angle)
+{
+}
+
+
+/*virtual*/ void Line::Scale(Vector point, double amount)
 {
-       return OTLine;
 }
-#endif
 
 
 void Line::SetDimensionOnLine(Dimension * dimension/*=NULL*/)
@@ -530,60 +640,6 @@ Object * Line::FindAttachedDimension(void)
 }
 
 
-bool Line::HitTest(Point point)
-{
-       SaveState();
-
-       hitPoint1 = hitPoint2 = hitLine = false;
-       Vector lineSegment = endpoint - position;
-       Vector v1 = point - position;
-       Vector v2 = point - endpoint;
-       double parameterizedPoint = lineSegment.Dot(v1) / lineSegment.Magnitude(), distance;
-
-       // Geometric interpretation:
-       // The parameterized point on the vector lineSegment is where the perpendicular
-       // intersects lineSegment. If pp < 0, then the perpendicular lies beyond the 1st
-       // endpoint. If pp > length of ls, then the perpendicular lies beyond the 2nd endpoint.
-
-       if (parameterizedPoint < 0.0)
-               distance = v1.Magnitude();
-       else if (parameterizedPoint > lineSegment.Magnitude())
-               distance = v2.Magnitude();
-       else
-               // distance = ?Det?(ls, v1) / |ls|
-               distance = fabs((lineSegment.x * v1.y - v1.x * lineSegment.y) / lineSegment.Magnitude());
-
-       // Geometric interpretation of the above:
-       // If the segment endpoints are s and e, and the point is p, then the test
-       // for the perpendicular intercepting the segment is equivalent to insisting
-       // that the two dot products {s-e}.{s-p} and {e-s}.{e-p} are both non-negative.
-       // Perpendicular distance from the point to the segment is computed by first
-       // computing the area of the triangle the three points form, then dividing by
-       // the length of the segment.  Distances are done just by the Pythagorean
-       // theorem. Twice the area of the triangle formed by three points is the
-       // determinant of the following matrix:
-       //
-       // sx sy 1       0  0  1       0  0  0
-       // ex ey 1  ==>  ex ey 1  ==>  ex ey 0
-       // px py 1       px py 1       px py 0
-       //
-       // By translating the start point to the origin, and subtracting row 1 from
-       // all other rows, we end up with the matrix on the right which greatly
-       // simplifies the calculation of the determinant.
-
-//How do we determine distance here? Especially if zoomed in or out???
-//#warning "!!! Distances tested for may not be valid if zoomed in or out !!!"
-// [FIXED]
-       if ((v1.Magnitude() * Painter::zoom) < 8.0)
-               hitPoint1 = true;
-       else if ((v2.Magnitude() * Painter::zoom) < 8.0)
-               hitPoint2 = true;
-       else if ((distance * Painter::zoom) < 5.0)
-               hitLine = true;
-
-       return StateChanged();
-}
-
 void Line::SaveState(void)
 {
        oldHitPoint1 = hitPoint1;
@@ -591,6 +647,7 @@ void Line::SaveState(void)
        oldHitLine = hitLine;
 }
 
+
 bool Line::StateChanged(void)
 {
        if ((hitPoint1 != oldHitPoint1) || (hitPoint2 != oldHitPoint2) || (hitLine != oldHitLine))
@@ -599,6 +656,7 @@ bool Line::StateChanged(void)
        return false;
 }
 
+
 /*
 Intersection of two lines: