diff --git a/Shape.cpp b/Shape.cpp index 927b231..fbfa349 100644 --- a/Shape.cpp +++ b/Shape.cpp @@ -31,24 +31,41 @@ void Shape::translate(int x, int y) void Polygon::setVertex(int i, const QPointF& v) { - // Weird, but nothing to do. - if (nVertices() <= 3) - { - Shape::setVertex(i, v); - return; - } - + // Constrain vertex. QPointF realV = v; + _constrainVertex(toPolygon(), i, realV); + // Really set the vertex. + _rawSetVertex(i, realV); +} + +void Polygon::_constrainVertex(const QPolygonF& polygon, int i, QPointF& v) +{ + // Weird, but nothing to do. + if (polygon.size() <= 3) + return; + + // Save previous position of vertex. + QPointF prevV = polygon.at(i); // Look at the two adjunct segments to vertex i and see if they // intersect with any non-adjacent segments. // Construct the list of segments (with the new candidate vertex). - QVector segments = _getSegments(); + QVector segments = _getSegments(polygon); int prev = wrapAround(i - 1, segments.size()); int next = wrapAround(i + 1, segments.size()); - segments[prev] = QLineF(vertices[prev], v); - segments[i] = QLineF(v, vertices[next]); + segments[prev] = QLineF(polygon.at(prev), v); + segments[i] = QLineF(v, polygon.at(next)); + + // We now stretch segments a little bit to cope with approximation errors. + for (QVector::Iterator it = segments.begin(); it != segments.end(); ++it) + { + QLineF& seg = *it; + QPointF p1 = seg.p1(); + QPointF p2 = seg.p2(); + seg.setP1( p1 + (p1 - p2) * 0.2f); + seg.setP2( p2 + (p2 - p1) * 0.2f); + } // For each adjunct segment. for (int adj=0; adj<2; adj++) @@ -65,20 +82,28 @@ void Polygon::setVertex(int i, const QPointF& v) { QPointF intersection; if (segments[idx].intersect(segments[j], &intersection) == QLineF::BoundedIntersection) - realV = intersection; + { + // Rearrange segments with new position at intersection point. + v = intersection; + segments[prev] = QLineF(polygon.at(prev), v); + segments[i] = QLineF(v, polygon.at(next)); + } } } } - - // Really set the vertex. - Shape::setVertex(i, realV); } + QVector Polygon::_getSegments() const +{ + return _getSegments(toPolygon()); +} + +QVector Polygon::_getSegments(const QPolygonF& polygon) { QVector segments; - for (int i=0; i 0) + { + Quad quad(getVertex2d(col, row), getVertex2d(col+1, row), getVertex2d(col+1, row-1), getVertex2d(col, row-1)); + _constrainVertex(quad.toPolygon(), 0, realV); + } + } + if (col > 0) + { + if (row < nRows() - 1) + { + Quad quad(getVertex2d(col, row), getVertex2d(col-1, row), getVertex2d(col-1, row+1), getVertex2d(col, row+1)); + _constrainVertex(quad.toPolygon(), 0, realV); + } + if (row > 0) + { + Quad quad(getVertex2d(col, row), getVertex2d(col-1, row), getVertex2d(col-1, row-1), getVertex2d(col, row-1)); + _constrainVertex(quad.toPolygon(), 0, realV); + } + } + + // Do set vertex. + _rawSetVertex(i, realV); } void Mesh::resizeVertices2d(IndexVector2d& vertices2d, int nColumns, int nRows) @@ -206,7 +266,7 @@ void Mesh::addColumn() { QPointF p = getVertex( _vertices2d[x][y] ); p -= diff * x * leftMoveProp; - setVertex( _vertices2d[x][y], p ); + _rawSetVertex( _vertices2d[x][y], p ); } // Create and add new point. @@ -259,7 +319,7 @@ void Mesh::addRow() { QPointF p = getVertex( _vertices2d[x][y] ); p -= diff * y * topMoveProp; - setVertex( _vertices2d[x][y], p ); + _rawSetVertex( _vertices2d[x][y], p ); } // Create and add new point. @@ -441,7 +501,7 @@ void Ellipse::setVertex(int i, const QPointF& v) QTransform transform = toUnitCircle(); // Change the vertex. - Shape::setVertex(i, v); + _rawSetVertex(i, v); // Combine with transformation circle -> ellipse_{t+1}. transform *= fromUnitCircle(); @@ -483,22 +543,22 @@ void Ellipse::setVertex(int i, const QPointF& v) QTransform transform = toUnitCircle(); // Change vertical points. - Shape::setVertex(1, v1); - Shape::setVertex(3, v3); + _rawSetVertex(1, v1); + _rawSetVertex(3, v3); // Combine with transformation circle -> ellipse_{t+1}. transform *= fromUnitCircle(); // Set vertices. if (hasCenterControl()) - Shape::setVertex(4, transform.map( getVertex(4) )); + _rawSetVertex(4, transform.map( getVertex(4) )); } // Center control point (make sure it stays inside!). else if (hasCenterControl()) { // Clip control point. - Shape::setVertex(4, clipInside(v)); + _rawSetVertex(4, clipInside(v)); } // Just to be sure. diff --git a/Shape.h b/Shape.h index 715008f..c68d60d 100644 --- a/Shape.h +++ b/Shape.h @@ -64,7 +64,7 @@ public: virtual void setVertex(int i, const QPointF& v) { - vertices[i] = v; + _rawSetVertex(i, v); } virtual void setVertex(int i, qreal x, qreal y) @@ -95,6 +95,11 @@ protected: vertices.push_back(vertex); } + void _rawSetVertex(int i, const QPointF& v) + { + vertices[i] = v; + } + }; /** @@ -116,8 +121,14 @@ public: virtual void setVertex(int i, const QPointF& v); protected: - // Returns all line segments of the polygon. + /// Returns all line segments of the polygon. QVector _getSegments() const; + + /// Returns all line segments of a polygon. + static QVector _getSegments(const QPolygonF& polygon); + + /// Makes sure vertex v as the i-th point of polygon stays inside the polygon. + static void _constrainVertex(const QPolygonF& polygon, int i, QPointF& v); }; /**