/* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup freestyle * \brief Classes to define a View Map (ViewVertex, ViewEdge, etc.) */ #include #include "ViewMap.h" #include "ViewMapAdvancedIterators.h" #include "ViewMapIterators.h" #include "../geometry/GeomUtils.h" #include "BLI_sys_types.h" namespace Freestyle { /**********************************/ /* */ /* */ /* ViewMap */ /* */ /* */ /**********************************/ ViewMap *ViewMap::_pInstance = nullptr; ViewMap::~ViewMap() { // The view vertices must be deleted here as some of them are shared between two shapes: for (vector::iterator vv = _VVertices.begin(), vvend = _VVertices.end(); vv != vvend; vv++) { delete (*vv); } _VVertices.clear(); for (vector::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) { delete (*vs); } _VShapes.clear(); _FEdges.clear(); _SVertices.clear(); _VEdges.clear(); } void ViewMap::Clean() { vector tmpEdges; for (vector::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) { vector &edges = (*vs)->sshape()->getEdgeList(); for (vector::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::iterator it = tmpEdges.begin(), itend = tmpEdges.end(); it != itend; it++) { for (vector::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(uint 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 = nullptr; 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(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 = nullptr; 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(x, y), A, B); if (dist < minDist) { minDist = dist; winner = (*fe); } } if (!winner) { return nullptr; } 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 &newViewEdges) { NonTVertex *vva = dynamic_cast(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 &fedges = iVertex->fedges(); if (fedges.size() != 2) { cerr << "ViewMap warning: Can't split the ViewEdge" << endl; return nullptr; } FEdge *fend(nullptr), *fbegin(nullptr); for (vector::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 != nullptr) && (fend != nullptr)) { 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() == nullptr) { // 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(nullptr); fbegin->setPreviousEdge(nullptr); // 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(nullptr); fbegin->setPreviousEdge(nullptr); // update new View Vertex: vva->AddOutgoingViewEdge(newVEdge); vva->AddIncomingViewEdge(ioEdge); NonTVertex *vvb = dynamic_cast(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 &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; } return (v1.x() > v2.x()); } if (v2.y() > 0) { return false; } return (v1.x() < v2.x()); } 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) { /* pass */ } _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) { /* pass */ } _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) { /* pass */ } _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) { /* pass */ } _sortedEdges.insert(dve, &_BackEdgeB); } else { _sortedEdges.push_back(&_BackEdgeB); } } void TVertex::Replace(ViewEdge *iOld, ViewEdge *iNew) { // theoretically, 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) { /* pass */ } _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) { /* pass */ } _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(nullptr, this->_FEdgeB); } ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_end() const { return const_fedge_iterator(nullptr, this->_FEdgeB); } //! embedding vertex iterator ViewEdge::const_vertex_iterator ViewEdge::vertices_begin() const { return const_vertex_iterator(this->_FEdgeA->vertexA(), nullptr, _FEdgeA); } ViewEdge::vertex_iterator ViewEdge::vertices_begin() { return vertex_iterator(this->_FEdgeA->vertexA(), nullptr, _FEdgeA); } ViewEdge::const_vertex_iterator ViewEdge::vertices_last() const { return const_vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, nullptr); } ViewEdge::vertex_iterator ViewEdge::vertices_last() { return vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, nullptr); } ViewEdge::const_vertex_iterator ViewEdge::vertices_end() const { return const_vertex_iterator(nullptr, _FEdgeB, nullptr); } ViewEdge::vertex_iterator ViewEdge::vertices_end() { return vertex_iterator(nullptr, _FEdgeB, nullptr); } Interface0DIterator ViewEdge::verticesBegin() { Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator( this->_FEdgeA->vertexA(), this->_FEdgeA->vertexA(), nullptr, _FEdgeA, 0.0f)); return ret; } Interface0DIterator ViewEdge::verticesEnd() { Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator( nullptr, this->_FEdgeA->vertexA(), _FEdgeB, nullptr, 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::iterator e = _Edges.begin(), eend = _Edges.end(); e != eend; e++) { delete (*e); } _Edges.clear(); } if (_SShape) { delete _SShape; _SShape = nullptr; } } void ViewShape::RemoveEdge(ViewEdge *iViewEdge) { FEdge *fedge = iViewEdge->fedgeA(); for (vector::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::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 (!ELEM(currentEdge, NULL, _FEdgeB)); // last one _FEdgeB->setViewEdge(this); } } /* namespace Freestyle */