[Bf-blender-cvs] [6860092] master: PyAPI: allow non-vector args for geometry module

Campbell Barton noreply at git.blender.org
Tue Dec 30 12:26:00 CET 2014


Commit: 68600920ced198eaa1524993f988f26118402e50
Author: Campbell Barton
Date:   Tue Dec 30 21:50:47 2014 +1100
Branches: master
https://developer.blender.org/rB68600920ced198eaa1524993f988f26118402e50

PyAPI: allow non-vector args for geometry module

Previously only vector args were accepted,
now allow generic sequence of numbers.

Was annoying to create vectors just to pass in args.

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

M	source/blender/python/mathutils/mathutils.c
M	source/blender/python/mathutils/mathutils.h
M	source/blender/python/mathutils/mathutils_geometry.c

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

diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 349f848..5c3f38e 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -69,8 +69,11 @@ static int mathutils_array_parse_fast(float *array,
 /* helper functionm returns length of the 'value', -1 on error */
 int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
 {
+	const int flag = array_max;
 	int size;
 
+	array_max &= ~(MU_ARRAY_ZERO | MU_ARRAY_SPILL);
+
 #if 1 /* approx 6x speedup for mathutils types */
 
 	if ((size = VectorObject_Check(value)     ? ((VectorObject *)value)->size : 0) ||
@@ -82,6 +85,10 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
 			return -1;
 		}
 
+		if (flag & MU_ARRAY_SPILL) {
+			CLAMP_MAX(size, array_max);
+		}
+
 		if (size > array_max || size < array_min) {
 			if (array_max == array_min) {
 				PyErr_Format(PyExc_ValueError,
@@ -97,7 +104,6 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
 		}
 
 		memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float));
-		return size;
 	}
 	else
 #endif
@@ -112,6 +118,10 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
 
 		size = PySequence_Fast_GET_SIZE(value_fast);
 
+		if (flag & MU_ARRAY_SPILL) {
+			CLAMP_MAX(size, array_max);
+		}
+
 		if (size > array_max || size < array_min) {
 			if (array_max == array_min) {
 				PyErr_Format(PyExc_ValueError,
@@ -127,8 +137,19 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
 			return -1;
 		}
 
-		return mathutils_array_parse_fast(array, size, value_fast, error_prefix);
+		size = mathutils_array_parse_fast(array, size, value_fast, error_prefix);
 	}
+
+	if (size != -1) {
+		if (flag & MU_ARRAY_ZERO) {
+			int size_left = array_max - size;
+			if (size_left) {
+				memset(&array[size], 0, sizeof(float) * size_left);
+			}
+		}
+	}
+
+	return size;
 }
 
 /* on error, -1 is returned and no allocation is made */
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index eb25d9b..5f89c78 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -109,6 +109,12 @@ int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, c
 int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix);
 int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
 
