]> Shamusworld >> Repos - architektonas/blobdiff - src/circle.cpp
Preliminary start on zooming/circle hover feedback.
[architektonas] / src / circle.cpp
index a8902cc4da11d38449e10f2a8f595991df01c881..ea56d906098e69a25e87ddd1c0101f84ed848a4b 100644 (file)
@@ -28,18 +28,14 @@ Circle::~Circle()
 
 /*virtual*/ void Circle::Draw(Painter * painter)
 {
-       if (state == OSSelected)
+       if (state == OSSelected || hitCircle || hitCenter)
                painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine));
        else
                painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
 
-//     if (draggingHandle1)
-       if (state == OSSelected)
+       if (state == OSSelected || hitCenter)
                painter->DrawEllipse(position, 4.0, 4.0);
 
-//     if (draggingHandle2)
-//     if (state == OSSelected)
-//             painter->drawEllipse(QPointF(endpoint.x, endpoint.y), 4.0, 4.0);
        if (state == OSSelected && dragging)
                painter->DrawEllipse(oldPoint, 4.0, 4.0);
 
@@ -53,7 +49,11 @@ Circle::~Circle()
 
 /*virtual*/ bool Circle::Collided(Vector point)
 {
+       // We can assume this, since this is a mouse down event here.
        objectWasDragged = false;
+       HitTest(point);
+
+//     objectWasDragged = false;
        Vector v1 = position - point;
 
        if (state == OSInactive)
@@ -106,6 +106,10 @@ Like so:
 
 /*virtual*/ void Circle::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);
+
        objectWasDragged = true;
 
        if (dragging)
@@ -136,8 +140,8 @@ Like so:
                oldPoint = point;
                needUpdate = true;
        }*/
-       else
-               needUpdate = false;
+//     else
+//             needUpdate = false;
 }
 
 /*virtual*/ void Circle::PointerReleased(void)
@@ -162,3 +166,82 @@ about keeping track of old states...
        return needUpdate;
 }
 #endif
+
+bool Circle::HitTest(Point point)
+{
+       SaveState();
+
+       hitCenter = hitCircle = false;
+
+#if 0
+       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 !!!"
+       if (v1.Magnitude() < 8.0)
+               hitPoint1 = true;
+       else if (v2.Magnitude() < 8.0)
+               hitPoint2 = true;
+       else if (distance < 5.0)
+               hitLine = true;
+#else
+       Vector v1 = position - point;
+//How to translate this into pixels from Document space???
+//Maybe we need to pass a scaling factor in here from the caller? That would make sense, as
+//the caller knows about the zoom factor and all that good kinda crap
+       if (v1.Magnitude() < 10.0)
+               hitCenter = true;
+       else if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
+               hitCircle = true;
+#endif
+
+       return StateChanged();
+}
+
+void Circle::SaveState(void)
+{
+       oldHitCenter = hitCenter;
+       oldHitCircle = hitCircle;
+}
+
+bool Circle::StateChanged(void)
+{
+       if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle))
+               return true;
+
+       return false;
+}