The view map is mostly treated as a read-only data structure by line stylization operations (i.e., selection, chaining, splitting, sorting and stroke creation). The only exception is the chaining operation in some cases where insertion of extra FEdge objects is necessary to ensure the continuity of underlying FEdges from which a chain is constructed. The present revision addresses the removal of extra FEdges so to keep the view map clean and suitable for reuse in subsequent render frames.
781 lines
23 KiB
C++
781 lines
23 KiB
C++
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* 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 2
|
|
* 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, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/freestyle/intern/view_map/ViewMap.cpp
|
|
* \ingroup freestyle
|
|
* \brief Classes to define a View Map (ViewVertex, ViewEdge, etc.)
|
|
* \author Stephane Grabli
|
|
* \date 03/09/2002
|
|
*/
|
|
|
|
#include <float.h>
|
|
|
|
#include "ViewMap.h"
|
|
#include "ViewMapIterators.h"
|
|
#include "ViewMapAdvancedIterators.h"
|
|
|
|
#include "../geometry/GeomUtils.h"
|
|
|
|
namespace Freestyle {
|
|
|
|
/**********************************/
|
|
/* */
|
|
/* */
|
|
/* ViewMap */
|
|
/* */
|
|
/* */
|
|
/**********************************/
|
|
|
|
ViewMap *ViewMap::_pInstance = NULL;
|
|
|
|
ViewMap::~ViewMap()
|
|
{
|
|
// The view vertices must be deleted here as some of them are shared between two shapes:
|
|
for (vector<ViewVertex*>::iterator vv = _VVertices.begin(), vvend = _VVertices.end(); vv != vvend; vv++) {
|
|
delete (*vv);
|
|
}
|
|
_VVertices.clear();
|
|
|
|
for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
|
|
delete (*vs);
|
|
}
|
|
_VShapes.clear();
|
|
|
|
_FEdges.clear();
|
|
_SVertices.clear();
|
|
_VEdges.clear();
|
|
}
|
|
|
|
void ViewMap::Clean()
|
|
{
|
|
vector<FEdge*> tmpEdges;
|
|
|
|
for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
|
|
vector<FEdge*>& edges = (*vs)->sshape()->getEdgeList();
|
|
for (vector<FEdge*>::iterator it = edges.begin(), itend = edges.end(); it != itend; it++) {
|
|
if ((*it)->isTemporary()) {
|
|
(*it)->setTemporary(false); // avoid being counted multiple times
|
|
tmpEdges.push_back(*it);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (vector<FEdge*>::iterator it = tmpEdges.begin(), itend = tmpEdges.end(); it != itend; it++) {
|
|
for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
|
|
(*vs)->sshape()->RemoveEdge(*it);
|
|
}
|
|
(*it)->vertexA()->RemoveFEdge(*it);
|
|
(*it)->vertexB()->RemoveFEdge(*it);
|
|
delete (*it);
|
|
}
|
|
}
|
|
|
|
ViewShape *ViewMap::viewShape(unsigned id)
|
|
{
|
|
int index = _shapeIdToIndex[id];
|
|
return _VShapes[ index ];
|
|
}
|
|
|
|
void ViewMap::AddViewShape(ViewShape *iVShape)
|
|
{
|
|
_shapeIdToIndex[iVShape->getId().getFirst()] = _VShapes.size();
|
|
_VShapes.push_back(iVShape);
|
|
}
|
|
|
|
const FEdge *ViewMap::getClosestFEdge(real x, real y) const
|
|
{
|
|
// find the closest of this candidates:
|
|
real minDist = DBL_MAX;
|
|
FEdge *winner = NULL;
|
|
for (fedges_container::const_iterator fe = _FEdges.begin(), feend = _FEdges.end(); fe != feend; fe++) {
|
|
Vec2d A((*fe)->vertexA()->point2D()[0], (*fe)->vertexA()->point2D()[1]);
|
|
Vec2d B((*fe)->vertexB()->point2D()[0], (*fe)->vertexB()->point2D()[1]);
|
|
real dist = GeomUtils::distPointSegment<Vec2r>(Vec2r(x, y), A, B);
|
|
if (dist < minDist) {
|
|
minDist = dist;
|
|
winner = (*fe);
|
|
}
|
|
}
|
|
|
|
return winner;
|
|
}
|
|
|
|
const ViewEdge *ViewMap::getClosestViewEdge(real x, real y) const
|
|
{
|
|
// find the closest of this candidates:
|
|
real minDist = DBL_MAX;
|
|
FEdge *winner = NULL;
|
|
for (fedges_container::const_iterator fe = _FEdges.begin(), feend = _FEdges.end(); fe != feend; fe++) {
|
|
Vec2d A((*fe)->vertexA()->point2D()[0], (*fe)->vertexA()->point2D()[1]);
|
|
Vec2d B((*fe)->vertexB()->point2D()[0], (*fe)->vertexB()->point2D()[1]);
|
|
real dist = GeomUtils::distPointSegment<Vec2r>(Vec2r(x, y), A, B);
|
|
if (dist < minDist) {
|
|
minDist = dist;
|
|
winner = (*fe);
|
|
}
|
|
}
|
|
if (!winner)
|
|
return NULL;
|
|
|
|
return winner->viewedge();
|
|
}
|
|
|
|
|
|
TVertex *ViewMap::CreateTVertex(const Vec3r& iA3D, const Vec3r& iA2D, FEdge *iFEdgeA,
|
|
const Vec3r& iB3D, const Vec3r& iB2D, FEdge *iFEdgeB, const Id& id)
|
|
{
|
|
ViewShape *vshapeA = iFEdgeA->viewedge()->viewShape();
|
|
SShape *shapeA = iFEdgeA->shape();
|
|
ViewShape *vshapeB = iFEdgeB->viewedge()->viewShape();
|
|
SShape *shapeB = iFEdgeB->shape();
|
|
|
|
SVertex *Ia = shapeA->CreateSVertex(iA3D, iA2D, iFEdgeA->vertexA()->getId());
|
|
SVertex *Ib = shapeB->CreateSVertex(iB3D, iB2D, iFEdgeB->vertexA()->getId());
|
|
|
|
// depending on which of these 2 svertices is the nearest from the viewpoint, we're going to build the TVertex
|
|
// by giving them in an order or another (the first one must be the nearest)
|
|
real dista = Ia->point2D()[2];
|
|
real distb = Ib->point2D()[2];
|
|
|
|
TVertex *tvertex;
|
|
if (dista < distb)
|
|
tvertex = new TVertex(Ia, Ib);
|
|
else
|
|
tvertex = new TVertex(Ib, Ia);
|
|
|
|
tvertex->setId(id);
|
|
|
|
// add these vertices to the view map
|
|
AddViewVertex(tvertex);
|
|
AddSVertex(Ia);
|
|
AddSVertex(Ib);
|
|
|
|
// and this T Vertex to the view shapes:
|
|
vshapeA->AddVertex(tvertex);
|
|
vshapeB->AddVertex(tvertex);
|
|
|
|
return tvertex;
|
|
}
|
|
|
|
ViewVertex *ViewMap::InsertViewVertex(SVertex *iVertex, vector<ViewEdge*>& newViewEdges)
|
|
{
|
|
NonTVertex *vva = dynamic_cast<NonTVertex*>(iVertex->viewvertex());
|
|
if (vva)
|
|
return vva;
|
|
// because it is not already a ViewVertex, this SVertex must have only 2 FEdges. The incoming one still belongs
|
|
// to ioEdge, the outgoing one now belongs to newVEdge
|
|
const vector<FEdge *>& fedges = iVertex->fedges();
|
|
if (fedges.size() != 2) {
|
|
cerr << "ViewMap warning: Can't split the ViewEdge" << endl;
|
|
return NULL;
|
|
}
|
|
FEdge *fend(NULL), *fbegin(NULL);
|
|
for (vector<FEdge *>::const_iterator fe = fedges.begin(), feend = fedges.end(); fe != feend; ++fe) {
|
|
if ((*fe)->vertexB() == iVertex) {
|
|
fend = (*fe);
|
|
}
|
|
if ((*fe)->vertexA() == iVertex) {
|
|
fbegin = (*fe);
|
|
}
|
|
if ((fbegin != NULL) && (fend != NULL))
|
|
break;
|
|
}
|
|
ViewEdge *ioEdge = fbegin->viewedge();
|
|
ViewShape *vshape = ioEdge->viewShape();
|
|
vva = new NonTVertex(iVertex);
|
|
// if the ViewEdge is a closed loop, we don't create a new VEdge
|
|
if (ioEdge->A() == 0) {
|
|
// closed loop
|
|
ioEdge->setA(vva);
|
|
ioEdge->setB(vva);
|
|
// update sshape
|
|
vshape->sshape()->RemoveEdgeFromChain(ioEdge->fedgeA());
|
|
vshape->sshape()->RemoveEdgeFromChain(ioEdge->fedgeB());
|
|
|
|
ioEdge->setFEdgeA(fbegin);
|
|
ioEdge->setFEdgeB(fend);
|
|
|
|
// Update FEdges
|
|
fend->setNextEdge(NULL);
|
|
fbegin->setPreviousEdge(NULL);
|
|
|
|
// update new View Vertex:
|
|
vva->AddOutgoingViewEdge(ioEdge);
|
|
vva->AddIncomingViewEdge(ioEdge);
|
|
|
|
vshape->sshape()->AddChain(ioEdge->fedgeA());
|
|
vshape->sshape()->AddChain(ioEdge->fedgeB());
|
|
}
|
|
else {
|
|
// Create new ViewEdge
|
|
ViewEdge *newVEdge = new ViewEdge(vva, ioEdge->B(), fbegin, ioEdge->fedgeB(), vshape);
|
|
newVEdge->setId(Id(ioEdge->getId().getFirst(), ioEdge->getId().getSecond() + 1));
|
|
newVEdge->setNature(ioEdge->getNature());
|
|
//newVEdge->UpdateFEdges(); // done in the ViewEdge constructor
|
|
// Update old ViewEdge
|
|
ioEdge->setB(vva);
|
|
ioEdge->setFEdgeB(fend);
|
|
|
|
// Update FEdges
|
|
fend->setNextEdge(NULL);
|
|
fbegin->setPreviousEdge(NULL);
|
|
|
|
// update new View Vertex:
|
|
vva->AddOutgoingViewEdge(newVEdge);
|
|
vva->AddIncomingViewEdge(ioEdge);
|
|
|
|
NonTVertex *vvb = dynamic_cast<NonTVertex*>(newVEdge->B());
|
|
if (vvb)
|
|
vvb->Replace(ioEdge, newVEdge);
|
|
|
|
// update ViewShape
|
|
//vshape->AddEdge(newVEdge);
|
|
// update SShape
|
|
vshape->sshape()->AddChain(fbegin);
|
|
// update ViewMap
|
|
//_VEdges.push_back(newVEdge);
|
|
newViewEdges.push_back(newVEdge);
|
|
}
|
|
|
|
// update ViewShape
|
|
vshape->AddVertex(vva);
|
|
|
|
// update ViewMap
|
|
_VVertices.push_back(vva);
|
|
|
|
return vva;
|
|
}
|
|
|
|
#if 0
|
|
FEdge *ViewMap::Connect(FEdge *ioEdge, SVertex *ioVertex, vector<ViewEdge*>& oNewVEdges)
|
|
{
|
|
SShape *sshape = ioEdge->shape();
|
|
FEdge *newFEdge = sshape->SplitEdgeIn2(ioEdge, ioVertex);
|
|
AddFEdge(newFEdge);
|
|
InsertViewVertex(ioVertex, oNewVEdges);
|
|
return newFEdge;
|
|
}
|
|
#endif
|
|
|
|
/**********************************/
|
|
/* */
|
|
/* */
|
|
/* TVertex */
|
|
/* */
|
|
/* */
|
|
/**********************************/
|
|
|
|
// is dve1 before dve2 ? (does it have a smaller angle ?)
|
|
static bool ViewEdgeComp(ViewVertex::directedViewEdge& dve1, ViewVertex::directedViewEdge& dve2)
|
|
{
|
|
FEdge *fe1;
|
|
if (dve1.second)
|
|
fe1 = dve1.first->fedgeB();
|
|
else
|
|
fe1 = dve1.first->fedgeA();
|
|
FEdge *fe2;
|
|
if (dve2.second)
|
|
fe2 = dve2.first->fedgeB();
|
|
else
|
|
fe2 = dve2.first->fedgeA();
|
|
|
|
Vec3r V1 = fe1->orientation2d();
|
|
Vec2r v1(V1.x(), V1.y());
|
|
v1.normalize();
|
|
Vec3r V2 = fe2->orientation2d();
|
|
Vec2r v2(V2.x(), V2.y());
|
|
v2.normalize();
|
|
if (v1.y() > 0) {
|
|
if (v2.y() < 0)
|
|
return true;
|
|
else
|
|
return (v1.x() > v2.x());
|
|
}
|
|
else {
|
|
if (v2.y() > 0)
|
|
return false;
|
|
else
|
|
return (v1.x() < v2.x());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void TVertex::setFrontEdgeA(ViewEdge *iFrontEdgeA, bool incoming)
|
|
{
|
|
if (!iFrontEdgeA) {
|
|
cerr << "Warning: null pointer passed as argument of TVertex::setFrontEdgeA()" << endl;
|
|
return;
|
|
}
|
|
_FrontEdgeA = directedViewEdge(iFrontEdgeA, incoming);
|
|
if (!_sortedEdges.empty()) {
|
|
edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
|
|
for (; (dve != dveend) && ViewEdgeComp(**dve, _FrontEdgeA); ++dve);
|
|
_sortedEdges.insert( dve, &_FrontEdgeA);
|
|
}
|
|
else {
|
|
_sortedEdges.push_back(&_FrontEdgeA);
|
|
}
|
|
}
|
|
|
|
void TVertex::setFrontEdgeB(ViewEdge *iFrontEdgeB, bool incoming)
|
|
{
|
|
if (!iFrontEdgeB) {
|
|
cerr << "Warning: null pointer passed as argument of TVertex::setFrontEdgeB()" << endl;
|
|
return;
|
|
}
|
|
_FrontEdgeB = directedViewEdge(iFrontEdgeB, incoming);
|
|
if (!_sortedEdges.empty()) {
|
|
edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
|
|
for (; (dve != dveend) && ViewEdgeComp(**dve, _FrontEdgeB); ++dve);
|
|
_sortedEdges.insert(dve, &_FrontEdgeB);
|
|
}
|
|
else {
|
|
_sortedEdges.push_back(&_FrontEdgeB);
|
|
}
|
|
}
|
|
|
|
void TVertex::setBackEdgeA(ViewEdge *iBackEdgeA, bool incoming)
|
|
{
|
|
if (!iBackEdgeA) {
|
|
cerr << "Warning: null pointer passed as argument of TVertex::setBackEdgeA()" << endl;
|
|
return;
|
|
}
|
|
_BackEdgeA = directedViewEdge(iBackEdgeA, incoming);
|
|
if (!_sortedEdges.empty()) {
|
|
edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
|
|
for (; (dve != dveend) && ViewEdgeComp(**dve, _BackEdgeA); ++dve);
|
|
_sortedEdges.insert(dve, &_BackEdgeA);
|
|
}
|
|
else {
|
|
_sortedEdges.push_back(&_BackEdgeA);
|
|
}
|
|
}
|
|
|
|
void TVertex::setBackEdgeB(ViewEdge *iBackEdgeB, bool incoming)
|
|
{
|
|
if (!iBackEdgeB) {
|
|
cerr << "Warning: null pointer passed as argument of TVertex::setBackEdgeB()" << endl;
|
|
return;
|
|
}
|
|
_BackEdgeB = directedViewEdge(iBackEdgeB, incoming);
|
|
if (!_sortedEdges.empty()) {
|
|
edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
|
|
for (; (dve != dveend) && ViewEdgeComp(**dve, _BackEdgeB); ++dve);
|
|
_sortedEdges.insert(dve, &_BackEdgeB);
|
|
}
|
|
else {
|
|
_sortedEdges.push_back(&_BackEdgeB);
|
|
}
|
|
}
|
|
|
|
void TVertex::Replace(ViewEdge *iOld, ViewEdge *iNew)
|
|
{
|
|
// theoritically, we only replace edges for which this
|
|
// view vertex is the B vertex
|
|
if ((iOld == _FrontEdgeA.first) && (_FrontEdgeA.first->B() == this)) {
|
|
_FrontEdgeA.first = iNew;
|
|
return;
|
|
}
|
|
if ((iOld == _FrontEdgeB.first) && (_FrontEdgeB.first->B() == this)) {
|
|
_FrontEdgeB.first = iNew;
|
|
return;
|
|
}
|
|
if ((iOld == _BackEdgeA.first) && (_BackEdgeA.first->B() == this)) {
|
|
_BackEdgeA.first = iNew;
|
|
return;
|
|
}
|
|
if ((iOld == _BackEdgeB.first) && (_BackEdgeB.first->B() == this)) {
|
|
_BackEdgeB.first = iNew;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*! iterators access */
|
|
ViewVertex::edge_iterator TVertex::edges_begin()
|
|
{
|
|
//return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, _FrontEdgeA);
|
|
return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
|
|
}
|
|
|
|
ViewVertex::const_edge_iterator TVertex::edges_begin() const
|
|
{
|
|
//return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, _FrontEdgeA);
|
|
return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
|
|
}
|
|
|
|
ViewVertex::edge_iterator TVertex::edges_end()
|
|
{
|
|
//return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, directedViewEdge(0,true));
|
|
return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end());
|
|
}
|
|
|
|
ViewVertex::const_edge_iterator TVertex::edges_end() const
|
|
{
|
|
//return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, directedViewEdge(0, true));
|
|
return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end());
|
|
}
|
|
|
|
ViewVertex::edge_iterator TVertex::edges_iterator(ViewEdge *iEdge)
|
|
{
|
|
for (edge_pointers_container::iterator it = _sortedEdges.begin(), itend = _sortedEdges.end(); it != itend; it++) {
|
|
if ((*it)->first == iEdge)
|
|
return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), it);
|
|
}
|
|
return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
|
|
|
|
#if 0
|
|
directedViewEdge dEdge;
|
|
if (_FrontEdgeA.first == iEdge)
|
|
dEdge = _FrontEdgeA;
|
|
else if (_FrontEdgeB.first == iEdge)
|
|
dEdge = _FrontEdgeB;
|
|
else if (_BackEdgeA.first == iEdge)
|
|
dEdge = _BackEdgeA;
|
|
else if (_BackEdgeB.first == iEdge)
|
|
dEdge = _BackEdgeB;
|
|
return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, dEdge);
|
|
#endif
|
|
}
|
|
|
|
ViewVertex::const_edge_iterator TVertex::edges_iterator(ViewEdge *iEdge) const
|
|
{
|
|
for (edge_pointers_container::const_iterator it = _sortedEdges.begin(), itend = _sortedEdges.end();
|
|
it != itend;
|
|
it++)
|
|
{
|
|
if ((*it)->first == iEdge)
|
|
return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), it);
|
|
}
|
|
return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
|
|
|
|
#if 0
|
|
directedViewEdge dEdge;
|
|
if (_FrontEdgeA.first == iEdge)
|
|
dEdge = _FrontEdgeA;
|
|
else if (_FrontEdgeB.first == iEdge)
|
|
dEdge = _FrontEdgeB;
|
|
else if (_BackEdgeA.first == iEdge)
|
|
dEdge = _BackEdgeA;
|
|
else if (_BackEdgeB.first == iEdge)
|
|
dEdge = _BackEdgeB;
|
|
return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, dEdge);
|
|
#endif
|
|
}
|
|
|
|
ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesBegin()
|
|
{
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
|
|
}
|
|
|
|
ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesEnd()
|
|
{
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end());
|
|
}
|
|
|
|
ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesIterator(ViewEdge *iEdge)
|
|
{
|
|
for (edge_pointers_container::iterator it = _sortedEdges.begin(), itend = _sortedEdges.end(); it != itend; it++) {
|
|
if ((*it)->first == iEdge)
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), it);
|
|
}
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
|
|
}
|
|
|
|
/**********************************/
|
|
/* */
|
|
/* */
|
|
/* NonTVertex */
|
|
/* */
|
|
/* */
|
|
/**********************************/
|
|
|
|
void NonTVertex::AddOutgoingViewEdge(ViewEdge *iVEdge)
|
|
{
|
|
// let's keep the viewedges ordered in CCW order in the 2D image plan
|
|
directedViewEdge idve(iVEdge, false);
|
|
if (!_ViewEdges.empty()) {
|
|
edges_container::iterator dve = _ViewEdges.begin(), dveend = _ViewEdges.end();
|
|
for (; (dve != dveend) && ViewEdgeComp(*dve, idve); ++dve);
|
|
_ViewEdges.insert(dve, idve);
|
|
}
|
|
else {
|
|
_ViewEdges.push_back(idve);
|
|
}
|
|
}
|
|
|
|
void NonTVertex::AddIncomingViewEdge(ViewEdge *iVEdge)
|
|
{
|
|
// let's keep the viewedges ordered in CCW order in the 2D image plan
|
|
directedViewEdge idve(iVEdge, true);
|
|
if (!_ViewEdges.empty()) {
|
|
edges_container::iterator dve = _ViewEdges.begin(), dveend = _ViewEdges.end();
|
|
for (; (dve != dveend) && ViewEdgeComp(*dve, idve); ++dve);
|
|
_ViewEdges.insert(dve, idve);
|
|
}
|
|
else {
|
|
_ViewEdges.push_back(idve);
|
|
}
|
|
}
|
|
|
|
/*! iterators access */
|
|
ViewVertex::edge_iterator NonTVertex::edges_begin()
|
|
{
|
|
return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
|
|
}
|
|
|
|
ViewVertex::const_edge_iterator NonTVertex::edges_begin() const
|
|
{
|
|
return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
|
|
}
|
|
|
|
ViewVertex::edge_iterator NonTVertex::edges_end()
|
|
{
|
|
return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end());
|
|
}
|
|
|
|
ViewVertex::const_edge_iterator NonTVertex::edges_end() const
|
|
{
|
|
return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end());
|
|
}
|
|
|
|
ViewVertex::edge_iterator NonTVertex::edges_iterator(ViewEdge *iEdge)
|
|
{
|
|
for (edges_container::iterator it = _ViewEdges.begin(), itend = _ViewEdges.end(); it != itend; it++) {
|
|
if ((it)->first == iEdge)
|
|
return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), it);
|
|
}
|
|
return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
|
|
}
|
|
|
|
ViewVertex::const_edge_iterator NonTVertex::edges_iterator(ViewEdge *iEdge) const
|
|
{
|
|
for (edges_container::const_iterator it = _ViewEdges.begin(), itend = _ViewEdges.end(); it != itend; it++) {
|
|
if ((it)->first == iEdge)
|
|
return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), it);
|
|
}
|
|
return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
|
|
}
|
|
|
|
ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesBegin()
|
|
{
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
|
|
}
|
|
|
|
ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesEnd()
|
|
{
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end());
|
|
}
|
|
|
|
ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesIterator(ViewEdge *iEdge)
|
|
{
|
|
for (edges_container::iterator it = _ViewEdges.begin(), itend = _ViewEdges.end(); it != itend; it++) {
|
|
if ((it)->first == iEdge)
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), it);
|
|
}
|
|
return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
|
|
}
|
|
|
|
/**********************************/
|
|
/* */
|
|
/* */
|
|
/* ViewEdge */
|
|
/* */
|
|
/* */
|
|
/**********************************/
|
|
|
|
real ViewEdge::getLength2D() const
|
|
{
|
|
float length = 0.0f;
|
|
ViewEdge::const_fedge_iterator itlast = fedge_iterator_last();
|
|
ViewEdge::const_fedge_iterator it = fedge_iterator_begin(), itend = fedge_iterator_end();
|
|
Vec2r seg;
|
|
do {
|
|
seg = Vec2r((*it)->orientation2d()[0], (*it)->orientation2d()[1]);
|
|
length += seg.norm();
|
|
++it;
|
|
} while ((it != itend) && (it != itlast));
|
|
return length;
|
|
}
|
|
|
|
//! view edge iterator
|
|
ViewEdge::edge_iterator ViewEdge::ViewEdge_iterator()
|
|
{
|
|
return edge_iterator(this);
|
|
}
|
|
|
|
ViewEdge::const_edge_iterator ViewEdge::ViewEdge_iterator() const
|
|
{
|
|
return const_edge_iterator((ViewEdge *)this);
|
|
}
|
|
|
|
//! feature edge iterator
|
|
ViewEdge::fedge_iterator ViewEdge::fedge_iterator_begin()
|
|
{
|
|
return fedge_iterator(this->_FEdgeA, this->_FEdgeB);
|
|
}
|
|
|
|
ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_begin() const
|
|
{
|
|
return const_fedge_iterator(this->_FEdgeA, this->_FEdgeB);
|
|
}
|
|
|
|
ViewEdge::fedge_iterator ViewEdge::fedge_iterator_last()
|
|
{
|
|
return fedge_iterator(this->_FEdgeB, this->_FEdgeB);
|
|
}
|
|
|
|
ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_last() const
|
|
{
|
|
return const_fedge_iterator(this->_FEdgeB, this->_FEdgeB);
|
|
}
|
|
|
|
ViewEdge::fedge_iterator ViewEdge::fedge_iterator_end()
|
|
{
|
|
return fedge_iterator(0, this->_FEdgeB);
|
|
}
|
|
|
|
ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_end() const
|
|
{
|
|
return const_fedge_iterator(0, this->_FEdgeB);
|
|
}
|
|
|
|
//! embedding vertex iterator
|
|
ViewEdge::const_vertex_iterator ViewEdge::vertices_begin() const
|
|
{
|
|
return const_vertex_iterator(this->_FEdgeA->vertexA(), 0, _FEdgeA);
|
|
}
|
|
|
|
ViewEdge::vertex_iterator ViewEdge::vertices_begin()
|
|
{
|
|
return vertex_iterator(this->_FEdgeA->vertexA(), 0, _FEdgeA);
|
|
}
|
|
|
|
ViewEdge::const_vertex_iterator ViewEdge::vertices_last() const
|
|
{
|
|
return const_vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, 0);
|
|
}
|
|
|
|
ViewEdge::vertex_iterator ViewEdge::vertices_last()
|
|
{
|
|
return vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, 0);
|
|
}
|
|
|
|
ViewEdge::const_vertex_iterator ViewEdge::vertices_end() const
|
|
{
|
|
return const_vertex_iterator(0, _FEdgeB, 0);
|
|
}
|
|
|
|
ViewEdge::vertex_iterator ViewEdge::vertices_end()
|
|
{
|
|
return vertex_iterator(0, _FEdgeB, 0);
|
|
}
|
|
|
|
Interface0DIterator ViewEdge::verticesBegin()
|
|
{
|
|
Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator(this->_FEdgeA->vertexA(),
|
|
this->_FEdgeA->vertexA(), NULL, _FEdgeA, 0.0f));
|
|
return ret;
|
|
}
|
|
|
|
Interface0DIterator ViewEdge::verticesEnd()
|
|
{
|
|
Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator(NULL, this->_FEdgeA->vertexA(),
|
|
_FEdgeB, NULL, getLength2D()));
|
|
return ret;
|
|
}
|
|
|
|
Interface0DIterator ViewEdge::pointsBegin(float t)
|
|
{
|
|
return verticesBegin();
|
|
}
|
|
|
|
Interface0DIterator ViewEdge::pointsEnd(float t)
|
|
{
|
|
return verticesEnd();
|
|
}
|
|
|
|
/**********************************/
|
|
/* */
|
|
/* */
|
|
/* ViewShape */
|
|
/* */
|
|
/* */
|
|
/**********************************/
|
|
|
|
ViewShape::~ViewShape()
|
|
{
|
|
_Vertices.clear();
|
|
|
|
if (!(_Edges.empty())) {
|
|
for (vector<ViewEdge*>::iterator e = _Edges.begin(), eend = _Edges.end(); e != eend; e++) {
|
|
delete (*e);
|
|
}
|
|
_Edges.clear();
|
|
}
|
|
|
|
if (_SShape) {
|
|
delete _SShape;
|
|
_SShape = NULL;
|
|
}
|
|
}
|
|
|
|
void ViewShape::RemoveEdge(ViewEdge *iViewEdge)
|
|
{
|
|
FEdge *fedge = iViewEdge->fedgeA();
|
|
for (vector<ViewEdge*>::iterator ve = _Edges.begin(), veend = _Edges.end(); ve != veend; ve++) {
|
|
if (iViewEdge == (*ve)) {
|
|
_Edges.erase(ve);
|
|
_SShape->RemoveEdge(fedge);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViewShape::RemoveVertex(ViewVertex *iViewVertex)
|
|
{
|
|
for (vector<ViewVertex*>::iterator vv = _Vertices.begin(), vvend = _Vertices.end(); vv != vvend; vv++) {
|
|
if (iViewVertex == (*vv)) {
|
|
_Vertices.erase(vv);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************/
|
|
/* */
|
|
/* */
|
|
/* ViewEdge */
|
|
/* */
|
|
/* */
|
|
/**********************************/
|
|
|
|
void ViewEdge::UpdateFEdges()
|
|
{
|
|
FEdge *currentEdge = _FEdgeA;
|
|
do {
|
|
currentEdge->setViewEdge(this);
|
|
currentEdge = currentEdge->nextEdge();
|
|
} while ((currentEdge != NULL) && (currentEdge != _FEdgeB));
|
|
// last one
|
|
_FEdgeB->setViewEdge(this);
|
|
}
|
|
|
|
} /* namespace Freestyle */
|