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')
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.cpp954
1 files changed, 954 insertions, 0 deletions
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
new file mode 100644
index 00000000000..7e6aa62ac59
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -0,0 +1,954 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/Stroke.cpp
+ * \ingroup freestyle
+ * \brief Classes to define a stroke
+ * \author Stephane Grabli
+ * \date 09/09/2002
+ */
+
+#include "Stroke.h"
+#include "StrokeAdvancedIterators.h"
+#include "StrokeIterators.h"
+#include "StrokeRenderer.h"
+
+#include "BKE_global.h"
+
+/**********************************/
+/* */
+/* */
+/* StrokeAttribute */
+/* */
+/* */
+/**********************************/
+
+StrokeAttribute::StrokeAttribute()
+{
+ int i;
+ _alpha = 1.0f;
+ _thickness[0] = 1.0f;
+ _thickness[1] = 1.0f;
+ for (i = 0; i < 3; ++i)
+ _color[i] = 0.2f;
+ _color[0] = 0.8f;
+ _userAttributesReal = NULL;
+ _userAttributesVec2f = NULL;
+ _userAttributesVec3f = NULL;
+ _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 = NULL;
+ if (iBrother._userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap(*iBrother._userAttributesVec2f);
+ else
+ _userAttributesVec2f = NULL;
+ if (iBrother._userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap(*iBrother._userAttributesVec3f);
+ else
+ _userAttributesVec3f = NULL;
+}
+
+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 = NULL;
+ _userAttributesVec2f = NULL;
+ _userAttributesVec3f = NULL;
+}
+
+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: to be checked (and enhanced)
+ 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 = NULL;
+ }
+ 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 = NULL;
+ }
+ 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 = NULL;
+ }
+}
+
+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 = NULL;
+ }
+ if (iBrother._userAttributesVec2f) {
+ if (!_userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap;
+ _userAttributesVec2f = new Vec2fMap(*(iBrother._userAttributesVec2f));
+ }
+ else {
+ _userAttributesVec2f = NULL;
+ }
+ if (iBrother._userAttributesVec3f) {
+ if (!_userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap;
+ _userAttributesVec3f = new Vec3fMap(*(iBrother._userAttributesVec3f));
+ }
+ else {
+ _userAttributesVec3f = NULL;
+ }
+ return *this;
+}
+
+float StrokeAttribute::getAttributeReal(const char *iName) const
+{
+ if (!_userAttributesReal) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no real attribute was defined" << endl;
+ }
+ return 0.0f;
+ }
+ realMap::iterator a = _userAttributesReal->find(iName);
+ if (a == _userAttributesReal->end()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no real attribute was added with the name " << iName << endl;
+ }
+ return 0.0f;
+ }
+ return (*a).second;
+}
+
+Vec2f StrokeAttribute::getAttributeVec2f(const char *iName) const
+{
+ if (!_userAttributesVec2f) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no Vec2f attribute was defined" << endl;
+ }
+ return 0;
+ }
+ Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
+ if (a == _userAttributesVec2f->end()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ 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) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no Vec3f attribute was defined" << endl;
+ }
+ return 0;
+ }
+ Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
+ if (a == _userAttributesVec3f->end()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ 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.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::StrokeVertex(const StrokeVertex& iBrother) : CurvePoint(iBrother)
+{
+ _Attribute = iBrother._Attribute;
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::StrokeVertex(SVertex *iSVertex) : CurvePoint(iSVertex, 0, 0.0f)
+{
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::StrokeVertex(CurvePoint *iPoint) : CurvePoint(*iPoint)
+{
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+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.0f)
+{
+ _Attribute = iAttribute;
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::~StrokeVertex() {}
+
+StrokeVertex& StrokeVertex::operator=(const StrokeVertex& iBrother)
+{
+ ((CurvePoint*)this)->operator=(iBrother);
+ _Attribute = iBrother._Attribute;
+
+ _CurvilignAbscissa = 0.0f;
+
+ _StrokeLength = 0.0f;
+ return *this;
+}
+
+
+
+/**********************************/
+/* */
+/* */
+/* Stroke */
+/* */
+/* */
+/**********************************/
+
+Stroke::Stroke()
+{
+ _Length = 0;
+ _id = 0;
+ _sampling = FLT_MAX;
+ //_mediumType = DEFAULT_STROKE;
+ _mediumType = OPAQUE_MEDIUM;
+ _textureId = 0;
+ _tips = false;
+ _rep = NULL;
+}
+
+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 = NULL;
+}
+
+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) {
+ delete _rep;
+ _rep = NULL;
+ }
+}
+
+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.0f;
+ StrokeVertex *newVertex = NULL;
+ vector<StrokeSegment> strokeSegments;
+ int N = 0;
+ float meanlength = 0;
+ int nsegments = 0;
+ while ((it != itend) && (next != itend)) {
+ Vec2r a((it)->getPoint());
+ Vec2r b((next)->getPoint());
+ Vec2r 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.0f)
+ 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.0f)*/)
+ 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.0f;
+ vertex_container newVertices;
+ real t = 0.0f;
+ const real limit = 0.99;
+ StrokeVertex *newVertex = NULL;
+ StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator next = it;
+ ++next;
+ StrokeInternal::StrokeVertexIterator itend = strokeVerticesEnd();
+ while ((it != itend) && (next != itend)) {
+ newVertices.push_back(&(*it));
+ Vec2r a((it)->getPoint());
+ Vec2r b((next)->getPoint());
+ Vec2r 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;
+ 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 curvilinear abscissa and stroke length
+ float curvabsc = 0.0f;
+ vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end();
+ vertex_container::iterator previous = it;
+ for (; it != itend; ++it) {
+ curvabsc += ((*it)->getPoint() - (*previous)->getPoint()).norm();
+ (*it)->setCurvilinearAbscissa(curvabsc);
+ previous = it;
+ }
+ _Length = curvabsc;
+ for (it = _Vertices.begin(); 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();
+}
+
+#if 0
+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;
+}
+
+#if 0
+inline const polygon3d& occludee() const
+{
+ return *(_FEdgeA->aFace());
+}
+#endif
+
+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);
+}
+#endif