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:
parent
5ee55caba5
commit
812515b623
|
@ -151,10 +151,16 @@ static PyObject *Stroke_resample(BPy_Stroke *self, PyObject *args, PyObject *kwd
|
|||
float f;
|
||||
|
||||
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)) {
|
||||
self->s->Resample(f);
|
||||
if (self->s->Resample(f) < 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex interval) failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid argument");
|
||||
|
|
|
@ -508,11 +508,11 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void Stroke::Resample(int iNPoints)
|
||||
int Stroke::Resample(int iNPoints)
|
||||
{
|
||||
int vertsize = strokeVerticesSize();
|
||||
if (iNPoints <= vertsize)
|
||||
return;
|
||||
int NPointsToAdd = iNPoints - strokeVerticesSize();
|
||||
if (NPointsToAdd <= 0)
|
||||
return 0;
|
||||
|
||||
StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
|
||||
StrokeInternal::StrokeVertexIterator next = it;
|
||||
|
@ -531,7 +531,7 @@ void Stroke::Resample(int iNPoints)
|
|||
Vec2r b((next)->getPoint());
|
||||
Vec2r vec_tmp(b - a);
|
||||
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);
|
||||
strokeSegments.push_back(StrokeSegment(it, next, norm_var, numberOfPointsToAdd, csampling));
|
||||
N += numberOfPointsToAdd;
|
||||
|
@ -543,9 +543,10 @@ void Stroke::Resample(int iNPoints)
|
|||
meanlength /= (float)nsegments;
|
||||
|
||||
// if we don't have enough points let's resample finer some segments
|
||||
int NPointsToAdd = iNPoints - vertsize;
|
||||
bool checkEveryone = false;
|
||||
bool resampled;
|
||||
while (N < NPointsToAdd) {
|
||||
resampled = false;
|
||||
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
|
||||
if (s->_sampling == 0.0f)
|
||||
continue;
|
||||
|
@ -556,14 +557,20 @@ void Stroke::Resample(int iNPoints)
|
|||
//resample
|
||||
s->_n = s->_n + 1;
|
||||
s->_sampling = s->_length / (float)(s->_n + 1);
|
||||
s->_resampled = true;
|
||||
s->_resampled = resampled = true;
|
||||
N++;
|
||||
if (N == NPointsToAdd)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (checkEveryone && !resampled)
|
||||
break;
|
||||
checkEveryone = true;
|
||||
}
|
||||
if (N < NPointsToAdd) {
|
||||
// fatal error, likely because _Length is inconsistent with the stroke length computed with the vertices
|
||||
return -1;
|
||||
}
|
||||
//actually resample:
|
||||
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
|
||||
newVertices.push_back(&(*(s->_begin)));
|
||||
|
@ -598,15 +605,17 @@ void Stroke::Resample(int iNPoints)
|
|||
delete _rep;
|
||||
_rep = new StrokeRep(this);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Stroke::Resample(float iSampling)
|
||||
int Stroke::Resample(float iSampling)
|
||||
{
|
||||
//cerr << "old size :" << strokeVerticesSize() << endl;
|
||||
if (iSampling == 0)
|
||||
return;
|
||||
return 0;
|
||||
if (iSampling >= _sampling)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
_sampling = iSampling;
|
||||
// Resample...
|
||||
|
@ -655,6 +664,7 @@ void Stroke::Resample(float iSampling)
|
|||
delete _rep;
|
||||
_rep = new StrokeRep(this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Stroke::RemoveAllVertices()
|
||||
|
|
|
@ -588,7 +588,7 @@ public:
|
|||
* \param iNPoints
|
||||
* The number of vertices we eventually want in our stroke.
|
||||
*/
|
||||
void Resample(int iNPoints);
|
||||
int Resample(int iNPoints);
|
||||
|
||||
/*! Resampling method.
|
||||
* Resamples the curve with a given sampling.
|
||||
|
@ -596,7 +596,7 @@ public:
|
|||
* \param iSampling
|
||||
* The new sampling value.
|
||||
*/
|
||||
void Resample(float iSampling);
|
||||
int Resample(float iSampling);
|
||||
|
||||
/*! Removes all vertices from the Stroke.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue