47
46
#include "BLI_math.h"
48
47
#include "BLI_utildefines.h"
50
#define SWAP_FLOAT(a, b, tmp) tmp = a; a = b; b = tmp
52
49
/*-------------------------DOC STRINGS ---------------------------*/
53
50
PyDoc_STRVAR(M_Geometry_doc,
54
51
"The Blender geometry module"
57
//---------------------------------INTERSECTION FUNCTIONS--------------------
54
/* ---------------------------------INTERSECTION FUNCTIONS-------------------- */
59
56
PyDoc_STRVAR(M_Geometry_intersect_ray_tri_doc,
60
57
".. function:: intersect_ray_tri(v1, v2, v3, ray, orig, clip=True)\n"
260
//----------------------------geometry.normal() -------------------
254
/* Line-Line intersection using algorithm from mathworld.wolfram.com */
256
PyDoc_STRVAR(M_Geometry_intersect_sphere_sphere_2d_doc,
257
".. function:: intersect_sphere_sphere_2d(p_a, radius_a, p_b, radius_b)\n"
259
" Returns 2 points on between intersecting circles.\n"
261
" :arg p_a: Center of the first circle\n"
262
" :type p_a: :class:`mathutils.Vector`\n"
263
" :arg radius_a: Radius of the first circle\n"
264
" :type radius_a: float\n"
265
" :arg p_b: Center of the second circle\n"
266
" :type p_b: :class:`mathutils.Vector`\n"
267
" :arg radius_b: Radius of the second circle\n"
268
" :type radius_b: float\n"
269
" :rtype: tuple of :class:`mathutils.Vector`'s or None when there is no intersection\n"
271
static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), PyObject *args)
274
VectorObject *vec_a, *vec_b;
280
if (!PyArg_ParseTuple(args, "O!fO!f:intersect_sphere_sphere_2d",
281
&vector_Type, &vec_a, &rad_a,
282
&vector_Type, &vec_b, &rad_b))
287
if (BaseMath_ReadCallback(vec_a) == -1 ||
288
BaseMath_ReadCallback(vec_b) == -1)
293
ret = PyTuple_New(2);
298
sub_v2_v2v2(v_ab, v_b, v_a);
301
if (/* out of range */
302
(dist > rad_a + rad_b) ||
303
/* fully-contained in the other */
304
(dist < abs(rad_a - rad_b)) ||
306
(dist < FLT_EPSILON))
309
PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None);
310
PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None);
313
const float dist_delta = ((rad_a * rad_a) - (rad_b * rad_b) + (dist * dist)) / (2.0f * dist);
314
const float h = powf(fabsf((rad_a * rad_a) - (dist_delta * dist_delta)), 0.5f);
318
i_cent[0] = v_a[0] + ((v_ab[0] * dist_delta) / dist);
319
i_cent[1] = v_a[1] + ((v_ab[1] * dist_delta) / dist);
321
i1[0] = i_cent[0] + h * v_ab[1] / dist;
322
i1[1] = i_cent[1] - h * v_ab[0] / dist;
324
i2[0] = i_cent[0] - h * v_ab[1] / dist;
325
i2[1] = i_cent[1] + h * v_ab[0] / dist;
327
PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(i1, 2, Py_NEW, NULL));
328
PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(i2, 2, Py_NEW, NULL));
261
334
PyDoc_STRVAR(M_Geometry_normal_doc,
262
335
".. function:: normal(v1, v2, v3, v4=None)\n"
748
822
/* accept 2d verts */
749
if (pt->size == 3) { copy_v3_v3(pt_in, pt->vec); }
750
else { pt_in[2] = 0.0f; copy_v2_v2(pt_in, pt->vec); }
752
if (line_1->size == 3) { copy_v3_v3(l1, line_1->vec); }
753
else { l1[2] = 0.0f; copy_v2_v2(l1, line_1->vec); }
755
if (line_2->size == 3) { copy_v3_v3(l2, line_2->vec); }
756
else { l2[2] = 0.0f; copy_v2_v2(l2, line_2->vec); }
823
if (pt->size >= 3) { copy_v3_v3(pt_in, pt->vec); size = 3; }
824
else { copy_v2_v2(pt_in, pt->vec); pt_in[2] = 0.0f; }
826
if (line_1->size >= 3) { copy_v3_v3(l1, line_1->vec); size = 3; }
827
else { copy_v2_v2(l1, line_1->vec); l1[2] = 0.0f; }
829
if (line_2->size >= 3) { copy_v3_v3(l2, line_2->vec); size = 3; }
830
else { copy_v2_v2(l2, line_2->vec); l2[2] = 0.0f; }
758
832
/* do the calculation */
759
833
lambda = closest_to_line_v3(pt_out, pt_in, l1, l2);
761
835
ret = PyTuple_New(2);
762
PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(pt_out, 3, Py_NEW, NULL));
836
PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(pt_out, size, Py_NEW, NULL));
763
837
PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(lambda));
944
1019
return Vector_CreatePyObject(vec, 3, Py_NEW, NULL);
1022
PyDoc_STRVAR(M_Geometry_points_in_planes_doc,
1023
".. function:: points_in_planes(planes)\n"
1025
" Returns a list of points inside all planes given and a list of index values for the planes used.\n"
1027
" :arg planes: List of planes (4D vectors).\n"
1028
" :type planes: list of :class:`mathutils.Vector`\n"
1029
" :return: two lists, once containing the vertices inside the planes, another containing the plane indicies used\n"
1030
" :rtype: pair of lists\n"
1032
/* note: this function could be optimized by some spatial structure */
1033
static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *args)
1035
PyObject *py_planes;
1037
unsigned int planes_len;
1039
if (!PyArg_ParseTuple(args, "O:points_in_planes",
1045
if ((planes_len = mathutils_array_parse_alloc_v((float **)&planes, 4, py_planes, "points_in_planes")) == -1) {
1049
/* note, this could be refactored into plain C easy - py bits are noted */
1050
const float eps = 0.0001f;
1051
const unsigned int len = (unsigned int)planes_len;
1052
unsigned int i, j, k, l;
1054
float n1n2[3], n2n3[3], n3n1[3];
1055
float potentialVertex[3];
1056
char *planes_used = PyMem_Malloc(sizeof(char) * len);
1059
PyObject *py_verts = PyList_New(0);
1060
PyObject *py_plene_index = PyList_New(0);
1062
memset(planes_used, 0, sizeof(char) * len);
1064
for (i = 0; i < len; i++) {
1065
const float *N1 = planes[i];
1066
for (j = i + 1; j < len; j++) {
1067
const float *N2 = planes[j];
1068
cross_v3_v3v3(n1n2, N1, N2);
1069
if (len_squared_v3(n1n2) > eps) {
1070
for (k = j + 1; k < len; k++) {
1071
const float *N3 = planes[k];
1072
cross_v3_v3v3(n2n3, N2, N3);
1073
if (len_squared_v3(n2n3) > eps) {
1074
cross_v3_v3v3(n3n1, N3, N1);
1075
if (len_squared_v3(n3n1) > eps) {
1076
const float quotient = dot_v3v3(N1, n2n3);
1077
if (fabsf(quotient) > eps) {
1078
/* potentialVertex = (n2n3 * N1[3] + n3n1 * N2[3] + n1n2 * N3[3]) * (-1.0 / quotient); */
1079
const float quotient_ninv = -1.0f / quotient;
1080
potentialVertex[0] = ((n2n3[0] * N1[3]) + (n3n1[0] * N2[3]) + (n1n2[0] * N3[3])) * quotient_ninv;
1081
potentialVertex[1] = ((n2n3[1] * N1[3]) + (n3n1[1] * N2[3]) + (n1n2[1] * N3[3])) * quotient_ninv;
1082
potentialVertex[2] = ((n2n3[2] * N1[3]) + (n3n1[2] * N2[3]) + (n1n2[2] * N3[3])) * quotient_ninv;
1083
for (l = 0; l < len; l++) {
1084
const float *NP = planes[l];
1085
if ((dot_v3v3(NP, potentialVertex) + NP[3]) > 0.000001f) {
1090
if (l == len) { /* ok */
1092
PyObject *item = Vector_CreatePyObject(potentialVertex, 3, Py_NEW, NULL);
1093
PyList_Append(py_verts, item);
1096
planes_used[i] = planes_used[j] = planes_used[k] = TRUE;
1108
/* now make a list of used planes */
1109
for (i = 0; i < len; i++) {
1110
if (planes_used[i]) {
1111
PyObject *item = PyLong_FromLong(i);
1112
PyList_Append(py_plene_index, item);
1116
PyMem_Free(planes_used);
1119
PyObject *ret = PyTuple_New(2);
1120
PyTuple_SET_ITEM(ret, 0, py_verts);
1121
PyTuple_SET_ITEM(ret, 1, py_plene_index);
947
1127
#ifndef MATH_STANDALONE
949
1129
PyDoc_STRVAR(M_Geometry_interpolate_bezier_doc,
1012
1192
coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier");
1013
1193
for (i = 0; i < dims; i++) {
1014
forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array + i, resolu - 1, sizeof(float) * dims);
1194
BKE_curve_forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array + i, resolu - 1, sizeof(float) * dims);
1017
1197
list = PyList_New(resolu);
1245
1425
len = PyList_GET_SIZE(boxlist);
1247
boxPack *boxarray = NULL;
1427
BoxPack *boxarray = NULL;
1248
1428
if (boxPack_FromPyObject(boxlist, &boxarray) == -1) {
1249
1429
return NULL; /* exception set */
1252
1432
/* Non Python function */
1253
boxPack2D(boxarray, len, &tot_width, &tot_height);
1433
BLI_box_pack_2D(boxarray, len, &tot_width, &tot_height);
1255
1435
boxPack_ToPyObject(boxlist, &boxarray);
1276
1456
{"intersect_line_sphere", (PyCFunction) M_Geometry_intersect_line_sphere, METH_VARARGS, M_Geometry_intersect_line_sphere_doc},
1277
1457
{"intersect_line_sphere_2d", (PyCFunction) M_Geometry_intersect_line_sphere_2d, METH_VARARGS, M_Geometry_intersect_line_sphere_2d_doc},
1278
1458
{"distance_point_to_plane", (PyCFunction) M_Geometry_distance_point_to_plane, METH_VARARGS, M_Geometry_distance_point_to_plane_doc},
1459
{"intersect_sphere_sphere_2d", (PyCFunction) M_Geometry_intersect_sphere_sphere_2d, METH_VARARGS, M_Geometry_intersect_sphere_sphere_2d_doc},
1279
1460
{"area_tri", (PyCFunction) M_Geometry_area_tri, METH_VARARGS, M_Geometry_area_tri_doc},
1280
1461
{"normal", (PyCFunction) M_Geometry_normal, METH_VARARGS, M_Geometry_normal_doc},
1281
1462
{"barycentric_transform", (PyCFunction) M_Geometry_barycentric_transform, METH_VARARGS, M_Geometry_barycentric_transform_doc},
1463
{"points_in_planes", (PyCFunction) M_Geometry_points_in_planes, METH_VARARGS, M_Geometry_points_in_planes_doc},
1282
1464
#ifndef MATH_STANDALONE
1283
1465
{"interpolate_bezier", (PyCFunction) M_Geometry_interpolate_bezier, METH_VARARGS, M_Geometry_interpolate_bezier_doc},
1284
1466
{"tessellate_polygon", (PyCFunction) M_Geometry_tessellate_polygon, METH_O, M_Geometry_tessellate_polygon_doc},