]> Shamusworld >> Repos - architektonas/commitdiff
Further refinements to the Circle class.
authorShamus Hammons <jlhamm@acm.org>
Tue, 27 Sep 2011 20:36:35 +0000 (20:36 +0000)
committerShamus Hammons <jlhamm@acm.org>
Tue, 27 Sep 2011 20:36:35 +0000 (20:36 +0000)
Makefile
src/circle.cpp
src/circle.h
src/line.cpp
src/painter.cpp
src/painter.h

index 37fab8be07c3b6a0a352693f5c77066f35ad4dac..cee9a70af8f086d1af7d3a1916756057d6212a45 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -45,10 +45,13 @@ clean:
 #docu:
 #      -(doxygen ./doxygen.cfg)
 
+# ANSI colors:
+# (00) 31 = dark red, 32 = dark green, 33 = brown, 34 = dark blue, 35 = dark purple, 36 = dark cyan, 37 = grey
+# (01) 31 = red, 32 = green, 33 = yellow, 34 = blue, 35 = purple, 36 = cyan, 37 = white
 statistics:
-       @echo -n "Lines in source files: "
+       @echo -ne "\033[01;35mLines in source files:\033[00m "
        @-$(FIND) ./src -name "*.cpp" | xargs cat | wc -l
-       @echo -n "Lines in header files: "
+       @echo -ne "\033[01;35mLines in header files:\033[00m "
        @-$(FIND) ./src -name "*.h" | xargs cat | wc -l
 
 dist:  clean
index ea56d906098e69a25e87ddd1c0101f84ed848a4b..35c9d7c2e53f224dd97323229027b37c246ce88a 100644 (file)
@@ -9,6 +9,8 @@
 // WHO  WHEN        WHAT
 // ---  ----------  ------------------------------------------------------------
 // JLH  03/28/2011  Created this file
+// JLH  09/26/2011  Added hover effects
+// JLH  09/26/2011  Major cleanup of this class
 //
 
 #include "circle.h"
@@ -18,7 +20,7 @@
 
 
 Circle::Circle(Vector p1, double r, Object * p/*= NULL*/): Object(p1, p), radius(r),
-       dragging(false), draggingHandle1(false), draggingHandle2(false)//, needUpdate(false)
+       draggingEdge(false), draggingCenter(false), hitCenter(false), hitCircle(false)
 {
 }
 
@@ -33,12 +35,14 @@ Circle::~Circle()
        else
                painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
 
+       // Draw handles (if needed)
        if (state == OSSelected || hitCenter)
-               painter->DrawEllipse(position, 4.0, 4.0);
+               painter->DrawHandle(position);
 
-       if (state == OSSelected && dragging)
-               painter->DrawEllipse(oldPoint, 4.0, 4.0);
+       if (state == OSSelected && draggingEdge && objectWasDragged)
+               painter->DrawHandle(dragPoint);
 
+       // & finally, draw the object!
        painter->DrawEllipse(position, radius, radius);
 }
 
@@ -53,53 +57,18 @@ Circle::~Circle()
        objectWasDragged = false;
        HitTest(point);
 
-//     objectWasDragged = false;
-       Vector v1 = position - point;
+       draggingCenter = hitCenter;
+       draggingEdge = hitCircle;
 
-       if (state == OSInactive)
+       if (hitCenter || hitCircle)
        {
-//printf("Circle: pp = %lf, length = %lf, distance = %lf\n", parameterizedPoint, lineSegment.Magnitude(), distance);
-//printf("      v1.Magnitude = %lf, v2.Magnitude = %lf\n", v1.Magnitude(), v2.Magnitude());
-//printf("      point = %lf,%lf,%lf; p1 = %lf,%lf,%lf; p2 = %lf,%lf,%lf\n", point.x, point.y, point.z, position.x, position.y, position.z, endpoint.x, endpoint.y, endpoint.z);
-//printf("      \n", );
-//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)
-               {
-                       oldState = state;
-                       state = OSSelected;
-                       oldPoint = position; //maybe "position"?
-                       draggingHandle1 = true;
-                       return true;
-               }
-               else if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
-               {
-                       oldState = state;
-                       state = OSSelected;
-                       oldPoint = point;
-                       dragging = true;
-                       return true;
-               }
-       }
-       else if (state == OSSelected)
-       {
-               // Here we test for collision with handles as well! (SOON!)
-/*
-Like so:
-               if (v1.Magnitude() < 2.0) // Handle #1
-               else if (v2.Magnitude() < 2.0) // Handle #2
-*/
-               if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
-               {
-                       oldState = state;
-//                     state = OSInactive;
-                       oldPoint = point;
-                       dragging = true;
-                       return true;
-               }
+               dragPoint = point;
+               oldState = state;
+               state = OSSelected;
+               return true;
        }
 
+       // We didn't hit anything, so deselect this object and report failure to hit
        state = OSInactive;
        return false;
 }
@@ -109,125 +78,47 @@ Like so:
        // 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 = (draggingEdge | draggingCenter);
 
