This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/freestyle/intern/winged_edge/WEdge.cpp
Sybren A. Stüvel 16732def37 Cleanup: Clang-Tidy modernize-use-nullptr
Replace `NULL` with `nullptr` in C++ code.

No functional changes.
2020-11-06 18:08:25 +01:00

735 lines
18 KiB
C++

/*
* 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.
*/
/** \file
* \ingroup freestyle
* \brief Classes to define a Winged Edge data structure.
*/
#include <iostream>
#include "WEdge.h"
namespace Freestyle {
/*! Temporary structures */
class vertexdata {
public:
WVertex *_copy;
};
class oedgedata {
public:
WOEdge *_copy;
};
class edgedata {
public:
WEdge *_copy;
};
class facedata {
public:
WFace *_copy;
};
/**********************************
* *
* *
* WVertex *
* *
* *
**********************************/
WVertex::WVertex(WVertex &iBrother)
{
_Id = iBrother._Id;
_Vertex = iBrother._Vertex;
_EdgeList = iBrother._EdgeList;
_Shape = iBrother._Shape;
_Smooth = iBrother._Smooth;
_Border = iBrother._Border;
userdata = nullptr;
iBrother.userdata = new vertexdata;
((vertexdata *)(iBrother.userdata))->_copy = this;
}
WVertex *WVertex::duplicate()
{
WVertex *clone = new WVertex(*this);
return clone;
}
WOEdge *WVertex::incoming_edge_iterator::operator*()
{
return _current;
}
void WVertex::incoming_edge_iterator::increment()
{
WOEdge *twin = _current->twin();
if (!twin) {
// we reached a hole
_current = nullptr;
return;
}
WOEdge *next = twin->getPrevOnFace();
if (next == _begin) {
next = nullptr;
}
_current = next;
}
WFace *WVertex::face_iterator::operator*()
{
WOEdge *woedge = *_edge_it;
if (!woedge) {
return nullptr;
}
return (woedge)->GetbFace();
}
#if 0
bool WVertex::isBoundary() const
{
return _Border;
}
#endif
bool WVertex::isBoundary()
{
if (_Border == 1) {
return true;
}
if (_Border == 0) {
return false;
}
vector<WEdge *>::const_iterator it;
for (it = _EdgeList.begin(); it != _EdgeList.end(); it++) {
if ((*it)->GetNumberOfOEdges() == 1) {
_Border = 1;
return true;
}
}
#if 0
if (!(*it)->GetaOEdge()->GetaFace()) {
return true;
}
#endif
_Border = 0;
return false;
}
void WVertex::AddEdge(WEdge *iEdge)
{
_EdgeList.push_back(iEdge);
}
WVertex::incoming_edge_iterator WVertex::incoming_edges_begin()
{
WOEdge *begin;
WEdge *wedge = _EdgeList.front();
WOEdge *aOEdge = wedge->GetaOEdge();
if (aOEdge->GetbVertex() == this) {
begin = aOEdge;
}
else {
begin = _EdgeList.front()->GetbOEdge();
}
return incoming_edge_iterator(this, begin, begin);
}
WVertex::incoming_edge_iterator WVertex::incoming_edges_end()
{
WOEdge *begin;
WOEdge *aOEdge = _EdgeList.front()->GetaOEdge();
if (aOEdge->GetbVertex() == this) {
begin = aOEdge;
}
else {
begin = _EdgeList.front()->GetbOEdge();
}
return incoming_edge_iterator(this, begin, nullptr);
}
#if 0
WOEdge **WVertex::incoming_edge_iterator::operator->()
{
WOEdge **ppaOEdge = (*_iter)->GetaOEdge();
if (aOEdge->GetbVertex() == _vertex) {
return ppaOEdge;
}
else {
WOEdge *bOEdge = (*_iter)->GetbOEdge();
return &bOEdge;
}
}
#endif
/**********************************
* *
* *
* WOEdge *
* *
* *
**********************************/
WOEdge::WOEdge(WOEdge &iBrother)
{
_paVertex = iBrother.GetaVertex();
_pbVertex = iBrother.GetbVertex();
_paFace = iBrother.GetaFace();
_pbFace = iBrother.GetbFace();
_pOwner = iBrother.GetOwner();
userdata = nullptr;
iBrother.userdata = new oedgedata;
((oedgedata *)(iBrother.userdata))->_copy = this;
_vec = iBrother._vec;
_angle = iBrother._angle;
}
WOEdge *WOEdge::duplicate()
{
WOEdge *clone = new WOEdge(*this);
return clone;
}
WOEdge *WOEdge::twin()
{
return GetOwner()->GetOtherOEdge(this);
}
WOEdge *WOEdge::getPrevOnFace()
{
return _pbFace->GetPrevOEdge(this);
}
/**********************************
* *
* *
* WEdge *
* *
* *
**********************************/
WEdge::WEdge(WEdge &iBrother)
{
_paOEdge = nullptr;
_pbOEdge = nullptr;
WOEdge *aoedge = iBrother.GetaOEdge();
WOEdge *boedge = iBrother.GetbOEdge();
userdata = nullptr;
if (aoedge) {
//_paOEdge = new WOEdge(*aoedge);
_paOEdge = aoedge->duplicate();
}
if (boedge) {
//_pbOEdge = new WOEdge(*boedge);
_pbOEdge = boedge->duplicate();
}
_nOEdges = iBrother.GetNumberOfOEdges();
_Id = iBrother.GetId();
iBrother.userdata = new edgedata;
((edgedata *)(iBrother.userdata))->_copy = this;
}
WEdge *WEdge::duplicate()
{
WEdge *clone = new WEdge(*this);
return clone;
}
/**********************************
* *
* *
* WFace *
* *
* *
**********************************/
WFace::WFace(WFace &iBrother)
{
_OEdgeList = iBrother.getEdgeList();
_Normal = iBrother.GetNormal();
_VerticesNormals = iBrother._VerticesNormals;
_VerticesTexCoords = iBrother._VerticesTexCoords;
_Id = iBrother.GetId();
_FrsMaterialIndex = iBrother._FrsMaterialIndex;
_Mark = iBrother._Mark;
userdata = nullptr;
iBrother.userdata = new facedata;
((facedata *)(iBrother.userdata))->_copy = this;
}
WFace *WFace::duplicate()
{
WFace *clone = new WFace(*this);
return clone;
}
const FrsMaterial &WFace::frs_material()
{
return getShape()->frs_material(_FrsMaterialIndex);
}
WOEdge *WFace::MakeEdge(WVertex *v1, WVertex *v2)
{
// First check whether the same oriented edge already exists or not:
vector<WEdge *> &v1Edges = v1->GetEdges();
for (vector<WEdge *>::iterator it1 = v1Edges.begin(), end = v1Edges.end(); it1 != end; it1++) {
WEdge *we = (*it1);
WOEdge *woea = we->GetaOEdge();
if ((woea->GetaVertex() == v1) && (woea->GetbVertex() == v2)) {
// The oriented edge already exists
cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId()
<< " appears twice, correcting" << endl;
// Adds the edge to the face
AddEdge(woea);
(*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
// sets these vertices as border:
v1->setBorder(true);
v2->setBorder(true);
return woea;
}
WOEdge *woeb = we->GetbOEdge();
if (woeb && (woeb->GetaVertex() == v1) && (woeb->GetbVertex() == v2)) {
// The oriented edge already exists
cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId()
<< " appears twice, correcting" << endl;
// Adds the edge to the face
AddEdge(woeb);
(*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
// sets these vertices as border:
v1->setBorder(true);
v2->setBorder(true);
return woeb;
}
}
// the oriented edge we're about to build
WOEdge *pOEdge = new WOEdge;
// The edge containing the oriented edge.
WEdge *edge;
// checks whether this edge already exists or not
// If it exists, it points outward v2
bool exist = false;
WOEdge *pInvertEdge = nullptr; // The inverted edge if it exists
vector<WEdge *> &v2Edges = v2->GetEdges();
vector<WEdge *>::iterator it;
for (it = v2Edges.begin(); it != v2Edges.end(); it++) {
if ((*it)->GetbVertex() == v1) {
// The invert edge already exists
exist = true;
pInvertEdge = (*it)->GetaOEdge();
break;
}
}
// DEBUG:
if (true == exist) { // The invert edge already exists
// Retrieves the corresponding edge
edge = pInvertEdge->GetOwner();
// Sets the a Face (retrieved from pInvertEdge
pOEdge->setaFace(pInvertEdge->GetbFace());
// Updates the invert edge:
pInvertEdge->setaFace(this);
}
else { // The invert edge does not exist yet
// we must create a new edge
// edge = new WEdge;
edge = instanciateEdge();
// updates the a,b vertex edges list:
v1->AddEdge(edge);
v2->AddEdge(edge);
}
pOEdge->setOwner(edge);
// Add the vertices:
pOEdge->setaVertex(v1);
pOEdge->setbVertex(v2);
// Debug:
if (v1->GetId() == v2->GetId()) {
cerr << "Warning: edge " << this << " null with vertex " << v1->GetId() << endl;
}
edge->AddOEdge(pOEdge);
// edge->setNumberOfOEdges(edge->GetNumberOfOEdges() + 1);
// Add this face (the b face)
pOEdge->setbFace(this);
// Adds the edge to the face
AddEdge(pOEdge);
return pOEdge;
}
bool WFace::getOppositeEdge(const WVertex *v, WOEdge *&e)
{
if (_OEdgeList.size() != 3) {
return false;
}
vector<WOEdge *>::iterator it;
e = nullptr;
for (it = _OEdgeList.begin(); it != _OEdgeList.end(); it++) {
if ((*it)->GetaVertex() == v) {
e = *it;
}
}
if (!e) {
return false;
}
e = nullptr;
for (it = _OEdgeList.begin(); it != _OEdgeList.end(); it++) {
if (((*it)->GetaVertex() != v) && ((*it)->GetbVertex() != v)) {
e = *it;
}
}
if (!e) {
return false;
}
return true;
}
float WFace::getArea()
{
vector<WOEdge *>::iterator it;
Vec3f origin = (*(_OEdgeList.begin()))->GetaVertex()->GetVertex();
it = _OEdgeList.begin();
float a = 0;
for (it = it++; it != _OEdgeList.end(); it++) {
Vec3f v1 = Vec3f((*it)->GetaVertex()->GetVertex() - origin);
Vec3f v2 = Vec3f((*it)->GetbVertex()->GetVertex() - origin);
a += (v1 ^ v2).norm() / 2.0f;
}
return a;
}
WOEdge *WFace::GetPrevOEdge(WOEdge *iOEdge)
{
vector<WOEdge *>::iterator woe, woend, woefirst;
woefirst = _OEdgeList.begin();
woend = _OEdgeList.end();
WOEdge *prev = *woefirst;
woe = woefirst;
++woe;
for (; woe != woend; woe++) {
if ((*woe) == iOEdge) {
return prev;
}
prev = *woe;
}
// We left the loop. That means that the first OEdge was the good one:
if ((*woefirst) == iOEdge) {
return prev;
}
return nullptr;
}
WShape *WFace::getShape()
{
return GetVertex(0)->shape();
}
/**********************************
* *
* *
* WShape *
* *
* *
**********************************/
unsigned WShape::_SceneCurrentId = 0;
WShape *WShape::duplicate()
{
WShape *clone = new WShape(*this);
return clone;
}
WShape::WShape(WShape &iBrother)
{
_Id = iBrother.GetId();
_Name = iBrother._Name;
_LibraryPath = iBrother._LibraryPath;
_FrsMaterials = iBrother._FrsMaterials;
#if 0
_meanEdgeSize = iBrother._meanEdgeSize;
iBrother.bbox(_min, _max);
#endif
vector<WVertex *> &vertexList = iBrother.getVertexList();
vector<WVertex *>::iterator v = vertexList.begin(), vend = vertexList.end();
for (; v != vend; ++v) {
// WVertex *newVertex = new WVertex(*(*v));
WVertex *newVertex = (*v)->duplicate();
newVertex->setShape(this);
AddVertex(newVertex);
}
vector<WEdge *> &edgeList = iBrother.getEdgeList();
vector<WEdge *>::iterator e = edgeList.begin(), eend = edgeList.end();
for (; e != eend; ++e) {
// WEdge *newEdge = new WEdge(*(*e));
WEdge *newEdge = (*e)->duplicate();
AddEdge(newEdge);
}
vector<WFace *> &faceList = iBrother.GetFaceList();
vector<WFace *>::iterator f = faceList.begin(), fend = faceList.end();
for (; f != fend; ++f) {
// WFace *newFace = new WFace(*(*f));
WFace *newFace = (*f)->duplicate();
AddFace(newFace);
}
// update all pointed addresses thanks to the newly created objects:
vend = _VertexList.end();
for (v = _VertexList.begin(); v != vend; ++v) {
const vector<WEdge *> &vedgeList = (*v)->GetEdges();
vector<WEdge *> newvedgelist;
unsigned int i;
for (i = 0; i < vedgeList.size(); i++) {
WEdge *current = vedgeList[i];
edgedata *currentvedata = (edgedata *)current->userdata;
newvedgelist.push_back(currentvedata->_copy);
}
(*v)->setEdges(newvedgelist);
}
eend = _EdgeList.end();
for (e = _EdgeList.begin(); e != eend; ++e) {
// update aOedge:
WOEdge *aoEdge = (*e)->GetaOEdge();
aoEdge->setaVertex(((vertexdata *)(aoEdge->GetaVertex()->userdata))->_copy);
aoEdge->setbVertex(((vertexdata *)(aoEdge->GetbVertex()->userdata))->_copy);
if (aoEdge->GetaFace()) {
aoEdge->setaFace(((facedata *)(aoEdge->GetaFace()->userdata))->_copy);
}
aoEdge->setbFace(((facedata *)(aoEdge->GetbFace()->userdata))->_copy);
aoEdge->setOwner(((edgedata *)(aoEdge->GetOwner()->userdata))->_copy);
// update bOedge:
WOEdge *boEdge = (*e)->GetbOEdge();
if (boEdge) {
boEdge->setaVertex(((vertexdata *)(boEdge->GetaVertex()->userdata))->_copy);
boEdge->setbVertex(((vertexdata *)(boEdge->GetbVertex()->userdata))->_copy);
if (boEdge->GetaFace()) {
boEdge->setaFace(((facedata *)(boEdge->GetaFace()->userdata))->_copy);
}
boEdge->setbFace(((facedata *)(boEdge->GetbFace()->userdata))->_copy);
boEdge->setOwner(((edgedata *)(boEdge->GetOwner()->userdata))->_copy);
}
}
fend = _FaceList.end();
for (f = _FaceList.begin(); f != fend; ++f) {
unsigned int i;
const vector<WOEdge *> &oedgeList = (*f)->getEdgeList();
vector<WOEdge *> newoedgelist;
unsigned int n = oedgeList.size();
for (i = 0; i < n; i++) {
WOEdge *current = oedgeList[i];
oedgedata *currentoedata = (oedgedata *)current->userdata;
newoedgelist.push_back(currentoedata->_copy);
// oedgeList[i] = currentoedata->_copy;
// oedgeList[i] = ((oedgedata *)(oedgeList[i]->userdata))->_copy;
}
(*f)->setEdgeList(newoedgelist);
}
// Free all memory (arghh!)
// Vertex
vend = iBrother.getVertexList().end();
for (v = iBrother.getVertexList().begin(); v != vend; ++v) {
delete (vertexdata *)((*v)->userdata);
(*v)->userdata = nullptr;
}
// Edges and OEdges:
eend = iBrother.getEdgeList().end();
for (e = iBrother.getEdgeList().begin(); e != eend; ++e) {
delete (edgedata *)((*e)->userdata);
(*e)->userdata = nullptr;
// OEdge a:
delete (oedgedata *)((*e)->GetaOEdge()->userdata);
(*e)->GetaOEdge()->userdata = nullptr;
// OEdge b:
WOEdge *oedgeb = (*e)->GetbOEdge();
if (oedgeb) {
delete (oedgedata *)(oedgeb->userdata);
oedgeb->userdata = nullptr;
}
}
// Faces
fend = iBrother.GetFaceList().end();
for (f = iBrother.GetFaceList().begin(); f != fend; ++f) {
delete (facedata *)((*f)->userdata);
(*f)->userdata = nullptr;
}
}
WFace *WShape::MakeFace(vector<WVertex *> &iVertexList,
vector<bool> &iFaceEdgeMarksList,
unsigned iMaterial)
{
// allocate the new face
WFace *face = instanciateFace();
WFace *result = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial, face);
if (!result) {
delete face;
}
return result;
}
WFace *WShape::MakeFace(vector<WVertex *> &iVertexList,
vector<Vec3f> &iNormalsList,
vector<Vec2f> &iTexCoordsList,
vector<bool> &iFaceEdgeMarksList,
unsigned iMaterial)
{
// allocate the new face
WFace *face = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial);
if (!face) {
return nullptr;
}
// set the list of per-vertex normals
face->setNormalList(iNormalsList);
// set the list of per-vertex tex coords
face->setTexCoordsList(iTexCoordsList);
return face;
}
WFace *WShape::MakeFace(vector<WVertex *> &iVertexList,
vector<bool> &iFaceEdgeMarksList,
unsigned iMaterial,
WFace *face)
{
int id = _FaceList.size();
face->setFrsMaterialIndex(iMaterial);
// Check whether we have a degenerated face:
// LET'S HACK IT FOR THE TRIANGLE CASE:
if (3 == iVertexList.size()) {
if ((iVertexList[0] == iVertexList[1]) || (iVertexList[0] == iVertexList[2]) ||
(iVertexList[2] == iVertexList[1])) {
cerr << "Warning: degenerated triangle detected, correcting" << endl;
return nullptr;
}
}
vector<WVertex *>::iterator it;
// compute the face normal (v1v2 ^ v1v3)
// Double precision numbers are used here to avoid truncation errors [T47705]
Vec3r v1, v2, v3;
it = iVertexList.begin();
v1 = (*it)->GetVertex();
it++;
v2 = (*it)->GetVertex();
it++;
v3 = (*it)->GetVertex();
Vec3r vector1(v2 - v1);
Vec3r vector2(v3 - v1);
Vec3r normal(vector1 ^ vector2);
normal.normalize();
face->setNormal(normal);
vector<bool>::iterator mit = iFaceEdgeMarksList.begin();
face->setMark(*mit);
mit++;
// vertex pointers used to build each edge
vector<WVertex *>::iterator va, vb;
va = iVertexList.begin();
vb = va;
for (; va != iVertexList.end(); va = vb) {
++vb;
// Adds va to the vertex list:
// face->AddVertex(*va);
WOEdge *oedge;
if (*va == iVertexList.back()) {
oedge = face->MakeEdge(*va, iVertexList.front()); // for the last (closing) edge
}
else {
oedge = face->MakeEdge(*va, *vb);
}
if (!oedge) {
return nullptr;
}
WEdge *edge = oedge->GetOwner();
if (1 == edge->GetNumberOfOEdges()) {
// means that we just created a new edge and that we must add it to the shape's edges list
edge->setId(_EdgeList.size());
AddEdge(edge);
#if 0
// compute the mean edge value:
_meanEdgeSize += edge->GetaOEdge()->GetVec().norm();
#endif
}
edge->setMark(*mit);
++mit;
}
// Add the face to the shape's faces list:
face->setId(id);
AddFace(face);
return face;
}
real WShape::ComputeMeanEdgeSize() const
{
real meanEdgeSize = 0.0;
for (vector<WEdge *>::const_iterator it = _EdgeList.begin(), itend = _EdgeList.end();
it != itend;
it++) {
meanEdgeSize += (*it)->GetaOEdge()->GetVec().norm();
}
return meanEdgeSize / (real)_EdgeList.size();
}
} /* namespace Freestyle */