/*
 * ***** 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 <float.h>
#include <iostream>
#include <set>
#include <string>
#include <vector>

#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<ViewShape*> 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<FEdge*> fedges_container;

private:
	Id _Id;
	Vec3r _Point3D;
	Vec3r _Point2D;
	set<Vec3r> _Normals; 
	vector<FEdge*> _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<Vec3r> normals()
	{
		return _Normals;
	}

	/*! Returns the number of different normals for this vertex. */
	inline unsigned normalsSize() const
	{
		return _Normals.size();
	}

	inline const vector<FEdge*>& 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<FEdge*>& 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<FEdge *>::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<FEdge *>::iterator insertedfe;
		for (vector<FEdge *>::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<Polygon3r> _Occludees;
	//  Vec3r intersection;
	//  vector<Vec3i> _Cells;

protected:
	SVertex *_VertexA;
	SVertex *_VertexB;
	Id _Id;
	Nature::EdgeNature _Nature;
	//vector<Polygon3r> _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<Polygon3r>& 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<const SVertexIterator*>(&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<FEdge*> _chains;          // list of fedges that are chains starting points.
	vector<SVertex*> _verticesList;  // list of all vertices
	vector<FEdge*> _edgesList;       // list of all edges
	Id _Id;
	const char *_Name;
	const char *_LibraryPath;
	BBox<Vec3r> _BBox;
	vector<FrsMaterial> _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;
		_Name = NULL;
		_LibraryPath = NULL;
	}

	/*! Copy constructor */
	inline SShape(SShape& iBrother)
	{
		userdata = NULL;
		_Id = iBrother._Id;
		_Name = iBrother._Name;
		_LibraryPath = iBrother._LibraryPath;
		_BBox = iBrother.bbox();
		_FrsMaterials = iBrother._FrsMaterials;
		_importance = iBrother._importance;
		_ViewShape = iBrother._ViewShape;

		//---------
		// vertices
		//---------
		vector<SVertex*>::iterator sv, svend;
		vector<SVertex*>& 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<FEdge*>::iterator e, eend;
		vector<FEdge*>& 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<FEdge*>::iterator fe, fend;
		vector<FEdge*>& 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<FEdge*>& fedgeList = (*sv)->fedges();
			vector<FEdge*> newfedgelist;
			for (vector<FEdge*>::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<SVertex*>::iterator sv, svend;
		vector<FEdge*>::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<Vec2r>& iParameters, vector<FEdge*>& 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<SVertex*> intersections;
		real t, T;
		for (vector<Vec2r>::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<SVertex*>::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<FEdgeSmooth*>(newEdge);
				FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
				se->setFrsMaterialIndex(fes->frs_materialIndex());
			}
			else {
				newEdge = new FEdgeSharp((*sv), svB);
				FEdgeSharp *se = dynamic_cast<FEdgeSharp*>(newEdge);
				FEdgeSharp *fes = dynamic_cast<FEdgeSharp*>(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<FEdgeSmooth*>(newEdge);
			FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(ioEdge);
			se->setNormal(fes->normal());
			se->setFrsMaterialIndex(fes->frs_materialIndex());
			se->setFaceMark(fes->faceMark());
		}
		else {
			newEdge = new FEdgeSharp(ioNewVertex, B);
			FEdgeSharp *se = dynamic_cast<FEdgeSharp*>(newEdge);
			FEdgeSharp *fes = dynamic_cast<FEdgeSharp*>(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<Vec3r>& 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<SVertex*>::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>(Vec3r(XMin, YMin, ZMin), Vec3r(XMax, YMax, ZMax)));
	}

	inline void RemoveEdgeFromChain(FEdge *iEdge)
	{
		for (vector<FEdge*>::iterator fe = _chains.begin(), feend = _chains.end(); fe != feend; fe++) {
			if (iEdge == (*fe)) {
				_chains.erase(fe);
				break;
			}
		}
	}

	inline void RemoveEdge(FEdge *iEdge)
	{
		for (vector<FEdge*>::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<SVertex*>& getVertexList()
	{
		return _verticesList;
	}

	/*! Returns the list of FEdges of the Shape. */
	inline vector<FEdge*>& getEdgeList()
	{
		return _edgesList;
	}

	inline vector<FEdge*>& getChains()
	{
		return _chains;
	}

	/*! Returns the bounding box of the shape. */
	inline const BBox<Vec3r>& 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<FrsMaterial>& 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 char *getName() const
	{
		return _Name;
	}

	/*! Returns the library path of the Shape. */
	inline const char *getLibraryPath() const
	{
		return _LibraryPath;
	}

	/* Modififers */
	/*! Sets the Id of the shape.*/
	inline void setId(Id id)
	{
		_Id = id;
	}

	/*! Sets the name of the shape.*/
	inline void setName(const char *name)
	{
		_Name = name;
	}

	/*! Sets the library path of the shape.*/
	inline void setLibraryPath(const char *path)
	{
		_LibraryPath = path;
	}

	/*! Sets the list of materials for the shape */
	inline void setFrsMaterials(const vector<FrsMaterial>& 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__
