From 8256ace2e17d8a71901f34551189594048555b6b Mon Sep 17 00:00:00 2001 From: Tats Date: Sun, 2 Mar 2014 22:29:36 -0500 Subject: [PATCH] Added sanity check for ellipses (makes sure the points are ok). --- Shape.cpp | 10 +++---- Shape.h | 78 ++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 16 deletions(-) diff --git a/Shape.cpp b/Shape.cpp index 8c8d8a4..c43c980 100644 --- a/Shape.cpp +++ b/Shape.cpp @@ -458,12 +458,10 @@ void Ellipse::setVertex(int i, const QPointF& v) // Center control point (make sure it stays inside!). else if (hasCenterControl()) { - // Map point as vector on a unit circle. - QVector2D vector(toUnitCircle().map(v)); - // Clip control point. - Shape::setVertex(4, vector.length() <= 1 ? - v : - fromUnitCircle().map(vector.normalized().toPointF())); + Shape::setVertex(4, clipInside(v)); } + + // Just to be sure. + sanitize(); } diff --git a/Shape.h b/Shape.h index c4f2378..b625149 100644 --- a/Shape.h +++ b/Shape.h @@ -213,6 +213,16 @@ protected: class Ellipse : public Shape { public: Ellipse() {} + Ellipse(QPointF p1, QPointF p2, QPointF p3, QPointF p4, QPointF p5) + { + _addVertex(p1); + _addVertex(p2); + _addVertex(p3); + _addVertex(p4); + _addVertex(p5); + sanitize(); + } + Ellipse(QPointF p1, QPointF p2, QPointF p3, QPointF p4, bool hasCenterControl=true) { _addVertex(p1); @@ -220,47 +230,94 @@ public: _addVertex(p3); _addVertex(p4); if (hasCenterControl) - _addVertex(getCenter()); // add a point in the center + _addVertex(getCenter()); + sanitize(); } + + /// Remaps points so as to make sure this is a correct ellipse, keeping vertices 0 and 2 as + /// reference for the horizzontal axis. + void sanitize() + { + // Get horizontal axis rotated 90 degrees CW + QVector2D hAxis = getHorizontalAxis(); + const QVector2D center(getCenter()); + QVector2D hAxisRotated(hAxis.y(), -hAxis.x()); + + // Project vertex 1 onto it. + QVector2D vAxisNormalized = hAxisRotated.normalized(); + + QVector2D vFromCenter = QVector2D(getVertex(1)) - center; + const QVector2D& projection = QVector2D::dotProduct( vFromCenter, vAxisNormalized ) * vAxisNormalized; + Shape::setVertex(1, (center + projection).toPointF()); + Shape::setVertex(3, (center - projection).toPointF()); + + if (hasCenterControl()) + { + // Clip control point. + Shape::setVertex(4, clipInside(getVertex(4))); + } + } + virtual ~Ellipse() {} virtual QString getType() const { return "ellipse"; } - qreal getRotationRadians() const { + qreal getRotationRadians() const + { QVector2D hAxis = getHorizontalAxis(); return atan2( hAxis.y(), hAxis.x() ); } - qreal getRotation() const { + qreal getRotation() const + { return radiansToDegrees( getRotationRadians() ); } - bool hasCenterControl() const { + bool hasCenterControl() const + { return (nVertices() == 5); } + /// If v is outside boundaries, remap it to the border. + QPointF clipInside(const QPointF& v) const + { + // Map point as vector on a unit circle. + QVector2D vector(toUnitCircle().map(v)); + + // Clip control point. + return (vector.length() <= 1 ? + v : + fromUnitCircle().map(vector.normalized().toPointF())); + + } + // QRect getBoundingRect() const { // return QRect(0, getVerticalAxis().manhattanLength(), // getHorizontalAxis().manhattanLength(), getVerticalAxis().manhattanLength()); // } // - QPointF getCenter() const { + QPointF getCenter() const + { return (QVector2D(getVertex(0)) - (getHorizontalAxis() / 2)).toPointF(); } - QVector2D getHorizontalAxis() const { + QVector2D getHorizontalAxis() const + { return QVector2D(getVertex(0)) - QVector2D(getVertex(2)); } - QVector2D getVerticalAxis() const { + QVector2D getVerticalAxis() const + { return QVector2D(getVertex(1)) - QVector2D(getVertex(3)); } - qreal getHorizontalRadius() const { + qreal getHorizontalRadius() const + { return getHorizontalAxis().length() / 2; } - qreal getVerticalRadius() const { + qreal getVerticalRadius() const + { return getVerticalAxis().length() / 2; } @@ -276,7 +333,8 @@ public: */ virtual bool includesPoint(qreal x, qreal y); - virtual bool includesPoint(const QPointF& p) { + virtual bool includesPoint(const QPointF& p) + { return includesPoint(p.x(), p.y()); }