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.
727 lines
18 KiB
C++
727 lines
18 KiB
C++
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup freestyle
|
|
* \brief Classes to define a Winged Edge data structure.
|
|
*/
|
|
|
|
#include <iostream>
|
|
|
|
#include "WEdge.h"
|
|
|
|
#include "BLI_sys_types.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 *
|
|
* *
|
|
* *
|
|
**********************************/
|
|
|
|
uint 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;
|
|
uint 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) {
|
|
uint i;
|
|
const vector<WOEdge *> &oedgeList = (*f)->getEdgeList();
|
|
vector<WOEdge *> newoedgelist;
|
|
|
|
uint 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,
|
|
uint 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,
|
|
uint 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,
|
|
uint 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 [#47705]
|
|
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 */
|