diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-03-14 10:14:15 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-03-14 10:14:15 +0400 |
commit | ee9a00948b950f8361ef280b5f88674721a6698f (patch) | |
tree | f75025f04750f530692baf00cc924bbb57d4f5f2 | |
parent | f15c15e992a9836a7295166af275522690ada315 (diff) |
mathutils py api:
Vector.angle_signed(other)
for 2D vectors to get the clockwise angle between them.
in BLI math its called - angle_signed_v2v2()
shorthand for...
atan2f((v1[1] * v2[0]) - (v1[0] * v2[1]), dot_v2v2(v1, v2))
also corrects compile error in last commit.
-rw-r--r-- | source/blender/blenlib/BLI_math_vector.h | 1 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_geom.c | 41 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_vector.c | 6 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_vector_inline.c | 6 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_select.c | 2 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Vector.c | 61 |
6 files changed, 92 insertions, 25 deletions
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 1a24acfe1a5..b8b53f1ba7c 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -176,6 +176,7 @@ MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const flo /* - angle_normalized_* is faster equivalent if vectors are normalized */ float angle_v2v2(const float a[2], const float b[2]); +float angle_signed_v2v2(const float v1[2], const float v2[2]); float angle_v2v2v2(const float a[2], const float b[2], const float c[2]); float angle_normalized_v2v2(const float a[2], const float b[2]); float angle_v3v3(const float a[3], const float b[3]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index f491ea25075..84bc397a7f8 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -1726,31 +1726,29 @@ static float tri_signed_area(const float v1[3], const float v2[3], const float v return 0.5f*((v1[i]-v2[i])*(v2[j]-v3[j]) + (v1[j]-v2[j])*(v3[i]-v2[i])); } +/* return 1 when degenerate */ static int barycentric_weights(const float v1[3], const float v2[3], const float v3[3], const float co[3], const float n[3], float w[3]) { - float a1, a2, a3, asum; + float wtot; int i, j; axis_dominant_v3(&i, &j, n); - a1= tri_signed_area(v2, v3, co, i, j); - a2= tri_signed_area(v3, v1, co, i, j); - a3= tri_signed_area(v1, v2, co, i, j); + w[0] = tri_signed_area(v2, v3, co, i, j); + w[1] = tri_signed_area(v3, v1, co, i, j); + w[2] = tri_signed_area(v1, v2, co, i, j); - asum= a1 + a2 + a3; + wtot = w[0] + w[1] + w[2]; - if (fabsf(asum) < FLT_EPSILON) { + if (fabsf(wtot) > FLT_EPSILON) { + mul_v3_fl(w, 1.0f / wtot); + return 0; + } + else { /* zero area triangle */ - w[0]= w[1]= w[2]= 1.0f/3.0f; + copy_v3_fl(w, 1.0f / 3.0f); return 1; } - - asum= 1.0f/asum; - w[0]= a1*asum; - w[1]= a2*asum; - w[2]= a3*asum; - - return 0; } void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]) @@ -1809,22 +1807,19 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co * note: using area_tri_signed_v2 means locations outside the triangle are correctly weighted */ void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) { - float wtot_inv, wtot; + float wtot; w[0] = area_tri_signed_v2(v2, v3, co); w[1] = area_tri_signed_v2(v3, v1, co); w[2] = area_tri_signed_v2(v1, v2, co); - wtot = w[0]+w[1]+w[2]; + wtot = w[0] + w[1] + w[2]; if (wtot != 0.0f) { - wtot_inv = 1.0f/wtot; - - w[0] = w[0]*wtot_inv; - w[1] = w[1]*wtot_inv; - w[2] = w[2]*wtot_inv; + mul_v3_fl(w, 1.0f / wtot); + } + else { /* dummy values for zero area face */ + copy_v3_fl(w, 1.0f / 3.0f); } - else /* dummy values for zero area face */ - w[0] = w[1] = w[2] = 1.0f/3.0f; } /* given 2 triangles in 3D space, and a point in relation to the first triangle. diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 01ba62bc741..39e1a9b31f0 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -174,6 +174,12 @@ float angle_v2v2(const float v1[2], const float v2[2]) return angle_normalized_v2v2(vec1, vec2); } +float angle_signed_v2v2(const float v1[2], const float v2[2]) +{ + const float perp_dot = (v1[1] * v2[0]) - (v1[0] * v2[1]); + return atan2f(perp_dot, dot_v2v2(v1, v2)); +} + float angle_normalized_v3v3(const float v1[3], const float v2[3]) { /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */ diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 6414245fb3e..96587da9784 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -625,6 +625,12 @@ MINLINE void normal_float_to_short_v3(short out[3], const float in[3]) /********************************* Comparison ********************************/ + +MINLINE int is_zero_v2(const float v[3]) +{ + return (v[0] == 0 && v[1] == 0); +} + MINLINE int is_zero_v3(const float v[3]) { return (v[0] == 0 && v[1] == 0 && v[2] == 0); diff --git a/source/blender/python/bmesh/bmesh_py_select.c b/source/blender/python/bmesh/bmesh_py_select.c index a9fb5b2b018..37beb43eeb5 100644 --- a/source/blender/python/bmesh/bmesh_py_select.c +++ b/source/blender/python/bmesh/bmesh_py_select.c @@ -122,7 +122,7 @@ static PyObject *bpy_bmeditselseq_add(BPy_BMEditSelSeq *self, BPy_BMElem *value) return NULL; } - BM_select_history_store(self->bm, value->ele) + BM_select_history_store(self->bm, value->ele); Py_RETURN_NONE; } diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 6a7ace9c2a4..3434aadced5 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -920,7 +920,7 @@ PyDoc_STRVAR(Vector_angle_doc, " :return: angle in radians or fallback when given\n" " :rtype: float\n" "\n" -" .. note:: Zero length vectors raise an :exc:`AttributeError`.\n" +" .. note:: Zero length vectors raise an :exc:`ValueError`.\n" ); static PyObject *Vector_angle(VectorObject *self, PyObject *args) { @@ -971,6 +971,64 @@ static PyObject *Vector_angle(VectorObject *self, PyObject *args) return PyFloat_FromDouble(saacos(dot / (sqrt(dot_self) * sqrt(dot_other)))); } +PyDoc_STRVAR(Vector_angle_signed_doc, +".. function:: angle_signed(other, fallback)\n" +"\n" +" Return the signed angle between two 2D vectors (clockwise is positive).\n" +"\n" +" :arg other: another vector to compare the angle with\n" +" :type other: :class:`Vector`\n" +" :arg fallback: return this value when the angle cant be calculated\n" +" (zero length vector)\n" +" :type fallback: any\n" +" :return: angle in radians or fallback when given\n" +" :rtype: float\n" +"\n" +" .. note:: Zero length vectors raise an :exc:`ValueError`.\n" +); +static PyObject *Vector_angle_signed(VectorObject *self, PyObject *args) +{ + float tvec[2]; + + PyObject *value; + PyObject *fallback = NULL; + + if (!PyArg_ParseTuple(args, "O|O:angle_signed", &value, &fallback)) + return NULL; + + if (BaseMath_ReadCallback(self) == -1) + return NULL; + + /* don't use clamped size, rule of thumb is vector sizes must match, + * even though n this case 'w' is ignored */ + if (mathutils_array_parse(tvec, 2, 2, value, "Vector.angle_signed(other), invalid 'other' arg") == -1) + return NULL; + + if (self->size != 2) { + PyErr_SetString(PyExc_ValueError, + "Vector must be 2D"); + return NULL; + } + + if (is_zero_v2(self->vec) || is_zero_v2(tvec)) { + /* avoid exception */ + if (fallback) { + Py_INCREF(fallback); + return fallback; + } + else { + PyErr_SetString(PyExc_ValueError, + "Vector.angle_signed(other): " + "zero length vectors have no valid angle"); + return NULL; + } + } + + + return PyFloat_FromDouble(angle_signed_v2v2(self->vec, tvec)); +} + + PyDoc_STRVAR(Vector_rotation_difference_doc, ".. function:: rotation_difference(other)\n" "\n" @@ -2705,6 +2763,7 @@ static struct PyMethodDef Vector_methods[] = { {"cross", (PyCFunction) Vector_cross, METH_O, Vector_cross_doc}, {"dot", (PyCFunction) Vector_dot, METH_O, Vector_dot_doc}, {"angle", (PyCFunction) Vector_angle, METH_VARARGS, Vector_angle_doc}, + {"angle_signed", (PyCFunction) Vector_angle_signed, METH_VARARGS, Vector_angle_signed_doc}, {"rotation_difference", (PyCFunction) Vector_rotation_difference, METH_O, Vector_rotation_difference_doc}, {"project", (PyCFunction) Vector_project, METH_O, Vector_project_doc}, {"lerp", (PyCFunction) Vector_lerp, METH_VARARGS, Vector_lerp_doc}, |