1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup freestyle
19  * \brief Classes to define a Winged Edge data structure.
20  */
21 
22 #include <iostream>
23 
24 #include "WEdge.h"
25 
26 namespace Freestyle {
27 
28 /*! Temporary structures */
29 class vertexdata {
30  public:
31   WVertex *_copy;
32 };
33 
34 class oedgedata {
35  public:
36   WOEdge *_copy;
37 };
38 
39 class edgedata {
40  public:
41   WEdge *_copy;
42 };
43 
44 class facedata {
45  public:
46   WFace *_copy;
47 };
48 
49 /**********************************
50  *                                *
51  *                                *
52  *             WVertex            *
53  *                                *
54  *                                *
55  **********************************/
56 
WVertex(WVertex & iBrother)57 WVertex::WVertex(WVertex &iBrother)
58 {
59   _Id = iBrother._Id;
60   _Vertex = iBrother._Vertex;
61   _EdgeList = iBrother._EdgeList;
62 
63   _Shape = iBrother._Shape;
64   _Smooth = iBrother._Smooth;
65   _Border = iBrother._Border;
66   userdata = NULL;
67   iBrother.userdata = new vertexdata;
68   ((vertexdata *)(iBrother.userdata))->_copy = this;
69 }
70 
duplicate()71 WVertex *WVertex::duplicate()
72 {
73   WVertex *clone = new WVertex(*this);
74   return clone;
75 }
76 
operator *()77 WOEdge *WVertex::incoming_edge_iterator::operator*()
78 {
79   return _current;
80 }
81 
increment()82 void WVertex::incoming_edge_iterator::increment()
83 {
84   WOEdge *twin = _current->twin();
85   if (!twin) {
86     // we reached a hole
87     _current = 0;
88     return;
89   }
90   WOEdge *next = twin->getPrevOnFace();
91   if (next == _begin) {
92     next = NULL;
93   }
94   _current = next;
95 }
96 
operator *()97 WFace *WVertex::face_iterator::operator*()
98 {
99   WOEdge *woedge = *_edge_it;
100   if (!woedge) {
101     return NULL;
102   }
103   return (woedge)->GetbFace();
104 }
105 
106 #if 0
107 bool WVertex::isBoundary() const
108 {
109   return _Border;
110 }
111 #endif
isBoundary()112 bool WVertex::isBoundary()
113 {
114   if (_Border == 1) {
115     return true;
116   }
117   if (_Border == 0) {
118     return false;
119   }
120 
121   vector<WEdge *>::const_iterator it;
122   for (it = _EdgeList.begin(); it != _EdgeList.end(); it++) {
123     if ((*it)->GetNumberOfOEdges() == 1) {
124       _Border = 1;
125       return true;
126     }
127   }
128 #if 0
129   if (!(*it)->GetaOEdge()->GetaFace()) {
130     return true;
131   }
132 #endif
133   _Border = 0;
134   return false;
135 }
136 
AddEdge(WEdge * iEdge)137 void WVertex::AddEdge(WEdge *iEdge)
138 {
139   _EdgeList.push_back(iEdge);
140 }
141 
incoming_edges_begin()142 WVertex::incoming_edge_iterator WVertex::incoming_edges_begin()
143 {
144   WOEdge *begin;
145   WEdge *wedge = _EdgeList.front();
146   WOEdge *aOEdge = wedge->GetaOEdge();
147   if (aOEdge->GetbVertex() == this) {
148     begin = aOEdge;
149   }
150   else {
151     begin = _EdgeList.front()->GetbOEdge();
152   }
153   return incoming_edge_iterator(this, begin, begin);
154 }
155 
incoming_edges_end()156 WVertex::incoming_edge_iterator WVertex::incoming_edges_end()
157 {
158   WOEdge *begin;
159   WOEdge *aOEdge = _EdgeList.front()->GetaOEdge();
160   if (aOEdge->GetbVertex() == this) {
161     begin = aOEdge;
162   }
163   else {
164     begin = _EdgeList.front()->GetbOEdge();
165   }
166   return incoming_edge_iterator(this, begin, 0);
167 }
168 #if 0
169 WOEdge **WVertex::incoming_edge_iterator::operator->()
170 {
171   WOEdge **ppaOEdge = (*_iter)->GetaOEdge();
172   if (aOEdge->GetbVertex() == _vertex) {
173     return ppaOEdge;
174   }
175   else {
176     WOEdge *bOEdge = (*_iter)->GetbOEdge();
177     return &bOEdge;
178   }
179 }
180 #endif
181 
182 /**********************************
183  *                                *
184  *                                *
185  *             WOEdge             *
186  *                                *
187  *                                *
188  **********************************/
189 
WOEdge(WOEdge & iBrother)190 WOEdge::WOEdge(WOEdge &iBrother)
191 {
192   _paVertex = iBrother.GetaVertex();
193   _pbVertex = iBrother.GetbVertex();
194   _paFace = iBrother.GetaFace();
195   _pbFace = iBrother.GetbFace();
196   _pOwner = iBrother.GetOwner();
197   userdata = NULL;
198   iBrother.userdata = new oedgedata;
199   ((oedgedata *)(iBrother.userdata))->_copy = this;
200 
201   _vec = iBrother._vec;
202   _angle = iBrother._angle;
203 }
204 
duplicate()205 WOEdge *WOEdge::duplicate()
206 {
207   WOEdge *clone = new WOEdge(*this);
208   return clone;
209 }
210 
twin()211 WOEdge *WOEdge::twin()
212 {
213   return GetOwner()->GetOtherOEdge(this);
214 }
215 
getPrevOnFace()216 WOEdge *WOEdge::getPrevOnFace()
217 {
218   return _pbFace->GetPrevOEdge(this);
219 }
220 
221 /**********************************
222  *                                *
223  *                                *
224  *             WEdge              *
225  *                                *
226  *                                *
227  **********************************/
228 
WEdge(WEdge & iBrother)229 WEdge::WEdge(WEdge &iBrother)
230 {
231   _paOEdge = NULL;
232   _pbOEdge = NULL;
233   WOEdge *aoedge = iBrother.GetaOEdge();
234   WOEdge *boedge = iBrother.GetbOEdge();
235   userdata = NULL;
236 
237   if (aoedge) {
238     //_paOEdge = new WOEdge(*aoedge);
239     _paOEdge = aoedge->duplicate();
240   }
241   if (boedge) {
242     //_pbOEdge = new WOEdge(*boedge);
243     _pbOEdge = boedge->duplicate();
244   }
245 
246   _nOEdges = iBrother.GetNumberOfOEdges();
247   _Id = iBrother.GetId();
248   iBrother.userdata = new edgedata;
249   ((edgedata *)(iBrother.userdata))->_copy = this;
250 }
251 
duplicate()252 WEdge *WEdge::duplicate()
253 {
254   WEdge *clone = new WEdge(*this);
255   return clone;
256 }
257 
258 /**********************************
259  *                                *
260  *                                *
261  *             WFace              *
262  *                                *
263  *                                *
264  **********************************/
265 
WFace(WFace & iBrother)266 WFace::WFace(WFace &iBrother)
267 {
268   _OEdgeList = iBrother.getEdgeList();
269   _Normal = iBrother.GetNormal();
270   _VerticesNormals = iBrother._VerticesNormals;
271   _VerticesTexCoords = iBrother._VerticesTexCoords;
272   _Id = iBrother.GetId();
273   _FrsMaterialIndex = iBrother._FrsMaterialIndex;
274   _Mark = iBrother._Mark;
275   userdata = NULL;
276   iBrother.userdata = new facedata;
277   ((facedata *)(iBrother.userdata))->_copy = this;
278 }
279 
duplicate()280 WFace *WFace::duplicate()
281 {
282   WFace *clone = new WFace(*this);
283   return clone;
284 }
285 
frs_material()286 const FrsMaterial &WFace::frs_material()
287 {
288   return getShape()->frs_material(_FrsMaterialIndex);
289 }
290 
MakeEdge(WVertex * v1,WVertex * v2)291 WOEdge *WFace::MakeEdge(WVertex *v1, WVertex *v2)
292 {
293   // First check whether the same oriented edge already exists or not:
294   vector<WEdge *> &v1Edges = v1->GetEdges();
295   for (vector<WEdge *>::iterator it1 = v1Edges.begin(), end = v1Edges.end(); it1 != end; it1++) {
296     WEdge *we = (*it1);
297     WOEdge *woea = we->GetaOEdge();
298 
299     if ((woea->GetaVertex() == v1) && (woea->GetbVertex() == v2)) {
300       // The oriented edge already exists
301       cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId()
302            << " appears twice, correcting" << endl;
303       // Adds the edge to the face
304       AddEdge(woea);
305       (*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
306       // sets these vertices as border:
307       v1->setBorder(true);
308       v2->setBorder(true);
309       return woea;
310     }
311 
312     WOEdge *woeb = we->GetbOEdge();
313     if (woeb && (woeb->GetaVertex() == v1) && (woeb->GetbVertex() == v2)) {
314       // The oriented edge already exists
315       cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId()
316            << " appears twice, correcting" << endl;
317       // Adds the edge to the face
318       AddEdge(woeb);
319       (*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
320       // sets these vertices as border:
321       v1->setBorder(true);
322       v2->setBorder(true);
323       return woeb;
324     }
325   }
326 
327   // the oriented edge we're about to build
328   WOEdge *pOEdge = new WOEdge;
329   // The edge containing the oriented edge.
330   WEdge *edge;
331 
332   // checks whether this edge already exists or not
333   // If it exists, it points outward v2
334   bool exist = false;
335   WOEdge *pInvertEdge = NULL;  // The inverted edge if it exists
336   vector<WEdge *> &v2Edges = v2->GetEdges();
337   vector<WEdge *>::iterator it;
338   for (it = v2Edges.begin(); it != v2Edges.end(); it++) {
339     if ((*it)->GetbVertex() == v1) {
340       // The invert edge already exists
341       exist = true;
342       pInvertEdge = (*it)->GetaOEdge();
343       break;
344     }
345   }
346 
347   // DEBUG:
348   if (true == exist) {  // The invert edge already exists
349     // Retrieves the corresponding edge
350     edge = pInvertEdge->GetOwner();
351 
352     // Sets the a Face (retrieved from pInvertEdge
353     pOEdge->setaFace(pInvertEdge->GetbFace());
354 
355     // Updates the invert edge:
356     pInvertEdge->setaFace(this);
357   }
358   else {  // The invert edge does not exist yet
359     // we must create a new edge
360     // edge = new WEdge;
361     edge = instanciateEdge();
362 
363     // updates the a,b vertex edges list:
364     v1->AddEdge(edge);
365     v2->AddEdge(edge);
366   }
367 
368   pOEdge->setOwner(edge);
369   // Add the vertices:
370   pOEdge->setaVertex(v1);
371   pOEdge->setbVertex(v2);
372 
373   // Debug:
374   if (v1->GetId() == v2->GetId()) {
375     cerr << "Warning: edge " << this << " null with vertex " << v1->GetId() << endl;
376   }
377 
378   edge->AddOEdge(pOEdge);
379   // edge->setNumberOfOEdges(edge->GetNumberOfOEdges() + 1);
380 
381   // Add this face (the b face)
382   pOEdge->setbFace(this);
383 
384   // Adds the edge to the face
385   AddEdge(pOEdge);
386 
387   return pOEdge;
388 }
389 
getOppositeEdge(const WVertex * v,WOEdge * & e)390 bool WFace::getOppositeEdge(const WVertex *v, WOEdge *&e)
391 {
392   if (_OEdgeList.size() != 3) {
393     return false;
394   }
395 
396   vector<WOEdge *>::iterator it;
397   e = NULL;
398   for (it = _OEdgeList.begin(); it != _OEdgeList.end(); it++) {
399     if ((*it)->GetaVertex() == v) {
400       e = *it;
401     }
402   }
403   if (!e) {
404     return false;
405   }
406   e = NULL;
407   for (it = _OEdgeList.begin(); it != _OEdgeList.end(); it++) {
408     if (((*it)->GetaVertex() != v) && ((*it)->GetbVertex() != v)) {
409       e = *it;
410     }
411   }
412   if (!e) {
413     return false;
414   }
415 
416   return true;
417 }
418 
getArea()419 float WFace::getArea()
420 {
421   vector<WOEdge *>::iterator it;
422   Vec3f origin = (*(_OEdgeList.begin()))->GetaVertex()->GetVertex();
423   it = _OEdgeList.begin();
424   float a = 0;
425   for (it = it++; it != _OEdgeList.end(); it++) {
426     Vec3f v1 = Vec3f((*it)->GetaVertex()->GetVertex() - origin);
427     Vec3f v2 = Vec3f((*it)->GetbVertex()->GetVertex() - origin);
428     a += (v1 ^ v2).norm() / 2.0f;
429   }
430   return a;
431 }
432 
GetPrevOEdge(WOEdge * iOEdge)433 WOEdge *WFace::GetPrevOEdge(WOEdge *iOEdge)
434 {
435   vector<WOEdge *>::iterator woe, woend, woefirst;
436   woefirst = _OEdgeList.begin();
437   woend = _OEdgeList.end();
438   WOEdge *prev = *woefirst;
439   woe = woefirst;
440   ++woe;
441   for (; woe != woend; woe++) {
442     if ((*woe) == iOEdge) {
443       return prev;
444     }
445     prev = *woe;
446   }
447   // We left the loop. That means that the first OEdge was the good one:
448   if ((*woefirst) == iOEdge) {
449     return prev;
450   }
451 
452   return NULL;
453 }
454 
getShape()455 WShape *WFace::getShape()
456 {
457   return GetVertex(0)->shape();
458 }
459 
460 /**********************************
461  *                                *
462  *                                *
463  *             WShape             *
464  *                                *
465  *                                *
466  **********************************/
467 
468 unsigned WShape::_SceneCurrentId = 0;
469 
duplicate()470 WShape *WShape::duplicate()
471 {
472   WShape *clone = new WShape(*this);
473   return clone;
474 }
475 
WShape(WShape & iBrother)476 WShape::WShape(WShape &iBrother)
477 {
478   _Id = iBrother.GetId();
479   _Name = iBrother._Name;
480   _LibraryPath = iBrother._LibraryPath;
481   _FrsMaterials = iBrother._FrsMaterials;
482 #if 0
483   _meanEdgeSize = iBrother._meanEdgeSize;
484   iBrother.bbox(_min, _max);
485 #endif
486   vector<WVertex *> &vertexList = iBrother.getVertexList();
487   vector<WVertex *>::iterator v = vertexList.begin(), vend = vertexList.end();
488   for (; v != vend; ++v) {
489     // WVertex *newVertex = new WVertex(*(*v));
490     WVertex *newVertex = (*v)->duplicate();
491 
492     newVertex->setShape(this);
493     AddVertex(newVertex);
494   }
495 
496   vector<WEdge *> &edgeList = iBrother.getEdgeList();
497   vector<WEdge *>::iterator e = edgeList.begin(), eend = edgeList.end();
498   for (; e != eend; ++e) {
499     // WEdge *newEdge = new WEdge(*(*e));
500     WEdge *newEdge = (*e)->duplicate();
501     AddEdge(newEdge);
502   }
503 
504   vector<WFace *> &faceList = iBrother.GetFaceList();
505   vector<WFace *>::iterator f = faceList.begin(), fend = faceList.end();
506   for (; f != fend; ++f) {
507     // WFace *newFace = new WFace(*(*f));
508     WFace *newFace = (*f)->duplicate();
509     AddFace(newFace);
510   }
511 
512   // update all pointed addresses thanks to the newly created objects:
513   vend = _VertexList.end();
514   for (v = _VertexList.begin(); v != vend; ++v) {
515     const vector<WEdge *> &vedgeList = (*v)->GetEdges();
516     vector<WEdge *> newvedgelist;
517     unsigned int i;
518     for (i = 0; i < vedgeList.size(); i++) {
519       WEdge *current = vedgeList[i];
520       edgedata *currentvedata = (edgedata *)current->userdata;
521       newvedgelist.push_back(currentvedata->_copy);
522     }
523     (*v)->setEdges(newvedgelist);
524   }
525 
526   eend = _EdgeList.end();
527   for (e = _EdgeList.begin(); e != eend; ++e) {
528     // update aOedge:
529     WOEdge *aoEdge = (*e)->GetaOEdge();
530     aoEdge->setaVertex(((vertexdata *)(aoEdge->GetaVertex()->userdata))->_copy);
531     aoEdge->setbVertex(((vertexdata *)(aoEdge->GetbVertex()->userdata))->_copy);
532     if (aoEdge->GetaFace()) {
533       aoEdge->setaFace(((facedata *)(aoEdge->GetaFace()->userdata))->_copy);
534     }
535     aoEdge->setbFace(((facedata *)(aoEdge->GetbFace()->userdata))->_copy);
536     aoEdge->setOwner(((edgedata *)(aoEdge->GetOwner()->userdata))->_copy);
537 
538     // update bOedge:
539     WOEdge *boEdge = (*e)->GetbOEdge();
540     if (boEdge) {
541       boEdge->setaVertex(((vertexdata *)(boEdge->GetaVertex()->userdata))->_copy);
542       boEdge->setbVertex(((vertexdata *)(boEdge->GetbVertex()->userdata))->_copy);
543       if (boEdge->GetaFace()) {
544         boEdge->setaFace(((facedata *)(boEdge->GetaFace()->userdata))->_copy);
545       }
546       boEdge->setbFace(((facedata *)(boEdge->GetbFace()->userdata))->_copy);
547       boEdge->setOwner(((edgedata *)(boEdge->GetOwner()->userdata))->_copy);
548     }
549   }
550 
551   fend = _FaceList.end();
552   for (f = _FaceList.begin(); f != fend; ++f) {
553     unsigned int i;
554     const vector<WOEdge *> &oedgeList = (*f)->getEdgeList();
555     vector<WOEdge *> newoedgelist;
556 
557     unsigned int n = oedgeList.size();
558     for (i = 0; i < n; i++) {
559       WOEdge *current = oedgeList[i];
560       oedgedata *currentoedata = (oedgedata *)current->userdata;
561       newoedgelist.push_back(currentoedata->_copy);
562       // oedgeList[i] = currentoedata->_copy;
563       // oedgeList[i] = ((oedgedata *)(oedgeList[i]->userdata))->_copy;
564     }
565     (*f)->setEdgeList(newoedgelist);
566   }
567 
568   // Free all memory (arghh!)
569   // Vertex
570   vend = iBrother.getVertexList().end();
571   for (v = iBrother.getVertexList().begin(); v != vend; ++v) {
572     delete (vertexdata *)((*v)->userdata);
573     (*v)->userdata = NULL;
574   }
575 
576   // Edges and OEdges:
577   eend = iBrother.getEdgeList().end();
578   for (e = iBrother.getEdgeList().begin(); e != eend; ++e) {
579     delete (edgedata *)((*e)->userdata);
580     (*e)->userdata = NULL;
581     // OEdge a:
582     delete (oedgedata *)((*e)->GetaOEdge()->userdata);
583     (*e)->GetaOEdge()->userdata = NULL;
584     // OEdge b:
585     WOEdge *oedgeb = (*e)->GetbOEdge();
586     if (oedgeb) {
587       delete (oedgedata *)(oedgeb->userdata);
588       oedgeb->userdata = NULL;
589     }
590   }
591 
592   // Faces
593   fend = iBrother.GetFaceList().end();
594   for (f = iBrother.GetFaceList().begin(); f != fend; ++f) {
595     delete (facedata *)((*f)->userdata);
596     (*f)->userdata = NULL;
597   }
598 }
599 
MakeFace(vector<WVertex * > & iVertexList,vector<bool> & iFaceEdgeMarksList,unsigned iMaterial)600 WFace *WShape::MakeFace(vector<WVertex *> &iVertexList,
601                         vector<bool> &iFaceEdgeMarksList,
602                         unsigned iMaterial)
603 {
604   // allocate the new face
605   WFace *face = instanciateFace();
606 
607   WFace *result = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial, face);
608   if (!result) {
609     delete face;
610   }
611   return result;
612 }
613 
MakeFace(vector<WVertex * > & iVertexList,vector<Vec3f> & iNormalsList,vector<Vec2f> & iTexCoordsList,vector<bool> & iFaceEdgeMarksList,unsigned iMaterial)614 WFace *WShape::MakeFace(vector<WVertex *> &iVertexList,
615                         vector<Vec3f> &iNormalsList,
616                         vector<Vec2f> &iTexCoordsList,
617                         vector<bool> &iFaceEdgeMarksList,
618                         unsigned iMaterial)
619 {
620   // allocate the new face
621   WFace *face = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial);
622 
623   if (!face) {
624     return NULL;
625   }
626 
627   // set the list of per-vertex normals
628   face->setNormalList(iNormalsList);
629   // set the list of per-vertex tex coords
630   face->setTexCoordsList(iTexCoordsList);
631 
632   return face;
633 }
634 
MakeFace(vector<WVertex * > & iVertexList,vector<bool> & iFaceEdgeMarksList,unsigned iMaterial,WFace * face)635 WFace *WShape::MakeFace(vector<WVertex *> &iVertexList,
636                         vector<bool> &iFaceEdgeMarksList,
637                         unsigned iMaterial,
638                         WFace *face)
639 {
640   int id = _FaceList.size();
641 
642   face->setFrsMaterialIndex(iMaterial);
643 
644   // Check whether we have a degenerated face:
645 
646   // LET'S HACK IT FOR THE TRIANGLE CASE:
647 
648   if (3 == iVertexList.size()) {
649     if ((iVertexList[0] == iVertexList[1]) || (iVertexList[0] == iVertexList[2]) ||
650         (iVertexList[2] == iVertexList[1])) {
651       cerr << "Warning: degenerated triangle detected, correcting" << endl;
652       return NULL;
653     }
654   }
655 
656   vector<WVertex *>::iterator it;
657 
658   // compute the face normal (v1v2 ^ v1v3)
659   // Double precision numbers are used here to avoid truncation errors [T47705]
660   Vec3r v1, v2, v3;
661   it = iVertexList.begin();
662   v1 = (*it)->GetVertex();
663   it++;
664   v2 = (*it)->GetVertex();
665   it++;
666   v3 = (*it)->GetVertex();
667 
668   Vec3r vector1(v2 - v1);
669   Vec3r vector2(v3 - v1);
670 
671   Vec3r normal(vector1 ^ vector2);
672   normal.normalize();
673   face->setNormal(normal);
674 
675   vector<bool>::iterator mit = iFaceEdgeMarksList.begin();
676   face->setMark(*mit);
677   mit++;
678 
679   // vertex pointers used to build each edge
680   vector<WVertex *>::iterator va, vb;
681 
682   va = iVertexList.begin();
683   vb = va;
684   for (; va != iVertexList.end(); va = vb) {
685     ++vb;
686     // Adds va to the vertex list:
687     // face->AddVertex(*va);
688 
689     WOEdge *oedge;
690     if (*va == iVertexList.back()) {
691       oedge = face->MakeEdge(*va, iVertexList.front());  // for the last (closing) edge
692     }
693     else {
694       oedge = face->MakeEdge(*va, *vb);
695     }
696 
697     if (!oedge) {
698       return NULL;
699     }
700 
701     WEdge *edge = oedge->GetOwner();
702     if (1 == edge->GetNumberOfOEdges()) {
703       // means that we just created a new edge and that we must add it to the shape's edges list
704       edge->setId(_EdgeList.size());
705       AddEdge(edge);
706 #if 0
707       // compute the mean edge value:
708       _meanEdgeSize += edge->GetaOEdge()->GetVec().norm();
709 #endif
710     }
711 
712     edge->setMark(*mit);
713     ++mit;
714   }
715 
716   // Add the face to the shape's faces list:
717   face->setId(id);
718   AddFace(face);
719 
720   return face;
721 }
722 
ComputeMeanEdgeSize() const723 real WShape::ComputeMeanEdgeSize() const
724 {
725   real meanEdgeSize = 0.0;
726   for (vector<WEdge *>::const_iterator it = _EdgeList.begin(), itend = _EdgeList.end();
727        it != itend;
728        it++) {
729     meanEdgeSize += (*it)->GetaOEdge()->GetVec().norm();
730   }
731   return meanEdgeSize / (real)_EdgeList.size();
732 }
733 
734 } /* namespace Freestyle */
735