+/* zero remaining unused elements of the array */
+#define MU_ARRAY_ZERO      (1 << 30)
+/* ignore larger py sequences than requested (just use first elements),
+ * handy when using 3d vectors as 2d */
+#define MU_ARRAY_SPILL     (1 << 31)
+
 int column_vector_multiplication(float rvec[4], VectorObject *vec, MatrixObject *mat);
 
 #ifndef MATH_STANDALONE
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 013c874..2a570ed 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -72,48 +72,37 @@ PyDoc_STRVAR(M_Geometry_intersect_ray_tri_doc,
 );
 static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args)
 {
-	VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
-	float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
+	const char *error_prefix = "intersect_ray_tri";
+	PyObject *py_ray, *py_ray_off, *py_tri[3];
+	float dir[3], orig[3], tri[3][3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
 	float det, inv_det, u, v, t;
 	int clip = 1;
+	int i;
 
-	if (!PyArg_ParseTuple(args,
-	                      "O!O!O!O!O!|i:intersect_ray_tri",
-	                      &vector_Type, &vec1,
-	                      &vector_Type, &vec2,
-	                      &vector_Type, &vec3,
-	                      &vector_Type, &ray,
-	                      &vector_Type, &ray_off, &clip))
+	if (!PyArg_ParseTuple(
+	        args, "OOOOO|i:intersect_ray_tri",
+	        UNPACK3_EX(&, py_tri, ), &py_ray, &py_ray_off, &clip))
 	{
 		return NULL;
 	}
-	if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
-		PyErr_SetString(PyExc_ValueError,
-		                "only 3D vectors for all parameters");
-		return NULL;
-	}
 
-	if (BaseMath_ReadCallback(vec1) == -1 ||
-	    BaseMath_ReadCallback(vec2) == -1 ||
-	    BaseMath_ReadCallback(vec3) == -1 ||
-	    BaseMath_ReadCallback(ray)  == -1 ||
-	    BaseMath_ReadCallback(ray_off) == -1)
+	if (((mathutils_array_parse(dir, 3, 3, py_ray, error_prefix) != -1) &&
+	     (mathutils_array_parse(orig, 3, 3, py_ray_off, error_prefix) != -1)) == 0)
 	{
 		return NULL;
 	}
 
-	copy_v3_v3(v1, vec1->vec);
-	copy_v3_v3(v2, vec2->vec);
-	copy_v3_v3(v3, vec3->vec);
+	for (i = 0; i < ARRAY_SIZE(tri); i++) {
+		if (mathutils_array_parse(tri[i], 2, 2 | MU_ARRAY_SPILL, py_tri[i], error_prefix) == -1) {
+			return NULL;
+		}
+	}
 
-	copy_v3_v3(dir, ray->vec);
 	normalize_v3(dir);
 
-	copy_v3_v3(orig, ray_off->vec);
-
 	/* find vectors for two edges sharing v1 */
-	sub_v3_v3v3(e1, v2, v1);
-	sub_v3_v3v3(e2, v3, v1);
+	sub_v3_v3v3(e1, tri[1], tri[0]);
+	sub_v3_v3v3(e2, tri[2], tri[0]);
 
 	/* begin calculating determinant - also used to calculated U parameter */
 	cross_v3_v3v3(pvec, dir, e2);
@@ -128,7 +117,7 @@ static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *
 	inv_det = 1.0f / det;
 
 	/* calculate distance from v1 to ray origin */
-	sub_v3_v3v3(tvec, orig, v1);
+	sub_v3_v3v3(tvec, orig, tri[0]);
 
 	/* calculate U parameter and test bounds */
 	u = dot_v3v3(tvec, pvec) * inv_det;
@@ -179,82 +168,48 @@ PyDoc_STRVAR(M_Geometry_intersect_line_line_doc,
 );
 static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject *args)
 {
+	const char *error_prefix = "intersect_line_line";
 	PyObject *tuple;
-	VectorObject *vec1, *vec2, *vec3, *vec4;
-	float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
-
-	if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line",
-	                      &vector_Type, &vec1,
-	                      &vector_Type, &vec2,
-	                      &vector_Type, &vec3,
-	                      &vector_Type, &vec4))
+	PyObject *py_lines[4];
+	float lines[4][3], i1[3], i2[3];
+	int len;
+	int result;
+
+	if (!PyArg_ParseTuple(
+	        args, "OOOO:intersect_line_line",
+	        UNPACK4_EX(&, py_lines, )))
 	{
 		return NULL;
 	}
 
-	if (vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) {
-		PyErr_SetString(PyExc_ValueError,
-		                "vectors must be of the same size");
-		return NULL;
-	}
-
-	if (BaseMath_ReadCallback(vec1) == -1 ||
-	    BaseMath_ReadCallback(vec2) == -1 ||
-	    BaseMath_ReadCallback(vec3) == -1 ||
-	    BaseMath_ReadCallback(vec4) == -1)
+	if ((((len = mathutils_array_parse(lines[0], 2, 3, py_lines[0], error_prefix)) != -1) &&
+	     (mathutils_array_parse(lines[1], len, len, py_lines[1], error_prefix) != -1) &&
+	     (mathutils_array_parse(lines[2], len, len, py_lines[2], error_prefix) != -1) &&
+	     (mathutils_array_parse(lines[3], len, len, py_lines[3], error_prefix) != -1)) == 0)
 	{
 		return NULL;
 	}
 
