diff options
5 files changed, 67 insertions, 28 deletions
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py index 6ab4184651a..ebd09bd0181 100644 --- a/release/scripts/freestyle/modules/parameter_editor.py +++ b/release/scripts/freestyle/modules/parameter_editor.py @@ -814,17 +814,14 @@ class FaceMarkOneUP1D(UnaryPredicate1D): class MaterialBoundaryUP0D(UnaryPredicate0D): def __call__(self, it): - if it.is_begin: + # can't use only it.is_end here, see commit rBeb8964fb7f19 + if it.is_begin or it.at_last or it.is_end: return False - it_prev = Interface0DIterator(it) - it_prev.decrement() - v = it.object - it.increment() - if it.is_end: - return False - fe = v.get_fedge(it_prev.object) + it.decrement() + prev, v, succ = next(it), next(it), next(it) + fe = v.get_fedge(prev) idx1 = fe.material_index if fe.is_smooth else fe.material_index_left - fe = v.get_fedge(it.object) + fe = v.get_fedge(succ) idx2 = fe.material_index if fe.is_smooth else fe.material_index_left return idx1 != idx2 diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp index faf99e90111..fca4c979bbb 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp @@ -120,19 +120,14 @@ static PyObject *Interface0DIterator_iternext(BPy_Interface0DIterator *self) self->if0D_it->decrement(); } else { - if (self->if0D_it->isEnd()) { + if (self->if0D_it->atLast() || self->if0D_it->isEnd()) { PyErr_SetNone(PyExc_StopIteration); return NULL; } if (self->at_start) self->at_start = false; - else { + else self->if0D_it->increment(); - if (self->if0D_it->isEnd()) { - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } - } } Interface0D *if0D = self->if0D_it->operator->(); return Any_BPy_Interface0D_from_Interface0D(*if0D); @@ -177,11 +172,24 @@ static PyObject *Interface0DIterator_u_get(BPy_Interface0DIterator *self, void * return PyFloat_FromDouble(self->if0D_it->u()); } +PyDoc_STRVAR(Interface0DIterator_at_last_doc, +"True if the interator points to the last valid element.\n" +"For its counterpart (pointing to the first valid element), use it.is_begin.\n" +"\n" +":type: bool"); + +static PyObject *Interface0DIterator_at_last_get(BPy_Interface0DIterator *self, void *UNUSED(closure)) +{ + return PyBool_from_bool(self->if0D_it->atLast()); +} + static PyGetSetDef BPy_Interface0DIterator_getseters[] = { {(char *)"object", (getter)Interface0DIterator_object_get, (setter)NULL, (char *)Interface0DIterator_object_doc, NULL}, {(char *)"t", (getter)Interface0DIterator_t_get, (setter)NULL, (char *)Interface0DIterator_t_doc, NULL}, {(char *)"u", (getter)Interface0DIterator_u_get, (setter)NULL, (char *)Interface0DIterator_u_doc, NULL}, + {(char *)"at_last", (getter)Interface0DIterator_at_last_get, (setter)NULL, + (char *)Interface0DIterator_at_last_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp index 2906f20be06..18d1b37eb3b 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp @@ -102,8 +102,8 @@ static PyObject *StrokeVertexIterator_iter(BPy_StrokeVertexIterator *self) static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) { /* Because Freestyle iterators for which it.isEnd() holds true have no valid object - * (referencing it.object in this case leads to a crash), we must check if it.object - * is valid after incrementing, to prevent crashes in Python. + * (they point to the past-the-end element and can't be dereferenced), we have to check + * iterators for validity. * Additionally, the at_start attribute is used to keep Freestyle iterator objects * and Python for loops in sync. */ @@ -115,7 +115,10 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) self->sv_it->decrement(); } else { - if (self->sv_it->isEnd()) { + /* if sv_it.isEnd() is true, the iterator can't be incremented. if sv_it.isLast() is true, + * the iterator is currently pointing to the final valid argument. Incrementing it further would + * give a python object that can't be dereferenced. */ + if (self->sv_it->atLast() || self->sv_it->isEnd()) { PyErr_SetNone(PyExc_StopIteration); return NULL; } @@ -123,15 +126,8 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) * and don't increment, to keep for-loops in sync */ if (self->at_start) self->at_start = false; - /* after incrementing, check if the iterator is at its end - * exit the loop if it is. not doing so will result in a crash */ - else { + else self->sv_it->increment(); - if (self->sv_it->isEnd()) { - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } - } } StrokeVertex *sv = self->sv_it->operator->(); return BPy_StrokeVertex_from_StrokeVertex(*sv); @@ -194,7 +190,7 @@ static PyObject *StrokeVertexIterator_reversed(BPy_StrokeVertexIterator *self) } static PyMethodDef BPy_StrokeVertexIterator_methods[] = { - {"incremented", (PyCFunction) StrokeVertexIterator_incremented, METH_NOARGS, StrokeVertexIterator_incremented_doc}, + {"incremented", (PyCFunction)StrokeVertexIterator_incremented, METH_NOARGS, StrokeVertexIterator_incremented_doc}, {"decremented", (PyCFunction)StrokeVertexIterator_decremented, METH_NOARGS, StrokeVertexIterator_decremented_doc}, {"reversed", (PyCFunction)StrokeVertexIterator_reversed, METH_NOARGS, StrokeVertexIterator_reversed_doc}, {NULL, NULL, 0, NULL} @@ -239,11 +235,25 @@ static PyObject *StrokeVertexIterator_u_get(BPy_StrokeVertexIterator *self, void return PyFloat_FromDouble(self->sv_it->u()); } +PyDoc_STRVAR(StrokeVertexIterator_at_last_doc, +"True if the interator points to the last valid element.\n" +"For its counterpart (pointing to the first valid element), use it.is_begin.\n" +"\n" +":type: bool"); + +static PyObject *StrokeVertexIterator_at_last_get(BPy_StrokeVertexIterator *self) +{ + return PyBool_from_bool(self->sv_it->atLast()); + +} + static PyGetSetDef BPy_StrokeVertexIterator_getseters[] = { {(char *)"object", (getter)StrokeVertexIterator_object_get, (setter)NULL, (char *)StrokeVertexIterator_object_doc, NULL}, {(char *)"t", (getter)StrokeVertexIterator_t_get, (setter)NULL, (char *)StrokeVertexIterator_t_doc, NULL}, {(char *)"u", (getter)StrokeVertexIterator_u_get, (setter)NULL, (char *)StrokeVertexIterator_u_doc, NULL}, + {(char *)"at_last", (getter)StrokeVertexIterator_at_last_get, (setter)NULL, + (char *)StrokeVertexIterator_at_last_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/source/blender/freestyle/intern/stroke/StrokeIterators.h b/source/blender/freestyle/intern/stroke/StrokeIterators.h index a8ec529fbfa..1df9aa2794a 100644 --- a/source/blender/freestyle/intern/stroke/StrokeIterators.h +++ b/source/blender/freestyle/intern/stroke/StrokeIterators.h @@ -171,6 +171,18 @@ public: return _it == _begin; } + /*! Returns true if the pointed StrokeVertex is the final valid StrokeVertex of the Stroke. */ + bool atLast() + { + if (_it == _end) + return false; + + ++_it; + bool result = (_it == _end); + --_it; + return result; + } + /*! Returns true if the pointed StrokeVertex is after the last StrokeVertex of the Stroke. */ bool isEnd() const { diff --git a/source/blender/freestyle/intern/view_map/Interface0D.h b/source/blender/freestyle/intern/view_map/Interface0D.h index 123253bf3e1..da71d7ad949 100644 --- a/source/blender/freestyle/intern/view_map/Interface0D.h +++ b/source/blender/freestyle/intern/view_map/Interface0D.h @@ -302,6 +302,18 @@ public: return _iterator->isEnd(); } + /*! Returns true when the iterator is pointing to the final valid element. */ + virtual bool atLast() const + { + if (_iterator->isEnd()) + return false; + + _iterator->increment(); + bool result = _iterator->isEnd(); + _iterator->decrement(); + return result; + } + /*! operator == . */ bool operator==(const Interface0DIterator& it) const { |