From 3b9b56d429a8a8733c8195e41f9b5e525b9b730d Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Mon, 26 Sep 2011 11:55:17 +0000 Subject: [PATCH] Preliminary start on zooming/circle hover feedback. --- src/circle.cpp | 99 +++++++++++++++++++++++++++++++++++++++++---- src/circle.h | 7 ++++ src/drawingview.cpp | 11 +++-- src/line.cpp | 3 +- src/painter.cpp | 15 +++---- src/painter.h | 4 +- 6 files changed, 116 insertions(+), 23 deletions(-) diff --git a/src/circle.cpp b/src/circle.cpp index a8902cc..ea56d90 100644 --- a/src/circle.cpp +++ b/src/circle.cpp @@ -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; +} diff --git a/src/circle.h b/src/circle.h index cc5159f..1a000da 100644 --- a/src/circle.h +++ b/src/circle.h @@ -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__ diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 148a34e..a5349d9 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -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 diff --git a/src/line.cpp b/src/line.cpp index 06fbbc6..7f04a19 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -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); diff --git a/src/painter.cpp b/src/painter.cpp index 8e664d2..2a0c600 100644 --- a/src/painter.cpp +++ b/src/painter.cpp @@ -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(); diff --git a/src/painter.h b/src/painter.h index e32ba97..367c7a8 100644 --- a/src/painter.h +++ b/src/painter.h @@ -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 -- 2.37.2