/*
* 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();
}