735 lines
18 KiB
C++
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 */
|