-	if (vec1->size == 3 || vec1->size == 2) {
-		int result;
-
-		if (vec1->size == 3) {
-			copy_v3_v3(v1, vec1->vec);
-			copy_v3_v3(v2, vec2->vec);
-			copy_v3_v3(v3, vec3->vec);
-			copy_v3_v3(v4, vec4->vec);
-		}
-		else {
-			v1[0] = vec1->vec[0];
-			v1[1] = vec1->vec[1];
-			v1[2] = 0.0f;
-
-			v2[0] = vec2->vec[0];
-			v2[1] = vec2->vec[1];
-			v2[2] = 0.0f;
-
-			v3[0] = vec3->vec[0];
-			v3[1] = vec3->vec[1];
-			v3[2] = 0.0f;
-
-			v4[0] = vec4->vec[0];
-			v4[1] = vec4->vec[1];
-			v4[2] = 0.0f;
-		}
+	if (len == 2) {
+		lines[0][2] = lines[1][2] = lines[2][2] = lines[3][2] = 0.0f;
+	}
 
-		result = isect_line_line_v3(v1, v2, v3, v4, i1, i2);
-		/* The return-code isnt exposed,
-		 * this way we can check know how close the lines are. */
-		if (result == 1) {
-			closest_to_line_v3(i2, i1, v3, v4);
-		}
+	result = isect_line_line_v3(UNPACK4(lines), i1, i2);
+	/* The return-code isnt exposed,
+	 * this way we can check know how close the lines are. */
+	if (result == 1) {
+		closest_to_line_v3(i2, i1, lines[2], lines[3]);
+	}
 
-		if (result == 0) {
-			/* colinear */
-			Py_RETURN_NONE;
-		}
-		else {
-			tuple = PyTuple_New(2);
-			PyTuple_SET_ITEM(tuple, 0, Vector_CreatePyObject(i1, vec1->size, Py_NEW, NULL));
-			PyTuple_SET_ITEM(tuple, 1, Vector_CreatePyObject(i2, vec1->size, Py_NEW, NULL));
-			return tuple;
-		}
+	if (result == 0) {
+		/* colinear */
+		Py_RETURN_NONE;
 	}
 	else {
-		PyErr_SetString(PyExc_ValueError,
-		                "2D/3D vectors only");
-		return NULL;
+		tuple = PyTuple_New(2);
+		PyTuple_SET_ITEM(tuple, 0, Vector_CreatePyObject(i1, len, Py_NEW, NULL));
+		PyTuple_SET_ITEM(tuple, 1, Vector_CreatePyObject(i2, len, Py_NEW, NULL));
+		return tuple;
 	}
 }
 
@@ -277,31 +232,30 @@ PyDoc_STRVAR(M_Geometry_intersect_sphere_sphere_2d_doc,
 );
 static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), PyObject *args)
 {
+	const char *error_prefix = "intersect_sphere_sphere_2d";
 	PyObject *ret;
-	VectorObject *vec_a, *vec_b;
-	const float *v_a, *v_b;
+	PyObject *py_v_a, *py_v_b;
+	float v_a[2], v_b[2];
 	float rad_a, rad_b;
 	float v_ab[2];
 	float dist;
 
-	if (!PyArg_ParseTuple(args, "O!fO!f:intersect_sphere_sphere_2d",
-	                      &vector_Type, &vec_a, &rad_a,
-	                      &vector_Type, &vec_b, &rad_b))
+	if (!PyArg_ParseTuple(
+	        args, "OfOf:intersect_sphere_sphere_2d",
+	        &py_v_a, &rad_a,
+	        &py_v_b, &rad_b))
 	{
 		return NULL;
 	}
 
-	if (BaseMath_ReadCallback(vec_a) == -1 ||
-	    BaseMath_ReadCallback(vec_b) == -1)
+	if (((mathutils_array_parse(v_a, 2, 2, py_v_a, error_prefix) != -1) &&
+	     (mathutils_array_parse(v_b, 2, 2, py_v_b, error_prefix) != -1)) == 0)
 	{
 		return NULL;
 	}
 
 	ret = PyTuple_New(2);
 
-	v_a = vec_a->vec;
-	v_b = vec_b->vec;
-
 	su

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list