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;
 | 
			
		||||
 | 
			
		||||
	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.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user