/* * ***** BEGIN GPL LICENSE BLOCK ***** * * 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. * * ***** END GPL LICENSE BLOCK ***** */ #ifndef __FREESTYLE_SILHOUETTE_H__ #define __FREESTYLE_SILHOUETTE_H__ /** \file blender/freestyle/intern/view_map/Silhouette.h * \ingroup freestyle * \brief Classes to define a silhouette structure * \author Stephane Grabli * \date 25/03/2002 */ #include #include #include #include #include #include "Interface0D.h" #include "Interface1D.h" #include "../geometry/BBox.h" #include "../geometry/Geom.h" #include "../geometry/Polygon.h" #include "../scene_graph/FrsMaterial.h" #include "../system/Exception.h" #include "../system/FreestyleConfig.h" #include "../winged_edge/Curvature.h" #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" #endif using namespace std; namespace Freestyle { using namespace Geometry; class ViewShape; typedef vector occluder_container; /**********************************/ /* */ /* */ /* SVertex */ /* */ /* */ /**********************************/ class FEdge; class ViewVertex; class SShape; /*! Class to define a vertex of the embedding. */ class SVertex : public Interface0D { public: // Implementation of Interface0D /*! Returns the string "SVertex" .*/ virtual string getExactTypeName() const { return "SVertex"; } // Data access methods /*! Returns the 3D x coordinate of the vertex .*/ virtual real getX() const { return _Point3D.x(); } /*! Returns the 3D y coordinate of the vertex .*/ virtual real getY() const { return _Point3D.y(); } /*! Returns the 3D z coordinate of the vertex .*/ virtual real getZ() const { return _Point3D.z(); } /*! Returns the 3D point. */ virtual Vec3r getPoint3D() const { return _Point3D; } /*! Returns the projected 3D x coordinate of the vertex .*/ virtual real getProjectedX() const { return _Point2D.x(); } /*! Returns the projected 3D y coordinate of the vertex .*/ virtual real getProjectedY() const { return _Point2D.y(); } /*! Returns the projected 3D z coordinate of the vertex .*/ virtual real getProjectedZ() const { return _Point2D.z(); } /*! Returns the 2D point. */ virtual Vec2r getPoint2D() const { return Vec2r(_Point2D.x(), _Point2D.y()); } /*! Returns the FEdge that lies between this Svertex and the Interface0D given as argument. */ virtual FEdge *getFEdge(Interface0D&); /*! Returns the Id of the vertex .*/ virtual Id getId() const { return _Id; } /*! Returns the nature of the vertex .*/ virtual Nature::VertexNature getNature() const; /*! Cast the Interface0D in SVertex if it can be. */ virtual SVertex *castToSVertex(); /*! Cast the Interface0D in ViewVertex if it can be. */ virtual ViewVertex *castToViewVertex(); /*! Cast the Interface0D in NonTVertex if it can be. */ virtual NonTVertex *castToNonTVertex(); /*! Cast the Interface0D in TVertex if it can be. */ virtual TVertex *castToTVertex(); public: typedef vector fedges_container; private: Id _Id; Vec3r _Point3D; Vec3r _Point2D; set _Normals; vector _FEdges; // the edges containing this vertex SShape *_Shape; // the shape to which belongs the vertex ViewVertex *_pViewVertex; // The associated viewvertex, in case there is one. #if 0 real _curvatureFredo; Vec2r _directionFredo; #endif CurvatureInfo *_curvature_info; public: /*! A field that can be used by the user to store any data. * This field must be reseted afterwards using ResetUserData(). */ void *userdata; /*! Default constructor.*/ inline SVertex() { _Id = 0; userdata = NULL; _Shape = NULL; _pViewVertex = 0; _curvature_info = 0; } /*! Builds a SVertex from 3D coordinates and an Id. */ inline SVertex(const Vec3r &iPoint3D, const Id& id) { _Point3D = iPoint3D; _Id = id; userdata = NULL; _Shape = NULL; _pViewVertex = 0; _curvature_info = 0; } /*! Copy constructor. */ inline SVertex(SVertex& iBrother) { _Id = iBrother._Id; _Point3D = iBrother.point3D(); _Point2D = iBrother.point2D(); _Normals = iBrother._Normals; _FEdges = iBrother.fedges(); _Shape = iBrother.shape(); _pViewVertex = iBrother._pViewVertex; if (!(iBrother._curvature_info)) _curvature_info = 0; else _curvature_info = new CurvatureInfo(*(iBrother._curvature_info)); iBrother.userdata = this; userdata = 0; } /*! Destructor. */ virtual ~SVertex() { if (_curvature_info) delete _curvature_info; } /*! Cloning method. */ virtual SVertex *duplicate() { SVertex *clone = new SVertex(*this); return clone; } /*! operator == */ virtual bool operator==(const SVertex& iBrother) { return ((_Point2D == iBrother._Point2D) && (_Point3D == iBrother._Point3D)); } /* accessors */ inline const Vec3r& point3D() const { return _Point3D; } inline const Vec3r& point2D() const { return _Point2D; } /*! Returns the set of normals for this Vertex. * In a smooth surface, a vertex has exactly one normal. * In a sharp surface, a vertex can have any number of normals. */ inline set normals() { return _Normals; } /*! Returns the number of different normals for this vertex. */ inline unsigned normalsSize() const { return _Normals.size(); } inline const vector& fedges() { return _FEdges; } inline fedges_container::iterator fedges_begin() { return _FEdges.begin(); } inline fedges_container::iterator fedges_end() { return _FEdges.end(); } inline SShape *shape() { return _Shape; } inline real z() const { return _Point2D[2]; } /*! If this SVertex is also a ViewVertex, this method returns a pointer onto this ViewVertex. * 0 is returned otherwise. */ inline ViewVertex *viewvertex() { return _pViewVertex; } /*! modifiers */ /*! Sets the 3D coordinates of the SVertex. */ inline void setPoint3D(const Vec3r &iPoint3D) { _Point3D = iPoint3D; } /*! Sets the 3D projected coordinates of the SVertex. */ inline void setPoint2D(const Vec3r &iPoint2D) { _Point2D = iPoint2D; } /*! Adds a normal to the Svertex's set of normals. If the same normal is already in the set, nothing changes. */ inline void AddNormal(const Vec3r& iNormal) { _Normals.insert(iNormal); // if iNormal in the set already exists, nothing is done } void setCurvatureInfo(CurvatureInfo *ci) { if (_curvature_info) // Q. is this an error condition? (T.K. 02-May-2011) delete _curvature_info; _curvature_info = ci; } const CurvatureInfo *getCurvatureInfo() const { return _curvature_info; } #if 0 /* Fredo's normal and curvature*/ void setCurvatureFredo(real c) { _curvatureFredo = c; } void setDirectionFredo(Vec2r d) { _directionFredo = d; } real curvatureFredo () { return _curvatureFredo; } const Vec2r directionFredo () { return _directionFredo; } #endif /*! Sets the Id */ inline void setId(const Id& id) { _Id = id; } inline void setFEdges(const vector& iFEdges) { _FEdges = iFEdges; } inline void setShape(SShape *iShape) { _Shape = iShape; } inline void setViewVertex(ViewVertex *iViewVertex) { _pViewVertex = iViewVertex; } /*! Add an FEdge to the list of edges emanating from this SVertex. */ inline void AddFEdge(FEdge *iFEdge) { _FEdges.push_back(iFEdge); } /*! Remove an FEdge from the list of edges emanating from this SVertex. */ inline void RemoveFEdge(FEdge *iFEdge) { for (vector::iterator fe = _FEdges.begin(), fend = _FEdges.end(); fe != fend; fe++) { if (iFEdge == (*fe)) { _FEdges.erase(fe); break; } } } /* replaces edge 1 by edge 2 in the list of edges */ inline void Replace(FEdge *e1, FEdge *e2) { vector::iterator insertedfe; for (vector::iterator fe = _FEdges.begin(), fend = _FEdges.end(); fe != fend; fe++) { if ((*fe) == e1) { insertedfe = _FEdges.insert(fe, e2);// inserts e2 before fe. // returns an iterator pointing toward e2. fe is invalidated. // we want to remove e1, but we can't use fe anymore: ++insertedfe; // insertedfe points now to e1 _FEdges.erase(insertedfe); return; } } } public: /* Information access interface */ FEdge *fedge(); // for non T vertex inline const Vec3r& point2d() const { return point2D(); } inline const Vec3r& point3d() const { return point3D(); } inline Vec3r normal() const { if (_Normals.size() == 1) return (*(_Normals.begin())); Exception::raiseException(); return *(_Normals.begin()); } //Material material() const ; Id shape_id() const; const SShape *shape() const; float shape_importance() const; const int qi() const; occluder_container::const_iterator occluders_begin() const; occluder_container::const_iterator occluders_end() const; bool occluders_empty() const; int occluders_size() const; const Polygon3r& occludee() const; const SShape *occluded_shape() const; const bool occludee_empty() const; real z_discontinuity() const; #if 0 inline float local_average_depth() const; inline float local_depth_variance() const; inline real local_average_density(float sigma = 2.3f) const; inline Vec3r shaded_color() const; inline Vec3r orientation2d() const; inline Vec3r orientation3d() const; inline Vec3r curvature2d_as_vector() const; /*! angle in radians */ inline real curvature2d_as_angle() const; #endif #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SVertex") #endif }; /**********************************/ /* */ /* */ /* FEdge */ /* */ /* */ /**********************************/ class ViewEdge; /*! Base Class for feature edges. * This FEdge can represent a silhouette, a crease, a ridge/valley, a border or a suggestive contour. * For silhouettes, the FEdge is oriented such as, the visible face lies on the left of the edge. * For borders, the FEdge is oriented such as, the face lies on the left of the edge. * An FEdge can represent an initial edge of the mesh or runs accross a face of the initial mesh depending * on the smoothness or sharpness of the mesh. * This class is specialized into a smooth and a sharp version since their properties slightly vary from * one to the other. */ class FEdge : public Interface1D { public: // Implementation of Interface0D /*! Returns the string "FEdge". */ virtual string getExactTypeName() const { return "FEdge"; } // Data access methods /*! Returns the 2D length of the FEdge. */ virtual real getLength2D() const { if (!_VertexA || !_VertexB) return 0; return (_VertexB->getPoint2D() - _VertexA->getPoint2D()).norm(); } /*! Returns the Id of the FEdge. */ virtual Id getId() const { return _Id; } public: // An edge can only be of one kind (SILHOUETTE or BORDER, etc...) // For an multi-nature edge there must be several different FEdge. // DEBUG: // Vec3r A; // Vec3r u; // vector _Occludees; // Vec3r intersection; // vector _Cells; protected: SVertex *_VertexA; SVertex *_VertexB; Id _Id; Nature::EdgeNature _Nature; //vector _Occluders; // visibility // NOT HANDLED BY THE COPY CONSTRUCTOR!! FEdge *_NextEdge; // next edge on the chain FEdge *_PreviousEdge; ViewEdge *_ViewEdge; // Sometimes we need to deport the visibility computation onto another edge. For example the exact edges use // edges of the mesh to compute their visibility Polygon3r _aFace; // The occluded face which lies on the right of a silhouette edge Vec3r _occludeeIntersection; bool _occludeeEmpty; bool _isSmooth; bool _isInImage; bool _isTemporary; public: /*! A field that can be used by the user to store any data. * This field must be reseted afterwards using ResetUserData(). */ void *userdata; /*! Default constructor */ inline FEdge() { userdata = NULL; _VertexA = NULL; _VertexB = NULL; _Nature = Nature::NO_FEATURE; _NextEdge = NULL; _PreviousEdge = NULL; _ViewEdge = NULL; //_hasVisibilityPoint = false; _occludeeEmpty = true; _isSmooth = false; _isInImage = true; _isTemporary = false; } /*! Builds an FEdge going from vA to vB. */ inline FEdge(SVertex *vA, SVertex *vB) { userdata = NULL; _VertexA = vA; _VertexB = vB; _Nature = Nature::NO_FEATURE; _NextEdge = NULL; _PreviousEdge = NULL; _ViewEdge = NULL; //_hasVisibilityPoint = false; _occludeeEmpty = true; _isSmooth = false; _isInImage = true; _isTemporary = false; } /*! Copy constructor */ inline FEdge(FEdge& iBrother) { _VertexA = iBrother.vertexA(); _VertexB = iBrother.vertexB(); _NextEdge = iBrother.nextEdge(); _PreviousEdge = iBrother._PreviousEdge; _Nature = iBrother.getNature(); _Id = iBrother._Id; _ViewEdge = iBrother._ViewEdge; //_hasVisibilityPoint = iBrother._hasVisibilityPoint; //_VisibilityPointA = iBrother._VisibilityPointA; //_VisibilityPointB = iBrother._VisibilityPointB; _aFace = iBrother._aFace; _occludeeEmpty = iBrother._occludeeEmpty; _isSmooth = iBrother._isSmooth; _isInImage = iBrother._isInImage; _isTemporary = iBrother._isTemporary; iBrother.userdata = this; userdata = 0; } /*! Destructor */ virtual ~FEdge() {} /*! Cloning method. */ virtual FEdge *duplicate() { FEdge *clone = new FEdge(*this); return clone; } /* accessors */ /*! Returns the first SVertex. */ inline SVertex *vertexA() { return _VertexA; } /*! Returns the second SVertex. */ inline SVertex *vertexB() { return _VertexB; } /*! Returns the first SVertex if i=0, the seccond SVertex if i=1. */ inline SVertex *operator[](const unsigned short int& i) const { return (i % 2 == 0) ? _VertexA : _VertexB; } /*! Returns the nature of the FEdge. */ inline Nature::EdgeNature getNature() const { return _Nature; } /*! Returns the FEdge following this one in the ViewEdge. * If this FEdge is the last of the ViewEdge, 0 is returned. */ inline FEdge *nextEdge() { return _NextEdge; } /*! Returns the Edge preceding this one in the ViewEdge. * If this FEdge is the first one of the ViewEdge, 0 is returned. */ inline FEdge *previousEdge() { return _PreviousEdge; } inline SShape *shape() { return _VertexA->shape(); } #if 0 inline int invisibility() const { return _Occluders.size(); } #endif int invisibility() const; #if 0 inline const vector& occluders() const { return _Occluders; } #endif /*! Returns a pointer to the ViewEdge to which this FEdge belongs to. */ inline ViewEdge *viewedge() const { return _ViewEdge; } inline Vec3r center3d() { return Vec3r((_VertexA->point3D() + _VertexB->point3D()) / 2.0); } inline Vec3r center2d() { return Vec3r((_VertexA->point2D() + _VertexB->point2D()) / 2.0); } #if 0 inline bool hasVisibilityPoint() const { return _hasVisibilityPoint; } inline Vec3r visibilityPointA() const { return _VisibilityPointA; } inline Vec3r visibilityPointB() const { return _VisibilityPointB; } #endif inline const Polygon3r& aFace() const { return _aFace; } inline const Vec3r& getOccludeeIntersection() { return _occludeeIntersection; } inline bool getOccludeeEmpty() { return _occludeeEmpty; } /*! Returns true if this FEdge is a smooth FEdge. */ inline bool isSmooth() const { return _isSmooth; } inline bool isInImage () const { return _isInImage; } inline bool isTemporary() const { return _isTemporary; } /* modifiers */ /*! Sets the first SVertex. */ inline void setVertexA(SVertex *vA) { _VertexA = vA; } /*! Sets the second SVertex. */ inline void setVertexB(SVertex *vB) { _VertexB = vB; } /*! Sets the FEdge Id . */ inline void setId(const Id& id) { _Id = id; } /*! Sets the pointer to the next FEdge. */ inline void setNextEdge(FEdge *iEdge) { _NextEdge = iEdge; } /*! Sets the pointer to the previous FEdge. */ inline void setPreviousEdge(FEdge *iEdge) { _PreviousEdge = iEdge; } /*! Sets the nature of this FEdge. */ inline void setNature(Nature::EdgeNature iNature) { _Nature = iNature; } #if 0 inline void AddOccluder(Polygon3r& iPolygon) { _Occluders.push_back(iPolygon); } #endif /*! Sets the ViewEdge to which this FEdge belongs to. */ inline void setViewEdge(ViewEdge *iViewEdge) { _ViewEdge = iViewEdge; } #if 0 inline void setHasVisibilityPoint(bool iBool) { _hasVisibilityPoint = iBool; } inline void setVisibilityPointA(const Vec3r& iPoint) { _VisibilityPointA = iPoint; } inline void setVisibilityPointB(const Vec3r& iPoint) { _VisibilityPointB = iPoint; } #endif inline void setaFace(Polygon3r& iFace) { _aFace = iFace; } inline void setOccludeeIntersection(const Vec3r& iPoint) { _occludeeIntersection = iPoint; } inline void setOccludeeEmpty(bool iempty) { _occludeeEmpty = iempty; } /*! Sets the flag telling whether this FEdge is smooth or sharp. * true for Smooth, false for Sharp. */ inline void setSmooth(bool iFlag) { _isSmooth = iFlag; } inline void setIsInImage (bool iFlag) { _isInImage = iFlag; } inline void setTemporary(bool iFlag) { _isTemporary = iFlag; } /* checks whether two FEdge have a common vertex. * Returns a pointer on the common vertex if it exists, NULL otherwise. */ static inline SVertex *CommonVertex(FEdge *iEdge1, FEdge *iEdge2) { if ((NULL == iEdge1) || (NULL == iEdge2)) return NULL; SVertex *sv1 = iEdge1->vertexA(); SVertex *sv2 = iEdge1->vertexB(); SVertex *sv3 = iEdge2->vertexA(); SVertex *sv4 = iEdge2->vertexB(); if ((sv1 == sv3) || (sv1 == sv4)) { return sv1; } else if ((sv2 == sv3) || (sv2 == sv4)) { return sv2; } return NULL; } inline const SVertex *min2d() const { if (_VertexA->point2D() < _VertexB->point2D()) return _VertexA; else return _VertexB; } inline const SVertex *max2d() const { if (_VertexA->point2D() < _VertexB->point2D()) return _VertexB; else return _VertexA; } /* Information access interface */ //Material material() const; Id shape_id() const; const SShape *shape() const; float shape_importance() const; inline const int qi() const { return invisibility(); } occluder_container::const_iterator occluders_begin() const; occluder_container::const_iterator occluders_end() const; bool occluders_empty() const; int occluders_size() const; inline const Polygon3r& occludee() const { return aFace(); } const SShape *occluded_shape() const; #if 0 inline const bool occludee_empty() const { return _occludeeEmpty; } #endif const bool occludee_empty() const; real z_discontinuity() const; #if 0 inline float local_average_depth(int iCombination = 0) const; inline float local_depth_variance(int iCombination = 0) const; inline real local_average_density(float sigma = 2.3f, int iCombination = 0) const; inline Vec3r shaded_color(int iCombination = 0) const {} #endif int viewedge_nature() const; //float viewedge_length() const; inline Vec3r orientation2d() const { return Vec3r(_VertexB->point2d() - _VertexA->point2d()); } inline Vec3r orientation3d() const { return Vec3r(_VertexB->point3d() - _VertexA->point3d()); } #if 0 inline real curvature2d() const { return viewedge()->curvature2d((_VertexA->point2d() + _VertexB->point2d()) / 2.0); } inline Vec3r curvature2d_as_vector(int iCombination = 0) const; /* angle in degrees*/ inline real curvature2d_as_angle(int iCombination = 0) const; #endif // Iterator access (Interface1D) /*! Returns an iterator over the 2 (!) SVertex pointing to the first SVertex. */ virtual inline Interface0DIterator verticesBegin(); /*! Returns an iterator over the 2 (!) SVertex pointing after the last SVertex. */ virtual inline Interface0DIterator verticesEnd(); /*! Returns an iterator over the FEdge points, pointing to the first point. The difference with verticesBegin() * is that here we can iterate over points of the FEdge at a any given sampling. * Indeed, for each iteration, a virtual point is created. * \param t * The sampling with which we want to iterate over points of this FEdge. */ virtual inline Interface0DIterator pointsBegin(float t = 0.0f); /*! Returns an iterator over the FEdge points, pointing after the last point. The difference with verticesEnd() * is that here we can iterate over points of the FEdge at a any given sampling. * Indeed, for each iteration, a virtual point is created. * \param t * The sampling with which we want to iterate over points of this FEdge. */ virtual inline Interface0DIterator pointsEnd(float t = 0.0f); #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdge") #endif }; // // SVertexIterator // ///////////////////////////////////////////////// namespace FEdgeInternal { class SVertexIterator : public Interface0DIteratorNested { public: SVertexIterator() { _vertex = NULL; _edge = NULL; } SVertexIterator(const SVertexIterator& vi) { _vertex = vi._vertex; _edge = vi._edge; } SVertexIterator(SVertex *v, FEdge *edge) { _vertex = v; _edge = edge; } SVertexIterator& operator=(const SVertexIterator& vi) { _vertex = vi._vertex; _edge = vi._edge; return *this; } virtual string getExactTypeName() const { return "SVertexIterator"; } virtual SVertex& operator*() { return *_vertex; } virtual SVertex *operator->() { return &(operator*()); } virtual SVertexIterator& operator++() { increment(); return *this; } virtual SVertexIterator operator++(int) { SVertexIterator ret(*this); increment(); return ret; } virtual SVertexIterator& operator--() { decrement(); return *this; } virtual SVertexIterator operator--(int) { SVertexIterator ret(*this); decrement(); return ret; } virtual int increment() { if (_vertex == _edge->vertexB()) { _vertex = 0; return 0; } _vertex = _edge->vertexB(); return 0; } virtual int decrement() { if (_vertex == _edge->vertexA()) { _vertex = 0; return 0; } _vertex = _edge->vertexA(); return 0; } virtual bool isBegin() const { return _vertex == _edge->vertexA(); } virtual bool isEnd() const { return _vertex == _edge->vertexB(); } virtual bool operator==(const Interface0DIteratorNested& it) const { const SVertexIterator *it_exact = dynamic_cast(&it); if (!it_exact) return false; return ((_vertex == it_exact->_vertex) && (_edge == it_exact->_edge)); } virtual float t() const { if (_vertex == _edge->vertexA()) { return 0.0f; } return ((float)_edge->getLength2D()); } virtual float u() const { if (_vertex == _edge->vertexA()) { return 0.0f; } return 1.0f; } virtual SVertexIterator *copy() const { return new SVertexIterator(*this); } private: SVertex *_vertex; FEdge *_edge; }; } // end of namespace FEdgeInternal // Iterator access (implementation) Interface0DIterator FEdge::verticesBegin() { Interface0DIterator ret(new FEdgeInternal::SVertexIterator(_VertexA, this)); return ret; } Interface0DIterator FEdge::verticesEnd() { Interface0DIterator ret(new FEdgeInternal::SVertexIterator(0, this)); return ret; } Interface0DIterator FEdge::pointsBegin(float t) { return verticesBegin(); } Interface0DIterator FEdge::pointsEnd(float t) { return verticesEnd(); } /*! Class defining a sharp FEdge. A Sharp FEdge corresponds to an initial edge of the input mesh. * It can be a silhouette, a crease or a border. If it is a crease edge, then it is borded * by two faces of the mesh. Face a lies on its right whereas Face b lies on its left. * If it is a border edge, then it doesn't have any face on its right, and thus Face a = 0. */ class FEdgeSharp : public FEdge { protected: Vec3r _aNormal; // When following the edge, normal of the right face Vec3r _bNormal; // When following the edge, normal of the left face unsigned _aFrsMaterialIndex; unsigned _bFrsMaterialIndex; bool _aFaceMark; bool _bFaceMark; public: /*! Returns the string "FEdgeSharp" . */ virtual string getExactTypeName() const { return "FEdgeSharp"; } /*! Default constructor. */ inline FEdgeSharp() : FEdge() { _aFrsMaterialIndex = _bFrsMaterialIndex = 0; _aFaceMark = _bFaceMark = false; } /*! Builds an FEdgeSharp going from vA to vB. */ inline FEdgeSharp(SVertex *vA, SVertex *vB) : FEdge(vA, vB) { _aFrsMaterialIndex = _bFrsMaterialIndex = 0; _aFaceMark = _bFaceMark = false; } /*! Copy constructor. */ inline FEdgeSharp(FEdgeSharp& iBrother) : FEdge(iBrother) { _aNormal = iBrother._aNormal; _bNormal = iBrother._bNormal; _aFrsMaterialIndex = iBrother._aFrsMaterialIndex; _bFrsMaterialIndex = iBrother._bFrsMaterialIndex; _aFaceMark = iBrother._aFaceMark; _bFaceMark = iBrother._bFaceMark; } /*! Destructor. */ virtual ~FEdgeSharp() {} /*! Cloning method. */ virtual FEdge *duplicate() { FEdge *clone = new FEdgeSharp(*this); return clone; } /*! Returns the normal to the face lying on the right of the FEdge. If this FEdge is a border, * it has no Face on its right and therefore, no normal. */ inline const Vec3r& normalA() { return _aNormal; } /*! Returns the normal to the face lying on the left of the FEdge. */ inline const Vec3r& normalB() { return _bNormal; } /*! Returns the index of the material of the face lying on the * right of the FEdge. If this FEdge is a border, * it has no Face on its right and therefore, no material. */ inline unsigned aFrsMaterialIndex() const { return _aFrsMaterialIndex; } /*! Returns the material of the face lying on the right of the FEdge. If this FEdge is a border, * it has no Face on its right and therefore, no material. */ const FrsMaterial& aFrsMaterial() const; /*! Returns the index of the material of the face lying on the left of the FEdge. */ inline unsigned bFrsMaterialIndex() const { return _bFrsMaterialIndex; } /*! Returns the material of the face lying on the left of the FEdge. */ const FrsMaterial& bFrsMaterial() const; /*! Returns the face mark of the face lying on the right of the FEdge. * If this FEdge is a border, it has no Face on its right and thus false is returned. */ inline bool aFaceMark() const { return _aFaceMark; } /*! Returns the face mark of the face lying on the left of the FEdge. */ inline bool bFaceMark() const { return _bFaceMark; } /*! Sets the normal to the face lying on the right of the FEdge. */ inline void setNormalA(const Vec3r& iNormal) { _aNormal = iNormal; } /*! Sets the normal to the face lying on the left of the FEdge. */ inline void setNormalB(const Vec3r& iNormal) { _bNormal = iNormal; } /*! Sets the index of the material lying on the right of the FEdge.*/ inline void setaFrsMaterialIndex(unsigned i) { _aFrsMaterialIndex = i; } /*! Sets the index of the material lying on the left of the FEdge.*/ inline void setbFrsMaterialIndex(unsigned i) { _bFrsMaterialIndex = i; } /*! Sets the face mark of the face lying on the right of the FEdge. */ inline void setaFaceMark(bool iFaceMark) { _aFaceMark = iFaceMark; } /*! Sets the face mark of the face lying on the left of the FEdge. */ inline void setbFaceMark(bool iFaceMark) { _bFaceMark = iFaceMark; } #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdgeSharp") #endif }; /*! Class defining a smooth edge. This kind of edge typically runs across a face of the input mesh. It can be * a silhouette, a ridge or valley, a suggestive contour. */ class FEdgeSmooth : public FEdge { protected: Vec3r _Normal; unsigned _FrsMaterialIndex; #if 0 bool _hasVisibilityPoint; Vec3r _VisibilityPointA; // The edge on which the visibility will be computed represented Vec3r _VisibilityPointB; // using its 2 extremity points A and B #endif void *_Face; // In case of exact silhouette, Face is the WFace crossed by Fedge // NOT HANDLED BY THE COPY CONSTRUCTEUR bool _FaceMark; public: /*! Returns the string "FEdgeSmooth" . */ virtual string getExactTypeName() const { return "FEdgeSmooth"; } /*! Default constructor. */ inline FEdgeSmooth() : FEdge() { _Face = NULL; _FaceMark = false; _FrsMaterialIndex = 0; _isSmooth = true; } /*! Builds an FEdgeSmooth going from vA to vB. */ inline FEdgeSmooth(SVertex *vA, SVertex *vB) : FEdge(vA, vB) { _Face = NULL; _FaceMark = false; _FrsMaterialIndex = 0; _isSmooth = true; } /*! Copy constructor. */ inline FEdgeSmooth(FEdgeSmooth& iBrother) : FEdge(iBrother) { _Normal = iBrother._Normal; _Face = iBrother._Face; _FaceMark = iBrother._FaceMark; _FrsMaterialIndex = iBrother._FrsMaterialIndex; _isSmooth = true; } /*! Destructor. */ virtual ~FEdgeSmooth() {} /*! Cloning method. */ virtual FEdge *duplicate() { FEdge *clone = new FEdgeSmooth(*this); return clone; } inline void *face() const { return _Face; } /*! Returns the face mark of the face it is running across. */ inline bool faceMark() const { return _FaceMark; } /*! Returns the normal to the Face it is running accross. */ inline const Vec3r& normal() { return _Normal; } /*! Returns the index of the material of the face it is running accross. */ inline unsigned frs_materialIndex() const { return _FrsMaterialIndex; } /*! Returns the material of the face it is running accross. */ const FrsMaterial& frs_material() const; inline void setFace(void *iFace) { _Face = iFace; } /*! Sets the face mark of the face it is running across. */ inline void setFaceMark(bool iFaceMark) { _FaceMark = iFaceMark; } /*! Sets the normal to the Face it is running accross. */ inline void setNormal(const Vec3r& iNormal) { _Normal = iNormal; } /*! Sets the index of the material of the face it is running accross. */ inline void setFrsMaterialIndex(unsigned i) { _FrsMaterialIndex = i; } #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdgeSmooth") #endif }; /**********************************/ /* */ /* */ /* SShape */ /* */ /* */ /**********************************/ /*! Class to define a feature shape. It is the gathering of feature elements from an identified input shape */ class SShape { private: vector _chains; // list of fedges that are chains starting points. vector _verticesList; // list of all vertices vector _edgesList; // list of all edges Id _Id; string _Name; BBox _BBox; vector _FrsMaterials; float _importance; ViewShape *_ViewShape; public: /*! A field that can be used by the user to store any data. * This field must be reseted afterwards using ResetUserData(). */ void *userdata; // added by E.T. /*! Default constructor */ inline SShape() { userdata = NULL; _importance = 0.0f; _ViewShape = NULL; } /*! Copy constructor */ inline SShape(SShape& iBrother) { userdata = NULL; _Id = iBrother._Id; _Name = iBrother._Name; _BBox = iBrother.bbox(); _FrsMaterials = iBrother._FrsMaterials; _importance = iBrother._importance; _ViewShape = iBrother._ViewShape; //--------- // vertices //--------- vector::iterator sv, svend; vector& verticesList = iBrother.getVertexList(); for (sv = verticesList.begin(), svend = verticesList.end(); sv != svend; sv++) { SVertex *newv = new SVertex(*(*sv)); newv->setShape(this); _verticesList.push_back(newv); } //------ // edges //------ vector::iterator e, eend; vector& edgesList = iBrother.getEdgeList(); for (e = edgesList.begin(), eend = edgesList.end(); e != eend; e++) { FEdge *newe = (*e)->duplicate(); _edgesList.push_back(newe); } //------------------------- // starting chain edges //------------------------- vector::iterator fe, fend; vector& fedges = iBrother.getChains(); for (fe = fedges.begin(), fend = fedges.end(); fe != fend; fe++) { _chains.push_back((FEdge *)((*fe)->userdata)); } //------------------------- // remap edges in vertices: //------------------------- for (sv = _verticesList.begin(), svend = _verticesList.end(); sv != svend; sv++) { const vector& fedgeList = (*sv)->fedges(); vector newfedgelist; for (vector::const_iterator fed = fedgeList.begin(), fedend = fedgeList.end(); fed != fedend; fed++) { FEdge *current = *fed; newfedgelist.push_back((FEdge *)current->userdata); } (*sv)->setFEdges(newfedgelist); } //------------------------------------- // remap vertices and nextedge in edges: //------------------------------------- for (e = _edgesList.begin(), eend = _edgesList.end(); e != eend; e++) { (*e)->setVertexA((SVertex *)((*e)->vertexA()->userdata)); (*e)->setVertexB((SVertex *)((*e)->vertexB()->userdata)); (*e)->setNextEdge((FEdge *)((*e)->nextEdge()->userdata)); (*e)->setPreviousEdge((FEdge *)((*e)->previousEdge()->userdata)); } // reset all brothers userdata to NULL: //------------------------------------- //--------- // vertices //--------- for (sv = _verticesList.begin(), svend = _verticesList.end(); sv != svend; sv++) { (*sv)->userdata = NULL; } //------ // edges //------ for (e = _edgesList.begin(), eend = _edgesList.end(); e != eend; e++) { (*e)->userdata = NULL; } } /*! Cloning method. */ virtual SShape *duplicate() { SShape *clone = new SShape(*this); return clone; } /*! Destructor. */ virtual inline ~SShape() { vector::iterator sv, svend; vector::iterator e, eend; if (0 != _verticesList.size()) { for (sv = _verticesList.begin(), svend = _verticesList.end(); sv != svend; sv++) { delete (*sv); } _verticesList.clear(); } if (0 != _edgesList.size()) { for (e = _edgesList.begin(), eend = _edgesList.end(); e != eend; e++) { delete (*e); } _edgesList.clear(); } //! Clear the chains list //----------------------- if (0 != _chains.size()) { _chains.clear(); } } /*! Adds a FEdge to the list of FEdges. */ inline void AddEdge(FEdge *iEdge) { _edgesList.push_back(iEdge); } /*! Adds a SVertex to the list of SVertex of this Shape. * The SShape attribute of the SVertex is also set to 'this'. */ inline void AddNewVertex(SVertex *iv) { iv->setShape(this); _verticesList.push_back(iv); } inline void AddChain(FEdge *iEdge) { _chains.push_back(iEdge); } inline SVertex *CreateSVertex(const Vec3r& P3D, const Vec3r& P2D, const Id& id) { SVertex *Ia = new SVertex(P3D, id); Ia->setPoint2D(P2D); AddNewVertex(Ia); return Ia; } /*! Splits an edge into several edges. * The edge's vertices are passed rather than the edge itself. This way, all feature edges (SILHOUETTE, * CREASE, BORDER) are splitted in the same time. * The processed edges are flagged as done (using the userdata flag).One single new vertex is created whereas * several splitted edges might created for the different kinds of edges. These new elements are added to the lists * maintained by the shape. * New chains are also created. * ioA * The first vertex for the edge that gets splitted * ioB * The second vertex for the edge that gets splitted * iParameters * A vector containing 2D real vectors indicating the parameters giving the intersections coordinates in * 3D and in 2D. These intersections points must be sorted from B to A. * Each parameter defines the intersection point I as I=A+T*AB. T<0 and T>1 are then incorrect insofar as * they give intersections points that lie outside the segment. * ioNewEdges * The edges that are newly created (the initial edges are not included) are added to this list. */ inline void SplitEdge(FEdge *fe, const vector& iParameters, vector& ioNewEdges) { SVertex *ioA = fe->vertexA(); SVertex *ioB = fe->vertexB(); Vec3r A = ioA->point3D(); Vec3r B = ioB->point3D(); Vec3r a = ioA->point2D(); Vec3r b = ioB->point2D(); Vec3r newpoint3d, newpoint2d; vector intersections; real t, T; for (vector::const_iterator p = iParameters.begin(), pend = iParameters.end(); p != pend; p++) { T = (*p)[0]; t = (*p)[1]; if ((t < 0) || (t > 1)) cerr << "Warning: Intersection out of range for edge " << ioA->getId() << " - " << ioB->getId() << endl; // compute the 3D and 2D coordinates for the intersections points: newpoint3d = Vec3r(A + T * (B - A)); newpoint2d = Vec3r(a + t * (b - a)); // create new SVertex: // (we keep B's id) SVertex *newVertex = new SVertex(newpoint3d, ioB->getId()); newVertex->setPoint2D(newpoint2d); // Add this vertex to the intersections list: intersections.push_back(newVertex); // Add this vertex to this sshape: AddNewVertex(newVertex); } for (vector::iterator sv = intersections.begin(), svend = intersections.end(); sv != svend; sv++) { //SVertex *svA = fe->vertexA(); SVertex *svB = fe->vertexB(); // We split edge AB into AA' and A'B. A' and A'B are created. // AB becomes (address speaking) AA'. B is updated. //-------------------------------------------------- // The edge AB becomes edge AA'. (fe)->setVertexB((*sv)); // a new edge, A'B is created. FEdge *newEdge; if (fe->isSmooth()) { newEdge = new FEdgeSmooth((*sv), svB); FEdgeSmooth *se = dynamic_cast(newEdge); FEdgeSmooth *fes = dynamic_cast(fe); se->setFrsMaterialIndex(fes->frs_materialIndex()); } else { newEdge = new FEdgeSharp((*sv), svB); FEdgeSharp *se = dynamic_cast(newEdge); FEdgeSharp *fes = dynamic_cast(fe); se->setaFrsMaterialIndex(fes->aFrsMaterialIndex()); se->setbFrsMaterialIndex(fes->bFrsMaterialIndex()); } newEdge->setNature((fe)->getNature()); // to build a new chain: AddChain(newEdge); // add the new edge to the sshape edges list. AddEdge(newEdge); // add new edge to the list of new edges passed as argument: ioNewEdges.push_back(newEdge); // update edge A'B for the next pointing edge newEdge->setNextEdge((fe)->nextEdge()); fe->nextEdge()->setPreviousEdge(newEdge); Id id(fe->getId().getFirst(), fe->getId().getSecond() + 1); newEdge->setId(fe->getId()); fe->setId(id); // update edge AA' for the next pointing edge //ioEdge->setNextEdge(newEdge); (fe)->setNextEdge(NULL); // update vertex pointing edges list: // -- vertex B -- svB->Replace((fe), newEdge); // -- vertex A' -- (*sv)->AddFEdge((fe)); (*sv)->AddFEdge(newEdge); } } /* splits an edge into 2 edges. The new vertex and edge are added to the sshape list of vertices and edges * a new chain is also created. * returns the new edge. * ioEdge * The edge that gets splitted * newpoint * x,y,z coordinates of the new point. */ inline FEdge *SplitEdgeIn2(FEdge *ioEdge, SVertex *ioNewVertex) { //soc unused - SVertex *A = ioEdge->vertexA(); SVertex *B = ioEdge->vertexB(); // We split edge AB into AA' and A'B. A' and A'B are created. // AB becomes (address speaking) AA'. B is updated. //-------------------------------------------------- // a new edge, A'B is created. FEdge *newEdge; if (ioEdge->isSmooth()) { newEdge = new FEdgeSmooth(ioNewVertex, B); FEdgeSmooth *se = dynamic_cast(newEdge); FEdgeSmooth *fes = dynamic_cast(ioEdge); se->setNormal(fes->normal()); se->setFrsMaterialIndex(fes->frs_materialIndex()); se->setFaceMark(fes->faceMark()); } else { newEdge = new FEdgeSharp(ioNewVertex, B); FEdgeSharp *se = dynamic_cast(newEdge); FEdgeSharp *fes = dynamic_cast(ioEdge); se->setNormalA(fes->normalA()); se->setNormalB(fes->normalB()); se->setaFrsMaterialIndex(fes->aFrsMaterialIndex()); se->setbFrsMaterialIndex(fes->bFrsMaterialIndex()); se->setaFaceMark(fes->aFaceMark()); se->setbFaceMark(fes->bFaceMark()); } newEdge->setNature(ioEdge->getNature()); if (ioEdge->nextEdge() != 0) ioEdge->nextEdge()->setPreviousEdge(newEdge); // update edge A'B for the next pointing edge newEdge->setNextEdge(ioEdge->nextEdge()); // update edge A'B for the previous pointing edge newEdge->setPreviousEdge(0); // because it is now a TVertex Id id(ioEdge->getId().getFirst(), ioEdge->getId().getSecond() + 1); newEdge->setId(ioEdge->getId()); ioEdge->setId(id); // update edge AA' for the next pointing edge ioEdge->setNextEdge(0); // because it is now a TVertex // update vertex pointing edges list: // -- vertex B -- B->Replace(ioEdge, newEdge); // -- vertex A' -- ioNewVertex->AddFEdge(ioEdge); ioNewVertex->AddFEdge(newEdge); // to build a new chain: AddChain(newEdge); AddEdge(newEdge); // FIXME ?? // The edge AB becomes edge AA'. ioEdge->setVertexB(ioNewVertex); if (ioEdge->isSmooth()) { ((FEdgeSmooth *)newEdge)->setFace(((FEdgeSmooth *)ioEdge)->face()); } return newEdge; } /*! Sets the Bounding Box of the Shape */ inline void setBBox(const BBox& iBBox) { _BBox = iBBox; } /*! Compute the bbox of the sshape */ inline void ComputeBBox() { if (0 == _verticesList.size()) return; Vec3r firstVertex = _verticesList[0]->point3D(); real XMax = firstVertex[0]; real YMax = firstVertex[1]; real ZMax = firstVertex[2]; real XMin = firstVertex[0]; real YMin = firstVertex[1]; real ZMin = firstVertex[2]; vector::iterator v, vend; // parse all the coordinates to find the Xmax, YMax, ZMax for (v = _verticesList.begin(), vend = _verticesList.end(); v != vend; v++) { Vec3r vertex = (*v)->point3D(); // X real x = vertex[0]; if (x > XMax) XMax = x; else if (x < XMin) XMin = x; // Y real y = vertex[1]; if (y > YMax) YMax = y; else if (y < YMin) YMin = y; // Z real z = vertex[2]; if (z > ZMax) ZMax = z; else if (z < ZMin) ZMin = z; } setBBox(BBox(Vec3r(XMin, YMin, ZMin), Vec3r(XMax, YMax, ZMax))); } inline void RemoveEdgeFromChain(FEdge *iEdge) { for (vector::iterator fe = _chains.begin(), feend = _chains.end(); fe != feend; fe++) { if (iEdge == (*fe)) { _chains.erase(fe); break; } } } inline void RemoveEdge(FEdge *iEdge) { for (vector::iterator fe = _edgesList.begin(), feend = _edgesList.end(); fe != feend; fe++) { if (iEdge == (*fe)) { _edgesList.erase(fe); break; } } } /* accessors */ /*! Returns the list of SVertex of the Shape. */ inline vector& getVertexList() { return _verticesList; } /*! Returns the list of FEdges of the Shape. */ inline vector& getEdgeList() { return _edgesList; } inline vector& getChains() { return _chains; } /*! Returns the bounding box of the shape. */ inline const BBox& bbox() { return _BBox; } /*! Returns the ith material of the shape. */ inline const FrsMaterial& frs_material(unsigned i) const { return _FrsMaterials[i]; } /*! Returns the list of materials of the Shape. */ inline const vector& frs_materials() const { return _FrsMaterials; } inline ViewShape *viewShape() { return _ViewShape; } inline float importance() const { return _importance; } /*! Returns the Id of the Shape. */ inline Id getId() const { return _Id; } /*! Returns the name of the Shape. */ inline const string& getName() const { return _Name; } /* Modififers */ /*! Sets the Id of the shape.*/ inline void setId(Id id) { _Id = id; } /*! Sets the name of the shape.*/ inline void setName(const string& name) { _Name = name; } /*! Sets the list of materials for the shape */ inline void setFrsMaterials(const vector& iMaterials) { _FrsMaterials = iMaterials; } inline void setViewShape(ViewShape *iShape) { _ViewShape = iShape; } inline void setImportance(float importance) { _importance = importance; } #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SShape") #endif }; } /* namespace Freestyle */ #endif // __FREESTYLE_SILHOUETTE_H__