Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/freestyle/intern/stroke/Stroke.cpp')
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Stroke.cpp947
1 files changed, 947 insertions, 0 deletions
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
new file mode 100755
index 00000000000..3675a6c0ce2
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -0,0 +1,947 @@
+
+//
+// Copyright (C) : Please refer to the COPYRIGHT file distributed
+// with this source distribution.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "Stroke.h"
+#include "StrokeRenderer.h"
+#include "StrokeIterators.h"
+#include "StrokeAdvancedIterators.h"
+
+ /**********************************/
+ /* */
+ /* */
+ /* StrokeAttribute */
+ /* */
+ /* */
+ /**********************************/
+
+StrokeAttribute::StrokeAttribute()
+{
+ int i;
+ _alpha = 1.f;
+ _thickness[0] = 1.f;
+ _thickness[1] = 1.f;
+ for(i=0; i<3; ++i)
+ _color[i] = 0.2f;
+ _color[0]=0.8;
+ _userAttributesReal = 0;
+ _userAttributesVec2f = 0;
+ _userAttributesVec3f = 0;
+ _visible = true;
+}
+StrokeAttribute::StrokeAttribute(const StrokeAttribute& iBrother)
+{
+ _alpha = iBrother._alpha;
+ _thickness[0] = iBrother._thickness[0];
+ _thickness[1] = iBrother._thickness[1];
+ for(int i=0; i<3; ++i)
+ _color[i] = iBrother._color[i];
+ _visible = iBrother._visible;
+ if(iBrother._userAttributesReal)
+ _userAttributesReal = new realMap(*iBrother._userAttributesReal);
+ else
+ _userAttributesReal = 0;
+ if(iBrother._userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap(*iBrother._userAttributesVec2f);
+ else
+ _userAttributesVec2f = 0;
+ if(iBrother._userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap(*iBrother._userAttributesVec3f);
+ else
+ _userAttributesVec3f = 0;
+}
+StrokeAttribute::StrokeAttribute( float iRColor, float iGColor, float iBColor,
+ float iAlpha,
+ float iRThickness, float iLThickness)
+{
+ _color[0] = iRColor;
+ _color[1] = iGColor;
+ _color[2] = iBColor;
+
+ _alpha = iAlpha;
+
+ _thickness[0] = iRThickness;
+ _thickness[1] = iLThickness;
+
+ _visible = true;
+
+ _userAttributesReal = 0;
+ _userAttributesVec2f = 0;
+ _userAttributesVec3f = 0;
+}
+StrokeAttribute::StrokeAttribute(const StrokeAttribute& a1, const StrokeAttribute& a2, float t)
+
+{
+
+ _alpha = (1-t)*a1._alpha + t*a2._alpha;
+ _thickness[0] = (1-t)*a1._thickness[0] + t*a2._thickness[0];
+ _thickness[1] = (1-t)*a1._thickness[1] + t*a2._thickness[1];
+ for(int i=0; i<3; ++i)
+ _color[i] = (1-t)*a1._color[i] + t*a2._color[i];
+
+ _visible = true;
+
+ // FIXME: a verifier (et a ameliorer)
+ if((a1._userAttributesReal) && (a2._userAttributesReal)){
+ if(a1._userAttributesReal->size() == a2._userAttributesReal->size()){
+ _userAttributesReal = new realMap;
+ realMap::iterator it1=a1._userAttributesReal->begin(), it1end=a1._userAttributesReal->end();
+ realMap::iterator it2=a2._userAttributesReal->begin(), it2end=a2._userAttributesReal->end();
+ for(; (it1!=it1end); ++it1){
+ (*_userAttributesReal)[(*it1).first] = ((1-t)*(*it1).second+t*(*it2).second);
+ }
+ }
+ }else{
+ _userAttributesReal = 0;
+ }
+ if((a1._userAttributesVec2f) && (a2._userAttributesVec2f)){
+ if(a1._userAttributesVec2f->size() == a2._userAttributesVec2f->size()){
+ _userAttributesVec2f = new Vec2fMap;
+ Vec2fMap::iterator it1=a1._userAttributesVec2f->begin(), it1end=a1._userAttributesVec2f->end();
+ Vec2fMap::iterator it2=a2._userAttributesVec2f->begin(), it2end=a2._userAttributesVec2f->end();
+ for(; (it1!=it1end); ++it1){
+ (*_userAttributesVec2f)[(*it1).first] = ((1-t)*(*it1).second+t*(*it2).second);
+ }
+ }
+ }else{
+ _userAttributesVec2f = 0;
+ }
+ if((a1._userAttributesVec3f) && (a2._userAttributesVec3f)){
+ if(a1._userAttributesVec3f->size() == a2._userAttributesVec3f->size()){
+ _userAttributesVec3f = new Vec3fMap;
+ Vec3fMap::iterator it1=a1._userAttributesVec3f->begin(), it1end=a1._userAttributesVec3f->end();
+ Vec3fMap::iterator it2=a2._userAttributesVec3f->begin(), it2end=a2._userAttributesVec3f->end();
+ for(; (it1!=it1end); ++it1){
+ (*_userAttributesVec3f)[(*it1).first] = ((1-t)*(*it1).second+t*(*it2).second);
+ }
+ }
+ }else{
+ _userAttributesVec3f = 0;
+ }
+}
+
+StrokeAttribute::~StrokeAttribute()
+{
+ if(_userAttributesReal){
+ _userAttributesReal->clear();
+ delete _userAttributesReal;
+ }
+ if(_userAttributesVec2f){
+ _userAttributesVec2f->clear();
+ delete _userAttributesVec2f;
+ }
+ if(_userAttributesVec3f){
+ _userAttributesVec3f->clear();
+ delete _userAttributesVec3f;
+ }
+}
+
+StrokeAttribute& StrokeAttribute::operator=(const StrokeAttribute& iBrother)
+{
+ int i;
+ _alpha = iBrother._alpha;
+ _thickness[0] = iBrother._thickness[0];
+ _thickness[1] = iBrother._thickness[1];
+ for(i=0; i<3; ++i)
+ _color[i] = iBrother._color[i];
+ _visible = iBrother._visible;
+ if(iBrother._userAttributesReal){
+ if(!_userAttributesReal)
+ _userAttributesReal = new realMap;
+ _userAttributesReal = new realMap(*(iBrother._userAttributesReal));
+ }else{
+ _userAttributesReal = 0;
+ }
+ if(iBrother._userAttributesVec2f){
+ if(!_userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap;
+ _userAttributesVec2f = new Vec2fMap(*(iBrother._userAttributesVec2f));
+ }else{
+ _userAttributesVec2f = 0;
+ }
+ if(iBrother._userAttributesVec3f){
+ if(!_userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap;
+ _userAttributesVec3f = new Vec3fMap(*(iBrother._userAttributesVec3f));
+ }else{
+ _userAttributesVec3f = 0;
+ }
+ return *this;
+}
+
+float StrokeAttribute::getAttributeReal(const char *iName) const{
+ if(!_userAttributesReal){
+ cout << "StrokeAttribute warning: no real attribute was defined"<< endl;
+ return 0;
+ }
+ realMap::iterator a = _userAttributesReal->find(iName);
+ if(a ==_userAttributesReal->end()){
+ cout << "StrokeAttribute warning: no real attribute was added with the name " << iName << endl;
+ return 0;
+ }
+ return (*a).second;
+}
+Vec2f StrokeAttribute::getAttributeVec2f(const char *iName) const{
+ if(!_userAttributesVec2f){
+ cout << "StrokeAttribute warning: no Vec2f attribute was defined "<< endl;
+ return 0;
+ }
+ Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
+ if(a ==_userAttributesVec2f->end()){
+ cout << "StrokeAttribute warning: no Vec2f attribute was added with the name " << iName << endl;
+ return 0;
+ }
+ return (*a).second;
+}
+Vec3f StrokeAttribute::getAttributeVec3f(const char *iName) const{
+ if(!_userAttributesVec3f){
+ cout << "StrokeAttribute warning: no Vec3f attribute was defined"<< endl;
+ return 0;
+ }
+ Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
+ if(a ==_userAttributesVec3f->end()){
+ cout << "StrokeAttribute warning: no Vec3f attribute was added with the name " << iName << endl;
+ return 0;
+ }
+ return (*a).second;
+}
+bool StrokeAttribute::isAttributeAvailableReal(const char *iName) const{
+ if(!_userAttributesReal){
+ return false;
+ }
+ realMap::iterator a = _userAttributesReal->find(iName);
+ if(a ==_userAttributesReal->end()){
+ return false;
+ }
+ return true;
+}
+bool StrokeAttribute::isAttributeAvailableVec2f(const char *iName) const{
+ if(!_userAttributesVec2f){
+ return false;
+ }
+ Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
+ if(a ==_userAttributesVec2f->end()){
+ return false;
+ }
+ return true;
+}
+bool StrokeAttribute::isAttributeAvailableVec3f(const char *iName) const{
+ if(!_userAttributesVec3f){
+ return false;
+ }
+ Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
+ if(a ==_userAttributesVec3f->end()){
+ return false;
+ }
+ return true;
+}
+void StrokeAttribute::setAttributeReal(const char *iName, float att){
+ if(!_userAttributesReal)
+ _userAttributesReal = new realMap;
+ (*_userAttributesReal)[iName] = att;
+}
+void StrokeAttribute::setAttributeVec2f(const char *iName, const Vec2f& att){
+ if(!_userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap;
+ (*_userAttributesVec2f)[iName] = att;
+}
+void StrokeAttribute::setAttributeVec3f(const char *iName, const Vec3f& att){
+ if(!_userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap;
+ (*_userAttributesVec3f)[iName] = att;
+}
+ /**********************************/
+ /* */
+ /* */
+ /* StrokeVertex */
+ /* */
+ /* */
+ /**********************************/
+
+StrokeVertex::StrokeVertex()
+
+:CurvePoint()
+{
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+}
+
+
+
+StrokeVertex::StrokeVertex(const StrokeVertex& iBrother)
+
+:CurvePoint(iBrother)
+{
+ _Attribute = iBrother._Attribute;
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+}
+StrokeVertex::StrokeVertex(SVertex *iSVertex)
+
+:CurvePoint(iSVertex,0,0.f)
+
+{
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+
+}
+
+
+
+StrokeVertex::StrokeVertex(CurvePoint *iPoint)
+
+:CurvePoint(*iPoint)
+
+{
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+
+}
+
+
+
+StrokeVertex::StrokeVertex(StrokeVertex *iA, StrokeVertex *iB, float t3)
+
+:CurvePoint(iA,iB,t3)
+
+{
+
+ // interpolate attributes:
+
+ _Attribute = StrokeAttribute(iA->attribute(), iB->attribute(), t3);
+ _CurvilignAbscissa = (1-t3)*iA->curvilinearAbscissa()+t3*iB->curvilinearAbscissa();
+ _StrokeLength = iA->strokeLength();
+
+}
+
+
+
+StrokeVertex::StrokeVertex(SVertex *iSVertex, const StrokeAttribute& iAttribute)
+
+:CurvePoint(iSVertex,0,0.f)
+
+{
+
+ _Attribute = iAttribute;
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+
+}
+StrokeVertex::~StrokeVertex()
+{
+}
+
+StrokeVertex& StrokeVertex::operator=(const StrokeVertex& iBrother)
+{
+ ((CurvePoint*)this)->operator=(iBrother);
+ _Attribute = iBrother._Attribute;
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+ return *this;
+}
+
+ /**********************************/
+ /* */
+ /* */
+ /* Stroke */
+ /* */
+ /* */
+ /**********************************/
+
+Stroke::Stroke()
+{
+ _Length = 0;
+ _id = 0;
+ _sampling = FLT_MAX;
+ //_mediumType = DEFAULT_STROKE;
+ _mediumType = OPAQUE_MEDIUM;
+ _textureId = 0;
+ _tips = false;
+ _rep = 0;
+}
+
+Stroke::Stroke(const Stroke& iBrother)
+{
+ for(vertex_container::const_iterator v=iBrother._Vertices.begin(), vend=iBrother._Vertices.end();
+ v!=vend;
+ v++)
+ {
+ _Vertices.push_back(*v);
+ }
+ _Length = 0;
+ _id = iBrother._id;
+ _ViewEdges = iBrother._ViewEdges;
+ _sampling = iBrother._sampling;
+ _mediumType = iBrother._mediumType;
+ _textureId = iBrother._textureId;
+ _tips = iBrother._tips;
+ if(iBrother._rep)
+ _rep = new StrokeRep(*(iBrother._rep));
+ else
+ _rep = 0;
+
+}
+
+Stroke::~Stroke()
+{
+ if(!_Vertices.empty())
+ {
+ for(vertex_container::iterator v=_Vertices.begin(), vend=_Vertices.end();
+ v!=vend;
+ v++)
+ {
+ delete (*v);
+ }
+ _Vertices.clear();
+ }
+
+ _ViewEdges.clear();
+ if(_rep != 0)
+ {
+ delete _rep;
+ _rep = 0;
+ }
+}
+
+Stroke& Stroke::operator=(const Stroke& iBrother)
+{
+ if(!_Vertices.empty())
+ _Vertices.clear();
+
+ for(vertex_container::const_iterator v=iBrother._Vertices.begin(), vend=iBrother._Vertices.end();
+ v!=vend;
+ v++)
+ {
+ _Vertices.push_back(*v);
+ }
+ _Length = iBrother._Length;
+ _id = iBrother._id;
+ _ViewEdges = iBrother._ViewEdges;
+ _sampling = iBrother._sampling;
+ if(_rep) delete _rep;
+ if(iBrother._rep)
+ _rep = new StrokeRep(*(iBrother._rep));
+ return *this;
+}
+
+
+void Stroke::setLength(float iLength)
+{
+ _Length = iLength;
+ for(vertex_container::iterator v=_Vertices.begin(), vend=_Vertices.end();
+ v!=vend;
+ ++v)
+ {
+ (*v)->setStrokeLength(iLength);
+ }
+}
+
+float Stroke::ComputeSampling(int iNVertices)
+{
+ if(iNVertices <= (int)_Vertices.size()) //soc
+ return _sampling;
+
+ float sampling = _Length/(float)(iNVertices-_Vertices.size()+1);
+ return sampling;
+}
+
+class StrokeSegment
+{
+public:
+ StrokeInternal::StrokeVertexIterator _begin;
+ StrokeInternal::StrokeVertexIterator _end;
+ float _length;
+ int _n;
+ float _sampling;
+ bool _resampled;
+
+ StrokeSegment(StrokeInternal::StrokeVertexIterator ibegin,
+ StrokeInternal::StrokeVertexIterator iend,
+ float ilength,
+ int in,
+ float isampling)
+ {
+ _begin=ibegin;
+ _end=iend;
+ _length=ilength;
+ _n=in;
+ _sampling = isampling;
+ _resampled = false;
+ }
+};
+
+void Stroke::Resample(int iNPoints)
+{
+ int vertsize = strokeVerticesSize();
+ if(iNPoints <= vertsize)
+ return;
+
+ StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator next = it;++next;
+ StrokeInternal::StrokeVertexIterator itend = strokeVerticesEnd();
+
+ vertex_container newVertices;
+ real t=0.f;
+ StrokeVertex * newVertex = 0;
+ vector<StrokeSegment> strokeSegments;
+ int N=0;
+ float meanlength = 0;
+ int nsegments = 0;
+ while(((it!=itend)&&(next!=itend)))
+ {
+ Vec3r a((it)->point2d());
+ Vec3r b((next)->point2d());
+ Vec3r vec_tmp(b - a);
+ real norm_var = vec_tmp.norm();
+ int numberOfPointsToAdd = (int)floor((iNPoints-strokeVerticesSize())*norm_var/_Length);
+ float csampling = norm_var/(float)(numberOfPointsToAdd+1);
+ strokeSegments.push_back(StrokeSegment(it,next,norm_var,numberOfPointsToAdd, csampling));
+ N+=numberOfPointsToAdd;
+ meanlength += norm_var;
+ ++nsegments;
+ ++it; ++next;
+ }
+ meanlength /= (float)nsegments;
+
+ // if we don't have enough points let's resample
+ // finer some segments
+ int NPointsToAdd = iNPoints-vertsize;
+ bool checkEveryone = false;
+ while(N < NPointsToAdd)
+ {
+ for(vector<StrokeSegment>::iterator s=strokeSegments.begin(), send=strokeSegments.end();
+ s!=send;
+ ++s)
+ {
+ if(s->_sampling == 0.f)
+ continue;
+
+ if(s->_resampled == false)
+ {
+ if((!checkEveryone) && (s->_length < meanlength))
+ continue;
+ //resample
+ s->_n = s->_n+1;
+ s->_sampling = s->_length/(float)(s->_n+1);
+ s->_resampled = true;
+ N++;
+ if(N == NPointsToAdd)
+ break;
+ }
+ }
+ checkEveryone = true;
+ }
+ //actually resample:
+ for(vector<StrokeSegment>::iterator s=strokeSegments.begin(), send=strokeSegments.end();
+ s!=send;
+ ++s)
+ {
+ newVertices.push_back(&(*(s->_begin)));
+ if(s->_sampling < _sampling)
+ _sampling = s->_sampling;
+
+ t = s->_sampling/s->_length;
+ for(int i=0; i<s->_n; ++i)
+ {
+ newVertex = new StrokeVertex(&(*(s->_begin)),&(*(s->_end)),t);
+ newVertices.push_back(newVertex);
+ t += s->_sampling/s->_length;
+ }
+ it=s->_begin;
+ next=s->_end;
+ }
+
+ // add last:
+ ++it;++next;
+ if((it != itend) && (next == itend))// && (t == 0.f))
+ newVertices.push_back(&(*it));
+
+ int newsize = newVertices.size();
+ if(newsize != iNPoints)
+ cerr << "Warning: incorrect points number" << endl;
+
+ _Vertices.clear();
+ _Vertices = newVertices;
+ newVertices.clear();
+
+ if(_rep)
+ {
+ delete _rep;
+ _rep = new StrokeRep(this);
+ }
+}
+
+
+void Stroke::Resample(float iSampling)
+{
+ // cerr<<"old size :"<<strokeVerticesSize()<<endl;
+ if(iSampling == 0)
+
+ return;
+ if(iSampling >= _sampling)
+ return ;
+
+ _sampling = iSampling;
+ // Resample...
+ //real curvilinearLength = 0.f;
+ vertex_container newVertices;
+ real t=0.f;
+ StrokeVertex * newVertex = 0;
+ StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator next = it;++next;
+ StrokeInternal::StrokeVertexIterator itend = strokeVerticesEnd();
+ while(((it!=itend)&&(next!=itend)))
+ {
+ newVertices.push_back(&(*it));
+ Vec3r a((it)->point2d());
+ Vec3r b((next)->point2d());
+ Vec3r vec_tmp(b - a);
+ real norm_var = vec_tmp.norm();
+ if(norm_var <= _sampling)
+ {
+ //curvilinearLength += norm_var;
+ ++it; ++next;
+ continue;
+ }
+
+ //curvilinearLength += _sampling;
+ t = _sampling/norm_var;
+ float limit = 0.99f;
+ while(t<limit)
+ {
+ newVertex = new StrokeVertex(&(*it),&(*next),t);
+ //newVertex->setCurvilinearAbscissa(curvilinearLength);
+ newVertices.push_back(newVertex);
+ t = t + _sampling/norm_var;
+ }
+ ++it; ++next;
+ }
+ // add last:
+ if((it != itend) && (next == itend))// && (t == 0.f))
+ newVertices.push_back(&(*it));
+
+ _Vertices.clear();
+ _Vertices = newVertices;
+ newVertices.clear();
+
+ if(_rep)
+ {
+ delete _rep;
+ _rep = new StrokeRep(this);
+ }
+}
+
+void Stroke::RemoveVertex(StrokeVertex *iVertex)
+{
+ vertex_container::iterator it=_Vertices.begin(), itend=_Vertices.end();
+ for(;
+ it!=itend;
+ ++it)
+ {
+ if((*it) == iVertex)
+ {
+ delete iVertex;
+ it = _Vertices.erase(it); // it is now the element just after the erased element
+ break;
+ }
+ }
+ UpdateLength();
+}
+
+void Stroke::InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next)
+{
+ vertex_container::iterator it=_Vertices.begin(), itend=_Vertices.end();
+
+ vertex_container::iterator itnext = next.getIt();
+ _Vertices.insert(itnext, iVertex);
+ UpdateLength();
+}
+
+void Stroke::UpdateLength()
+{
+ // recompute various values (length, curvilign abscissa)
+ float curvabsc = 0.f;
+ vertex_container::iterator it=_Vertices.begin(), itend=_Vertices.end();
+ vertex_container::iterator previous=it;
+ for(;
+ (it!=itend);
+ ++it)
+ {
+ curvabsc += ((*it)->point2d()-(*previous)->point2d()).norm();
+ (*it)->setCurvilinearAbscissa(curvabsc);
+ previous = it;
+ }
+ _Length = curvabsc;
+ for(;
+ (it!=itend);
+ ++it)
+ {
+ (*it)->setStrokeLength(_Length);
+ }
+}
+
+//! embedding vertex iterator
+Stroke::const_vertex_iterator Stroke::vertices_begin() const { return const_vertex_iterator(_Vertices.begin(),_Vertices.begin(), _Vertices.end()); }
+Stroke::const_vertex_iterator Stroke::vertices_end() const { return const_vertex_iterator(_Vertices.end(),_Vertices.begin(), _Vertices.end()); }
+Stroke::vertex_iterator Stroke::vertices_end() { return vertex_iterator(_Vertices.end(),_Vertices.begin(), _Vertices.end()); }
+
+StrokeInternal::StrokeVertexIterator Stroke::strokeVerticesBegin(float t) {
+ if((t!=0) && (t < _sampling))
+ Resample(t);
+ return StrokeInternal::StrokeVertexIterator(this->_Vertices.begin(), this->_Vertices.begin(), this->_Vertices.end());
+}
+
+StrokeInternal::StrokeVertexIterator Stroke::strokeVerticesEnd() {
+ return StrokeInternal::StrokeVertexIterator(this->_Vertices.end(), this->_Vertices.begin(), this->_Vertices.end());
+}
+
+Interface0DIterator Stroke::verticesBegin() {
+ Interface0DIterator ret(new StrokeInternal::StrokeVertexIterator(this->_Vertices.begin(),
+ this->_Vertices.begin(),
+ this->_Vertices.end()));
+ return ret;
+}
+
+Interface0DIterator Stroke::verticesEnd() {
+ Interface0DIterator ret(new StrokeInternal::StrokeVertexIterator(this->_Vertices.end(),
+ this->_Vertices.begin(),
+ this->_Vertices.end()));
+ return ret;
+}
+
+Interface0DIterator Stroke::pointsBegin(float t) {
+ return verticesBegin(); // FIXME
+}
+
+Interface0DIterator Stroke::pointsEnd(float t) {
+ return verticesEnd();
+}
+
+void Stroke::ScaleThickness(float iFactor)
+{
+ for(vertex_container::iterator it=_Vertices.begin(), itend=_Vertices.end();
+ it!=itend;
+ ++it)
+ {
+ StrokeAttribute& attr = (*it)->attribute();
+ attr.setThickness(iFactor * attr.getThicknessR(), iFactor * attr.getThicknessL());
+ }
+}
+
+void Stroke::Render(const StrokeRenderer *iRenderer)
+{
+ if(!_rep)
+ _rep = new StrokeRep(this);
+ iRenderer->RenderStrokeRep(_rep);
+}
+
+void Stroke::RenderBasic(const StrokeRenderer *iRenderer)
+{
+ if(!_rep)
+ _rep = new StrokeRep(this);
+ iRenderer->RenderStrokeRepBasic(_rep);
+}
+
+Stroke::vertex_iterator Stroke::vertices_begin(float sampling)
+{
+ // Resample if necessary
+ if((sampling != 0) && (sampling < _sampling))
+ Resample(sampling);
+ return vertex_iterator(_Vertices.begin(),_Vertices.begin(),_Vertices.end());
+ //return _Vertices.begin();
+}
+//
+//Stroke::vertex_iterator Stroke::vertices_last()
+//{
+// vertex_iterator res = vertices_begin();
+// vertex_iterator next = res;++next;
+// while(!next.end())
+// {
+// ++next;
+// ++res;
+// }
+// return res;
+//}
+//
+//Stroke::const_vertex_iterator Stroke::vertices_last() const
+//{
+// const_vertex_iterator res = vertices_begin();
+// const_vertex_iterator next = res;++next;
+// while(!next.end())
+// {
+// ++next;
+// ++res;
+// }
+// return res;
+//}
+
+//Stroke::vertex_container::reverse_iterator Stroke::vertices_last(float sampling)
+//{
+// // Resample if necessary
+// if(sampling < _sampling)
+// Resample(sampling);
+// return _Vertices.rbegin();
+//}
+
+
+//inline Vec3r shaded_color(int iCombination = 0) const ;
+//inline Vec<3,real> Stroke::orientation2d(const_vertex_iterator it) const
+//{
+// return iterator_edge_orientation2d_function<Stroke, const_vertex_iterator>(this, it);
+//}
+// Vec3r Stroke::orientation2d(int iCombination) const
+// {
+// return edge_orientation2d_function<Stroke>(*this, iCombination);
+// }
+//inline Vec3r Stroke::orientation3d(const_vertex_iterator it) const
+//{
+// return iterator_edge_orientation3d_function<Stroke, const_vertex_iterator>(*this, it);
+//}
+// Vec3r Stroke::orientation3d(int iCombination) const
+// {
+// return edge_orientation3d_function<Stroke>(*this, iCombination);
+// }
+
+//Material Stroke::material() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=strokeVerticesEnd();
+// Material mat = (*v)->material();
+// for(;v!=vend;++v)
+// {
+// if(mat != (*v)->material())
+// Exception::raiseException();
+// }
+// return mat;
+//}
+
+//int Stroke::qi() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// int qi_= (*v)->qi();
+// for(;v!=vend;++v)
+// {
+// if((*v)->qi() != qi_)
+// Exception::raiseException();
+// }
+// return qi_;
+//}
+//inline occluder_container::const_iterator occluders_begin() const {return _FEdgeA->occluders().begin();}
+//inline occluder_container::const_iterator occluders_end() const {return _FEdgeA->occluders().end();}
+
+//int Stroke::occluders_size() const
+//{
+// return qi();
+//}
+//
+//bool Stroke::occluders_empty() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// bool empty = (*v)->occluders_empty();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occluders_empty() != empty)
+// Exception::raiseException();
+// }
+// return empty;
+//}
+////inline const polygon3d& occludee() const {return *(_FEdgeA->aFace());}
+//const SShape * Stroke::occluded_shape() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// const SShape *sshape = (*v)->occluded_shape();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occluded_shape() != sshape)
+// Exception::raiseException();
+// }
+// return sshape;
+//}
+//
+//const bool Stroke::occludee_empty() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// bool empty = (*v)->occludee_empty();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occludee_empty() != empty)
+// Exception::raiseException();
+// }
+// return empty;
+//}
+
+//const SShape * Stroke::shape() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// const SShape *sshape = (*v)->shape();
+// for(;v!=vend;++v)
+// {
+// if((*v)->shape() != sshape)
+// Exception::raiseException();
+// }
+// return sshape;
+//}
+
+// real Stroke::z_discontinuity(int iCombination) const
+// {
+// return z_discontinuity_edge_function<Stroke>(*this, iCombination);
+// }
+
+// Vec3r Stroke::curvature2d_as_vector(int iCombination) const
+// {
+// return curvature2d_as_vector_edge_function<Stroke>(*this, iCombination);
+// }
+
+// real Stroke::curvature2d_as_angle(int iCombination) const
+// {
+// return curvature2d_as_angle_edge_function<Stroke>(*this, iCombination);
+// }
+
+// float Stroke::shape_importance(int iCombination) const
+// {
+// return shape_importance_edge_function<Stroke>(*this, iCombination);
+// }
+
+
+// float Stroke::local_average_depth(int iCombination ) const
+// {
+// return local_average_depth_edge_function<Stroke >(*this, iCombination);
+// }
+
+// float Stroke::local_depth_variance(int iCombination) const
+// {
+// return local_depth_variance_edge_function<Stroke>(*this, iCombination);
+// }
+
+// real Stroke::local_average_density(float sigma , int iCombination ) const
+// {
+// return density_edge_function<Stroke>(*this, iCombination);
+// }