/* * Shape.cpp * * (c) 2013 Sofian Audry -- info(@)sofianaudry(.)com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Shape.h" void Shape::translate(int x, int y) { for (QVector::iterator it = vertices.begin() ; it != vertices.end(); ++it) { it->setX(it->x() + x); it->setY(it->y() + y); } } void Polygon::setVertex(int i, const QPointF& v) { // Weird, but nothing to do. if (nVertices() <= 3) { Shape::setVertex(i, v); return; } QPointF realV = v; // 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(); 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]); // For each adjunct segment. for (int adj=0; adj<2; adj++) { int idx = wrapAround(i + adj - 1, segments.size()); for (int j=0; j Polygon::_getSegments() const { QVector segments; for (int i=0; i::const_iterator it = vertices.begin() ; it != vertices.end(); ++it) { polygon.append(*it); } return polygon; } Mesh::Mesh() : Quad(), _nColumns(0), _nRows(0) {} Mesh::Mesh(QPointF p1, QPointF p2, QPointF p3, QPointF p4) : Quad() { // Add points in standard order. QVector points; points.push_back(p1); points.push_back(p2); points.push_back(p4); points.push_back(p3); // Init. init(points, 2, 2); } Mesh::Mesh(const QVector& points, int nColumns, int nRows) : Quad() { init(points, nColumns, nRows); } void Mesh::init(const QVector& points, int nColumns, int nRows) { Q_ASSERT(nColumns >= 2 && nRows >= 2); Q_ASSERT(points.size() == nColumns * nRows); _nColumns = nColumns; _nRows = nRows; // Resize the vertices2d vector to appropriate dimensions. resizeVertices2d(_vertices2d, _nColumns, _nRows); // Just build vertices2d in the standard order. int k = 0; for (int x=0; x<_nColumns; x++) for (int y=0; y<_nRows; y++) { vertices.push_back( points[k] ); _vertices2d[x][y] = k; k++; } } QPolygonF Mesh::toPolygon() const { QPolygonF polygon; for (int i=0; i=0; i--) polygon.append(getVertex2d(i, nRows()-1)); for (int i=nRows()-1; i>=1; i--) polygon.append(getVertex2d(0, i)); return polygon; } void Mesh::setVertex(int i, const QPointF& v) { // TODO Shape::setVertex(i, v); } void Mesh::resizeVertices2d(IndexVector2d& vertices2d, int nColumns, int nRows) { vertices2d.resize(nColumns); for (int i=0; i= nColumns() && nRows_ >= nRows()); while (nColumns_ != nColumns()) addColumn(); while (nRows_ != nRows()) addRow(); } // void removeColumn(int columnId) // { // // Cannot remove first and last columns // Q_ASSERT(columnId >= 1 && columnId < nColumns()-1); // // std::vector< std::vector > newVertices2d; // resizeVertices2d(newVertices2d, nColumns()-1, nRows()); // // // Right displacement of points already there. // float rightMoveProp = 1.0f/(nColumns()-2) - 1.0f/(nColumns()-1); // // // Remove a point at each row. // int k = nVertices(); // for (int y=0; y Mesh::getQuads() const { QVector quads; for (int i=0; i > Mesh::getQuads2d() const { QVector< QVector > quads2d; for (int i=0; i column; for (int j=0; j newVertices(vertices.size()); int k = 0; for (int x=0; x circle. QTransform transform = toUnitCircle(); // Change the vertex. Shape::setVertex(i, v); // Combine with transformation circle -> ellipse_{t+1}. transform *= fromUnitCircle(); // Set vertices. Shape::setVertex(1, transform.map( getVertex(1) )); Shape::setVertex(3, transform.map( getVertex(3) )); if (hasCenterControl()) Shape::setVertex(4, transform.map( getVertex(4) )); } // If changed one of the two other points, just change the vertical axis. else if (i == 1 || i == 3) { // Retrieve the new horizontal axis vector and center. const QVector2D center(getCenter()); QVector2D vFromCenter = QVector2D(v) - center; // Find projection of v onto vAxis / 2. QVector2D vAxisNormalized = vAxis.normalized(); const QVector2D& projection = QVector2D::dotProduct( vFromCenter, vAxisNormalized ) * vAxisNormalized; // Assign vertical control points. QPointF v1; QPointF v3; if (i == 1) { v1 = (center + projection).toPointF(); v3 = (center - projection).toPointF(); } else { v1 = (center - projection).toPointF(); v3 = (center + projection).toPointF(); } // Transformation ellipse_t --> circle. QTransform transform = toUnitCircle(); // Change vertical points. Shape::setVertex(1, v1); Shape::setVertex(3, v3); // Combine with transformation circle -> ellipse_{t+1}. transform *= fromUnitCircle(); // Set vertices. if (hasCenterControl()) Shape::setVertex(4, transform.map( getVertex(4) )); } // Center control point (make sure it stays inside!). else if (hasCenterControl()) { // Clip control point. Shape::setVertex(4, clipInside(v)); } // Just to be sure. sanitize(); }