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 #pragma once
18 
19 /** \file
20  * \ingroup freestyle
21  * \brief Classes to define an Extended Winged Edge data structure.
22  */
23 
24 #include "Curvature.h"
25 #include "Nature.h"
26 #include "WEdge.h"
27 
28 #ifdef WITH_CXX_GUARDEDALLOC
29 #  include "MEM_guardedalloc.h"
30 #endif
31 
32 namespace Freestyle {
33 
34 typedef Nature::EdgeNature WXNature;
35 
36 /**********************************
37  *                                *
38  *                                *
39  *             WXVertex           *
40  *                                *
41  *                                *
42  **********************************/
43 
44 class WXVertex : public WVertex {
45  private:
46   // Curvature info
47   CurvatureInfo *_curvatures;
48 
49  public:
WXVertex(const Vec3f & v)50   inline WXVertex(const Vec3f &v) : WVertex(v)
51   {
52     _curvatures = NULL;
53   }
54 
55   /*! Copy constructor */
WXVertex(WXVertex & iBrother)56   WXVertex(WXVertex &iBrother) : WVertex(iBrother)
57   {
58     _curvatures = new CurvatureInfo(*iBrother._curvatures);
59   }
60 
duplicate()61   virtual WVertex *duplicate()
62   {
63     WXVertex *clone = new WXVertex(*this);
64     return clone;
65   }
66 
~WXVertex()67   virtual ~WXVertex()
68   {
69     if (_curvatures) {
70       delete _curvatures;
71     }
72   }
73 
Reset()74   virtual void Reset()
75   {
76     if (_curvatures) {
77       _curvatures->Kr = 0.0;
78     }
79   }
80 
setCurvatures(CurvatureInfo * ci)81   inline void setCurvatures(CurvatureInfo *ci)
82   {
83     _curvatures = ci;
84   }
85 
86   inline bool isFeature();
87 
curvatures()88   inline CurvatureInfo *curvatures()
89   {
90     return _curvatures;
91   }
92 
93 #ifdef WITH_CXX_GUARDEDALLOC
94   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:WXVertex")
95 #endif
96 };
97 
98 /**********************************
99  *                                *
100  *                                *
101  *             WXEdge             *
102  *                                *
103  *                                *
104  **********************************/
105 
106 class WXEdge : public WEdge {
107  private:
108   // flag to indicate whether the edge is a silhouette edge or not
109   WXNature _nature;
110   // 0: the order doesn't matter. 1: the order is the original one. -1: the order is not good
111   short _order;
112   // A front facing edge is an edge for which the bording face which is the nearest from the
113   // viewpoint is front. A back facing edge is the opposite.
114   bool _front;
115 
116  public:
WXEdge()117   inline WXEdge() : WEdge()
118   {
119     _nature = Nature::NO_FEATURE;
120     _front = false;
121     _order = 0;
122   }
123 
WXEdge(WOEdge * iOEdge)124   inline WXEdge(WOEdge *iOEdge) : WEdge(iOEdge)
125   {
126     _nature = Nature::NO_FEATURE;
127     _front = false;
128     _order = 0;
129   }
130 
WXEdge(WOEdge * iaOEdge,WOEdge * ibOEdge)131   inline WXEdge(WOEdge *iaOEdge, WOEdge *ibOEdge) : WEdge(iaOEdge, ibOEdge)
132   {
133     _nature = Nature::NO_FEATURE;
134     _front = false;
135     _order = 0;
136   }
137 
138   /*! Copy constructor */
WXEdge(WXEdge & iBrother)139   inline WXEdge(WXEdge &iBrother) : WEdge(iBrother)
140   {
141     _nature = iBrother.nature();
142     _front = iBrother._front;
143     _order = iBrother._order;
144   }
145 
duplicate()146   virtual WEdge *duplicate()
147   {
148     WXEdge *clone = new WXEdge(*this);
149     return clone;
150   }
151 
~WXEdge()152   virtual ~WXEdge()
153   {
154   }
155 
Reset()156   virtual void Reset()
157   {
158     _nature = _nature & ~Nature::SILHOUETTE;
159     _nature = _nature & ~Nature::SUGGESTIVE_CONTOUR;
160   }
161 
162   /*! accessors */
nature()163   inline WXNature nature()
164   {
165     return _nature;
166   }
167 
front()168   inline bool front()
169   {
170     return _front;
171   }
172 
order()173   inline short order() const
174   {
175     return _order;
176   }
177 
178   /*! modifiers */
setFront(bool iFront)179   inline void setFront(bool iFront)
180   {
181     _front = iFront;
182   }
183 
setNature(WXNature iNature)184   inline void setNature(WXNature iNature)
185   {
186     _nature = iNature;
187   }
188 
AddNature(WXNature iNature)189   inline void AddNature(WXNature iNature)
190   {
191     _nature = _nature | iNature;
192   }
193 
setOrder(int i)194   inline void setOrder(int i)
195   {
196     _order = i;
197   }
198 
199 #ifdef WITH_CXX_GUARDEDALLOC
200   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:WXEdge")
201 #endif
202 };
203 
204 /**********************************
205  *                                *
206  *                                *
207  *             WXFace             *
208  *                                *
209  *                                *
210  **********************************/
211 
212 /*! Class to store a smooth edge (i.e Hertzman & Zorin smooth silhouette edges) */
213 class WXSmoothEdge {
214  public:
215   typedef unsigned short Configuration;
216   static const Configuration EDGE_EDGE = 1;
217   static const Configuration VERTEX_EDGE = 2;
218   static const Configuration EDGE_VERTEX = 3;
219 
220   WOEdge *_woea;  // Oriented edge from which the silhouette edge starts
221   WOEdge *_woeb;  // Oriented edge where the silhouette edge ends
222   float _ta;  // The silhouette starting point's coordinates are : _woea[0]+ta*(_woea[1]-_woea[0])
223   float _tb;  // The silhouette ending point's coordinates are : _woeb[0]+ta*(_woeb[1]-_woeb[0])
224   bool _front;
225   Configuration _config;
226 
WXSmoothEdge()227   WXSmoothEdge()
228   {
229     _woea = NULL;
230     _woeb = NULL;
231     _ta = 0.0f;
232     _tb = 0.0f;
233     _front = false;
234     _config = EDGE_EDGE;
235   }
236 
WXSmoothEdge(const WXSmoothEdge & iBrother)237   WXSmoothEdge(const WXSmoothEdge &iBrother)
238   {
239     _woea = iBrother._woea;
240     _woeb = iBrother._woeb;
241     _ta = iBrother._ta;
242     _tb = iBrother._tb;
243     _config = iBrother._config;
244     _front = iBrother._front;
245   }
246 
~WXSmoothEdge()247   ~WXSmoothEdge()
248   {
249   }
250 
woea()251   inline WOEdge *woea()
252   {
253     return _woea;
254   }
255 
woeb()256   inline WOEdge *woeb()
257   {
258     return _woeb;
259   }
260 
ta()261   inline float ta() const
262   {
263     return _ta;
264   }
265 
tb()266   inline float tb() const
267   {
268     return _tb;
269   }
270 
front()271   inline bool front() const
272   {
273     return _front;
274   }
275 
configuration()276   inline Configuration configuration() const
277   {
278     return _config;
279   }
280 
281   /*! modifiers */
setWOeA(WOEdge * iwoea)282   inline void setWOeA(WOEdge *iwoea)
283   {
284     _woea = iwoea;
285   }
286 
setWOeB(WOEdge * iwoeb)287   inline void setWOeB(WOEdge *iwoeb)
288   {
289     _woeb = iwoeb;
290   }
291 
setTa(float ta)292   inline void setTa(float ta)
293   {
294     _ta = ta;
295   }
296 
setTb(float tb)297   inline void setTb(float tb)
298   {
299     _tb = tb;
300   }
301 
setFront(bool iFront)302   inline void setFront(bool iFront)
303   {
304     _front = iFront;
305   }
306 
setConfiguration(Configuration iConf)307   inline void setConfiguration(Configuration iConf)
308   {
309     _config = iConf;
310   }
311 
312 #ifdef WITH_CXX_GUARDEDALLOC
313   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:WXSmoothEdge")
314 #endif
315 };
316 
317 /* Class to store a value per vertex and a smooth edge.
318  * The WXFace stores a list of these
319  */
320 class WXFace;
321 
322 class WXFaceLayer {
323  public:
324   void *userdata;
325   WXFace *_pWXFace;
326   // in case of silhouette: the values obtained when computing the normal-view direction dot
327   // product. _DotP[i] is this value for the vertex i for that face.
328   vector<float> _DotP;
329   WXSmoothEdge *_pSmoothEdge;
330   WXNature _Nature;
331 
332   // oldtmp values
333   // count the number of positive dot products for vertices.
334   // if this number is != 0 and !=_DotP.size() -> it is a silhouette fac
335   unsigned _nPosDotP;
336 
337   unsigned _nNullDotP;  // count the number of null dot products for vertices.
338   unsigned _ClosestPointIndex;
339   bool _viewDependant;
340 
WXFaceLayer(WXFace * iFace,WXNature iNature,bool viewDependant)341   WXFaceLayer(WXFace *iFace, WXNature iNature, bool viewDependant)
342   {
343     _pWXFace = iFace;
344     _pSmoothEdge = NULL;
345     _nPosDotP = 0;
346     _nNullDotP = 0;
347     _Nature = iNature;
348     _viewDependant = viewDependant;
349     userdata = NULL;
350   }
351 
WXFaceLayer(const WXFaceLayer & iBrother)352   WXFaceLayer(const WXFaceLayer &iBrother)
353   {
354     _pWXFace = iBrother._pWXFace;
355     _pSmoothEdge = NULL;
356     _DotP = iBrother._DotP;
357     _nPosDotP = iBrother._nPosDotP;
358     _nNullDotP = iBrother._nNullDotP;
359     _Nature = iBrother._Nature;
360     if (iBrother._pSmoothEdge) {  // XXX ? It's set to null a few lines above!
361       _pSmoothEdge = new WXSmoothEdge(*(iBrother._pSmoothEdge));
362     }
363     _viewDependant = iBrother._viewDependant;
364     userdata = NULL;
365   }
366 
~WXFaceLayer()367   virtual ~WXFaceLayer()
368   {
369     if (!_DotP.empty()) {
370       _DotP.clear();
371     }
372     if (_pSmoothEdge) {
373       delete _pSmoothEdge;
374       _pSmoothEdge = NULL;
375     }
376   }
377 
dotP(int i)378   inline const float dotP(int i) const
379   {
380     return _DotP[i];
381   }
382 
nPosDotP()383   inline unsigned nPosDotP() const
384   {
385     return _nPosDotP;
386   }
387 
nNullDotP()388   inline unsigned nNullDotP() const
389   {
390     return _nNullDotP;
391   }
392 
closestPointIndex()393   inline int closestPointIndex() const
394   {
395     return _ClosestPointIndex;
396   }
397 
nature()398   inline WXNature nature() const
399   {
400     return _Nature;
401   }
402 
hasSmoothEdge()403   inline bool hasSmoothEdge() const
404   {
405     if (_pSmoothEdge) {
406       return true;
407     }
408     return false;
409   }
410 
getFace()411   inline WXFace *getFace()
412   {
413     return _pWXFace;
414   }
415 
getSmoothEdge()416   inline WXSmoothEdge *getSmoothEdge()
417   {
418     return _pSmoothEdge;
419   }
420 
isViewDependant()421   inline bool isViewDependant() const
422   {
423     return _viewDependant;
424   }
425 
setClosestPointIndex(int iIndex)426   inline void setClosestPointIndex(int iIndex)
427   {
428     _ClosestPointIndex = iIndex;
429   }
430 
removeSmoothEdge()431   inline void removeSmoothEdge()
432   {
433     if (!_DotP.empty()) {
434       _DotP.clear();
435     }
436     if (_pSmoothEdge) {
437       delete _pSmoothEdge;
438       _pSmoothEdge = NULL;
439     }
440   }
441 
442   /*! If one of the face layer vertex has a DotP equal to 0, this method returns the vertex where
443    * it happens */
444   unsigned int Get0VertexIndex() const;
445 
446   /*! In case one of the edge of the triangle is a smooth edge, this method allows to retrieve the
447    * concerned edge */
448   unsigned int GetSmoothEdgeIndex() const;
449 
450   /*! retrieves the edges of the triangle for which the signs are different (a null value is not
451    * considered) for the dotp values at each edge extremity
452    */
453   void RetrieveCuspEdgesIndices(vector<int> &oCuspEdges);
454 
455   WXSmoothEdge *BuildSmoothEdge();
456 
setDotP(const vector<float> & iDotP)457   inline void setDotP(const vector<float> &iDotP)
458   {
459     _DotP = iDotP;
460   }
461 
PushDotP(float iDotP)462   inline void PushDotP(float iDotP)
463   {
464     _DotP.push_back(iDotP);
465     if (iDotP > 0.0f) {
466       ++_nPosDotP;
467     }
468     if (iDotP == 0.0f) {  // TODO this comparison is weak, check if it actually works
469       ++_nNullDotP;
470     }
471   }
472 
ReplaceDotP(unsigned int index,float newDotP)473   inline void ReplaceDotP(unsigned int index, float newDotP)
474   {
475     _DotP[index] = newDotP;
476     updateDotPInfos();
477   }
478 
updateDotPInfos()479   inline void updateDotPInfos()
480   {
481     _nPosDotP = 0;
482     _nNullDotP = 0;
483     for (vector<float>::iterator d = _DotP.begin(), dend = _DotP.end(); d != dend; ++d) {
484       if ((*d) > 0.0f) {
485         ++_nPosDotP;
486       }
487       if ((*d) == 0.0f) {  // TODO ditto
488         ++_nNullDotP;
489       }
490     }
491   }
492 
493 #ifdef WITH_CXX_GUARDEDALLOC
494   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:WXFaceLayer")
495 #endif
496 };  // namespace Freestyle
497 
498 class WXFace : public WFace {
499  protected:
500   Vec3f _center;  // center of the face
501   float _Z;       // distance from viewpoint to the center of the face
502   bool _front;    // flag to tell whether the face is front facing or back facing
503   float _dotp;    // value obtained when computing the normal-viewpoint dot product
504 
505   vector<WXFaceLayer *> _SmoothLayers;  // The data needed to store one or several smooth edges
506                                         // that traverse the face
507 
508  public:
WXFace()509   inline WXFace() : WFace()
510   {
511     _Z = 0.0f;
512     _front = false;
513   }
514 
515   /*! Copy constructor */
WXFace(WXFace & iBrother)516   WXFace(WXFace &iBrother) : WFace(iBrother)
517   {
518     _center = iBrother.center();
519     _Z = iBrother.Z();
520     _front = iBrother.front();
521     for (vector<WXFaceLayer *>::iterator wxf = iBrother._SmoothLayers.begin(),
522                                          wxfend = iBrother._SmoothLayers.end();
523          wxf != wxfend;
524          ++wxf) {
525       _SmoothLayers.push_back(new WXFaceLayer(**wxf));
526     }
527   }
528 
duplicate()529   virtual WFace *duplicate()
530   {
531     WXFace *clone = new WXFace(*this);
532     return clone;
533   }
534 
~WXFace()535   virtual ~WXFace()
536   {
537     if (!_SmoothLayers.empty()) {
538       for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(),
539                                            wxfend = _SmoothLayers.end();
540            wxf != wxfend;
541            ++wxf) {
542         delete (*wxf);
543       }
544       _SmoothLayers.clear();
545     }
546   }
547 
548   /*! designed to build a specialized WEdge for use in MakeEdge */
instanciateEdge()549   virtual WEdge *instanciateEdge() const
550   {
551     return new WXEdge;
552   }
553 
554   /*! accessors */
center()555   inline Vec3f &center()
556   {
557     return _center;
558   }
559 
Z()560   inline float Z()
561   {
562     return _Z;
563   }
564 
front()565   inline bool front()
566   {
567     return _front;
568   }
569 
dotp()570   inline float dotp()
571   {
572     return _dotp;
573   }
574 
hasSmoothEdges()575   inline bool hasSmoothEdges() const
576   {
577     for (vector<WXFaceLayer *>::const_iterator wxf = _SmoothLayers.begin(),
578                                                wxfend = _SmoothLayers.end();
579          wxf != wxfend;
580          ++wxf) {
581       if ((*wxf)->hasSmoothEdge()) {
582         return true;
583       }
584     }
585     return false;
586   }
587 
getSmoothLayers()588   vector<WXFaceLayer *> &getSmoothLayers()
589   {
590     return _SmoothLayers;
591   }
592 
593   /*! retrieve the smooth edges that match the Nature given as argument */
retrieveSmoothEdges(WXNature iNature,vector<WXSmoothEdge * > & oSmoothEdges)594   void retrieveSmoothEdges(WXNature iNature, vector<WXSmoothEdge *> &oSmoothEdges)
595   {
596     for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
597          wxf != wxfend;
598          ++wxf) {
599       if ((*wxf)->hasSmoothEdge() && ((*wxf)->_Nature & iNature)) {
600         oSmoothEdges.push_back((*wxf)->_pSmoothEdge);
601       }
602     }
603   }
604 
retrieveSmoothEdgesLayers(WXNature iNature,vector<WXFaceLayer * > & oSmoothEdgesLayers)605   void retrieveSmoothEdgesLayers(WXNature iNature, vector<WXFaceLayer *> &oSmoothEdgesLayers)
606   {
607     for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
608          wxf != wxfend;
609          ++wxf) {
610       if ((*wxf)->hasSmoothEdge() && ((*wxf)->_Nature & iNature)) {
611         oSmoothEdgesLayers.push_back((*wxf));
612       }
613     }
614   }
615 
retrieveSmoothLayers(WXNature iNature,vector<WXFaceLayer * > & oSmoothLayers)616   void retrieveSmoothLayers(WXNature iNature, vector<WXFaceLayer *> &oSmoothLayers)
617   {
618     for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
619          wxf != wxfend;
620          ++wxf) {
621       if ((*wxf)->_Nature & iNature) {
622         oSmoothLayers.push_back(*wxf);
623       }
624     }
625   }
626 
627   /*! modifiers */
setCenter(const Vec3f & iCenter)628   inline void setCenter(const Vec3f &iCenter)
629   {
630     _center = iCenter;
631   }
632 
633   void ComputeCenter();
634 
setZ(float z)635   inline void setZ(float z)
636   {
637     _Z = z;
638   }
639 
setFront(bool iFront)640   inline void setFront(bool iFront)
641   {
642     _front = iFront;
643   }
644 
setDotP(float iDotP)645   inline void setDotP(float iDotP)
646   {
647     _dotp = iDotP;
648     if (_dotp > 0.0f) {
649       _front = true;
650     }
651     else {
652       _front = false;
653     }
654   }
655 
AddSmoothLayer(WXFaceLayer * iLayer)656   inline void AddSmoothLayer(WXFaceLayer *iLayer)
657   {
658     _SmoothLayers.push_back(iLayer);
659   }
660 
Reset()661   inline void Reset()
662   {
663     vector<WXFaceLayer *> layersToKeep;
664     for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
665          wxf != wxfend;
666          ++wxf) {
667       if ((*wxf)->isViewDependant()) {
668         delete (*wxf);
669       }
670       else {
671         layersToKeep.push_back(*wxf);
672       }
673     }
674     _SmoothLayers = layersToKeep;
675   }
676 
677   /*! Clears everything */
Clear()678   inline void Clear()
679   {
680     for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
681          wxf != wxfend;
682          ++wxf) {
683       delete (*wxf);
684     }
685     _SmoothLayers.clear();
686   }
687 
ResetUserData()688   virtual void ResetUserData()
689   {
690     WFace::ResetUserData();
691     for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
692          wxf != wxfend;
693          ++wxf) {
694       (*wxf)->userdata = NULL;
695     }
696   }
697 
698 #ifdef WITH_CXX_GUARDEDALLOC
699   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:WXFace")
700 #endif
701 };
702 
703 /**********************************
704  *                                *
705  *                                *
706  *             WXShape            *
707  *                                *
708  *                                *
709  **********************************/
710 
711 class WXShape : public WShape {
712 #if 0
713  public:
714   typedef WXShape type_name;
715 #endif
716 
717  protected:
718   bool _computeViewIndependent;  // flag to indicate whether the view independent stuff must be
719                                  // computed or not
720 
721  public:
WXShape()722   inline WXShape() : WShape()
723   {
724     _computeViewIndependent = true;
725   }
726 
727   /*! copy constructor */
WXShape(WXShape & iBrother)728   inline WXShape(WXShape &iBrother) : WShape(iBrother)
729   {
730     _computeViewIndependent = iBrother._computeViewIndependent;
731   }
732 
duplicate()733   virtual WShape *duplicate()
734   {
735     WXShape *clone = new WXShape(*this);
736     return clone;
737   }
738 
~WXShape()739   virtual ~WXShape()
740   {
741   }
742 
getComputeViewIndependentFlag()743   inline bool getComputeViewIndependentFlag() const
744   {
745     return _computeViewIndependent;
746   }
747 
setComputeViewIndependentFlag(bool iFlag)748   inline void setComputeViewIndependentFlag(bool iFlag)
749   {
750     _computeViewIndependent = iFlag;
751   }
752 
753   /*! designed to build a specialized WFace for use in MakeFace */
instanciateFace()754   virtual WFace *instanciateFace() const
755   {
756     return new WXFace;
757   }
758 
759   /*!
760    * Adds a new face to the shape returns the built face.
761    * - iVertexList
762    *   List of face's vertices.
763    *   These vertices are not added to the WShape vertex list; they are
764    *   supposed to be already stored when calling MakeFace. The order in which the vertices are
765    *   stored in the list determines the face's edges orientation and (so) the face orientation.
766    */
767   virtual WFace *MakeFace(vector<WVertex *> &iVertexList,
768                           vector<bool> &iFaceEdgeMarksList,
769                           unsigned iMaterialIndex);
770 
771   /*!
772    * Adds a new face to the shape.
773    * The difference with the previous method is that this one is designed to build a WingedEdge
774    * structure for which there are per vertex normals, opposed to per face normals.
775    * returns the built face.
776    *
777    * - iVertexList:
778    *   List of face's vertices. These vertices are not added to the WShape vertex list;
779    *   they are supposed to be already stored when calling MakeFace.
780    *   The order in which the vertices are stored in the list determines
781    *   the face's edges orientation and (so) the face orientation.
782    * - iNormalsList:
783    *   The list of normals, iNormalsList[i]
784    *   corresponding to the normal of the vertex iVertexList[i] for that face.
785    * - iTexCoordsList:
786    *   The list of tex coords, iTexCoordsList[i]
787    *   corresponding to the normal of the vertex iVertexList[i] for that face.
788    */
789   virtual WFace *MakeFace(vector<WVertex *> &iVertexList,
790                           vector<Vec3f> &iNormalsList,
791                           vector<Vec2f> &iTexCoordsList,
792                           vector<bool> &iFaceEdgeMarksList,
793                           unsigned iMaterialIndex);
794 
795   /*! Reset all edges and vertices flags (which might have been set up on a previous pass) */
Reset()796   virtual void Reset()
797   {
798     // Reset Edges
799     vector<WEdge *> &wedges = getEdgeList();
800     for (vector<WEdge *>::iterator we = wedges.begin(), weend = wedges.end(); we != weend; ++we) {
801       ((WXEdge *)(*we))->Reset();
802     }
803 
804     // Reset faces:
805     vector<WFace *> &wfaces = GetFaceList();
806     for (vector<WFace *>::iterator wf = wfaces.begin(), wfend = wfaces.end(); wf != wfend; ++wf) {
807       ((WXFace *)(*wf))->Reset();
808     }
809   }
810   /*! accessors */
811 
812 #ifdef WITH_CXX_GUARDEDALLOC
813   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:WXShape")
814 #endif
815 };
816 
817 /*
818  * #############################################
819  * #############################################
820  * #############################################
821  * ######                                 ######
822  * ######   I M P L E M E N T A T I O N   ######
823  * ######                                 ######
824  * #############################################
825  * #############################################
826  * #############################################
827  */
828 /* for inline functions */
829 
isFeature()830 bool WXVertex::isFeature()
831 {
832   int counter = 0;
833   vector<WEdge *> &vedges = GetEdges();
834   for (vector<WEdge *>::iterator ve = vedges.begin(), vend = vedges.end(); ve != vend; ++ve) {
835     if (((WXEdge *)(*ve))->nature() != Nature::NO_FEATURE) {
836       counter++;
837     }
838   }
839 
840   if ((counter == 1) || (counter > 2)) {
841     return true;
842   }
843   return false;
844 }
845 
846 } /* namespace Freestyle */
847