[Bf-blender-cvs] [812515b] master: Freestyle: Fix for a potential infinite loop in stroke resampling by vertex count.

Tamito Kajiyama noreply at git.blender.org
Wed Jun 4 08:05:29 CEST 2014


Commit: 812515b623be9179e67d97b84b10df587244d38c
Author: Tamito Kajiyama
Date:   Wed Jun 4 14:51:39 2014 +0900
https://developer.blender.org/rB812515b623be9179e67d97b84b10df587244d38c

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.

===================================================================

M	source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
M	source/blender/freestyle/intern/stroke/Stroke.cpp
M	source/blender/freestyle/intern/stroke/Stroke.h

===================================================================

diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
index 7110eef..aa8c90c 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
@@ -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");
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
index 6629de0..c85295e 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.cpp
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -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()
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
index 5e6c2fc..abbbcc3 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.h
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -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.
      */




More information about the Bf-blender-cvs mailing list