// // Filename : WEdge.h // Author(s) : Stephane Grabli // Purpose : Classes to define a Winged Edge data structure. // Date of creation : 18/02/2002 // /////////////////////////////////////////////////////////////////////////////// // // Copyright (C) : Please refer to the COPYRIGHT file distributed // with this source distribution. // // 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // /////////////////////////////////////////////////////////////////////////////// #ifndef WEDGE_H # define WEDGE_H # include # include # include "../system/FreestyleConfig.h" # include "../geometry/Geom.h" # include "../scene_graph/FrsMaterial.h" using namespace std; using namespace Geometry; /**********************************/ /* */ /* */ /* WVertex */ /* */ /* */ /**********************************/ class WOEdge; class WEdge; class WShape; class WFace; class LIB_WINGED_EDGE_EXPORT WVertex { protected: int _Id; // an identificator Vec3r _Vertex; vector _EdgeList; WShape * _Shape; // the shape to which the vertex belongs bool _Smooth; // flag to indicate whether the Vertex belongs to a smooth edge or not int _Border; // 1 -> border, 0 -> no border, -1 -> not set public: void * userdata; // designed to store specific user data inline WVertex(const Vec3r &v) {_Id = 0; _Vertex = v; userdata = NULL; _Shape = NULL;_Smooth=true;_Border=-1;} /*! Copy constructor */ WVertex(WVertex& iBrother); virtual WVertex * duplicate(); virtual ~WVertex() {} /*! accessors */ inline Vec3r& GetVertex() {return _Vertex;} inline vector& GetEdges() {return _EdgeList;} inline int GetId() {return _Id;} inline WShape * shape() const {return _Shape;} inline bool isSmooth() const {return _Smooth;} bool isBoundary(); /*! modifiers */ inline void setVertex(const Vec3r& v) {_Vertex = v;} inline void setEdges(const vector& iEdgeList) {_EdgeList = iEdgeList;} inline void setId(int id) {_Id = id;} inline void setShape(WShape *iShape) {_Shape = iShape;} inline void setSmooth(bool b) {_Smooth = b;} inline void setBorder(bool b) {if(b) _Border= 1; else _Border = 0;} /*! Adds an edge to the edges list */ void AddEdge(WEdge *iEdge) ; virtual void ResetUserData() {userdata = 0;} public: /*! Iterator to iterate over a vertex incoming edges in the CCW order*/ # if defined(__GNUC__) && (__GNUC__ < 3) class incoming_edge_iterator : public input_iterator # else class LIB_WINGED_EDGE_EXPORT incoming_edge_iterator : public iterator # endif { private: WVertex *_vertex; // WOEdge *_begin; WOEdge *_current; public: # if defined(__GNUC__) && (__GNUC__ < 3) inline incoming_edge_iterator() : input_iterator() {} # else inline incoming_edge_iterator() : iterator() {} # endif virtual ~incoming_edge_iterator() {}; //soc protected: friend class WVertex; inline incoming_edge_iterator( WVertex *iVertex, WOEdge * iBegin, WOEdge * iCurrent) # if defined(__GNUC__) && (__GNUC__ < 3) : input_iterator() # else : iterator() # endif { _vertex = iVertex; _begin = iBegin; _current = iCurrent; } public: inline incoming_edge_iterator(const incoming_edge_iterator& iBrother) # if defined(__GNUC__) && (__GNUC__ < 3) : input_iterator(iBrother) # else : iterator(iBrother) # endif { _vertex = iBrother._vertex; _begin = iBrother._begin; _current = iBrother._current; } public: // operators virtual incoming_edge_iterator& operator++() // operator corresponding to ++i { increment(); return *this; } virtual incoming_edge_iterator operator++(int) // opérateur correspondant à i++ { // c.a.d qui renvoie la valeur *puis* incrémente. incoming_edge_iterator tmp = *this; // C'est pour cela qu'on stocke la valeur increment(); // dans un temporaire. return tmp; } // comparibility virtual bool operator!=(const incoming_edge_iterator& b) const { return ((_current) != (b._current)); } virtual bool operator==(const incoming_edge_iterator& b) const { return ((_current)== (b._current)); } // dereferencing virtual WOEdge* operator*(); //virtual WOEdge** operator->(); protected: virtual void increment(); }; /*! Iterator to iterate over a vertex faces in the CCW order */ # if defined(__GNUC__) && (__GNUC__ < 3) class face_iterator : public input_iterator # else class LIB_WINGED_EDGE_EXPORT face_iterator : public iterator # endif { private: incoming_edge_iterator _edge_it; public: # if defined(__GNUC__) && (__GNUC__ < 3) inline face_iterator() : input_iterator() {} # else inline face_iterator() : iterator() {} # endif virtual ~face_iterator() {}; //soc protected: friend class WVertex; inline face_iterator( incoming_edge_iterator it) # if defined(__GNUC__) && (__GNUC__ < 3) : input_iterator() # else : iterator() # endif { _edge_it = it; } public: inline face_iterator(const face_iterator& iBrother) # if defined(__GNUC__) && (__GNUC__ < 3) : input_iterator(iBrother) # else : iterator(iBrother) # endif { _edge_it = iBrother._edge_it; } public: // operators virtual face_iterator& operator++() // operator corresponding to ++i { increment(); return *this; } virtual face_iterator operator++(int) // opérateur correspondant à i++ { // c.a.d qui renvoie la valeur *puis* incrémente. face_iterator tmp = *this; // C'est pour cela qu'on stocke la valeur increment(); // dans un temporaire. return tmp; } // comparibility virtual bool operator!=(const face_iterator& b) const { return ((_edge_it) != (b._edge_it)); } virtual bool operator==(const face_iterator& b) const { return ((_edge_it)== (b._edge_it)); } // dereferencing virtual WFace* operator*(); //virtual WOEdge** operator->(); protected: inline void increment(){ ++_edge_it; } }; public: /*! iterators access */ virtual incoming_edge_iterator incoming_edges_begin(); virtual incoming_edge_iterator incoming_edges_end() ; virtual face_iterator faces_begin() { return face_iterator(incoming_edges_begin()); } virtual face_iterator faces_end() { return face_iterator(incoming_edges_end()); } }; /**********************************/ /* */ /* */ /* WOEdge */ /* */ /* */ /**********************************/ class WFace; class WEdge; class LIB_WINGED_EDGE_EXPORT WOEdge { protected: // WOEdge *_paCWEdge; // edge reached when traveling clockwise on aFace from the edge // WOEdge *_pbCWEdge; // edge reached when traveling clockwise on bFace from the edge // WOEdge *_paCCWEdge; // edge reached when traveling counterclockwise on aFace from the edge // WOEdge *_pbCCWEdge; // edge reached when traveling counterclockwise on bFace from the edge WVertex *_paVertex; // starting vertex WVertex *_pbVertex; // ending vertex WFace *_paFace; // when following the edge, face on the right WFace *_pbFace; // when following the edge, face on the left WEdge *_pOwner; // Edge public: void *userdata; inline WOEdge() { // _paCWEdge = NULL; // _pbCWEdge = NULL; // _paCCWEdge = NULL; // _pbCCWEdge = NULL; _paVertex = NULL; _pbVertex = NULL; _paFace = NULL; _pbFace = NULL; _pOwner = NULL; userdata = NULL; } virtual ~WOEdge() {}; //soc /*! copy constructor */ WOEdge(WOEdge& iBrother); virtual WOEdge * duplicate(); /*! accessors */ // inline WOEdge *GetaCWEdge() {return _paCWEdge;} // inline WOEdge *GetbCWEdge() {return _pbCWEdge;} // inline WOEdge *GetaCCWEdge() {return _paCCWEdge;} // inline WOEdge *GetbCCWEdge() {return _pbCCWEdge;} inline WVertex *GetaVertex() {return _paVertex;} inline WVertex *GetbVertex() {return _pbVertex;} inline WFace *GetaFace() {return _paFace;} inline WFace *GetbFace() {return _pbFace;} inline WEdge *GetOwner() {return _pOwner;} /*! modifiers */ // inline void SetaCWEdge(WOEdge *pe) {_paCWEdge = pe;} // inline void SetbCWEdge(WOEdge *pe) {_pbCWEdge = pe;} // inline void SetaCCWEdge(WOEdge *pe) {_paCCWEdge = pe;} // inline void SetbCCCWEdge(WOEdge *pe) {_pbCCWEdge = pe;} inline void setaVertex(WVertex *pv) {_paVertex = pv;} inline void setbVertex(WVertex *pv) {_pbVertex = pv;} inline void setaFace(WFace *pf) {_paFace = pf;} inline void setbFace(WFace *pf) {_pbFace = pf;} inline void setOwner(WEdge *pe) {_pOwner = pe;} /*! Retrieves the list of edges in CW order */ inline void RetrieveCWOrderedEdges(vector& oEdges); /*! returns the vector between the two vertices */ Vec3r getVec3r (); WOEdge * twin (); WOEdge * getPrevOnFace(); virtual void ResetUserData() {userdata = 0;} }; /**********************************/ /* */ /* */ /* WEdge */ /* */ /* */ /**********************************/ class LIB_WINGED_EDGE_EXPORT WEdge { protected: WOEdge *_paOEdge; // first oriented edge WOEdge *_pbOEdge; // second oriented edge int _nOEdges; // number of oriented edges associated with this edge. (1 means border edge) int _Id; // Identifier for the edge public: void * userdata; // designed to store specific user data inline WEdge() { _paOEdge = NULL; _pbOEdge = NULL; _nOEdges = 0; userdata = NULL; } inline WEdge(WOEdge *iOEdge) { _paOEdge = iOEdge; _pbOEdge = NULL; _nOEdges = 1; userdata = NULL; } inline WEdge(WOEdge *iaOEdge, WOEdge *ibOEdge) { _paOEdge = iaOEdge; _pbOEdge = ibOEdge; _nOEdges = 2; userdata = NULL; } /*! Copy constructor */ WEdge(WEdge& iBrother); virtual WEdge * duplicate(); virtual ~WEdge() { if(NULL != _paOEdge) { delete _paOEdge; _paOEdge = NULL; } if(NULL != _pbOEdge) { delete _pbOEdge; _pbOEdge = NULL; } } /*! checks whether two WEdge have a common vertex. * Returns a pointer on the common vertex if it exists, * NULL otherwise. */ static inline WVertex* CommonVertex(WEdge *iEdge1, WEdge* iEdge2) { if((NULL == iEdge1) || (NULL == iEdge2)) return NULL; WVertex *wv1 = iEdge1->GetaOEdge()->GetaVertex(); WVertex *wv2 = iEdge1->GetaOEdge()->GetbVertex(); WVertex *wv3 = iEdge2->GetaOEdge()->GetaVertex(); WVertex *wv4 = iEdge2->GetaOEdge()->GetbVertex(); if((wv1 == wv3) || (wv1 == wv4)) { return wv1; } else if((wv2 == wv3) || (wv2 == wv4)) { return wv2; } return NULL; } /*! accessors */ inline WOEdge * GetaOEdge() {return _paOEdge;} inline WOEdge * GetbOEdge() {return _pbOEdge;} inline int GetNumberOfOEdges() {return _nOEdges;} inline int GetId() {return _Id;} inline WVertex * GetaVertex() {return _paOEdge->GetaVertex();} inline WVertex * GetbVertex() {return _paOEdge->GetbVertex();} inline WFace * GetaFace() {return _paOEdge->GetaFace();} inline WFace * GetbFace() {return _paOEdge->GetbFace();} inline WOEdge* GetOtherOEdge(WOEdge* iOEdge) { if(iOEdge == _paOEdge) return _pbOEdge; else return _paOEdge; } /*! modifiers */ inline void setaOEdge(WOEdge *iEdge) {_paOEdge = iEdge;} inline void setbOEdge(WOEdge *iEdge) {_pbOEdge = iEdge;} inline void AddOEdge(WOEdge *iEdge) { if(NULL == _paOEdge) { _paOEdge = iEdge; _nOEdges++; return; } if(NULL == _pbOEdge) { _pbOEdge = iEdge; _nOEdges++; return; } } inline void setNumberOfOEdges(int n) {_nOEdges = n;} inline void setId(int id) {_Id = id;} virtual void ResetUserData() {userdata = 0;} }; /**********************************/ /* */ /* */ /* WFace */ /* */ /* */ /**********************************/ class LIB_WINGED_EDGE_EXPORT WFace { protected: vector _OEdgeList; // list of oriented edges of bording the face Vec3r _Normal; // normal to the face vector _VerticesNormals; // in case there is a normal per vertex. // The normal number i corresponds to the // aVertex of the oedge number i, for that face vector _VerticesTexCoords; int _Id; unsigned _FrsMaterialIndex; public: void *userdata; inline WFace() {userdata = NULL;_FrsMaterialIndex = 0;} /*! copy constructor */ WFace(WFace& iBrother); virtual WFace * duplicate(); virtual ~WFace() {} /*! accessors */ inline const vector& getEdgeList() {return _OEdgeList;} inline WOEdge * GetOEdge(int i) {return _OEdgeList[i];} inline Vec3r& GetNormal() {return _Normal;} inline int GetId() {return _Id;} inline unsigned frs_materialIndex() const {return _FrsMaterialIndex;} const FrsMaterial& frs_material() ; /*! The vertex of index i corresponds to the a vertex * of the edge of index i */ inline WVertex* GetVertex(unsigned int index) { // if(index >= _OEdgeList.size()) // return NULL; return _OEdgeList[index]->GetaVertex(); } /*! returns the index at which iVertex is stored in the * array. * returns -1 if iVertex doesn't belong to the face. */ inline int GetIndex(WVertex *iVertex){ int index = 0; for(vector::iterator woe=_OEdgeList.begin(), woend=_OEdgeList.end(); woe!=woend; woe++){ if((*woe)->GetaVertex() == iVertex) return index; ++index; } return -1; } inline void RetrieveVertexList(vector& oVertices) { for(vector::iterator woe=_OEdgeList.begin(), woend=_OEdgeList.end(); woe!=woend; woe++) { oVertices.push_back((*woe)->GetaVertex()); } } inline void RetrieveBorderFaces(vector& oWFaces) { for(vector::iterator woe=_OEdgeList.begin(), woend=_OEdgeList.end(); woe!=woend; woe++) { WFace *af; if(NULL != (af = (*woe)->GetaFace())) oWFaces.push_back(af); } } inline WFace * GetBordingFace(int index) { // if(index >= _OEdgeList.size()) // return 0; return _OEdgeList[index]->GetaFace(); } inline WFace * GetBordingFace(WOEdge *iOEdge) { return iOEdge->GetaFace(); } inline vector& GetPerVertexNormals() { return _VerticesNormals; } inline vector& GetPerVertexTexCoords() { return _VerticesTexCoords; } /*! Returns the normal of the vertex of index index */ inline Vec3r& GetVertexNormal(int index) { return _VerticesNormals[index]; } /*! Returns the tex coords of the vertex of index index */ inline Vec2r& GetVertexTexCoords(int index) { return _VerticesTexCoords[index]; } /*! Returns the normal of the vertex iVertex for that face */ inline Vec3r& GetVertexNormal(WVertex *iVertex) { int i = 0; int index = 0; for(vector::const_iterator woe=_OEdgeList.begin(), woend=_OEdgeList.end(); woe!=woend; woe++) { if((*woe)->GetaVertex() == iVertex) { index = i; break; } ++i; } return _VerticesNormals[index]; } inline WOEdge* GetNextOEdge(WOEdge* iOEdge) { bool found = false; vector::iterator woe,woend, woefirst; woefirst = _OEdgeList.begin(); for(woe=woefirst,woend=_OEdgeList.end(); woe!=woend; woe++) { if(true == found) return (*woe); if((*woe) == iOEdge) { found = true; } } // We left the loop. That means that the first // OEdge was the good one: if(found) return (*woefirst); return NULL; } WOEdge* GetPrevOEdge(WOEdge* iOEdge); inline int numberOfEdges() const { return _OEdgeList.size();} inline int numberOfVertices() const { return _OEdgeList.size();} /*! Returns true if the face has one ot its edge which is a border * edge */ inline bool isBorder() const { for(vector::const_iterator woe=_OEdgeList.begin(), woeend=_OEdgeList.end(); woe!=woeend; ++woe) { if((*woe)->GetOwner()->GetbOEdge() == 0) return true; } return false; } /*! modifiers */ inline void setEdgeList(const vector& iEdgeList) {_OEdgeList = iEdgeList;} inline void setNormal(const Vec3r& iNormal) {_Normal = iNormal;} inline void setNormalList(const vector& iNormalsList) {_VerticesNormals = iNormalsList;} inline void setTexCoordsList(const vector& iTexCoordsList) {_VerticesTexCoords = iTexCoordsList;} inline void setId(int id) {_Id = id;} inline void setFrsMaterialIndex(unsigned iMaterialIndex) {_FrsMaterialIndex = iMaterialIndex;} /*! designed to build a specialized WEdge * for use in MakeEdge */ virtual WEdge * instanciateEdge() const {return new WEdge;} /*! Builds an oriented edge * Returns the built edge. * v1, v2 * Vertices at the edge's extremities * The edge is oriented from v1 to v2. */ virtual WOEdge * MakeEdge(WVertex *v1, WVertex *v2); /*! Adds an edge to the edges list */ inline void AddEdge(WOEdge *iEdge) {_OEdgeList.push_back(iEdge);} /*! For triangles, returns the edge opposite to the vertex in e. returns flase if the face is not a triangle or if the vertex is not found*/ bool getOppositeEdge (const WVertex *v, WOEdge* &e); /*! compute the area of the face */ real getArea (); WShape * getShape() ; virtual void ResetUserData() {userdata = 0;} }; /**********************************/ /* */ /* */ /* WShape */ /* */ /* */ /**********************************/ class LIB_WINGED_EDGE_EXPORT WShape { protected: vector _VertexList; vector _EdgeList; vector _FaceList; int _Id; static unsigned _SceneCurrentId; Vec3r _min; Vec3r _max; vector _FrsMaterials; real _meanEdgeSize; public: inline WShape() {_meanEdgeSize = 0;_Id = _SceneCurrentId; _SceneCurrentId++;} /*! copy constructor */ WShape(WShape& iBrother); virtual WShape * duplicate(); virtual ~WShape() { if(_EdgeList.size() != 0) { vector::iterator e; for(e=_EdgeList.begin(); e!=_EdgeList.end(); e++) { delete (*e); } _EdgeList.clear(); } if(_VertexList.size() != 0) { vector::iterator v; for(v=_VertexList.begin(); v!=_VertexList.end(); v++) { delete (*v); } _VertexList.clear(); } if(_FaceList.size() != 0) { vector::iterator f; for(f=_FaceList.begin(); f!=_FaceList.end(); f++) { delete (*f); } _FaceList.clear(); } } /*! accessors */ inline vector& getEdgeList() {return _EdgeList;} inline vector& getVertexList() {return _VertexList;} inline vector& GetFaceList() {return _FaceList;} inline unsigned GetId() {return _Id;} inline void bbox(Vec3r& min, Vec3r& max) {min=_min; max=_max;} inline const FrsMaterial& frs_material(unsigned i) const {return _FrsMaterials[i];} inline const vector& frs_materials() const {return _FrsMaterials;} inline const real getMeanEdgeSize() const {return _meanEdgeSize;} /*! modifiers */ static inline void setCurrentId(const unsigned id) { _SceneCurrentId = id; } inline void setEdgeList(const vector& iEdgeList) {_EdgeList = iEdgeList;} inline void setVertexList(const vector& iVertexList) {_VertexList = iVertexList;} inline void setFaceList(const vector& iFaceList) {_FaceList = iFaceList;} inline void setId(int id) {_Id = id;} inline void setBBox(const Vec3r& min, const Vec3r& max) {_min = min; _max=max;} inline void setFrsMaterial(const FrsMaterial& frs_material, unsigned i) {_FrsMaterials[i]=frs_material;} inline void setFrsMaterials(const vector& iMaterials) {_FrsMaterials = iMaterials;} /*! designed to build a specialized WFace * for use in MakeFace */ virtual WFace * instanciateFace() const {return new WFace;} /*! adds a new face to the shape * returns the built face. * iVertexList * List of face's vertices. These vertices are * not added to the WShape vertex list; they are * supposed to be already stored when calling MakeFace. * The order in which the vertices are stored in the list * determines the face's edges orientation and (so) the * face orientation. * iMaterialIndex * The material index for this face */ virtual WFace * MakeFace(vector& iVertexList, unsigned iMaterialIndex); /*! adds a new face to the shape. The difference with * the previous method is that this one is designed * to build a WingedEdge structure for which there are * per vertex normals, opposed to per face normals. * returns the built face. * iVertexList * List of face's vertices. These vertices are * not added to the WShape vertex list; they are * supposed to be already stored when calling MakeFace. * The order in which the vertices are stored in the list * determines the face's edges orientation and (so) the * face orientation. * iMaterialIndex * The materialIndex for this face * iNormalsList * The list of normals, iNormalsList[i] corresponding to the * normal of the vertex iVertexList[i] for that face. * iTexCoordsList * The list of tex coords, iTexCoordsList[i] corresponding to the * normal of the vertex iVertexList[i] for that face. */ virtual WFace * MakeFace(vector& iVertexList, vector& iNormalsList, vector& iTexCoordsList, unsigned iMaterialIndex); inline void AddEdge(WEdge *iEdge) {_EdgeList.push_back(iEdge);} inline void AddFace(WFace* iFace) {_FaceList.push_back(iFace);} inline void AddVertex(WVertex *iVertex) {iVertex->setShape(this); _VertexList.push_back(iVertex);} inline void ResetUserData() { for(vector::iterator v=_VertexList.begin(),vend=_VertexList.end(); v!=vend; v++) { (*v)->ResetUserData(); } for(vector::iterator e=_EdgeList.begin(),eend=_EdgeList.end(); e!=eend; e++) { (*e)->ResetUserData(); // manages WOEdge: WOEdge *oe = (*e)->GetaOEdge(); if(oe != NULL) oe->ResetUserData(); oe = (*e)->GetbOEdge(); if(oe != NULL) oe->ResetUserData(); } for(vector::iterator f=_FaceList.begin(),fend=_FaceList.end(); f!=fend; f++) { (*f)->ResetUserData(); } } inline void ComputeBBox() { _min = _VertexList[0]->GetVertex(); _max = _VertexList[0]->GetVertex(); Vec3r v; for(vector::iterator wv=_VertexList.begin(), wvend=_VertexList.end(); wv!=wvend; wv++) { for(unsigned int i=0; i<3; i++) { v = (*wv)->GetVertex(); if(v[i] < _min[i]) _min[i] = v[i]; if(v[i] > _max[i]) _max[i] = v[i]; } } } inline real ComputeMeanEdgeSize(){ _meanEdgeSize = _meanEdgeSize/(_EdgeList.size()); return _meanEdgeSize; } protected: /*! Builds the face passed as argument (which as already been allocated) * iVertexList * List of face's vertices. These vertices are * not added to the WShape vertex list; they are * supposed to be already stored when calling MakeFace. * The order in which the vertices are stored in the list * determines the face's edges orientation and (so) the * face orientation. * iMaterialIndex * The material index for this face * face * The Face that is filled in */ virtual WFace * MakeFace(vector& iVertexList, unsigned iMaterialIndex, WFace *face); }; /**********************************/ /* */ /* */ /* WingedEdge */ /* */ /* */ /**********************************/ class WingedEdge { public: WingedEdge() {} ~WingedEdge() { clear(); } void clear() { for (vector::iterator it = _wshapes.begin(); it != _wshapes.end(); it++) delete *it; _wshapes.clear(); } void addWShape(WShape* wshape) { _wshapes.push_back(wshape); } vector& getWShapes() { return _wshapes; } private: vector _wshapes; }; /* ############################################# ############################################# ############################################# ###### ###### ###### I M P L E M E N T A T I O N ###### ###### ###### ############################################# ############################################# ############################################# */ /* for inline functions */ void WOEdge::RetrieveCWOrderedEdges(vector& oEdges) { WOEdge *currentOEdge = this; do { WOEdge* nextOEdge = currentOEdge->GetbFace()->GetNextOEdge(currentOEdge); oEdges.push_back(nextOEdge->GetOwner()); currentOEdge = nextOEdge->GetOwner()->GetOtherOEdge(nextOEdge); } while((currentOEdge != NULL) && (currentOEdge->GetOwner() != GetOwner())); } #endif // WEDGE_H