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 ¢er()
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