1933 lines
44 KiB
C++
1933 lines
44 KiB
C++
/*
|
|
* ***** 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;
|
|
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;
|
|
}
|
|
|
|
/*! 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<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;
|
|
}
|
|
|
|
/* 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 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__
|