Blender V5.0
Stroke.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9
10#include "Stroke.h"
12#include "StrokeIterators.h"
13#include "StrokeRenderer.h"
14
15#include "BKE_global.hh"
16#include "BKE_node.hh"
17
18namespace Freestyle {
19
20/**********************************/
21/* */
22/* */
23/* StrokeAttribute */
24/* */
25/* */
26/**********************************/
27
29{
30 int i;
31 _alpha = 1.0f;
32 _thickness[0] = 1.0f;
33 _thickness[1] = 1.0f;
34 for (i = 0; i < 3; ++i) {
35 _color[i] = 0.2f;
36 }
37 _color[0] = 0.8f;
38 _userAttributesReal = nullptr;
39 _userAttributesVec2f = nullptr;
40 _userAttributesVec3f = nullptr;
41 _visible = true;
42}
43
45{
46 _alpha = iBrother._alpha;
47 _thickness[0] = iBrother._thickness[0];
48 _thickness[1] = iBrother._thickness[1];
49 for (int i = 0; i < 3; ++i) {
50 _color[i] = iBrother._color[i];
51 }
52 _visible = iBrother._visible;
53 if (iBrother._userAttributesReal) {
54 _userAttributesReal = new realMap(*iBrother._userAttributesReal);
55 }
56 else {
57 _userAttributesReal = nullptr;
58 }
59 if (iBrother._userAttributesVec2f) {
60 _userAttributesVec2f = new Vec2fMap(*iBrother._userAttributesVec2f);
61 }
62 else {
63 _userAttributesVec2f = nullptr;
64 }
65 if (iBrother._userAttributesVec3f) {
66 _userAttributesVec3f = new Vec3fMap(*iBrother._userAttributesVec3f);
67 }
68 else {
69 _userAttributesVec3f = nullptr;
70 }
71}
72
74 float iGColor,
75 float iBColor,
76 float iAlpha,
77 float iRThickness,
78 float iLThickness)
79{
80 _color[0] = iRColor;
81 _color[1] = iGColor;
82 _color[2] = iBColor;
83
84 _alpha = iAlpha;
85
86 _thickness[0] = iRThickness;
87 _thickness[1] = iLThickness;
88
89 _visible = true;
90
91 _userAttributesReal = nullptr;
92 _userAttributesVec2f = nullptr;
93 _userAttributesVec3f = nullptr;
94}
95
97{
98 _alpha = (1 - t) * a1._alpha + t * a2._alpha;
99 _thickness[0] = (1 - t) * a1._thickness[0] + t * a2._thickness[0];
100 _thickness[1] = (1 - t) * a1._thickness[1] + t * a2._thickness[1];
101 for (int i = 0; i < 3; ++i) {
102 _color[i] = (1 - t) * a1._color[i] + t * a2._color[i];
103 }
104
105 _visible = a1.isVisible();
106
107 // FIXME: to be checked (and enhanced)
108 if ((a1._userAttributesReal) && (a2._userAttributesReal)) {
109 if (a1._userAttributesReal->size() == a2._userAttributesReal->size()) {
110 _userAttributesReal = new realMap;
111 realMap::iterator it1 = a1._userAttributesReal->begin(),
112 it1end = a1._userAttributesReal->end();
113 realMap::iterator it2 = a2._userAttributesReal->begin();
114 for (; it1 != it1end; ++it1, ++it2) {
115 (*_userAttributesReal)[(*it1).first] = ((1 - t) * (*it1).second + t * (*it2).second);
116 }
117 }
118 }
119 else {
120 _userAttributesReal = nullptr;
121 }
122 if ((a1._userAttributesVec2f) && (a2._userAttributesVec2f)) {
123 if (a1._userAttributesVec2f->size() == a2._userAttributesVec2f->size()) {
124 _userAttributesVec2f = new Vec2fMap;
125 Vec2fMap::iterator it1 = a1._userAttributesVec2f->begin(),
126 it1end = a1._userAttributesVec2f->end();
127 Vec2fMap::iterator it2 = a2._userAttributesVec2f->begin();
128 for (; it1 != it1end; ++it1, ++it2) {
129 (*_userAttributesVec2f)[(*it1).first] = ((1 - t) * (*it1).second + t * (*it2).second);
130 }
131 }
132 }
133 else {
134 _userAttributesVec2f = nullptr;
135 }
136 if ((a1._userAttributesVec3f) && (a2._userAttributesVec3f)) {
137 if (a1._userAttributesVec3f->size() == a2._userAttributesVec3f->size()) {
138 _userAttributesVec3f = new Vec3fMap;
139 Vec3fMap::iterator it1 = a1._userAttributesVec3f->begin(),
140 it1end = a1._userAttributesVec3f->end();
141 Vec3fMap::iterator it2 = a2._userAttributesVec3f->begin();
142 for (; it1 != it1end; ++it1, ++it2) {
143 (*_userAttributesVec3f)[(*it1).first] = ((1 - t) * (*it1).second + t * (*it2).second);
144 }
145 }
146 }
147 else {
148 _userAttributesVec3f = nullptr;
149 }
150}
151
153{
154 if (_userAttributesReal) {
155 _userAttributesReal->clear();
156 delete _userAttributesReal;
157 }
158 if (_userAttributesVec2f) {
159 _userAttributesVec2f->clear();
160 delete _userAttributesVec2f;
161 }
162 if (_userAttributesVec3f) {
163 _userAttributesVec3f->clear();
164 delete _userAttributesVec3f;
165 }
166}
167
169{
170 int i;
171 _alpha = iBrother._alpha;
172 _thickness[0] = iBrother._thickness[0];
173 _thickness[1] = iBrother._thickness[1];
174 for (i = 0; i < 3; ++i) {
175 _color[i] = iBrother._color[i];
176 }
177 _visible = iBrother._visible;
178 if (iBrother._userAttributesReal) {
179 if (!_userAttributesReal) {
180 _userAttributesReal = new realMap;
181 }
182 _userAttributesReal = new realMap(*(iBrother._userAttributesReal));
183 }
184 else {
185 _userAttributesReal = nullptr;
186 }
187 if (iBrother._userAttributesVec2f) {
188 if (!_userAttributesVec2f) {
189 _userAttributesVec2f = new Vec2fMap;
190 }
191 _userAttributesVec2f = new Vec2fMap(*(iBrother._userAttributesVec2f));
192 }
193 else {
194 _userAttributesVec2f = nullptr;
195 }
196 if (iBrother._userAttributesVec3f) {
197 if (!_userAttributesVec3f) {
198 _userAttributesVec3f = new Vec3fMap;
199 }
200 _userAttributesVec3f = new Vec3fMap(*(iBrother._userAttributesVec3f));
201 }
202 else {
203 _userAttributesVec3f = nullptr;
204 }
205 return *this;
206}
207
208float StrokeAttribute::getAttributeReal(const char *iName) const
209{
210 if (!_userAttributesReal) {
211 if (G.debug & G_DEBUG_FREESTYLE) {
212 cout << "StrokeAttribute warning: no real attribute was defined" << endl;
213 }
214 return 0.0f;
215 }
216 realMap::iterator a = _userAttributesReal->find(iName);
217 if (a == _userAttributesReal->end()) {
218 if (G.debug & G_DEBUG_FREESTYLE) {
219 cout << "StrokeAttribute warning: no real attribute was added with the name " << iName
220 << endl;
221 }
222 return 0.0f;
223 }
224 return (*a).second;
225}
226
228{
229 if (!_userAttributesVec2f) {
230 if (G.debug & G_DEBUG_FREESTYLE) {
231 cout << "StrokeAttribute warning: no Vec2f attribute was defined" << endl;
232 }
233 return 0;
234 }
235 Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
236 if (a == _userAttributesVec2f->end()) {
237 if (G.debug & G_DEBUG_FREESTYLE) {
238 cout << "StrokeAttribute warning: no Vec2f attribute was added with the name " << iName
239 << endl;
240 }
241 return 0;
242 }
243 return (*a).second;
244}
245
247{
248 if (!_userAttributesVec3f) {
249 if (G.debug & G_DEBUG_FREESTYLE) {
250 cout << "StrokeAttribute warning: no Vec3f attribute was defined" << endl;
251 }
252 return 0;
253 }
254 Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
255 if (a == _userAttributesVec3f->end()) {
256 if (G.debug & G_DEBUG_FREESTYLE) {
257 cout << "StrokeAttribute warning: no Vec3f attribute was added with the name " << iName
258 << endl;
259 }
260 return 0;
261 }
262 return (*a).second;
263}
264
265bool StrokeAttribute::isAttributeAvailableReal(const char *iName) const
266{
267 if (!_userAttributesReal) {
268 return false;
269 }
270 realMap::iterator a = _userAttributesReal->find(iName);
271 if (a == _userAttributesReal->end()) {
272 return false;
273 }
274 return true;
275}
276
278{
279 if (!_userAttributesVec2f) {
280 return false;
281 }
282 Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
283 if (a == _userAttributesVec2f->end()) {
284 return false;
285 }
286 return true;
287}
288
290{
291 if (!_userAttributesVec3f) {
292 return false;
293 }
294 Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
295 if (a == _userAttributesVec3f->end()) {
296 return false;
297 }
298 return true;
299}
300
301void StrokeAttribute::setAttributeReal(const char *iName, float att)
302{
303 if (!_userAttributesReal) {
304 _userAttributesReal = new realMap;
305 }
306 (*_userAttributesReal)[iName] = att;
307}
308
309void StrokeAttribute::setAttributeVec2f(const char *iName, const Vec2f &att)
310{
311 if (!_userAttributesVec2f) {
312 _userAttributesVec2f = new Vec2fMap;
313 }
314 (*_userAttributesVec2f)[iName] = att;
315}
316
317void StrokeAttribute::setAttributeVec3f(const char *iName, const Vec3f &att)
318{
319 if (!_userAttributesVec3f) {
320 _userAttributesVec3f = new Vec3fMap;
321 }
322 (*_userAttributesVec3f)[iName] = att;
323}
324
325/**********************************/
326/* */
327/* */
328/* StrokeVertex */
329/* */
330/* */
331/**********************************/
332
334{
335 _CurvilignAbscissa = 0.0f;
336 _StrokeLength = 0.0f;
337}
338
340{
341 _Attribute = iBrother._Attribute;
342 _CurvilignAbscissa = 0.0f;
343 _StrokeLength = 0.0f;
344}
345
347{
348 _CurvilignAbscissa = 0.0f;
349 _StrokeLength = 0.0f;
350}
351
353{
354 _CurvilignAbscissa = 0.0f;
355 _StrokeLength = 0.0f;
356}
357
359{
360 // interpolate attributes:
361 _Attribute = StrokeAttribute(iA->attribute(), iB->attribute(), t3);
362 _CurvilignAbscissa = (1 - t3) * iA->curvilinearAbscissa() + t3 * iB->curvilinearAbscissa();
363 _StrokeLength = iA->strokeLength();
364}
365
367 : CurvePoint(iSVertex, nullptr, 0.0f)
368{
369 _Attribute = iAttribute;
370 _CurvilignAbscissa = 0.0f;
371 _StrokeLength = 0.0f;
372}
373
375{
376 ((CurvePoint *)this)->operator=(iBrother);
377 _Attribute = iBrother._Attribute;
378
379 _CurvilignAbscissa = 0.0f;
380
381 _StrokeLength = 0.0f;
382 return *this;
383}
384
385/**********************************/
386/* */
387/* */
388/* Stroke */
389/* */
390/* */
391/**********************************/
392
394{
395 _Length = 0;
396 _id = 0;
397 _sampling = FLT_MAX;
398 //_mediumType = DEFAULT_STROKE;
399 _mediumType = OPAQUE_MEDIUM;
400 _textureId = 0;
401 _textureStep = 1.0;
402 for (int a = 0; a < MAX_MTEX; a++) {
403 _mtex[a] = nullptr;
404 }
405 _nodeTree = nullptr;
406 _tips = false;
407 _rep = nullptr;
408}
409
410Stroke::Stroke(const Stroke &iBrother) : Interface1D(iBrother)
411{
412 for (vertex_container::const_iterator v = iBrother._Vertices.begin(),
413 vend = iBrother._Vertices.end();
414 v != vend;
415 v++)
416 {
417 _Vertices.push_back(*v);
418 }
419 _Length = 0;
420 _id = iBrother._id;
421 _ViewEdges = iBrother._ViewEdges;
422 _sampling = iBrother._sampling;
423 _mediumType = iBrother._mediumType;
424 _textureId = iBrother._textureId;
425 _textureStep = iBrother._textureStep;
426 for (int a = 0; a < MAX_MTEX; a++) {
427 _mtex[a] = iBrother._mtex[a];
428 }
429 _nodeTree = iBrother._nodeTree;
430 _tips = iBrother._tips;
431 if (iBrother._rep) {
432 _rep = new StrokeRep(*(iBrother._rep));
433 }
434 else {
435 _rep = nullptr;
436 }
437}
438
440{
441 if (!_Vertices.empty()) {
442 for (vertex_container::iterator v = _Vertices.begin(), vend = _Vertices.end(); v != vend; v++)
443 {
444 delete (*v);
445 }
446 _Vertices.clear();
447 }
448
449 _ViewEdges.clear();
450 if (_rep) {
451 delete _rep;
452 _rep = nullptr;
453 }
454}
455
457{
458 if (!_Vertices.empty()) {
459 _Vertices.clear();
460 }
461
462 for (vertex_container::const_iterator v = iBrother._Vertices.begin(),
463 vend = iBrother._Vertices.end();
464 v != vend;
465 v++)
466 {
467 _Vertices.push_back(*v);
468 }
469 _Length = iBrother._Length;
470 _id = iBrother._id;
471 _ViewEdges = iBrother._ViewEdges;
472 _sampling = iBrother._sampling;
473 delete _rep;
474 if (iBrother._rep) {
475 _rep = new StrokeRep(*(iBrother._rep));
476 }
477 else {
478 _rep = nullptr;
479 }
480 return *this;
481}
482
483void Stroke::setLength(float iLength)
484{
485 _Length = iLength;
486 for (vertex_container::iterator v = _Vertices.begin(), vend = _Vertices.end(); v != vend; ++v) {
487 (*v)->setStrokeLength(iLength);
488 }
489}
490
491float Stroke::ComputeSampling(int iNVertices)
492{
493 if (iNVertices <= int(_Vertices.size())) { // soc
494 return _sampling;
495 }
496
497 float sampling = _Length / float(iNVertices - _Vertices.size() + 1);
498 return sampling;
499}
500
502 public:
505 float _length;
506 int _n;
509
512 float ilength,
513 int in,
514 float isampling)
515 {
516 _begin = ibegin;
517 _end = iend;
518 _length = ilength;
519 _n = in;
520 _sampling = isampling;
521 _resampled = false;
522 }
523};
524
525int Stroke::Resample(int iNPoints)
526{
527 int NPointsToAdd = iNPoints - strokeVerticesSize();
528 if (NPointsToAdd <= 0) {
529 return 0;
530 }
531
534 ++next;
536
537 vertex_container newVertices;
538 real t = 0.0f;
539 StrokeVertex *newVertex = nullptr;
540 vector<StrokeSegment> strokeSegments;
541 int N = 0;
542 float meanlength = 0;
543 int nsegments = 0;
544 while ((it != itend) && (next != itend)) {
545 Vec2r a((it)->getPoint());
546 Vec2r b((next)->getPoint());
547 Vec2r vec_tmp(b - a);
548 real norm_var = vec_tmp.norm();
549 int numberOfPointsToAdd = int(floor(NPointsToAdd * norm_var / _Length));
550 float csampling = norm_var / float(numberOfPointsToAdd + 1);
551 strokeSegments.emplace_back(it, next, norm_var, numberOfPointsToAdd, csampling);
552 N += numberOfPointsToAdd;
553 meanlength += norm_var;
554 ++nsegments;
555 ++it;
556 ++next;
557 }
558 meanlength /= float(nsegments);
559
560 // if we don't have enough points let's resample finer some segments
561 bool checkEveryone = false;
562 bool resampled;
563 while (N < NPointsToAdd) {
564 resampled = false;
565 for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end();
566 s != send;
567 ++s)
568 {
569 if (s->_sampling == 0.0f) {
570 continue;
571 }
572
573 if (s->_resampled == false) {
574 if ((!checkEveryone) && (s->_length < meanlength)) {
575 continue;
576 }
577 // resample
578 s->_n = s->_n + 1;
579 s->_sampling = s->_length / float(s->_n + 1);
580 s->_resampled = resampled = true;
581 N++;
582 if (N == NPointsToAdd) {
583 break;
584 }
585 }
586 }
587 if (checkEveryone && !resampled) {
588 break;
589 }
590 checkEveryone = true;
591 }
592 if (N < NPointsToAdd) {
593 // fatal error, likely because _Length is inconsistent with the stroke length computed with the
594 // vertices
595 return -1;
596 }
597 // actually resample:
598 for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end();
599 s != send;
600 ++s)
601 {
602 newVertices.push_back(&*(s->_begin));
603 if (s->_sampling < _sampling) {
604 _sampling = s->_sampling;
605 }
606
607 t = s->_sampling / s->_length;
608 for (int i = 0; i < s->_n; ++i) {
609 newVertex = new StrokeVertex(&*(s->_begin), &*(s->_end), t);
610 newVertices.push_back(newVertex);
611 t += s->_sampling / s->_length;
612 }
613 it = s->_begin;
614 next = s->_end;
615 }
616
617 // add last:
618 ++it;
619 ++next;
620 if ((it != itend) && (next == itend) /* && (t == 0.0f) */) {
621 newVertices.push_back(&(*it));
622 }
623
624 int newsize = newVertices.size();
625 if (newsize != iNPoints) {
626 cerr << "Warning: incorrect points number" << endl;
627 }
628
629 _Vertices.clear();
630 _Vertices = newVertices;
631 newVertices.clear();
632
633 return 0;
634}
635
636int Stroke::Resample(float iSampling)
637{
638 // cerr << "old size :" << strokeVerticesSize() << endl;
639 if (iSampling == 0) {
640 return 0;
641 }
642 if (iSampling >= _sampling) {
643 return 0;
644 }
645
646 _sampling = iSampling;
647 // Resample...
648 // real curvilinearLength = 0.0f;
649 vertex_container newVertices;
650 real t = 0.0f;
651 const real limit = 0.99;
652 StrokeVertex *newVertex = nullptr;
655 ++next;
657 while ((it != itend) && (next != itend)) {
658 newVertices.push_back(&(*it));
659 Vec2r a((it)->getPoint());
660 Vec2r b((next)->getPoint());
661 Vec2r vec_tmp(b - a);
662 real norm_var = vec_tmp.norm();
663 if (norm_var <= _sampling) {
664 // curvilinearLength += norm_var;
665 ++it;
666 ++next;
667 continue;
668 }
669
670 // curvilinearLength += _sampling;
671 t = _sampling / norm_var;
672 while (t < limit) {
673 newVertex = new StrokeVertex(&(*it), &(*next), t);
674 // newVertex->setCurvilinearAbscissa(curvilinearLength);
675 newVertices.push_back(newVertex);
676 t = t + _sampling / norm_var;
677 }
678 ++it;
679 ++next;
680 }
681 // add last:
682 if ((it != itend) && (next == itend) /* && (t == 0.0f) */) {
683 newVertices.push_back(&(*it));
684 }
685
686 _Vertices.clear();
687 _Vertices = newVertices;
688 newVertices.clear();
689
690 return 0;
691}
692
694{
695 vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end();
696 for (; it != itend; ++it) {
697 delete (*it);
698 }
699 _Vertices.clear();
700 UpdateLength();
701}
702
704{
705 vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end();
706 for (; it != itend; ++it) {
707 if ((*it) == iVertex) {
708 delete iVertex;
709 it = _Vertices.erase(it); // it is now the element just after the erased element
710 break;
711 }
712 }
713 UpdateLength();
714}
715
717{
718 vertex_container::iterator itnext = next.getIt();
719 _Vertices.insert(itnext, iVertex);
720 UpdateLength();
721}
722
724{
725 // recompute curvilinear abscissa and stroke length
726 float curvabsc = 0.0f;
727 vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end();
728 vertex_container::iterator previous = it;
729 for (; it != itend; ++it) {
730 curvabsc += ((*it)->getPoint() - (*previous)->getPoint()).norm();
731 (*it)->setCurvilinearAbscissa(curvabsc);
732 previous = it;
733 }
734 _Length = curvabsc;
735 for (it = _Vertices.begin(); it != itend; ++it) {
736 (*it)->setStrokeLength(_Length);
737 }
738}
739
742{
743 return const_vertex_iterator(_Vertices.begin(), _Vertices.begin(), _Vertices.end());
744}
745
747{
748 return const_vertex_iterator(_Vertices.end(), _Vertices.begin(), _Vertices.end());
749}
750
752{
753 return vertex_iterator(_Vertices.end(), _Vertices.begin(), _Vertices.end());
754}
755
757{
758 if ((t != 0) && (t < _sampling)) {
759 Resample(t);
760 }
762 this->_Vertices.begin(), this->_Vertices.begin(), this->_Vertices.end());
763}
764
766{
768 this->_Vertices.end(), this->_Vertices.begin(), this->_Vertices.end());
769}
770
772{
774 this->_Vertices.begin(), this->_Vertices.begin(), this->_Vertices.end()));
775 return ret;
776}
777
779{
781 this->_Vertices.end(), this->_Vertices.begin(), this->_Vertices.end()));
782 return ret;
783}
784
786{
787 return verticesBegin(); // FIXME
788}
789
791{
792 return verticesEnd();
793}
794
795void Stroke::ScaleThickness(float iFactor)
796{
797 for (vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end(); it != itend;
798 ++it)
799 {
800 StrokeAttribute &attr = (*it)->attribute();
801 attr.setThickness(iFactor * attr.getThicknessR(), iFactor * attr.getThicknessL());
802 }
803}
804
805void Stroke::Render(const StrokeRenderer *iRenderer)
806{
807 if (!_rep) {
808 _rep = new StrokeRep(this);
809 }
810 iRenderer->RenderStrokeRep(_rep);
811}
812
814{
815 if (!_rep) {
816 _rep = new StrokeRep(this);
817 }
818 iRenderer->RenderStrokeRep(_rep);
819}
820
822{
823 // Resample if necessary
824 if ((sampling != 0) && (sampling < _sampling)) {
825 Resample(sampling);
826 }
827 return vertex_iterator(_Vertices.begin(), _Vertices.begin(), _Vertices.end());
828 // return _Vertices.begin();
829}
830
831#if 0
832Stroke::vertex_iterator Stroke::vertices_last()
833{
835 vertex_iterator next = res;
836 ++next;
837 while (!next.end()) {
838 ++next;
839 ++res;
840 }
841 return res;
842}
843
844Stroke::const_vertex_iterator Stroke::vertices_last() const
845{
848 ++next;
849 while (!next.end()) {
850 ++next;
851 ++res;
852 }
853 return res;
854}
855
856Stroke::vertex_container::reverse_iterator Stroke::vertices_last(float sampling)
857{
858 // Resample if necessary
859 if (sampling < _sampling) {
860 Resample(sampling);
861 }
862 return _Vertices.rbegin();
863}
864
865inline Vec3r shaded_color(int iCombination = 0) const;
866
867inline Vec<3, real> Stroke::orientation2d(const_vertex_iterator it) const
868{
869 return iterator_edge_orientation2d_function<Stroke, const_vertex_iterator>(this, it);
870}
871
872Vec3r Stroke::orientation2d(int iCombination) const
873{
874 return edge_orientation2d_function<Stroke>(*this, iCombination);
875}
876
877inline Vec3r Stroke::orientation3d(const_vertex_iterator it) const
878{
879 return iterator_edge_orientation3d_function<Stroke, const_vertex_iterator>(*this, it);
880}
881
882Vec3r Stroke::orientation3d(int iCombination) const
883{
884 return edge_orientation3d_function<Stroke>(*this, iCombination);
885}
886
887Material Stroke::material() const
888{
890 Material mat = (*v)->material();
891 for (; v != vend; ++v) {
892 if (mat != (*v)->material()) {
894 }
895 }
896 return mat;
897}
898
899int Stroke::qi() const
900{
902 int qi_ = (*v)->qi();
903 for (; v != vend; ++v) {
904 if ((*v)->qi() != qi_) {
906 }
907 }
908 return qi_;
909}
910
911inline occluder_container::const_iterator occluders_begin() const
912{
913 return _FEdgeA->occluders().begin();
914}
915
916inline occluder_container::const_iterator occluders_end() const
917{
918 return _FEdgeA->occluders().end();
919}
920
921int Stroke::occluders_size() const
922{
923 return qi();
924}
925
926bool Stroke::occluders_empty() const
927{
929 bool empty = (*v)->occluders_empty();
930 for (; v != vend; ++v) {
931 if ((*v)->occluders_empty() != empty) {
933 }
934 }
935 return empty;
936}
937
938# if 0
939inline const polygon3d &occludee() const
940{
941 return *(_FEdgeA->aFace());
942}
943# endif
944
945const SShape *Stroke::occluded_shape() const
946{
948 const SShape *sshape = (*v)->occluded_shape();
949 for (; v != vend; ++v) {
950 if ((*v)->occluded_shape() != sshape) {
952 }
953 }
954 return sshape;
955}
956
957const bool Stroke::occludee_empty() const
958{
960 bool empty = (*v)->occludee_empty();
961 for (; v != vend; ++v) {
962 if ((*v)->occludee_empty() != empty) {
964 }
965 }
966 return empty;
967}
968
969const SShape *Stroke::shape() const
970{
972 const SShape *sshape = (*v)->shape();
973 for (; v != vend; ++v) {
974 if ((*v)->shape() != sshape) {
976 }
977 }
978 return sshape;
979}
980
981real Stroke::z_discontinuity(int iCombination) const
982{
983 return z_discontinuity_edge_function<Stroke>(*this, iCombination);
984}
985
986Vec3r Stroke::curvature2d_as_vector(int iCombination) const
987{
988 return curvature2d_as_vector_edge_function<Stroke>(*this, iCombination);
989}
990
991real Stroke::curvature2d_as_angle(int iCombination) const
992{
993 return curvature2d_as_angle_edge_function<Stroke>(*this, iCombination);
994}
995
996float Stroke::shape_importance(int iCombination) const
997{
998 return shape_importance_edge_function<Stroke>(*this, iCombination);
999}
1000
1001float Stroke::local_average_depth(int iCombination) const
1002{
1003 return local_average_depth_edge_function<Stroke>(*this, iCombination);
1004}
1005
1006float Stroke::local_depth_variance(int iCombination) const
1007{
1008 return local_depth_variance_edge_function<Stroke>(*this, iCombination);
1009}
1010
1011real Stroke::local_average_density(float sigma, int iCombination) const
1012{
1013 return density_edge_function<Stroke>(*this, iCombination);
1014}
1015#endif
1016
1017} /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
struct Material Material
Iterators used to iterate over the elements of the Stroke. Can't be used in python.
Iterators used to iterate over the elements of the Stroke.
Classes to render a stroke with OpenGL.
Classes to define a stroke.
#define MAX_MTEX
Definition Stroke.h:31
ATTR_WARN_UNUSED_RESULT const BMVert * v
static int raiseException(exception_type exception=UNDEFINED)
Definition Exception.h:30
bool isAttributeAvailableVec3f(const char *iName) const
Definition Stroke.cpp:289
void setThickness(float tr, float tl)
Definition Stroke.h:233
Vec3f getAttributeVec3f(const char *iName) const
Definition Stroke.cpp:246
void setAttributeReal(const char *iName, float att)
Definition Stroke.cpp:301
void setAttributeVec3f(const char *iName, const Vec3f &att)
Definition Stroke.cpp:317
float getThicknessR() const
Definition Stroke.h:140
bool isVisible() const
Definition Stroke.h:159
float getThicknessL() const
Definition Stroke.h:146
bool isAttributeAvailableVec2f(const char *iName) const
Definition Stroke.cpp:277
Vec2f getAttributeVec2f(const char *iName) const
Definition Stroke.cpp:227
void setAttributeVec2f(const char *iName, const Vec2f &att)
Definition Stroke.cpp:309
StrokeAttribute & operator=(const StrokeAttribute &iBrother)
Definition Stroke.cpp:168
bool isAttributeAvailableReal(const char *iName) const
Definition Stroke.cpp:265
float getAttributeReal(const char *iName) const
Definition Stroke.cpp:208
virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const =0
StrokeInternal::StrokeVertexIterator _end
Definition Stroke.cpp:504
StrokeSegment(StrokeInternal::StrokeVertexIterator ibegin, StrokeInternal::StrokeVertexIterator iend, float ilength, int in, float isampling)
Definition Stroke.cpp:510
StrokeInternal::StrokeVertexIterator _begin
Definition Stroke.cpp:503
float curvilinearAbscissa() const
Definition Stroke.h:384
float strokeLength() const
Definition Stroke.h:390
const StrokeAttribute & attribute() const
Definition Stroke.h:372
StrokeVertex & operator=(const StrokeVertex &iBrother)
Definition Stroke.cpp:374
virtual Interface0DIterator pointsEnd(float t=0.0f)
Definition Stroke.cpp:790
const_vertex_iterator vertices_begin() const
embedding vertex iterator
Definition Stroke.cpp:741
void ScaleThickness(float iFactor)
Definition Stroke.cpp:795
virtual Interface0DIterator verticesBegin()
Definition Stroke.cpp:771
StrokeInternal::vertex_iterator_base< StrokeInternal::vertex_nonconst_traits > vertex_iterator
Definition Stroke.h:510
StrokeInternal::vertex_iterator_base< StrokeInternal::vertex_const_traits > const_vertex_iterator
Definition Stroke.h:512
void RemoveAllVertices()
Definition Stroke.cpp:693
virtual ~Stroke()
Definition Stroke.cpp:439
void RemoveVertex(StrokeVertex *iVertex)
Definition Stroke.cpp:703
void InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next)
Definition Stroke.cpp:716
const_vertex_iterator vertices_end() const
Definition Stroke.cpp:746
std::deque< StrokeVertex * > vertex_container
Definition Stroke.h:507
virtual Interface0DIterator verticesEnd()
Definition Stroke.cpp:778
void UpdateLength()
Definition Stroke.cpp:723
void Render(const StrokeRenderer *iRenderer)
Definition Stroke.cpp:805
uint strokeVerticesSize() const
Definition Stroke.h:833
virtual Interface0DIterator pointsBegin(float t=0.0f)
Definition Stroke.cpp:785
void RenderBasic(const StrokeRenderer *iRenderer)
Definition Stroke.cpp:813
Stroke & operator=(const Stroke &iBrother)
Definition Stroke.cpp:456
void setLength(float iLength)
Definition Stroke.cpp:483
float ComputeSampling(int iNVertices)
Definition Stroke.cpp:491
StrokeInternal::StrokeVertexIterator strokeVerticesEnd()
Definition Stroke.cpp:765
StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t=0.0f)
Definition Stroke.cpp:756
int Resample(int iNPoints)
Definition Stroke.cpp:525
value_type norm() const
Definition VecMat.h:92
nullptr float
#define in
#define floor
static ulong * next
#define N
#define G(x, y, z)
VecMat::Vec3< float > Vec3f
Definition Geom.h:28
VecMat::Vec2< real > Vec2r
Definition Geom.h:24
VecMat::Vec2< float > Vec2f
Definition Geom.h:22
VecMat::Vec3< real > Vec3r
Definition Geom.h:30
inherits from class Rep
Definition AppCanvas.cpp:20
static uint a[3]
Definition RandGen.cpp:82
double real
Definition Precision.h:14
return ret
#define FLT_MAX
Definition stdcycles.h:14
i
Definition text_draw.cc:230