-       objectWasDragged = true;
-
-       if (dragging)
-       {
-               // Here we need to check whether or not we're dragging a handle or the object itself...
-//             Vector delta = point - oldPoint;
-
-//             position += delta;
-//             endpoint += delta;
-               radius = Vector(point - position).Magnitude();
-
-               oldPoint = point;
-               needUpdate = true;
-       }
-       else if (draggingHandle1)
-       {
-               Vector delta = point - oldPoint;
-               position += delta;
-               oldPoint = point;
-               needUpdate = true;
-       }
-/*     else if (draggingHandle2)
-       {
-               Vector delta = point - oldPoint;
-
-               endpoint += delta;
+       if (draggingEdge)
+               radius = Vector::Magnitude(point, position);
+       else if (draggingCenter)
+               position = point;
 
-               oldPoint = point;
-               needUpdate = true;
-       }*/
-//     else
-//             needUpdate = false;
+       // Save this point so the rendering code knows where to draw the handle...
+       dragPoint = point;
 }
 
 /*virtual*/ void Circle::PointerReleased(void)
 {
-       dragging = false;
-       draggingHandle1 = false;
-       draggingHandle2 = 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...
-*/
+       // Mouse went up, so our dragging is done (if any *was* done, that is)
+       draggingEdge = draggingCenter = false;
+       hitCenter = hitCircle = false;
+
+       // If the object was dragged, then revert to the old state.
+       // Otherwise, we were probably just clicked, and want to stay in the selected state.
        if (objectWasDragged)
                state = oldState;
 }
 
-#if 0
-/*virtual*/ bool Circle::NeedsUpdate(void)
-{
-       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;
+       double length = Vector::Magnitude(position, point);
+//printf("Circle::length = %lf, radius = %lf\n", length, radius);
 //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)
+/*
+Document passes in the correct Cartesian coordinates being pointed to by the mouse.
+So all we have to be concerned with is properly scaling our hot zones/handle sizes,
+since we generally *don't* want those to scale with the zoom level. ;-)
+*/
+       if (length < 8.0)
                hitCenter = true;
-       else if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
+       else if ((length < (radius + 2.0)) && (length > (radius - 2.0)))
                hitCircle = true;
-#endif
 
        return StateChanged();
 }
index 1a000da1e976fc9067cef114afe54979cc211d84..cae030830d10951eaede7b37a30e3ffe8ec72489 100644 (file)
@@ -14,7 +14,6 @@ class Circle: public Object
                virtual bool Collided(Vector);
                virtual void PointerMoved(Vector);
                virtual void PointerReleased(void);
-//             virtual bool NeedsUpdate(void);
 
        protected:
                bool HitTest(Point);
@@ -23,13 +22,11 @@ class Circle: public Object
 
        protected:
                double radius;                                          // Center is Object::position
-               Vector oldPoint;                                        // Used for dragging
+               Vector dragPoint;                                       // Used for rendering edge dragging
 
        private:
-               bool dragging;
-               bool draggingHandle1;
-               bool draggingHandle2;
-//             bool needUpdate;
+               bool draggingEdge;
+               bool draggingCenter;
                bool objectWasDragged;
                bool hitCenter, hitCircle;
                bool oldHitCenter, oldHitCircle;
index 7f04a1989e25f17f0328ff0e1c0147408c23883b..2e3539f7b0cfa510045ce1569c1139578b304d1e 100644 (file)
@@ -49,10 +49,10 @@ Line::~Line()
        painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine));
 
        if ((state == OSSelected) || ((state == OSInactive) && hitPoint1))
-               painter->DrawEllipse(position, 4.0, 4.0);
+               painter->DrawHandle(position);
 
        if ((state == OSSelected) || ((state == OSInactive) && hitPoint2))
-               painter->DrawEllipse(endpoint, 4.0, 4.0);
+               painter->DrawHandle(endpoint);
 
        if ((state == OSInactive) && !hitLine)
                painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
index 2a0c60060869deed8771872a1fd4c06b3af97407..c0d2c4d2300843e80aaaee7a2b8b55e52b037a2f 100644 (file)
@@ -135,6 +135,8 @@ void Painter::DrawAngledText(Vector center, double angle, QString text)
 void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
 {
        center = CartesianToQtCoords(center);
+       // Need to multiply scalar quantities by the zoom factor as well...
+       radius *= zoom;
        QRectF rectangle(QPointF(center.x - radius, center.y - radius),
                QPointF(center.x + radius, center.y + radius));
        int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
@@ -144,8 +146,17 @@ void Painter::DrawArc(Vector center, double radius, double startAngle, double sp
 
 void Painter::DrawEllipse(Vector center, double axis1, double axis2)
 {
+       // Need to multiply scalar quantities by the zoom factor as well...
        center = CartesianToQtCoords(center);
-       painter->drawEllipse(QPointF(center.x, center.y), axis1, axis2);
+       painter->drawEllipse(QPointF(center.x, center.y), axis1 * zoom, axis2 * zoom);
+}
+
+// This function is for drawing object handles without regard for zoom level;
+// we don't want our object handle size to depend on the zoom level!
+void Painter::DrawHandle(Vector center)
+{
+       center = CartesianToQtCoords(center);
+       painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0);
 }
 
 void Painter::DrawLine(int x1, int y1, int x2, int y2)
index 367c7a84e6a4fb4b11a147e7e8198edc183ec832..52da1d5a212548f30c5aaebe98d87238cb2a3653 100644 (file)
@@ -19,6 +19,7 @@ class Painter
                void DrawAngledText(Vector, double, QString);
                void DrawArc(Vector, double, double, double);
                void DrawEllipse(Vector, double, double);
+               void DrawHandle(Vector);
                void DrawLine(int, int, int, int);
                void DrawLine(Vector, Vector);
                void DrawPoint(int, int);