Freestyle: Fix for a potential infinite loop in stroke resampling by vertex count.
Changes were made in Stroke::Resample(int) in C++ to prevent a potential infinite loop caused by an inconsistency between Stroke::_Length and the stroke length computed based on stroke vertices. Such a stroke length inconsistency is usually caused by missing calls of Stroke::UpdateLength() (i.e., API implementation bugs), but also may occur due to scripting errors in user-defined style modules. This commit is meant to help script writters to identify the latter error cases. Now Stroke.resample(int) may raise a runtime error to signal an error condition.
This commit is contained in:
@@ -151,10 +151,16 @@ static PyObject *Stroke_resample(BPy_Stroke *self, PyObject *args, PyObject *kwd
|
|||||||
float f;
|
float f;
|
||||||
|
|
||||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "i", (char **)kwlist_1, &i)) {
|
if (PyArg_ParseTupleAndKeywords(args, kwds, "i", (char **)kwlist_1, &i)) {
|
||||||
self->s->Resample(i);
|
if (self->s->Resample(i) < 0) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex count) failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (PyErr_Clear(), PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &f)) {
|
else if (PyErr_Clear(), PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &f)) {
|
||||||
self->s->Resample(f);
|
if (self->s->Resample(f) < 0) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex interval) failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyErr_SetString(PyExc_TypeError, "invalid argument");
|
PyErr_SetString(PyExc_TypeError, "invalid argument");
|
||||||
|
|||||||
@@ -508,11 +508,11 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void Stroke::Resample(int iNPoints)
|
int Stroke::Resample(int iNPoints)
|
||||||
{
|
{
|
||||||
int vertsize = strokeVerticesSize();
|
int NPointsToAdd = iNPoints - strokeVerticesSize();
|
||||||
if (iNPoints <= vertsize)
|
if (NPointsToAdd <= 0)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
|
StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
|
||||||
StrokeInternal::StrokeVertexIterator next = it;
|
StrokeInternal::StrokeVertexIterator next = it;
|
||||||
@@ -531,7 +531,7 @@ void Stroke::Resample(int iNPoints)
|
|||||||
Vec2r b((next)->getPoint());
|
Vec2r b((next)->getPoint());
|
||||||
Vec2r vec_tmp(b - a);
|
Vec2r vec_tmp(b - a);
|
||||||
real norm_var = vec_tmp.norm();
|
real norm_var = vec_tmp.norm();
|
||||||
int numberOfPointsToAdd = (int)floor((iNPoints - strokeVerticesSize()) * norm_var / _Length);
|
int numberOfPointsToAdd = (int)floor(NPointsToAdd * norm_var / _Length);
|
||||||
float csampling = norm_var / (float)(numberOfPointsToAdd + 1);
|
float csampling = norm_var / (float)(numberOfPointsToAdd + 1);
|
||||||
strokeSegments.push_back(StrokeSegment(it, next, norm_var, numberOfPointsToAdd, csampling));
|
strokeSegments.push_back(StrokeSegment(it, next, norm_var, numberOfPointsToAdd, csampling));
|
||||||
N += numberOfPointsToAdd;
|
N += numberOfPointsToAdd;
|
||||||
@@ -543,9 +543,10 @@ void Stroke::Resample(int iNPoints)
|
|||||||
meanlength /= (float)nsegments;
|
meanlength /= (float)nsegments;
|
||||||
|
|
||||||
// if we don't have enough points let's resample finer some segments
|
// if we don't have enough points let's resample finer some segments
|
||||||
int NPointsToAdd = iNPoints - vertsize;
|
|
||||||
bool checkEveryone = false;
|
bool checkEveryone = false;
|
||||||
|
bool resampled;
|
||||||
while (N < NPointsToAdd) {
|
while (N < NPointsToAdd) {
|
||||||
|
resampled = false;
|
||||||
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
|
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
|
||||||
if (s->_sampling == 0.0f)
|
if (s->_sampling == 0.0f)
|
||||||
continue;
|
continue;
|
||||||
@@ -556,14 +557,20 @@ void Stroke::Resample(int iNPoints)
|
|||||||
//resample
|
//resample
|
||||||
s->_n = s->_n + 1;
|
s->_n = s->_n + 1;
|
||||||
s->_sampling = s->_length / (float)(s->_n + 1);
|
s->_sampling = s->_length / (float)(s->_n + 1);
|
||||||
s->_resampled = true;
|
s->_resampled = resampled = true;
|
||||||
N++;
|
N++;
|
||||||
if (N == NPointsToAdd)
|
if (N == NPointsToAdd)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (checkEveryone && !resampled)
|
||||||
|
break;
|
||||||
checkEveryone = true;
|
checkEveryone = true;
|
||||||
}
|
}
|
||||||
|
if (N < NPointsToAdd) {
|
||||||
|
// fatal error, likely because _Length is inconsistent with the stroke length computed with the vertices
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
//actually resample:
|
//actually resample:
|
||||||
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
|
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
|
||||||
newVertices.push_back(&(*(s->_begin)));
|
newVertices.push_back(&(*(s->_begin)));
|
||||||
@@ -598,15 +605,17 @@ void Stroke::Resample(int iNPoints)
|
|||||||
delete _rep;
|
delete _rep;
|
||||||
_rep = new StrokeRep(this);
|
_rep = new StrokeRep(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stroke::Resample(float iSampling)
|
int Stroke::Resample(float iSampling)
|
||||||
{
|
{
|
||||||
//cerr << "old size :" << strokeVerticesSize() << endl;
|
//cerr << "old size :" << strokeVerticesSize() << endl;
|
||||||
if (iSampling == 0)
|
if (iSampling == 0)
|
||||||
return;
|
return 0;
|
||||||
if (iSampling >= _sampling)
|
if (iSampling >= _sampling)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
_sampling = iSampling;
|
_sampling = iSampling;
|
||||||
// Resample...
|
// Resample...
|
||||||
@@ -655,6 +664,7 @@ void Stroke::Resample(float iSampling)
|
|||||||
delete _rep;
|
delete _rep;
|
||||||
_rep = new StrokeRep(this);
|
_rep = new StrokeRep(this);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stroke::RemoveAllVertices()
|
void Stroke::RemoveAllVertices()
|
||||||
|
|||||||
@@ -588,7 +588,7 @@ public:
|
|||||||
* \param iNPoints
|
* \param iNPoints
|
||||||
* The number of vertices we eventually want in our stroke.
|
* The number of vertices we eventually want in our stroke.
|
||||||
*/
|
*/
|
||||||
void Resample(int iNPoints);
|
int Resample(int iNPoints);
|
||||||
|
|
||||||
/*! Resampling method.
|
/*! Resampling method.
|
||||||
* Resamples the curve with a given sampling.
|
* Resamples the curve with a given sampling.
|
||||||
@@ -596,7 +596,7 @@ public:
|
|||||||
* \param iSampling
|
* \param iSampling
|
||||||
* The new sampling value.
|
* The new sampling value.
|
||||||
*/
|
*/
|
||||||
void Resample(float iSampling);
|
int Resample(float iSampling);
|
||||||
|
|
||||||
/*! Removes all vertices from the Stroke.
|
/*! Removes all vertices from the Stroke.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user