Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
846 lines
23 KiB
C++
846 lines
23 KiB
C++
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup freestyle
|
|
* \brief Classes to define a View Map (ViewVertex, ViewEdge, etc.)
|
|
*/
|
|
|
|
#include <cfloat>
|
|
|
|
#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<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(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>(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>(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<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 nullptr;
|
|
}
|
|
FEdge *fend(nullptr), *fbegin(nullptr);
|
|
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 != 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<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;
|
|
}
|
|
|
|
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<ViewEdge *>::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<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 (!ELEM(currentEdge, nullptr, _FEdgeB));
|
|
// last one
|
|
_FEdgeB->setViewEdge(this);
|
|
}
|
|
|
|
} /* namespace Freestyle */
|