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/BasicStrokeShaders.cpp')
-rw-r--r--source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp2128
1 files changed, 1033 insertions, 1095 deletions
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
index eea6da40c9f..852a36571d4 100644
--- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
@@ -1,1170 +1,1108 @@
+/*
+ * ***** 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/BasicStrokeShaders.cpp
+ * \ingroup freestyle
+ * \brief Class gathering basic stroke shaders
+ * \author Stephane Grabli
+ * \date 17/12/2002
+ */
-//
-// 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 "StrokeRenderer.h"
#include <fstream>
+
+#include "AdvancedFunctions0D.h"
+#include "AdvancedFunctions1D.h"
#include "BasicStrokeShaders.h"
+#include "StrokeIO.h"
+#include "StrokeIterators.h"
+#include "StrokeRenderer.h"
+
#include "../system/PseudoNoise.h"
#include "../system/RandGen.h"
+#include "../system/StringUtils.h"
+
#include "../view_map/Functions0D.h"
#include "../view_map/Functions1D.h"
-#include "AdvancedFunctions0D.h"
-#include "AdvancedFunctions1D.h"
-#include "StrokeIterators.h"
-#include "../system/StringUtils.h"
-#include "StrokeIO.h"
//soc #include <qimage.h>
//soc #include <QString>
+
extern "C" {
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
+# include "IMB_imbuf.h"
+# include "IMB_imbuf_types.h"
}
// Internal function
-// soc
-// void convert(const QImage& iImage, float **oArray, unsigned &oSize) {
-// oSize = iImage.width();
-// *oArray = new float[oSize];
-// for(unsigned i=0; i<oSize; ++i) {
-// QRgb rgb = iImage.pixel(i,0);
-// (*oArray)[i] = ((float)qBlue(rgb))/255.f;
-// }
-// }
-static void convert(ImBuf *imBuf, float **oArray, unsigned &oSize) {
+#if 0 // soc
+void convert(const QImage& iImage, float **oArray, unsigned &oSize)
+{
+ oSize = iImage.width();
+ *oArray = new float[oSize];
+ for (unsigned int i = 0; i < oSize; ++i) {
+ QRgb rgb = iImage.pixel(i,0);
+ (*oArray)[i] = ((float)qBlue(rgb)) / 255.0f;
+ }
+}
+#endif
+
+static void convert(ImBuf *imBuf, float **oArray, unsigned &oSize)
+{
oSize = imBuf->x;
- *oArray = new float[oSize];
+ *oArray = new float[oSize];
char *pix;
- for(unsigned i=0; i < oSize; ++i) {
- pix = (char*) imBuf->rect + i*4;
- (*oArray)[i] = ((float) pix[2] )/255.f;
- }
+ for (unsigned int i = 0; i < oSize; ++i) {
+ pix = (char*) imBuf->rect + i * 4;
+ (*oArray)[i] = ((float) pix[2]) / 255.0f;
+ }
}
namespace StrokeShaders {
- //
- // Thickness modifiers
- //
- //////////////////////////////////////////////////////////
-
- int ConstantThicknessShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v, vend;
- int i=0;
- int size = stroke.strokeVerticesSize();
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
- ++v)
- {
- if((1 == i) || (size-2 == i))
- v->attribute().setThickness(_thickness/4.0,_thickness/4.0);
- if((0 == i) || (size-1 == i))
- v->attribute().setThickness(0,0);
-
- v->attribute().setThickness(_thickness/2.0, _thickness/2.0);
- }
+//
+// Thickness modifiers
+//
+//////////////////////////////////////////////////////////
+
+int ConstantThicknessShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ int size = stroke.strokeVerticesSize();
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop?
+ if ((1 == i) || (size - 2 == i))
+ v->attribute().setThickness(_thickness / 4.0, _thickness / 4.0);
+ if ((0 == i) || (size - 1 == i))
+ v->attribute().setThickness(0, 0);
+
+ v->attribute().setThickness(_thickness / 2.0, _thickness / 2.0);
+ }
return 0;
- }
-
- int ConstantExternThicknessShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v, vend;
- int i=0;
- int size = stroke.strokeVerticesSize();
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
- ++v)
- {
- if((1 == i) || (size-2 == i))
- v->attribute().setThickness(_thickness/2.0,0);
- if((0 == i) || (size-1 == i))
- v->attribute().setThickness(0,0);
-
- v->attribute().setThickness(_thickness, 0);
- }
+}
+
+int ConstantExternThicknessShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ int size = stroke.strokeVerticesSize();
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop?
+ if ((1 == i) || (size - 2 == i))
+ v->attribute().setThickness(_thickness / 2.0, 0);
+ if ((0 == i) || (size - 1 == i))
+ v->attribute().setThickness(0, 0);
+
+ v->attribute().setThickness(_thickness, 0);
+ }
return 0;
- }
-
- int IncreasingThicknessShader::shade(Stroke& stroke) const
- {
-
- int n=stroke.strokeVerticesSize()-1;
- StrokeInternal::StrokeVertexIterator v, vend;
- int i=0;
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
-
- ++v)
- {
- float t;
- if(i < (float)n/2.f)
- t = (1.0-(float)i/(float)n)*_ThicknessMin + (float)i/(float)n*_ThicknessMax;
- else
- t = (1.0-(float)i/(float)n)*_ThicknessMax + (float)i/(float)n*_ThicknessMin;
- v->attribute().setThickness(t/2.0, t/2.0);
- ++i;
- }
+}
+
+int IncreasingThicknessShader::shade(Stroke& stroke) const
+{
+ int n = stroke.strokeVerticesSize() - 1, i;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ v != vend;
+ ++v, ++i)
+ {
+ float t;
+ if (i < (float)n / 2.0f)
+ t = (1.0 - (float)i / (float)n) * _ThicknessMin + (float)i / (float)n * _ThicknessMax;
+ else
+ t = (1.0 - (float)i / (float)n) * _ThicknessMax + (float)i / (float)n * _ThicknessMin;
+ v->attribute().setThickness(t / 2.0, t / 2.0);
+ }
return 0;
- }
-
- int ConstrainedIncreasingThicknessShader::shade(Stroke& stroke) const
- {
- float slength = stroke.getLength2D();
- float maxT = min(_ratio*slength,_ThicknessMax);
- int n=stroke.strokeVerticesSize()-1;
- StrokeInternal::StrokeVertexIterator v, vend;
- int i=0;
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
-
- ++v)
- {
- float t;
- if(i < (float)n/2.f)
- t = (1.0-(float)i/(float)n)*_ThicknessMin + (float)i/(float)n*maxT;
- else
- t = (1.0-(float)i/(float)n)*maxT + (float)i/(float)n*_ThicknessMin;
- v->attribute().setThickness(t/2.0, t/2.0);
- if(i == n-1)
- v->attribute().setThickness(_ThicknessMin/2.0, _ThicknessMin/2.0);
- ++i;
- }
+}
+
+int ConstrainedIncreasingThicknessShader::shade(Stroke& stroke) const
+{
+ float slength = stroke.getLength2D();
+ float maxT = min(_ratio*slength,_ThicknessMax);
+ int n = stroke.strokeVerticesSize() - 1, i;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ v != vend;
+ ++v, ++i)
+ {
+ // XXX Why not using an if/else here? Else, if last condition is true, everything else is computed for nothing!
+ float t;
+ if (i < (float)n / 2.0f)
+ t = (1.0 - (float)i / (float)n) * _ThicknessMin + (float)i / (float)n * maxT;
+ else
+ t = (1.0 - (float)i / (float)n) * maxT + (float)i / (float)n * _ThicknessMin;
+ v->attribute().setThickness(t / 2.0, t / 2.0);
+ if (i == n - 1)
+ v->attribute().setThickness(_ThicknessMin / 2.0, _ThicknessMin / 2.0);
+ }
return 0;
- }
-
-
- int LengthDependingThicknessShader::shade(Stroke& stroke) const
- {
- float step = (_maxThickness-_minThickness)/3.f;
- float l = stroke.getLength2D();
- float thickness = 0.0;
- if(l>300.f)
- thickness = _minThickness+3.f*step;
- else if((l< 300.f) && (l>100.f))
- thickness = _minThickness+2.f*step;
- else if((l<100.f) && (l>50.f))
- thickness = _minThickness+1.f*step;
- else if(l< 50.f)
- thickness = _minThickness;
-
- StrokeInternal::StrokeVertexIterator v, vend;
- int i=0;
- int size = stroke.strokeVerticesSize();
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
- ++v)
- {
- if((1 == i) || (size-2 == i))
- v->attribute().setThickness(thickness/4.0,thickness/4.0);
- if((0 == i) || (size-1 == i))
- v->attribute().setThickness(0,0);
-
- v->attribute().setThickness(thickness/2.0, thickness/2.0);
- }
+}
+
+
+int LengthDependingThicknessShader::shade(Stroke& stroke) const
+{
+ float step = (_maxThickness - _minThickness) / 3.0f;
+ float l = stroke.getLength2D();
+ float thickness = 0.0f;
+ if (l > 300.0f)
+ thickness = _minThickness + 3.0f * step;
+ else if ((l < 300.0f) && (l > 100.0f))
+ thickness = _minThickness + 2.0f * step;
+ else if ((l < 100.0f) && (l > 50.0f))
+ thickness = _minThickness + 1.0f * step;
+ else // else if (l < 50.0f), tsst...
+ thickness = _minThickness;
+
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ int size = stroke.strokeVerticesSize();
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop?
+ if ((1 == i) || (size - 2 == i))
+ v->attribute().setThickness(thickness / 4.0, thickness / 4.0);
+ if ((0 == i) || (size - 1 == i))
+ v->attribute().setThickness(0, 0);
+
+ v->attribute().setThickness(thickness / 2.0, thickness / 2.0);
+ }
return 0;
- }
-
-
- ThicknessVariationPatternShader::ThicknessVariationPatternShader(const string pattern_name,
- float iMinThickness,
- float iMaxThickness,
- bool stretch)
- : StrokeShader() {
- _stretch = stretch;
- _minThickness = iMinThickness;
- _maxThickness = iMaxThickness;
- ImBuf *image = 0; //soc
- vector<string> pathnames;
- StringUtils::getPathName(TextureManager::Options::getPatternsPath(),
- pattern_name,
- pathnames);
- for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); j++) {
- ifstream ifs(j->c_str());
- if (ifs.is_open()) {
- //soc image.load(j->c_str());
- /* OCIO_TODO: support different input color space */
- image = IMB_loadiffname(j->c_str(), 0, NULL);
- break;
- }
- }
- if (image == 0) //soc
- cerr << "Error: cannot find pattern \"" << pattern_name
- << "\" - check the path in the Options" << endl;
- else
- convert(image, &_aThickness, _size);
- }
-
- int ThicknessVariationPatternShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v, vend;
- float *array = 0;
- int size;
- array = _aThickness;
- size = _size;
- // }
- int vert_size = stroke.strokeVerticesSize();
- int sig = 0;
- unsigned index;
- const float* originalThickness;
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
- ++v)
- {
- originalThickness = v->attribute().getThickness();
- if (_stretch) {
- float tmp = v->u()*(_size-1);
- index = (unsigned)floor(tmp);
- if((tmp-index) > (index+1-tmp))
- ++index;
+}
+
+
+ThicknessVariationPatternShader::ThicknessVariationPatternShader(const string pattern_name, float iMinThickness,
+ float iMaxThickness, bool stretch)
+: StrokeShader()
+{
+ _stretch = stretch;
+ _minThickness = iMinThickness;
+ _maxThickness = iMaxThickness;
+ ImBuf *image = NULL; //soc
+ vector<string> pathnames;
+ StringUtils::getPathName(TextureManager::Options::getPatternsPath(), pattern_name, pathnames);
+ for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); ++j) {
+ ifstream ifs(j->c_str());
+ if (ifs.is_open()) {
+ //soc image.load(j->c_str());
+ /* OCIO_TODO: support different input color space */
+ image = IMB_loadiffname(j->c_str(), 0, NULL);
+ break;
+ }
}
+ if (image == NULL) //soc
+ cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl;
else
- index = (unsigned)floor(v->curvilinearAbscissa());
- index %= _size;
- float thicknessR = array[index]*originalThickness[0];
- float thicknessL = array[index]*originalThickness[1];
- if(thicknessR+thicknessL < _minThickness)
- {
- thicknessL = _minThickness/2.f;
- thicknessR = _minThickness/2.f;
- }
- if(thicknessR+thicknessL > _maxThickness)
- {
- thicknessL = _maxThickness/2.f;
- thicknessR = _maxThickness/2.f;
- }
- if((sig==0) || (sig==vert_size-1))
- v->attribute().setThickness(1, 1);
- else
- v->attribute().setThickness(thicknessR, thicknessL);
- ++sig;
- }
+ convert(image, &_aThickness, _size);
+}
+
+
+int ThicknessVariationPatternShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ float *array = 0;
+ int size;
+ array = _aThickness;
+ size = _size;
+ int vert_size = stroke.strokeVerticesSize();
+ int sig = 0;
+ unsigned index;
+ const float* originalThickness;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ originalThickness = v->attribute().getThickness();
+ if (_stretch) {
+ float tmp = v->u() * (_size - 1);
+ index = (unsigned)floor(tmp);
+ if ((tmp - index) > (index + 1 - tmp))
+ ++index;
+ }
+ else {
+ index = (unsigned)floor(v->curvilinearAbscissa());
+ }
+ index %= _size;
+ float thicknessR = array[index] * originalThickness[0];
+ float thicknessL = array[index] * originalThickness[1];
+ if (thicknessR+thicknessL < _minThickness) {
+ thicknessL = _minThickness/2.0f;
+ thicknessR = _minThickness/2.0f;
+ }
+ if (thicknessR+thicknessL > _maxThickness) {
+ thicknessL = _maxThickness/2.0f;
+ thicknessR = _maxThickness/2.0f;
+ }
+ if ((sig == 0) || (sig == vert_size - 1))
+ v->attribute().setThickness(1, 1);
+ else
+ v->attribute().setThickness(thicknessR, thicknessL);
+ ++sig;
+ }
return 0;
- }
-
-
- static const unsigned NB_VALUE_NOISE = 512;
- ThicknessNoiseShader::ThicknessNoiseShader()
- :StrokeShader()
- {_amplitude=1.f;_scale=1.f/2.f/(float)NB_VALUE_NOISE;}
-
- ThicknessNoiseShader::ThicknessNoiseShader(float iAmplitude, float iPeriod)
- :StrokeShader()
- {_amplitude=iAmplitude;_scale=1.f/iPeriod/(float)NB_VALUE_NOISE;}
-
-
- int ThicknessNoiseShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- real initU1=v->strokeLength()*real(NB_VALUE_NOISE)+RandGen::drand48()*real(NB_VALUE_NOISE);
- real initU2=v->strokeLength()*real(NB_VALUE_NOISE)+RandGen::drand48()*real(NB_VALUE_NOISE);
-
- real bruit, bruit2;
- PseudoNoise mynoise, mynoise2;
- for(;
- v!=vend;
- ++v)
- {
-
- bruit=mynoise.turbulenceSmooth(_scale*v->curvilinearAbscissa()+initU1,
- 2); //2 : nbOctaves
- bruit2=mynoise2.turbulenceSmooth(_scale*v->curvilinearAbscissa()+initU2,
- 2); //2 : nbOctaves
- const float *originalThickness = v->attribute().getThickness();
- float r = bruit*_amplitude+originalThickness[0];
- float l = bruit2*_amplitude+originalThickness[1];
- v->attribute().setThickness(r,l);
- }
-
+}
+
+
+static const unsigned NB_VALUE_NOISE = 512;
+
+ThicknessNoiseShader::ThicknessNoiseShader() : StrokeShader()
+{
+ _amplitude = 1.0f;
+ _scale = 1.0f / 2.0f / (float)NB_VALUE_NOISE;
+}
+
+ThicknessNoiseShader::ThicknessNoiseShader(float iAmplitude, float iPeriod) : StrokeShader()
+{
+ _amplitude = iAmplitude;
+ _scale = 1.0f / iPeriod / (float)NB_VALUE_NOISE;
+}
+
+int ThicknessNoiseShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend;
+ real initU1 = v->strokeLength() * real(NB_VALUE_NOISE) + RandGen::drand48() * real(NB_VALUE_NOISE);
+ real initU2 = v->strokeLength() * real(NB_VALUE_NOISE) + RandGen::drand48() * real(NB_VALUE_NOISE);
+
+ real bruit, bruit2;
+ PseudoNoise mynoise, mynoise2;
+ for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ bruit = mynoise.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU1, 2); // 2 : nbOctaves
+ bruit2 = mynoise2.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU2, 2); // 2 : nbOctaves
+ const float *originalThickness = v->attribute().getThickness();
+ float r = bruit * _amplitude + originalThickness[0];
+ float l = bruit2 * _amplitude + originalThickness[1];
+ v->attribute().setThickness(r, l);
+ }
+
return 0;
- }
-
- //
- // Color shaders
- //
- ///////////////////////////////////////////////////////////////////////////////
-
- int ConstantColorShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v, vend;
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
- ++v)
- {
- v->attribute().setColor(_color[0], _color[1], _color[2]);
- v->attribute().setAlpha(_color[3]);
- }
+}
+
+//
+// Color shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+
+int ConstantColorShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ v->attribute().setColor(_color[0], _color[1], _color[2]);
+ v->attribute().setAlpha(_color[3]);
+ }
return 0;
- }
-
- int IncreasingColorShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v, vend;
- int n=stroke.strokeVerticesSize()-1;
- int yo=0;
- float newcolor[4];
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
-
- ++v)
- {
- for(int i=0; i<4; ++i)
- {
- newcolor[i] = (1.0-(float)yo/(float)n)*_colorMin[i] + (float)yo/(float)n*_colorMax[i];
- }
- v->attribute().setColor(newcolor[0], newcolor[1], newcolor[2]);
- v->attribute().setAlpha(newcolor[3]);
- ++yo;
- }
+}
+
+int IncreasingColorShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int n = stroke.strokeVerticesSize() - 1, yo;
+ float newcolor[4];
+ for (yo = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ v != vend;
+ ++v, ++yo)
+ {
+ for (int i = 0; i < 4; ++i) {
+ newcolor[i] = (1.0 - (float) yo / (float)n) * _colorMin[i] + (float)yo / (float)n * _colorMax[i];
+ }
+ v->attribute().setColor(newcolor[0], newcolor[1], newcolor[2]);
+ v->attribute().setAlpha(newcolor[3]);
+ }
return 0;
- }
-
- ColorVariationPatternShader::ColorVariationPatternShader(const string pattern_name,
- bool stretch)
- : StrokeShader() {
- _stretch = stretch;
- ImBuf *image = 0; //soc
- vector<string> pathnames;
- StringUtils::getPathName(TextureManager::Options::getPatternsPath(),
- pattern_name,
- pathnames);
- for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); j++) {
- ifstream ifs(j->c_str());
- if (ifs.is_open()) {
- /* OCIO_TODO: support different input color space */
- image = IMB_loadiffname(j->c_str(), 0, NULL); //soc
- break;
- }
- }
- if (image == 0) //soc
- cerr << "Error: cannot find pattern \"" << pattern_name
- << "\" - check the path in the Options" << endl;
- else
- convert(image, &_aVariation, _size);
- }
-
- int ColorVariationPatternShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v, vend;
- unsigned index;
- for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- v!=vend;
- ++v)
- {
- const float *originalColor = v->attribute().getColor();
- if (_stretch) {
- float tmp = v->u()*(_size-1);
- index = (unsigned)floor(tmp);
- if((tmp-index) > (index+1-tmp))
- ++index;
+}
+
+ColorVariationPatternShader::ColorVariationPatternShader(const string pattern_name, bool stretch) : StrokeShader()
+{
+ _stretch = stretch;
+ ImBuf *image = NULL; //soc
+ vector<string> pathnames;
+ StringUtils::getPathName(TextureManager::Options::getPatternsPath(), pattern_name, pathnames);
+ for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); ++j) {
+ ifstream ifs(j->c_str());
+ if (ifs.is_open()) {
+ /* OCIO_TODO: support different input color space */
+ image = IMB_loadiffname(j->c_str(), 0, NULL); //soc
+ break;
+ }
}
+ if (image == NULL) //soc
+ cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl;
else
- index = (unsigned)floor(v->curvilinearAbscissa());
- index %= _size;
- float r = _aVariation[index]*originalColor[0];
- float g = _aVariation[index]*originalColor[1];
- float b = _aVariation[index]*originalColor[2];
- v->attribute().setColor(r,g,b);
- }
+ convert(image, &_aVariation, _size);
+}
+
+int ColorVariationPatternShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ unsigned index;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ const float *originalColor = v->attribute().getColor();
+ if (_stretch) {
+ float tmp = v->u() * (_size - 1);
+ index = (unsigned)floor(tmp);
+ if ((tmp - index) > (index + 1 - tmp))
+ ++index;
+ }
+ else {
+ index = (unsigned)floor(v->curvilinearAbscissa());
+ }
+ index %= _size;
+ float r = _aVariation[index] * originalColor[0];
+ float g = _aVariation[index] * originalColor[1];
+ float b = _aVariation[index] * originalColor[2];
+ v->attribute().setColor(r, g, b);
+ }
return 0;
- }
-
- int MaterialColorShader::shade(Stroke& stroke) const
- {
- Interface0DIterator v, vend;
- Functions0D::MaterialF0D fun;
- StrokeVertex *sv;
- for(v=stroke.verticesBegin(), vend=stroke.verticesEnd();
- v!=vend;
- ++v)
- {
- if (fun(v) < 0)
- return -1;
- const float *diffuse = fun.result.diffuse();
- sv = dynamic_cast<StrokeVertex*>(&(*v));
- sv->attribute().setColor(diffuse[0]*_coefficient, diffuse[1]*_coefficient, diffuse[2]*_coefficient);
- sv->attribute().setAlpha(diffuse[3]);
- }
+}
+
+int MaterialColorShader::shade(Stroke& stroke) const
+{
+ Interface0DIterator v, vend;
+ Functions0D::MaterialF0D fun;
+ StrokeVertex *sv;
+ for (v = stroke.verticesBegin(), vend = stroke.verticesEnd(); v != vend; ++v) {
+ if (fun(v) < 0)
+ return -1;
+ const float *diffuse = fun.result.diffuse();
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ sv->attribute().setColor(diffuse[0] * _coefficient, diffuse[1] * _coefficient, diffuse[2] * _coefficient);
+ sv->attribute().setAlpha(diffuse[3]);
+ }
return 0;
- }
-
-
- int CalligraphicColorShader::shade(Stroke& stroke) const
- {
- Interface0DIterator v;
- Functions0D::VertexOrientation2DF0D fun;
- StrokeVertex* sv;
- for(v=stroke.verticesBegin();
- !v.isEnd();
- ++v)
- {
- if (fun(v) < 0)
- return -1;
- Vec2f vertexOri(fun.result);
- Vec2d ori2d(-vertexOri[1], vertexOri[0]);
- ori2d.normalizeSafe();
- real scal = ori2d * _orientation;
- sv = dynamic_cast<StrokeVertex*>(&(*v));
- if ((scal<0))
- sv->attribute().setColor(0,0,0);
- else
- sv->attribute().setColor(1,1,1);
- }
+}
+
+
+int CalligraphicColorShader::shade(Stroke& stroke) const
+{
+ Interface0DIterator v;
+ Functions0D::VertexOrientation2DF0D fun;
+ StrokeVertex *sv;
+ for (v = stroke.verticesBegin(); !v.isEnd(); ++v) {
+ if (fun(v) < 0)
+ return -1;
+ Vec2f vertexOri(fun.result);
+ Vec2d ori2d(-vertexOri[1], vertexOri[0]);
+ ori2d.normalizeSafe();
+ real scal = ori2d * _orientation;
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ if ((scal < 0))
+ sv->attribute().setColor(0, 0, 0);
+ else
+ sv->attribute().setColor(1, 1, 1);
+ }
return 0;
- }
-
-
- ColorNoiseShader::ColorNoiseShader()
- :StrokeShader()
- {_amplitude=1.f;_scale=1.f/2.f/(float)NB_VALUE_NOISE;}
-
- ColorNoiseShader::ColorNoiseShader(float iAmplitude, float iPeriod)
- :StrokeShader()
- {_amplitude=iAmplitude;_scale=1.f/iPeriod/(float)NB_VALUE_NOISE;}
-
-
- int ColorNoiseShader::shade(Stroke& stroke) const
- {
- StrokeInternal::StrokeVertexIterator v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- real initU=v->strokeLength()*real(NB_VALUE_NOISE)+RandGen::drand48()*real(NB_VALUE_NOISE);
-
- real bruit;
- PseudoNoise mynoise;
- for(;
- v!=vend;
- ++v)
- {
-
- bruit=mynoise.turbulenceSmooth(_scale*v->curvilinearAbscissa()+initU,
- 2); //2 : nbOctaves
- const float *originalColor = v->attribute().getColor();
- float r = bruit*_amplitude+originalColor[0];
- float g = bruit*_amplitude+originalColor[1];
- float b = bruit*_amplitude+originalColor[2];
- v->attribute().setColor(r,g,b);
- }
-
+}
+
+
+ColorNoiseShader::ColorNoiseShader() : StrokeShader()
+{
+ _amplitude = 1.0f;
+ _scale = 1.0f / 2.0f / (float)NB_VALUE_NOISE;
+}
+
+ColorNoiseShader::ColorNoiseShader(float iAmplitude, float iPeriod) : StrokeShader()
+{
+ _amplitude = iAmplitude;
+ _scale = 1.0f / iPeriod / (float)NB_VALUE_NOISE;
+}
+
+int ColorNoiseShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend;
+ real initU = v->strokeLength() * real(NB_VALUE_NOISE) + RandGen::drand48() * real(NB_VALUE_NOISE);
+
+ real bruit;
+ PseudoNoise mynoise;
+ for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ bruit = mynoise.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU, 2); // 2 : nbOctaves
+ const float *originalColor = v->attribute().getColor();
+ float r = bruit * _amplitude + originalColor[0];
+ float g = bruit * _amplitude + originalColor[1];
+ float b = bruit * _amplitude + originalColor[2];
+ v->attribute().setColor(r, g, b);
+ }
+
return 0;
- }
-
-
- //
- // Texture Shaders
- //
- ///////////////////////////////////////////////////////////////////////////////
-
- int TextureAssignerShader::shade(Stroke& stroke) const
- {
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::HUMID_MEDIUM);
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::HUMID_MEDIUM);
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/oil.bmp", Stroke::HUMID_MEDIUM);
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/oilnoblend.bmp", Stroke::HUMID_MEDIUM);
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::DRY_MEDIUM);
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::DRY_MEDIUM);
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueDryBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
- // getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
-
- TextureManager * instance = TextureManager::getInstance();
- if(!instance)
- return 0;
- string pathname;
- Stroke::MediumType mediumType;
- bool hasTips = false;
- switch(_textureId)
- {
- case 0:
- //pathname = TextureManager::Options::getBrushesPath() + "/charcoalAlpha.bmp";
+}
+
+
+//
+// Texture Shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+
+int TextureAssignerShader::shade(Stroke& stroke) const
+{
+#if 0
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/oil.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/oilnoblend.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::DRY_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::DRY_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueDryBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+#endif
+
+ TextureManager *instance = TextureManager::getInstance();
+ if (!instance)
+ return 0;
+ string pathname;
+ Stroke::MediumType mediumType;
+ bool hasTips = false;
+ switch (_textureId) {
+ case 0:
+ //pathname = TextureManager::Options::getBrushesPath() + "/charcoalAlpha.bmp";
pathname = "/charcoalAlpha.bmp";
- mediumType = Stroke::HUMID_MEDIUM;
- hasTips = false;
- break;
- case 1:
- pathname = "/washbrushAlpha.bmp";
- mediumType = Stroke::HUMID_MEDIUM;
- hasTips = true;
- break;
- case 2:
- pathname = "/oil.bmp";
- mediumType = Stroke::HUMID_MEDIUM;
- hasTips = true;
- break;
- case 3:
- pathname = "/oilnoblend.bmp";
- mediumType = Stroke::HUMID_MEDIUM;
- hasTips = true;
- break;
- case 4:
- pathname = "/charcoalAlpha.bmp";
- mediumType = Stroke::DRY_MEDIUM;
- hasTips = false;
- break;
- case 5:
- mediumType = Stroke::DRY_MEDIUM;
- hasTips = true;
- break;
- case 6:
- pathname = "/opaqueDryBrushAlpha.bmp";
- mediumType = Stroke::OPAQUE_MEDIUM;
- hasTips = true;
- break;
- case 7:
- pathname = "/opaqueBrushAlpha.bmp";
- mediumType = Stroke::OPAQUE_MEDIUM;
- hasTips = true;
- break;
- default:
- pathname = "/smoothAlpha.bmp";
- mediumType = Stroke::OPAQUE_MEDIUM;
- hasTips = false;
- break;
- }
- unsigned int texId = instance->getBrushTextureIndex(pathname, mediumType);
- stroke.setMediumType(mediumType);
- stroke.setTips(hasTips);
- stroke.setTextureId(texId);
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = false;
+ break;
+ case 1:
+ pathname = "/washbrushAlpha.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 2:
+ pathname = "/oil.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 3:
+ pathname = "/oilnoblend.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 4:
+ pathname = "/charcoalAlpha.bmp";
+ mediumType = Stroke::DRY_MEDIUM;
+ hasTips = false;
+ break;
+ case 5:
+ mediumType = Stroke::DRY_MEDIUM;
+ hasTips = true;
+ break;
+ case 6:
+ pathname = "/opaqueDryBrushAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = true;
+ break;
+ case 7:
+ pathname = "/opaqueBrushAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = true;
+ break;
+ default:
+ pathname = "/smoothAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = false;
+ break;
+ }
+ unsigned int texId = instance->getBrushTextureIndex(pathname, mediumType);
+ stroke.setMediumType(mediumType);
+ stroke.setTips(hasTips);
+ stroke.setTextureId(texId);
return 0;
- }
-
- // FIXME
- int StrokeTextureShader::shade(Stroke& stroke) const
- {
- TextureManager * instance = TextureManager::getInstance();
- if(!instance)
- return 0;
- string pathname = TextureManager::Options::getBrushesPath() + "/" + _texturePath;
- unsigned int texId = instance->getBrushTextureIndex(pathname, _mediumType);
- stroke.setMediumType(_mediumType);
- stroke.setTips(_tips);
- stroke.setTextureId(texId);
+}
+
+// FIXME
+int StrokeTextureShader::shade(Stroke& stroke) const
+{
+ TextureManager *instance = TextureManager::getInstance();
+ if (!instance)
+ return 0;
+ string pathname = TextureManager::Options::getBrushesPath() + "/" + _texturePath;
+ unsigned int texId = instance->getBrushTextureIndex(pathname, _mediumType);
+ stroke.setMediumType(_mediumType);
+ stroke.setTips(_tips);
+ stroke.setTextureId(texId);
return 0;
- }
-
- //
- // Geometry Shaders
- //
- ///////////////////////////////////////////////////////////////////////////////
-
- int BackboneStretcherShader::shade(Stroke& stroke) const
- {
- float l=stroke.getLength2D();
- if(l <= 1e-6)
- return 0;
-
- StrokeInternal::StrokeVertexIterator v0=stroke.strokeVerticesBegin();
- StrokeInternal::StrokeVertexIterator v1=v0;++v1;
- StrokeInternal::StrokeVertexIterator vn=stroke.strokeVerticesEnd();--vn;
- StrokeInternal::StrokeVertexIterator vn_1=vn;--vn_1;
-
-
- Vec2d first((v0)->x(), (v0)->y());
- Vec2d last((vn)->x(), (vn)->y());
-
- Vec2d d1(first-Vec2d((v1)->x(), (v1)->y()));
- d1.normalize();
- Vec2d dn(last-Vec2d((vn_1)->x(), (vn_1)->y()));
- dn.normalize();
-
- Vec2d newFirst(first+_amount*d1);
- (v0)->setPoint(newFirst[0], newFirst[1]);
- Vec2d newLast(last+_amount*dn);
- (vn)->setPoint(newLast[0], newLast[1]);
+}
+
+//
+// Geometry Shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+
+int BackboneStretcherShader::shade(Stroke& stroke) const
+{
+ float l = stroke.getLength2D();
+ if (l <= 1.0e-6)
+ return 0;
+
+ StrokeInternal::StrokeVertexIterator v0 = stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator v1 = v0;
+ ++v1;
+ StrokeInternal::StrokeVertexIterator vn = stroke.strokeVerticesEnd();
+ --vn;
+ StrokeInternal::StrokeVertexIterator vn_1 = vn;
+ --vn_1;
+
+
+ Vec2d first((v0)->x(), (v0)->y());
+ Vec2d last((vn)->x(), (vn)->y());
+
+ Vec2d d1(first-Vec2d((v1)->x(), (v1)->y()));
+ d1.normalize();
+ Vec2d dn(last-Vec2d((vn_1)->x(), (vn_1)->y()));
+ dn.normalize();
+
+ Vec2d newFirst(first + _amount * d1);
+ (v0)->setPoint(newFirst[0], newFirst[1]);
+ Vec2d newLast(last + _amount * dn);
+ (vn)->setPoint(newLast[0], newLast[1]);
stroke.UpdateLength();
return 0;
- }
+}
- int SamplingShader::shade(Stroke& stroke) const
- {
- stroke.Resample(_sampling);
+int SamplingShader::shade(Stroke& stroke) const
+{
+ stroke.Resample(_sampling);
return 0;
- }
-
- int ExternalContourStretcherShader::shade(Stroke& stroke) const
- {
- //float l=stroke.getLength2D();
- Interface0DIterator it=stroke.verticesBegin();
- Functions0D::Normal2DF0D fun;
- StrokeVertex* sv;
- while (!it.isEnd())
- {
- if (fun(it) < 0)
- return -1;
- Vec2f n(fun.result);
- sv = dynamic_cast<StrokeVertex*>(&(*it));
- Vec2d newPoint(sv->x()+_amount*n.x(), sv->y()+_amount*n.y());
- sv->setPoint(newPoint[0], newPoint[1]);
- ++it;
- }
+}
+
+int ExternalContourStretcherShader::shade(Stroke& stroke) const
+{
+ //float l = stroke.getLength2D();
+ Interface0DIterator it;
+ Functions0D::Normal2DF0D fun;
+ StrokeVertex* sv;
+ for (it = stroke.verticesBegin(); !it.isEnd(); ++it) {
+ if (fun(it) < 0)
+ return -1;
+ Vec2f n(fun.result);
+ sv = dynamic_cast<StrokeVertex*>(&(*it));
+ Vec2d newPoint(sv->x() + _amount * n.x(), sv->y() + _amount * n.y());
+ sv->setPoint(newPoint[0], newPoint[1]);
+ }
stroke.UpdateLength();
return 0;
- }
-
- int BSplineShader::shade(Stroke& stroke) const
- {
- if(stroke.strokeVerticesSize() < 4)
- return 0;
-
- // Find the new vertices
- vector<Vec2d> newVertices;
- double t=0.f;
- float _sampling = 5.f;
-
- StrokeInternal::StrokeVertexIterator p0,p1,p2,p3, end;
- p0 = stroke.strokeVerticesBegin();
- p1 = p0;
- p2 = p1;
- p3 = p2;
- end = stroke.strokeVerticesEnd();
- double a[4],b[4];
- int n=0;
- while(p1 != end)
- {
- // if(p1 == end)
- // p1 = p0;
- if(p2 == end)
- p2 = p1;
- if(p3 == end)
- p3 = p2;
- // compute new matrix
- a[0] = (-(p0)->x()+3*(p1)->x()-3*(p2)->x()+(p3)->x())/6.0;
- a[1] = (3*(p0)->x()-6*(p1)->x()+3*(p2)->x())/6.0;
- a[2] = (-3*(p0)->x()+3*(p2)->x())/6.0;
- a[3] = ((p0)->x()+4*(p1)->x()+(p2)->x())/6.0;
-
- b[0] = (-(p0)->y()+3*(p1)->y()-3*(p2)->y()+(p3)->y())/6.0;
- b[1] = (3*(p0)->y()-6*(p1)->y()+3*(p2)->y())/6.0;
- b[2] = (-3*(p0)->y()+3*(p2)->y())/6.0;
- b[3] = ((p0)->y()+4*(p1)->y()+(p2)->y())/6.0;
-
-
- // draw the spline depending on resolution:
- Vec2d p1p2((p2)->x()-(p1)->x(), (p2)->y()-(p1)->y());
- double norm = p1p2.norm();
- //t = _sampling/norm;
- t=0;
- while(t<1)
- {
- newVertices.push_back(Vec2d((a[3] + t*(a[2] + t*(a[1] + t*a[0]))),
- (b[3] + t*(b[2] + t*(b[1] + t*b[0])))));
- t = t + _sampling/norm;
- }
- if(n > 2)
- {
- ++p0;
- ++p1;
- ++p2;
- ++p3;
- }
- else
- {
- if(n==0)
- ++p3;
- if(n==1)
- {++p2;++p3;}
- if(n==2)
- {++p1;++p2;++p3;}
- ++n;
- }
- }
- //last point:
- newVertices.push_back(Vec2d((p0)->x(), (p0)->y()));
-
- int originalSize = newVertices.size();
- _sampling = stroke.ComputeSampling(originalSize);
-
- // Resample and set x,y coordinates
- stroke.Resample(_sampling);
- int newsize = stroke.strokeVerticesSize();
-
- int nExtraVertex=0;
- if(newsize < originalSize)
- cerr << "Warning: unsufficient resampling" << endl;
- else
- {
- nExtraVertex = newsize - originalSize;
- }
-
- // assigns the new coordinates:
- vector<Vec2d>::iterator p,pend;
- p=newVertices.begin();pend=newVertices.end();
- vector<Vec2d>::iterator last = p;
- n=0;
- StrokeInternal::StrokeVertexIterator it=stroke.strokeVerticesBegin(), itend=stroke.strokeVerticesEnd();
- it=stroke.strokeVerticesBegin();
- for(;
- ((it!=itend) && (p!=pend));
- ++it)
- {
- it->setX(p->x());
- it->setY(p->y());
- last = p;
- ++p;
- ++n;
- }
- // nExtraVertex should stay unassigned
- for(int i=0; i< nExtraVertex; ++i)
- {
- it->setX(last->x());
- it->setY(last->y());
- if(it.isEnd())
- cerr << "Warning: Problem encountered while creating B-spline" << endl;
- ++it;
- ++n;
- }
+}
+
+int BSplineShader::shade(Stroke& stroke) const
+{
+ if (stroke.strokeVerticesSize() < 4)
+ return 0;
+
+ // Find the new vertices
+ vector<Vec2d> newVertices;
+ double t = 0.0;
+ float _sampling = 5.0f;
+
+ StrokeInternal::StrokeVertexIterator p0, p1, p2, p3, end;
+ p0 = stroke.strokeVerticesBegin();
+ p1 = p0;
+ p2 = p1;
+ p3 = p2;
+ end = stroke.strokeVerticesEnd();
+ double a[4], b[4];
+ int n = 0;
+ while (p1 != end) {
+#if 0
+ if (p1 == end)
+ p1 = p0;
+#endif
+ if (p2 == end)
+ p2 = p1;
+ if (p3 == end)
+ p3 = p2;
+ // compute new matrix
+ a[0] = (-(p0)->x() + 3 * (p1)->x() - 3 * (p2)->x() + (p3)->x()) / 6.0;
+ a[1] = (3 * (p0)->x() - 6 * (p1)->x() + 3 * (p2)->x()) / 6.0;
+ a[2] = (-3 * (p0)->x() + 3 * (p2)->x()) / 6.0;
+ a[3] = ((p0)->x() + 4 * (p1)->x() + (p2)->x()) / 6.0;
+
+ b[0] = (-(p0)->y() + 3 * (p1)->y() - 3 * (p2)->y() + (p3)->y()) / 6.0;
+ b[1] = (3 * (p0)->y() - 6 * (p1)->y() + 3 * (p2)->y()) / 6.0;
+ b[2] = (-3 * (p0)->y() + 3 * (p2)->y()) / 6.0;
+ b[3] = ((p0)->y() + 4 * (p1)->y() + (p2)->y()) / 6.0;
+
+ // draw the spline depending on resolution:
+ Vec2d p1p2((p2)->x() - (p1)->x(), (p2)->y() - (p1)->y());
+ double norm = p1p2.norm();
+ //t = _sampling / norm;
+ t = 0;
+ while (t < 1) {
+ newVertices.push_back(Vec2d((a[3] + t * (a[2] + t * (a[1] + t * a[0]))),
+ (b[3] + t * (b[2] + t * (b[1] + t * b[0])))));
+ t = t + _sampling / norm;
+ }
+ if (n > 2) {
+ ++p0;
+ ++p1;
+ ++p2;
+ ++p3;
+ }
+ else {
+ if (n == 0)
+ ++p3;
+ if (n == 1) {
+ ++p2;
+ ++p3;
+ }
+ if (n == 2) {
+ ++p1;
+ ++p2;
+ ++p3;
+ }
+ ++n;
+ }
+ }
+ //last point:
+ newVertices.push_back(Vec2d((p0)->x(), (p0)->y()));
+
+ int originalSize = newVertices.size();
+ _sampling = stroke.ComputeSampling(originalSize);
+
+ // Resample and set x,y coordinates
+ stroke.Resample(_sampling);
+ int newsize = stroke.strokeVerticesSize();
+
+ int nExtraVertex = 0;
+ if (newsize < originalSize) {
+ cerr << "Warning: unsufficient resampling" << endl;
+ }
+ else {
+ nExtraVertex = newsize - originalSize;
+ }
+
+ // assigns the new coordinates:
+ vector<Vec2d>::iterator p = newVertices.begin(), pend = newVertices.end();
+ vector<Vec2d>::iterator last = p;
+ n = 0;
+ StrokeInternal::StrokeVertexIterator it, itend;
+ for (it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd();
+ (it != itend) && (p != pend);
+ ++it, ++p, ++n)
+ {
+ it->setX(p->x());
+ it->setY(p->y());
+ last = p;
+ }
+
+ // nExtraVertex should stay unassigned
+ for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) {
+ it->setX(last->x());
+ it->setY(last->y());
+ if (it.isEnd()) {
+ // XXX Shouldn't we break in this case???
+ cerr << "Warning: Problem encountered while creating B-spline" << endl;
+ }
+ }
stroke.UpdateLength();
return 0;
- }
-
- //!! Bezier curve stroke shader
- int BezierCurveShader::shade(Stroke& stroke) const
- {
- if(stroke.strokeVerticesSize() < 4)
- return 0;
-
- // Build the Bezier curve from this set of data points:
- vector<Vec2d> data;
- StrokeInternal::StrokeVertexIterator v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
- data.push_back(Vec2d(v->x(), v->y()));//first one
- StrokeInternal::StrokeVertexIterator previous = v;++v;
- for(;
- v!=vend;
- ++v)
- {
- if(!((fabs(v->x() -(previous)->x())<M_EPSILON) && ((fabs(v->y() - (previous)->y())<M_EPSILON))))
- data.push_back(Vec2d(v->x(), v->y()));
- previous = v;
- }
-
- // Vec2d tmp;bool equal=false;
- // if(data.front() == data.back())
- // {
- // tmp = data.back();
- // data.pop_back();
- // equal=true;
- // }
- // here we build the bezier curve
- BezierCurve bcurve(data, _error);
-
- // bad performances are here !!! // FIXME
- vector<Vec2d> CurveVertices;
- vector<BezierCurveSegment*>& bsegments = bcurve.segments();
- vector<BezierCurveSegment*>::iterator s=bsegments.begin(),send=bsegments.end();
- vector<Vec2d>& segmentsVertices = (*s)->vertices();
- vector<Vec2d>::iterator p,pend;
- // first point
- CurveVertices.push_back(segmentsVertices[0]);
- for(;
- s!=send;
- ++s)
- {
- segmentsVertices = (*s)->vertices();
- p=segmentsVertices.begin(); pend=segmentsVertices.end();
- ++p;
- for(;
- p!=pend;
- ++p)
- {
- CurveVertices.push_back((*p));
- }
- }
-
- //if(equal)
- // if(data.back() == data.front())
- // {
- // vector<Vec2d>::iterator d=data.begin(), dend=data.end();
- // cout << "ending point = starting point" << endl;
- // cout << "---------------DATA----------" << endl;
- // for(;
- // d!=dend;
- // ++d)
- // {
- // cout << d->x() << "-" << d->y() << endl;
- // }
- // cout << "--------------BEZIER RESULT----------" << endl;
- // d=CurveVertices.begin(), dend=CurveVertices.end();
- // for(;d!=dend;++d)
- // {
- // cout << d->x() << "-" << d->y() << endl;
- // }
- // }
-
- // Resample the Stroke depending on the number of
- // vertices of the bezier curve:
- int originalSize = CurveVertices.size();
- //float sampling = stroke.ComputeSampling(originalSize);
- //stroke.Resample(sampling);
- stroke.Resample(originalSize);
- int newsize = stroke.strokeVerticesSize();
- int nExtraVertex=0;
- if(newsize < originalSize)
- cerr << "Warning: unsufficient resampling" << endl;
- else
- {
- //cout << "Oversampling" << endl;
- nExtraVertex = newsize - originalSize;
- if(nExtraVertex != 0)
- cout << "Bezier Shader : Stroke " << stroke.getId() << " have not been resampled" << endl;
- }
-
- // assigns the new coordinates:
- p=CurveVertices.begin();pend=CurveVertices.end();
- vector<Vec2d>::iterator last = p;
- int n=0;
- StrokeInternal::StrokeVertexIterator it=stroke.strokeVerticesBegin(), itend=stroke.strokeVerticesEnd();
- // while(p!=pend)
- // {
- // ++n;
- // ++p;
- // }
- it=stroke.strokeVerticesBegin();
- for(;
- ((it!=itend) && (p!=pend));
- ++it)
- {
- it->setX(p->x());
- it->setY(p->y());
- // double x = p->x();
- // double y = p->y();
- // cout << "x = " << x << "-" << "y = " << y << endl;
- last = p;
- ++p;
- ++n;
- }
+}
+
+//!! Bezier curve stroke shader
+int BezierCurveShader::shade(Stroke& stroke) const
+{
+ if (stroke.strokeVerticesSize() < 4)
+ return 0;
+
+ // Build the Bezier curve from this set of data points:
+ vector<Vec2d> data;
+ StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend;
+ data.push_back(Vec2d(v->x(), v->y())); //first one
+ StrokeInternal::StrokeVertexIterator previous = v;
+ ++v;
+ for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ if (!((fabs(v->x() - (previous)->x()) < M_EPSILON) && ((fabs(v->y() - (previous)->y()) < M_EPSILON))))
+ data.push_back(Vec2d(v->x(), v->y()));
+ previous = v;
+ }
+
+#if 0
+ Vec2d tmp;
+ bool equal = false;
+ if (data.front() == data.back()) {
+ tmp = data.back();
+ data.pop_back();
+ equal = true;
+ }
+#endif
+ // here we build the bezier curve
+ BezierCurve bcurve(data, _error);
+
+ // bad performances are here !!! // FIXME
+ vector<Vec2d> CurveVertices;
+ vector<BezierCurveSegment*>& bsegments = bcurve.segments();
+ vector<BezierCurveSegment*>::iterator s = bsegments.begin(), send;
+ vector<Vec2d>& segmentsVertices = (*s)->vertices();
+ vector<Vec2d>::iterator p, pend;
+ // first point
+ CurveVertices.push_back(segmentsVertices[0]);
+ for (send = bsegments.end(); s != send; ++s) {
+ segmentsVertices = (*s)->vertices();
+ p = segmentsVertices.begin();
+ ++p;
+ for (pend = segmentsVertices.end(); p != pend; ++p) {
+ CurveVertices.push_back((*p));
+ }
+ }
+
+#if 0
+ if (equal) {
+ if (data.back() == data.front()) {
+ vector<Vec2d>::iterator d = data.begin(), dend;
+ cout << "ending point = starting point" << endl;
+ cout << "---------------DATA----------" << endl;
+ for (dend = data.end(); d != dend; ++d) {
+ cout << d->x() << "-" << d->y() << endl;
+ }
+ cout << "--------------BEZIER RESULT----------" << endl;
+ for (d = CurveVertices.begin(), dend = CurveVertices.end(); d != dend; ++d) {
+ cout << d->x() << "-" << d->y() << endl;
+ }
+ }
+ }
+#endif
+
+ // Resample the Stroke depending on the number of vertices of the bezier curve:
+ int originalSize = CurveVertices.size();
+#if 0
+ float sampling = stroke.ComputeSampling(originalSize);
+ stroke.Resample(sampling);
+#endif
+ stroke.Resample(originalSize);
+ int newsize = stroke.strokeVerticesSize();
+ int nExtraVertex = 0;
+ if (newsize < originalSize) {
+ cerr << "Warning: unsufficient resampling" << endl;
+ }
+ else {
+ //cout << "Oversampling" << endl;
+ nExtraVertex = newsize - originalSize;
+ if (nExtraVertex != 0)
+ cout << "Bezier Shader : Stroke " << stroke.getId() << " have not been resampled" << endl;
+ }
+
+ // assigns the new coordinates:
+ p = CurveVertices.begin();
+ vector<Vec2d>::iterator last = p;
+ int n;
+ StrokeInternal::StrokeVertexIterator it, itend;
+#if 0
+ for (; p != pend; ++n, ++p);
+#endif
+ for (n = 0, it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd(), pend = CurveVertices.end();
+ (it != itend) && (p != pend);
+ ++it, ++p, ++n)
+ {
+ it->setX(p->x());
+ it->setY(p->y());
+#if 0
+ double x = p->x();
+ double y = p->y();
+ cout << "x = " << x << "-" << "y = " << y << endl;
+#endif
+ last = p;
+ }
stroke.UpdateLength();
- // Deal with extra vertices:
- if(nExtraVertex == 0)
- return 0;
-
- // nExtraVertex should stay unassigned
- vector<StrokeAttribute> attributes;
- vector<StrokeVertex*> verticesToRemove;
- for(int i=0; i< nExtraVertex; ++i)
- {
- verticesToRemove.push_back(&(*it));
- if(it.isEnd())
- cout << "fucked up" << endl;
- ++it;
- ++n;
- }
- it=stroke.strokeVerticesBegin();
- for(;
- it!=itend;
- ++it)
- {
- attributes.push_back(it->attribute());
- }
-
- for(vector<StrokeVertex*>::iterator vr=verticesToRemove.begin(), vrend=verticesToRemove.end();
- vr!=vrend;
- ++vr)
- {
- stroke.RemoveVertex(*vr);
- }
- it=stroke.strokeVerticesBegin();
- itend=stroke.strokeVerticesEnd();
- vector<StrokeAttribute>::iterator a=attributes.begin(), aend=attributes.end();
- int index = 0;
- int index1 = (int)floor((float)originalSize/2.0);
- int index2 = index1+nExtraVertex;
- for(;
- (it!=itend) && (a!=aend);
- ++it)
- {
- (it)->setAttribute(*a);
- if((index <= index1)||(index>index2))
- ++a;
- ++index;
- }
+ // Deal with extra vertices:
+ if (nExtraVertex == 0)
+ return 0;
+
+ // nExtraVertex should stay unassigned
+ vector<StrokeAttribute> attributes;
+ vector<StrokeVertex*> verticesToRemove;
+ for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) {
+ verticesToRemove.push_back(&(*it));
+ if (it.isEnd()) {
+ // XXX Shocking! :P Shouldn't we break in this case???
+ cout << "fucked up" << endl;
+ }
+ }
+ for (it = stroke.strokeVerticesBegin(); it != itend; ++it) {
+ attributes.push_back(it->attribute());
+ }
+
+ for (vector<StrokeVertex*>::iterator vr = verticesToRemove.begin(), vrend = verticesToRemove.end();
+ vr != vrend;
+ ++vr)
+ {
+ stroke.RemoveVertex(*vr);
+ }
+
+ vector<StrokeAttribute>::iterator a = attributes.begin(), aend = attributes.end();
+ int index = 0;
+ int index1 = (int)floor((float)originalSize / 2.0);
+ int index2 = index1 + nExtraVertex;
+ for (it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd();
+ (it != itend) && (a != aend);
+ ++it)
+ {
+ (it)->setAttribute(*a);
+ if ((index <= index1) || (index > index2))
+ ++a;
+ ++index;
+ }
return 0;
- }
+}
- int InflateShader::shade(Stroke& stroke) const
- {
- // we're computing the curvature variance of the stroke.(Combo 5)
- // If it's too high, forget about it
- Functions1D::Curvature2DAngleF1D fun;
+int InflateShader::shade(Stroke& stroke) const
+{
+ // we're computing the curvature variance of the stroke. (Combo 5)
+ // If it's too high, forget about it
+ Functions1D::Curvature2DAngleF1D fun;
if (fun(stroke) < 0)
- return -1;
+ return -1;
if (fun.result > _curvatureThreshold)
- return 0;
-
- Functions0D::VertexOrientation2DF0D ori_fun;
- Functions0D::Curvature2DAngleF0D curv_fun;
- Functions1D::Normal2DF1D norm_fun;
- Interface0DIterator it=stroke.verticesBegin();
- StrokeVertex* sv;
- while (!it.isEnd())
- {
- if (ori_fun(it) < 0)
- return -1;
- Vec2f ntmp(ori_fun.result);
- Vec2f n(ntmp.y(), -ntmp.x());
- if (norm_fun(stroke) < 0)
- return -1;
- Vec2f strokeN(norm_fun.result);
- if(n*strokeN < 0)
- {
- n[0] = -n[0];
- n[1] = -n[1];
- }
- sv = dynamic_cast<StrokeVertex*>(&(*it));
- float u=sv->u();
- float t = 4.f*(0.25f - (u-0.5)*(u-0.5));
- if (curv_fun(it) < 0)
- return -1;
- float curvature_coeff = (M_PI-curv_fun.result)/M_PI;
- Vec2d newPoint(sv->x()+curvature_coeff*t*_amount*n.x(), sv->y()+curvature_coeff*t*_amount*n.y());
- sv->setPoint(newPoint[0], newPoint[1]);
- ++it;
- }
+ return 0;
+
+ Functions0D::VertexOrientation2DF0D ori_fun;
+ Functions0D::Curvature2DAngleF0D curv_fun;
+ Functions1D::Normal2DF1D norm_fun;
+ Interface0DIterator it;
+ StrokeVertex *sv;
+ for (it = stroke.verticesBegin(); !it.isEnd(); ++it) {
+ if (ori_fun(it) < 0)
+ return -1;
+ Vec2f ntmp(ori_fun.result);
+ Vec2f n(ntmp.y(), -ntmp.x());
+ if (norm_fun(stroke) < 0)
+ return -1;
+ Vec2f strokeN(norm_fun.result);
+ if (n*strokeN < 0) {
+ n[0] = -n[0];
+ n[1] = -n[1];
+ }
+ sv = dynamic_cast<StrokeVertex*>(&(*it));
+ float u = sv->u();
+ float t = 4.0f * (0.25f - (u - 0.5) * (u - 0.5));
+ if (curv_fun(it) < 0)
+ return -1;
+ float curvature_coeff = (M_PI - curv_fun.result) / M_PI;
+ Vec2d newPoint(sv->x() + curvature_coeff * t * _amount * n.x(),
+ sv->y() + curvature_coeff * t * _amount * n.y());
+ sv->setPoint(newPoint[0], newPoint[1]);
+ }
stroke.UpdateLength();
return 0;
- }
-
- class CurvePiece
- {
- public:
- StrokeInternal::StrokeVertexIterator _begin;
- StrokeInternal::StrokeVertexIterator _last;
- Vec2d A;
- Vec2d B;
- int size;
- float _error;
-
- CurvePiece(StrokeInternal::StrokeVertexIterator b, StrokeInternal::StrokeVertexIterator l, int iSize)
- {
- _begin = b;
- _last = l;
- A = Vec2d((_begin)->x(),(_begin)->y());
- B = Vec2d((_last)->x(),(_last)->y());
- size = iSize;
- }
-
- float error()
- {
- float maxE = 0.f;
- for(StrokeInternal::StrokeVertexIterator it=_begin;
- it!=_last;
- ++it)
+}
+
+class CurvePiece
+{
+public:
+ StrokeInternal::StrokeVertexIterator _begin;
+ StrokeInternal::StrokeVertexIterator _last;
+ Vec2d A;
+ Vec2d B;
+ int size;
+ float _error;
+
+ CurvePiece(StrokeInternal::StrokeVertexIterator b, StrokeInternal::StrokeVertexIterator l, int iSize)
{
- Vec2d P(it->x(), it->y());
- float d = GeomUtils::distPointSegment(P,A,B);
- if(d > maxE)
- maxE = d;
+ _begin = b;
+ _last = l;
+ A = Vec2d((_begin)->x(), (_begin)->y());
+ B = Vec2d((_last)->x(), (_last)->y());
+ size = iSize;
}
- _error = maxE;
- return maxE;
- }
- //! Subdivides the curve into two pieces.
- // The first piece is this same object (modified)
- // the second piece is returned by the method
- CurvePiece * subdivide()
- {
- StrokeInternal::StrokeVertexIterator it=_begin;
- int actualSize = 1;
- for(int i=0; i<size/2; ++i)
+
+ float error()
{
- ++it;
- ++actualSize;
+ float maxE = 0.0f;
+ for (StrokeInternal::StrokeVertexIterator it = _begin; it != _last; ++it) {
+ Vec2d P(it->x(), it->y());
+ float d = GeomUtils::distPointSegment(P, A, B);
+ if (d > maxE)
+ maxE = d;
+ }
+ _error = maxE;
+ return maxE;
+ }
+
+ //! Subdivides the curve into two pieces.
+ // The first piece is this same object (modified)
+ // The second piece is returned by the method
+ CurvePiece *subdivide()
+ {
+ StrokeInternal::StrokeVertexIterator it = _begin;
+ int actualSize = (size > 1) ? size / 2 : 1;
+ for (int i = 0; i <= actualSize; ++it, ++i);
+
+ CurvePiece *second = new CurvePiece(it, _last, size - actualSize + 1);
+ size = actualSize;
+ _last = it;
+ B = Vec2d((_last)->x(), (_last)->y());
+ return second;
+ }
+};
+
+int PolygonalizationShader::shade(Stroke& stroke) const
+{
+ vector<CurvePiece*> _pieces;
+ vector<CurvePiece*> _results;
+ vector<CurvePiece*>::iterator cp, cpend;
+
+ // Compute first approx:
+ StrokeInternal::StrokeVertexIterator a = stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator b = stroke.strokeVerticesEnd();
+ --b;
+ int size = stroke.strokeVerticesSize();
+
+ CurvePiece *piece = new CurvePiece(a, b, size);
+ _pieces.push_back(piece);
+
+ while (!_pieces.empty()) {
+ piece = _pieces.back();
+ _pieces.pop_back();
+ if (piece->error() > _error) {
+ CurvePiece *second = piece->subdivide();
+ _pieces.push_back(second);
+ _pieces.push_back(piece);
+ }
+ else {
+ _results.push_back(piece);
+ }
+ }
+
+ // actually modify the geometry for each piece:
+ for (cp = _results.begin(), cpend = _results.end(); cp != cpend; ++cp) {
+ a = (*cp)->_begin;
+ b = (*cp)->_last;
+ Vec2d u = (*cp)->B - (*cp)->A;
+ Vec2d n(u[1], -u[0]);
+ n.normalize();
+ //Vec2d n(0, 0);
+ float offset = ((*cp)->_error);
+ StrokeInternal::StrokeVertexIterator v;
+ for (v = a; v != b; ++v) {
+ v->setPoint((*cp)->A.x() + v->u() * u.x() + n.x() * offset,
+ (*cp)->A.y() + v->u() * u.y() + n.y() * offset);
+ }
+#if 0
+ u.normalize();
+ (*a)->setPoint((*a)->x() - u.x() * 10, (*a)->y() - u.y() * 10);
+#endif
}
- CurvePiece * second = new CurvePiece(it, _last, size-actualSize+1);
- size = actualSize;
- _last = it;
- B = Vec2d((_last)->x(), (_last)->y());
- return second;
- }
- };
-
- int PolygonalizationShader::shade(Stroke& stroke) const
- {
- vector<CurvePiece*> _pieces;
- vector<CurvePiece*> _results;
- vector<CurvePiece*>::iterator cp,cpend;
-
- // Compute first approx:
- StrokeInternal::StrokeVertexIterator a=stroke.strokeVerticesBegin();
- StrokeInternal::StrokeVertexIterator b=stroke.strokeVerticesEnd();--b;
- int size = stroke.strokeVerticesSize();
-
- CurvePiece * piece = new CurvePiece(a,b,size);
- _pieces.push_back(piece);
-
- while(!_pieces.empty())
- {
- piece = _pieces.back();_pieces.pop_back();
- if(piece->error() > _error)
- {
- CurvePiece * second = piece->subdivide();
- _pieces.push_back(second);
- _pieces.push_back(piece);
- }
- else
- {
- _results.push_back(piece);
- }
- }
-
- // actually modify the geometry for each piece:
- for(cp=_results.begin(), cpend=_results.end();
- cp!=cpend;
- ++cp)
- {
- a = (*cp)->_begin;
- b = (*cp)->_last;
- Vec2d u = (*cp)->B-(*cp)->A;
- Vec2d n(u[1], -u[0]);n.normalize();
- //Vec2d n(0,0);
- float offset = ((*cp)->_error);
- StrokeInternal::StrokeVertexIterator v,vlast;
- for(v=a;
- v!=b;
- ++v)
- {
- v->setPoint((*cp)->A.x()+v->u()*u.x()+n.x()*offset, (*cp)->A.y()+v->u()*u.y()+n.y()*offset);
- }
- // u.normalize();
- // (*a)->setPoint((*a)->x()-u.x()*10, (*a)->y()-u.y()*10);
- }
stroke.UpdateLength();
- // delete stuff
- for(cp=_results.begin(), cpend=_results.end();
- cp!=cpend;
- ++cp)
- {
- delete (*cp);
- }
- _results.clear();
+ // delete stuff
+ for (cp = _results.begin(), cpend = _results.end(); cp != cpend; ++cp) {
+ delete (*cp);
+ }
+ _results.clear();
return 0;
- }
-
- int GuidingLinesShader::shade(Stroke& stroke) const
- {
- Functions1D::Normal2DF1D norm_fun;
- StrokeInternal::StrokeVertexIterator a=stroke.strokeVerticesBegin();
- StrokeInternal::StrokeVertexIterator b=stroke.strokeVerticesEnd();--b;
- int size = stroke.strokeVerticesSize();
- CurvePiece piece(a,b,size);
-
- Vec2d u = piece.B-piece.A;
- Vec2f n(u[1], -u[0]);n.normalize();
+}
+
+int GuidingLinesShader::shade(Stroke& stroke) const
+{
+ Functions1D::Normal2DF1D norm_fun;
+ StrokeInternal::StrokeVertexIterator a = stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator b = stroke.strokeVerticesEnd();
+ --b;
+ int size = stroke.strokeVerticesSize();
+ CurvePiece piece(a, b, size);
+
+ Vec2d u = piece.B - piece.A;
+ Vec2f n(u[1], -u[0]);
+ n.normalize();
if (norm_fun(stroke) < 0)
- return -1;
- Vec2f strokeN(norm_fun.result);
- if(n*strokeN < 0)
- {
- n[0] = -n[0];
- n[1] = -n[1];
- }
- float offset = (piece.error())/2.f*_offset;
- StrokeInternal::StrokeVertexIterator v=a,vend=stroke.strokeVerticesEnd();
- for(;
- v!=vend;
- ++v)
- {
- v->setPoint(piece.A.x()+v->u()*u.x()+n.x()*offset, piece.A.y()+v->u()*u.y()+n.y()*offset);
- }
+ return -1;
+ Vec2f strokeN(norm_fun.result);
+ if (n * strokeN < 0) {
+ n[0] = -n[0];
+ n[1] = -n[1];
+ }
+ float offset = (piece.error()) / 2.0f * _offset;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (v = a, vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ v->setPoint(piece.A.x() + v->u() * u.x() + n.x() * offset,
+ piece.A.y() + v->u() * u.y() + n.y() * offset);
+ }
stroke.UpdateLength();
return 0;
- }
-
- /////////////////////////////////////////
- //
- // Tip Remover
- //
- /////////////////////////////////////////
-
-
- TipRemoverShader::TipRemoverShader(real tipLength)
- : StrokeShader()
- {
- _tipLength = tipLength;
- }
-
- int
- TipRemoverShader::shade(Stroke& stroke) const
- {
- int originalSize = stroke.strokeVerticesSize();
-
- if(originalSize<4)
- return 0;
-
- StrokeInternal::StrokeVertexIterator v, vend;
- vector<StrokeVertex*> verticesToRemove;
- vector<StrokeAttribute> oldAttributes;
- v=stroke.strokeVerticesBegin(); vend=stroke.strokeVerticesEnd();
- for(;
- v!=vend;
- ++v)
- {
- if ((v->curvilinearAbscissa()<_tipLength) ||
- (v->strokeLength()-v->curvilinearAbscissa()<_tipLength))
- {
- verticesToRemove.push_back(&(*v));
- }
- oldAttributes.push_back(v->attribute());
- }
-
- if(originalSize-verticesToRemove.size() < 2)
- return 0;
-
- vector<StrokeVertex*>::iterator sv=verticesToRemove.begin(), svend=verticesToRemove.end();
- for(;
- sv!=svend;
- ++sv)
- {
- stroke.RemoveVertex((*sv));
- }
-
- // Resample so that our new stroke have the same
- // number of vertices than before
- stroke.Resample(originalSize);
-
- if((int)stroke.strokeVerticesSize() != originalSize) //soc
- cerr << "Warning: resampling problem" << endl;
-
- // assign old attributes to new stroke vertices:
- v=stroke.strokeVerticesBegin(); vend=stroke.strokeVerticesEnd();
- vector<StrokeAttribute>::iterator a=oldAttributes.begin(), aend=oldAttributes.end();
- //cout << "-----------------------------------------------" << endl;
- for(;(v!=vend)&&(a!=aend);++v,++a)
- {
- v->setAttribute(*a);
- //cout << "thickness = " << (*a).getThickness()[0] << "-" << (*a).getThickness()[1] << endl;
- }
- // we're done!
+}
+
+/////////////////////////////////////////
+//
+// Tip Remover
+//
+/////////////////////////////////////////
+
+
+TipRemoverShader::TipRemoverShader(real tipLength) : StrokeShader()
+{
+ _tipLength = tipLength;
+}
+
+int TipRemoverShader::shade(Stroke& stroke) const
+{
+ int originalSize = stroke.strokeVerticesSize();
+
+ if (originalSize < 4)
+ return 0;
+
+ StrokeInternal::StrokeVertexIterator v, vend;
+ vector<StrokeVertex*> verticesToRemove;
+ vector<StrokeAttribute> oldAttributes;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ if ((v->curvilinearAbscissa() < _tipLength) || (v->strokeLength() - v->curvilinearAbscissa() < _tipLength)) {
+ verticesToRemove.push_back(&(*v));
+ }
+ oldAttributes.push_back(v->attribute());
+ }
+
+ if (originalSize - verticesToRemove.size() < 2)
+ return 0;
+
+ vector<StrokeVertex*>::iterator sv, svend;
+ for (sv = verticesToRemove.begin(), svend = verticesToRemove.end(); sv != svend; ++sv) {
+ stroke.RemoveVertex((*sv));
+ }
+
+ // Resample so that our new stroke have the same number of vertices than before
+ stroke.Resample(originalSize);
+
+ if ((int)stroke.strokeVerticesSize() != originalSize) //soc
+ cerr << "Warning: resampling problem" << endl;
+
+ // assign old attributes to new stroke vertices:
+ vector<StrokeAttribute>::iterator a = oldAttributes.begin(), aend = oldAttributes.end();
+ //cout << "-----------------------------------------------" << endl;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ (v != vend) && (a != aend);
+ ++v, ++a)
+ {
+ v->setAttribute(*a);
+ //cout << "thickness = " << (*a).getThickness()[0] << "-" << (*a).getThickness()[1] << endl;
+ }
+ // we're done!
return 0;
- }
+}
- int streamShader::shade(Stroke& stroke) const{
- cout << stroke << endl;
+int streamShader::shade(Stroke& stroke) const
+{
+ cout << stroke << endl;
return 0;
- }
- int fstreamShader::shade(Stroke& stroke) const{
- _stream << stroke << endl;
+}
+
+int fstreamShader::shade(Stroke& stroke) const
+{
+ _stream << stroke << endl;
return 0;
- }
+}
} // end of namespace StrokeShaders
-