/* * Mesh.cpp * * (c) 2016 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 "Mesh.h" MM_BEGIN_NAMESPACE Mesh::Mesh() : Quad() { // Create dummy points (will be all overwritten later on by load/save). QVector points(4); init(points, 2, 2); } 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::build() { // Resize the vertices2d vector to appropriate dimensions. resizeVertices2d(_vertices2d, _nColumns, _nRows); // Just build vertices2d in the standard order. int k = 0; for (int y=0; y<_nRows; y++) for (int x=0; x<_nColumns; x++) { _vertices2d[x][y] = k; k++; } } 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; setVertices(points); build(); } 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) { // Extract column and row of vertex. int col = i % nColumns(); int row = i / nColumns(); // Make a copy. QPointF realV = v; // Constrain vertex to stay within the internal quads it is part of. if (col < nColumns()-1) { 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); } } 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) { vertices2d.resize(nColumns); for (int i=0; i= 1 && columnId < nColumns()-1); // Temporary containers that will be used to rebuild new vertex space. IndexVector2d newVertices2d; resizeVertices2d(newVertices2d, nColumns()-1, nRows()); QVector newVertices(vertices.size()-nRows()); // Right displacement of points already there. qreal rightMoveProp = 1.0f/(nColumns()-2) - 1.0f/(nColumns()-1); // Process all rows. int k = 0; for (int y=0; y 0 && x < nColumns()-1) { p += (x < columnId ? +1 : -1) * diff * newX * rightMoveProp; } // Assign new containers. newVertices[k] = p; newVertices2d[newX][y] = k; k++; } } // Copy new mapping. vertices = newVertices; _vertices2d = newVertices2d; // Decrement number of columns. _nColumns--; // Reorder. _reorderVertices(); } void Mesh::removeRow(int rowId) { // Cannot remove first and last columns Q_ASSERT(rowId >= 1 && rowId < nRows()-1); // Temporary containers that will be used to rebuild new vertex space. IndexVector2d newVertices2d; resizeVertices2d(newVertices2d, nColumns(), nRows()-1); QVector newVertices(vertices.size()-nColumns()); // Bottom displacement of points already there. qreal bottomMoveProp = 1.0f/(nRows()-2) - 1.0f/(nRows()-1); // Process all columns. int k = 0; for (int x=0; x 0 && y < nRows()-1) { p += (y < rowId ? +1 : -1) * diff * newY * bottomMoveProp; } // Assign new containers. newVertices[k] = p; newVertices2d[x][newY] = k; k++; } } // Copy new mapping. vertices = newVertices; _vertices2d = newVertices2d; // Decrement number of rows. _nRows--; // Reorder. _reorderVertices(); } void Mesh::resize(int nColumns_, int nRows_) { // Brutal: if asked to reduce columns or rows, just delete and redo. if (nColumns_ < nColumns()) { while (nColumns_ != nColumns()) removeColumn(nColumns()-2); } if (nRows_ < nRows()) { while (nRows_ != nRows()) removeRow(nRows()-2); } if (nColumns_ > nColumns()) { while (nColumns_ != nColumns()) addColumn(); } if (nRows_ > nRows()) { while (nRows_ != nRows()) addRow(); } } QVector 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 y=0; y