]> Shamusworld >> Repos - architektonas/commitdiff
Preliminary start on zooming/circle hover feedback.
authorShamus Hammons <jlhamm@acm.org>
Mon, 26 Sep 2011 11:55:17 +0000 (11:55 +0000)
committerShamus Hammons <jlhamm@acm.org>
Mon, 26 Sep 2011 11:55:17 +0000 (11:55 +0000)
src/circle.cpp
src/circle.h
src/drawingview.cpp
src/line.cpp
src/painter.cpp
src/painter.h

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;
+}
index cc5159fd581a2da6bd8f32052d550d46a5a387d3..1a000da1e976fc9067cef114afe54979cc211d84 100644 (file)
@@ -16,6 +16,11 @@ class Circle: public Object
                virtual void PointerReleased(void);
 //             virtual bool NeedsUpdate(void);
 
+       protected:
+               bool HitTest(Point);
+               void SaveState(void);
+               bool StateChanged(void);
+
        protected:
                double radius;                                          // Center is Object::position
                Vector oldPoint;                                        // Used for dragging
@@ -26,6 +31,8 @@ class Circle: public Object
                bool draggingHandle2;
 //             bool needUpdate;
                bool objectWasDragged;
+               bool hitCenter, hitCircle;
+               bool oldHitCenter, oldHitCircle;
 };
 
 #endif // __CIRCLE_H__
index 148a34eed24bb9ded6dc67ca6f2359c7984d1bcb..a5349d98b8721da800da1f497055dd06f435b6d4 100644 (file)
@@ -101,6 +101,7 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
                qtPainter.setRenderHint(QPainter::Antialiasing);
 
        Painter::screenSize = Vector(size().width(), size().height());
+       Painter::zoom = 2.0;    // 200% zoom
 #if 0
 #if 0
        painter.translate(QPoint(-offsetX, size.height() - (-offsetY)));
@@ -163,8 +164,9 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::LeftButton)
        {
-               QPoint pt = GetAdjustedMousePosition(event);
-               Vector point(pt.x(), pt.y());
+//             QPoint pt = GetAdjustedMousePosition(event);
+//             Vector point(pt.x(), pt.y());
+               Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
 
                collided = document.Collided(point);
 
@@ -175,8 +177,9 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
 
 void DrawingView::mouseMoveEvent(QMouseEvent * event)
 {
-       QPoint pt = GetAdjustedMousePosition(event);
-       Vector point(pt.x(), pt.y());
+//     QPoint pt = GetAdjustedMousePosition(event);
+//     Vector point(pt.x(), pt.y());
+       Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
 
        // Grid processing...
 #if 1
index 06fbbc6a28cfe7cffecc8169e0069a58c369828c..7f04a1989e25f17f0328ff0e1c0147408c23883b 100644 (file)
@@ -86,8 +86,7 @@ Line::~Line()
 
 /*virtual*/ bool Line::Collided(Vector point)
 {
-// Can't assume this!
-// Actually, we can, since this is a mouse down event here.
+       // We can assume this, since this is a mouse down event here.
        objectWasDragged = false;
        HitTest(point);
 
index 8e664d21b4fdc54a50d30bd347b6d5fff46f1df1..2a0c60060869deed8771872a1fd4c06b3af97407 100644 (file)
@@ -38,7 +38,7 @@ Vector Painter::CartesianToQtCoords(Vector v)
        return Vector((v.x - origin.x) * zoom, screenSize.y - ((v.y - origin.y) * zoom));
 }
 
-Vector Painter::QtCoordsToCartesian(Vector v)
+Vector Painter::QtToCartesianCoords(Vector v)
 {
        // Convert screen location, with inverted Y-axis coordinates, to regular
        // Cartesian coordinates at the current zoom level.
@@ -100,6 +100,9 @@ void Painter::SetPen(QPen pen)
 
 void Painter::DrawAngledText(Vector center, double angle, QString text)
 {
+       // Strategy: Since Qt doesn't have any rotated text drawing functions,
+       // we instead translate the origin to the center of the text to be drawn and
+       // then rotate the frame to the desired angle.
        center = CartesianToQtCoords(center);
 
        // We may need this stuff... If dimension text is large enough.
@@ -107,17 +110,13 @@ void Painter::DrawAngledText(Vector center, double angle, QString text)
 //     int textHeight = QFontMetrics(painter->font()).height();
        QRectF textBox(-100, -100, 200, 200);   // x, y, w, h; x/y = upper left corner
 
-       // 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(center.x, center.y);
        // This is in pixels. Might not render correctly at all zoom levels.
        // Need to figure out if dimensions are always rendered at one size regardless of zoom,
        // or if they have a definite size, and are thus zoomable.
        // If zoomable, this is incorrect:
        int yOffset = -12;
 
-       //Fix text so it isn't upside down...
+       // Fix text so it isn't upside down...
        if ((angle > PI * 0.5) && (angle < PI * 1.5))
        {
                angle += PI;
@@ -125,7 +124,9 @@ void Painter::DrawAngledText(Vector center, double angle, QString text)
        }
 
        textBox.translate(0, yOffset);
-       // Angles are backwards in the Qt coord system...
+       painter->save();
+       painter->translate(center.x, center.y);
+       // Angles are backwards in the Qt coord system, so we flip ours...
        painter->rotate(-angle * RADIANS_TO_DEGREES);
        painter->drawText(textBox, Qt::AlignCenter, text);
        painter->restore();
index e32ba975f80263868c52609fe5d6af85f835bf68..367c7a84e6a4fb4b11a147e7e8198edc183ec832 100644 (file)
@@ -26,8 +26,8 @@ class Painter
                void DrawText(QRectF, int, QString);
 
        public:
-               Vector CartesianToQtCoords(Vector);
-               Vector QtCoordsToCartesian(Vector);
+               static Vector CartesianToQtCoords(Vector);
+               static Vector QtToCartesianCoords(Vector);
 
        public:
                // Class variables