Blender V2.61 - r43446
|
00001 /* 00002 * 00003 * ***** BEGIN GPL LICENSE BLOCK ***** 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software Foundation, 00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00020 * All rights reserved. 00021 * 00022 * This is a new part of Blender. 00023 * 00024 * Contributor(s): Joseph Gilbert, Campbell Barton 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <Python.h> 00035 00036 #include "mathutils_geometry.h" 00037 00038 /* Used for PolyFill */ 00039 #ifndef MATH_STANDALONE /* define when building outside blender */ 00040 # include "MEM_guardedalloc.h" 00041 # include "BLI_blenlib.h" 00042 # include "BLI_boxpack2d.h" 00043 # include "BKE_displist.h" 00044 # include "BKE_curve.h" 00045 #endif 00046 00047 #include "BLI_math.h" 00048 #include "BLI_utildefines.h" 00049 00050 #define SWAP_FLOAT(a, b, tmp) tmp = a; a = b; b = tmp 00051 00052 /*-------------------------DOC STRINGS ---------------------------*/ 00053 PyDoc_STRVAR(M_Geometry_doc, 00054 "The Blender geometry module" 00055 ); 00056 00057 //---------------------------------INTERSECTION FUNCTIONS-------------------- 00058 00059 PyDoc_STRVAR(M_Geometry_intersect_ray_tri_doc, 00060 ".. function:: intersect_ray_tri(v1, v2, v3, ray, orig, clip=True)\n" 00061 "\n" 00062 " Returns the intersection between a ray and a triangle, if possible, returns None otherwise.\n" 00063 "\n" 00064 " :arg v1: Point1\n" 00065 " :type v1: :class:`mathutils.Vector`\n" 00066 " :arg v2: Point2\n" 00067 " :type v2: :class:`mathutils.Vector`\n" 00068 " :arg v3: Point3\n" 00069 " :type v3: :class:`mathutils.Vector`\n" 00070 " :arg ray: Direction of the projection\n" 00071 " :type ray: :class:`mathutils.Vector`\n" 00072 " :arg orig: Origin\n" 00073 " :type orig: :class:`mathutils.Vector`\n" 00074 " :arg clip: When False, don't restrict the intersection to the area of the triangle, use the infinite plane defined by the triangle.\n" 00075 " :type clip: boolean\n" 00076 " :return: The point of intersection or None if no intersection is found\n" 00077 " :rtype: :class:`mathutils.Vector` or None\n" 00078 ); 00079 static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args) 00080 { 00081 VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; 00082 float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; 00083 float det, inv_det, u, v, t; 00084 int clip = 1; 00085 00086 if (!PyArg_ParseTuple(args, 00087 "O!O!O!O!O!|i:intersect_ray_tri", 00088 &vector_Type, &vec1, 00089 &vector_Type, &vec2, 00090 &vector_Type, &vec3, 00091 &vector_Type, &ray, 00092 &vector_Type, &ray_off, &clip)) 00093 { 00094 return NULL; 00095 } 00096 if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { 00097 PyErr_SetString(PyExc_ValueError, 00098 "only 3D vectors for all parameters"); 00099 return NULL; 00100 } 00101 00102 if ( BaseMath_ReadCallback(vec1) == -1 || 00103 BaseMath_ReadCallback(vec2) == -1 || 00104 BaseMath_ReadCallback(vec3) == -1 || 00105 BaseMath_ReadCallback(ray) == -1 || 00106 BaseMath_ReadCallback(ray_off) == -1) 00107 { 00108 return NULL; 00109 } 00110 00111 copy_v3_v3(v1, vec1->vec); 00112 copy_v3_v3(v2, vec2->vec); 00113 copy_v3_v3(v3, vec3->vec); 00114 00115 copy_v3_v3(dir, ray->vec); 00116 normalize_v3(dir); 00117 00118 copy_v3_v3(orig, ray_off->vec); 00119 00120 /* find vectors for two edges sharing v1 */ 00121 sub_v3_v3v3(e1, v2, v1); 00122 sub_v3_v3v3(e2, v3, v1); 00123 00124 /* begin calculating determinant - also used to calculated U parameter */ 00125 cross_v3_v3v3(pvec, dir, e2); 00126 00127 /* if determinant is near zero, ray lies in plane of triangle */ 00128 det = dot_v3v3(e1, pvec); 00129 00130 if (det > -0.000001f && det < 0.000001f) { 00131 Py_RETURN_NONE; 00132 } 00133 00134 inv_det = 1.0f / det; 00135 00136 /* calculate distance from v1 to ray origin */ 00137 sub_v3_v3v3(tvec, orig, v1); 00138 00139 /* calculate U parameter and test bounds */ 00140 u = dot_v3v3(tvec, pvec) * inv_det; 00141 if (clip && (u < 0.0f || u > 1.0f)) { 00142 Py_RETURN_NONE; 00143 } 00144 00145 /* prepare to test the V parameter */ 00146 cross_v3_v3v3(qvec, tvec, e1); 00147 00148 /* calculate V parameter and test bounds */ 00149 v = dot_v3v3(dir, qvec) * inv_det; 00150 00151 if (clip && (v < 0.0f || u + v > 1.0f)) { 00152 Py_RETURN_NONE; 00153 } 00154 00155 /* calculate t, ray intersects triangle */ 00156 t = dot_v3v3(e2, qvec) * inv_det; 00157 00158 mul_v3_fl(dir, t); 00159 add_v3_v3v3(pvec, orig, dir); 00160 00161 return Vector_CreatePyObject(pvec, 3, Py_NEW, NULL); 00162 } 00163 00164 /* Line-Line intersection using algorithm from mathworld.wolfram.com */ 00165 00166 PyDoc_STRVAR(M_Geometry_intersect_line_line_doc, 00167 ".. function:: intersect_line_line(v1, v2, v3, v4)\n" 00168 "\n" 00169 " Returns a tuple with the points on each line respectively closest to the other.\n" 00170 "\n" 00171 " :arg v1: First point of the first line\n" 00172 " :type v1: :class:`mathutils.Vector`\n" 00173 " :arg v2: Second point of the first line\n" 00174 " :type v2: :class:`mathutils.Vector`\n" 00175 " :arg v3: First point of the second line\n" 00176 " :type v3: :class:`mathutils.Vector`\n" 00177 " :arg v4: Second point of the second line\n" 00178 " :type v4: :class:`mathutils.Vector`\n" 00179 " :rtype: tuple of :class:`mathutils.Vector`'s\n" 00180 ); 00181 static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject *args) 00182 { 00183 PyObject *tuple; 00184 VectorObject *vec1, *vec2, *vec3, *vec4; 00185 float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3]; 00186 00187 if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line", 00188 &vector_Type, &vec1, 00189 &vector_Type, &vec2, 00190 &vector_Type, &vec3, 00191 &vector_Type, &vec4)) 00192 { 00193 return NULL; 00194 } 00195 00196 if (vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) { 00197 PyErr_SetString(PyExc_ValueError, 00198 "vectors must be of the same size"); 00199 return NULL; 00200 } 00201 00202 if ( BaseMath_ReadCallback(vec1) == -1 || 00203 BaseMath_ReadCallback(vec2) == -1 || 00204 BaseMath_ReadCallback(vec3) == -1 || 00205 BaseMath_ReadCallback(vec4) == -1) 00206 { 00207 return NULL; 00208 } 00209 00210 if (vec1->size == 3 || vec1->size == 2) { 00211 int result; 00212 00213 if (vec1->size == 3) { 00214 copy_v3_v3(v1, vec1->vec); 00215 copy_v3_v3(v2, vec2->vec); 00216 copy_v3_v3(v3, vec3->vec); 00217 copy_v3_v3(v4, vec4->vec); 00218 } 00219 else { 00220 v1[0] = vec1->vec[0]; 00221 v1[1] = vec1->vec[1]; 00222 v1[2] = 0.0f; 00223 00224 v2[0] = vec2->vec[0]; 00225 v2[1] = vec2->vec[1]; 00226 v2[2] = 0.0f; 00227 00228 v3[0] = vec3->vec[0]; 00229 v3[1] = vec3->vec[1]; 00230 v3[2] = 0.0f; 00231 00232 v4[0] = vec4->vec[0]; 00233 v4[1] = vec4->vec[1]; 00234 v4[2] = 0.0f; 00235 } 00236 00237 result = isect_line_line_v3(v1, v2, v3, v4, i1, i2); 00238 00239 if (result == 0) { 00240 /* colinear */ 00241 Py_RETURN_NONE; 00242 } 00243 else { 00244 tuple = PyTuple_New(2); 00245 PyTuple_SET_ITEM(tuple, 0, Vector_CreatePyObject(i1, vec1->size, Py_NEW, NULL)); 00246 PyTuple_SET_ITEM(tuple, 1, Vector_CreatePyObject(i2, vec1->size, Py_NEW, NULL)); 00247 return tuple; 00248 } 00249 } 00250 else { 00251 PyErr_SetString(PyExc_ValueError, 00252 "2D/3D vectors only"); 00253 return NULL; 00254 } 00255 } 00256 00257 00258 00259 00260 //----------------------------geometry.normal() ------------------- 00261 PyDoc_STRVAR(M_Geometry_normal_doc, 00262 ".. function:: normal(v1, v2, v3, v4=None)\n" 00263 "\n" 00264 " Returns the normal of the 3D tri or quad.\n" 00265 "\n" 00266 " :arg v1: Point1\n" 00267 " :type v1: :class:`mathutils.Vector`\n" 00268 " :arg v2: Point2\n" 00269 " :type v2: :class:`mathutils.Vector`\n" 00270 " :arg v3: Point3\n" 00271 " :type v3: :class:`mathutils.Vector`\n" 00272 " :arg v4: Point4 (optional)\n" 00273 " :type v4: :class:`mathutils.Vector`\n" 00274 " :rtype: :class:`mathutils.Vector`\n" 00275 ); 00276 static PyObject *M_Geometry_normal(PyObject *UNUSED(self), PyObject *args) 00277 { 00278 VectorObject *vec1, *vec2, *vec3, *vec4; 00279 float n[3]; 00280 00281 if (PyTuple_GET_SIZE(args) == 3) { 00282 if (!PyArg_ParseTuple(args, "O!O!O!:normal", 00283 &vector_Type, &vec1, 00284 &vector_Type, &vec2, 00285 &vector_Type, &vec3)) 00286 { 00287 return NULL; 00288 } 00289 00290 if (vec1->size != vec2->size || vec1->size != vec3->size) { 00291 PyErr_SetString(PyExc_ValueError, 00292 "vectors must be of the same size"); 00293 return NULL; 00294 } 00295 if (vec1->size < 3) { 00296 PyErr_SetString(PyExc_ValueError, 00297 "2D vectors unsupported"); 00298 return NULL; 00299 } 00300 00301 if ( BaseMath_ReadCallback(vec1) == -1 || 00302 BaseMath_ReadCallback(vec2) == -1 || 00303 BaseMath_ReadCallback(vec3) == -1) 00304 { 00305 return NULL; 00306 } 00307 00308 normal_tri_v3(n, vec1->vec, vec2->vec, vec3->vec); 00309 } 00310 else { 00311 if (!PyArg_ParseTuple(args, "O!O!O!O!:normal", 00312 &vector_Type, &vec1, 00313 &vector_Type, &vec2, 00314 &vector_Type, &vec3, 00315 &vector_Type, &vec4)) 00316 { 00317 return NULL; 00318 } 00319 if (vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) { 00320 PyErr_SetString(PyExc_ValueError, 00321 "vectors must be of the same size"); 00322 return NULL; 00323 } 00324 if (vec1->size < 3) { 00325 PyErr_SetString(PyExc_ValueError, 00326 "2D vectors unsupported"); 00327 return NULL; 00328 } 00329 00330 if ( BaseMath_ReadCallback(vec1) == -1 || 00331 BaseMath_ReadCallback(vec2) == -1 || 00332 BaseMath_ReadCallback(vec3) == -1 || 00333 BaseMath_ReadCallback(vec4) == -1) 00334 { 00335 return NULL; 00336 } 00337 00338 normal_quad_v3(n, vec1->vec, vec2->vec, vec3->vec, vec4->vec); 00339 } 00340 00341 return Vector_CreatePyObject(n, 3, Py_NEW, NULL); 00342 } 00343 00344 //--------------------------------- AREA FUNCTIONS-------------------- 00345 00346 PyDoc_STRVAR(M_Geometry_area_tri_doc, 00347 ".. function:: area_tri(v1, v2, v3)\n" 00348 "\n" 00349 " Returns the area size of the 2D or 3D triangle defined.\n" 00350 "\n" 00351 " :arg v1: Point1\n" 00352 " :type v1: :class:`mathutils.Vector`\n" 00353 " :arg v2: Point2\n" 00354 " :type v2: :class:`mathutils.Vector`\n" 00355 " :arg v3: Point3\n" 00356 " :type v3: :class:`mathutils.Vector`\n" 00357 " :rtype: float\n" 00358 ); 00359 static PyObject *M_Geometry_area_tri(PyObject *UNUSED(self), PyObject *args) 00360 { 00361 VectorObject *vec1, *vec2, *vec3; 00362 00363 if (!PyArg_ParseTuple(args, "O!O!O!:area_tri", 00364 &vector_Type, &vec1, 00365 &vector_Type, &vec2, 00366 &vector_Type, &vec3)) 00367 { 00368 return NULL; 00369 } 00370 00371 if (vec1->size != vec2->size || vec1->size != vec3->size) { 00372 PyErr_SetString(PyExc_ValueError, 00373 "vectors must be of the same size"); 00374 return NULL; 00375 } 00376 00377 if ( BaseMath_ReadCallback(vec1) == -1 || 00378 BaseMath_ReadCallback(vec2) == -1 || 00379 BaseMath_ReadCallback(vec3) == -1) 00380 { 00381 return NULL; 00382 } 00383 00384 if (vec1->size == 3) { 00385 return PyFloat_FromDouble(area_tri_v3(vec1->vec, vec2->vec, vec3->vec)); 00386 } 00387 else if (vec1->size == 2) { 00388 return PyFloat_FromDouble(area_tri_v2(vec1->vec, vec2->vec, vec3->vec)); 00389 } 00390 else { 00391 PyErr_SetString(PyExc_ValueError, 00392 "only 2D,3D vectors are supported"); 00393 return NULL; 00394 } 00395 } 00396 00397 00398 PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc, 00399 ".. function:: intersect_line_line_2d(lineA_p1, lineA_p2, lineB_p1, lineB_p2)\n" 00400 "\n" 00401 " Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n" 00402 "\n" 00403 " :arg lineA_p1: First point of the first line\n" 00404 " :type lineA_p1: :class:`mathutils.Vector`\n" 00405 " :arg lineA_p2: Second point of the first line\n" 00406 " :type lineA_p2: :class:`mathutils.Vector`\n" 00407 " :arg lineB_p1: First point of the second line\n" 00408 " :type lineB_p1: :class:`mathutils.Vector`\n" 00409 " :arg lineB_p2: Second point of the second line\n" 00410 " :type lineB_p2: :class:`mathutils.Vector`\n" 00411 " :return: The point of intersection or None when not found\n" 00412 " :rtype: :class:`mathutils.Vector` or None\n" 00413 ); 00414 static PyObject *M_Geometry_intersect_line_line_2d(PyObject *UNUSED(self), PyObject *args) 00415 { 00416 VectorObject *line_a1, *line_a2, *line_b1, *line_b2; 00417 float vi[2]; 00418 if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line_2d", 00419 &vector_Type, &line_a1, 00420 &vector_Type, &line_a2, 00421 &vector_Type, &line_b1, 00422 &vector_Type, &line_b2)) 00423 { 00424 return NULL; 00425 } 00426 00427 if ( BaseMath_ReadCallback(line_a1) == -1 || 00428 BaseMath_ReadCallback(line_a2) == -1 || 00429 BaseMath_ReadCallback(line_b1) == -1 || 00430 BaseMath_ReadCallback(line_b2) == -1) 00431 { 00432 return NULL; 00433 } 00434 00435 if (isect_seg_seg_v2_point(line_a1->vec, line_a2->vec, line_b1->vec, line_b2->vec, vi) == 1) { 00436 return Vector_CreatePyObject(vi, 2, Py_NEW, NULL); 00437 } 00438 else { 00439 Py_RETURN_NONE; 00440 } 00441 } 00442 00443 00444 PyDoc_STRVAR(M_Geometry_intersect_line_plane_doc, 00445 ".. function:: intersect_line_plane(line_a, line_b, plane_co, plane_no, no_flip=False)\n" 00446 "\n" 00447 " Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n" 00448 "\n" 00449 " :arg line_a: First point of the first line\n" 00450 " :type line_a: :class:`mathutils.Vector`\n" 00451 " :arg line_b: Second point of the first line\n" 00452 " :type line_b: :class:`mathutils.Vector`\n" 00453 " :arg plane_co: A point on the plane\n" 00454 " :type plane_co: :class:`mathutils.Vector`\n" 00455 " :arg plane_no: The direction the plane is facing\n" 00456 " :type plane_no: :class:`mathutils.Vector`\n" 00457 " :arg no_flip: Always return an intersection on the directon defined bt line_a -> line_b\n" 00458 " :type no_flip: :boolean\n" 00459 " :return: The point of intersection or None when not found\n" 00460 " :rtype: :class:`mathutils.Vector` or None\n" 00461 ); 00462 static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObject *args) 00463 { 00464 VectorObject *line_a, *line_b, *plane_co, *plane_no; 00465 int no_flip = 0; 00466 float isect[3]; 00467 if (!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_line_plane", 00468 &vector_Type, &line_a, 00469 &vector_Type, &line_b, 00470 &vector_Type, &plane_co, 00471 &vector_Type, &plane_no, 00472 &no_flip)) 00473 { 00474 return NULL; 00475 } 00476 00477 if ( BaseMath_ReadCallback(line_a) == -1 || 00478 BaseMath_ReadCallback(line_b) == -1 || 00479 BaseMath_ReadCallback(plane_co) == -1 || 00480 BaseMath_ReadCallback(plane_no) == -1) 00481 { 00482 return NULL; 00483 } 00484 00485 if (ELEM4(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { 00486 PyErr_SetString(PyExc_ValueError, 00487 "geometry.intersect_line_plane(...): " 00488 " can't use 2D Vectors"); 00489 return NULL; 00490 } 00491 00492 if (isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec, no_flip) == 1) { 00493 return Vector_CreatePyObject(isect, 3, Py_NEW, NULL); 00494 } 00495 else { 00496 Py_RETURN_NONE; 00497 } 00498 } 00499 00500 PyDoc_STRVAR(M_Geometry_intersect_plane_plane_doc, 00501 ".. function:: intersect_plane_plane(plane_a_co, plane_a_no, plane_b_co, plane_b_no)\n" 00502 "\n" 00503 " Return the intersection between two planes\n" 00504 "\n" 00505 " :arg plane_a_co: Point on the first plane\n" 00506 " :type plane_a_co: :class:`mathutils.Vector`\n" 00507 " :arg plane_a_no: Normal of the first plane\n" 00508 " :type plane_a_no: :class:`mathutils.Vector`\n" 00509 " :arg plane_b_co: Point on the second plane\n" 00510 " :type plane_b_co: :class:`mathutils.Vector`\n" 00511 " :arg plane_b_no: Normal of the second plane\n" 00512 " :type plane_b_no: :class:`mathutils.Vector`\n" 00513 " :return: The line of the intersection represented as a point and a vector\n" 00514 " :rtype: tuple pair of :class:`mathutils.Vector`\n" 00515 ); 00516 static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObject *args) 00517 { 00518 PyObject *ret; 00519 VectorObject *plane_a_co, *plane_a_no, *plane_b_co, *plane_b_no; 00520 00521 float isect_co[3]; 00522 float isect_no[3]; 00523 00524 if (!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_plane_plane", 00525 &vector_Type, &plane_a_co, 00526 &vector_Type, &plane_a_no, 00527 &vector_Type, &plane_b_co, 00528 &vector_Type, &plane_b_no)) 00529 { 00530 return NULL; 00531 } 00532 00533 if ( BaseMath_ReadCallback(plane_a_co) == -1 || 00534 BaseMath_ReadCallback(plane_a_no) == -1 || 00535 BaseMath_ReadCallback(plane_b_co) == -1 || 00536 BaseMath_ReadCallback(plane_b_no) == -1) 00537 { 00538 return NULL; 00539 } 00540 00541 if (ELEM4(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) { 00542 PyErr_SetString(PyExc_ValueError, 00543 "geometry.intersect_plane_plane(...): " 00544 " can't use 2D Vectors"); 00545 return NULL; 00546 } 00547 00548 isect_plane_plane_v3(isect_co, isect_no, 00549 plane_a_co->vec, plane_a_no->vec, 00550 plane_b_co->vec, plane_b_no->vec); 00551 00552 normalize_v3(isect_no); 00553 00554 ret = PyTuple_New(2); 00555 PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_co, 3, Py_NEW, NULL)); 00556 PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_no, 3, Py_NEW, NULL)); 00557 return ret; 00558 } 00559 00560 PyDoc_STRVAR(M_Geometry_intersect_line_sphere_doc, 00561 ".. function:: intersect_line_sphere(line_a, line_b, sphere_co, sphere_radius, clip=True)\n" 00562 "\n" 00563 " Takes a lines (as 2 vectors), a sphere as a point and a radius and\n" 00564 " returns the intersection\n" 00565 "\n" 00566 " :arg line_a: First point of the first line\n" 00567 " :type line_a: :class:`mathutils.Vector`\n" 00568 " :arg line_b: Second point of the first line\n" 00569 " :type line_b: :class:`mathutils.Vector`\n" 00570 " :arg sphere_co: The center of the sphere\n" 00571 " :type sphere_co: :class:`mathutils.Vector`\n" 00572 " :arg sphere_radius: Radius of the sphere\n" 00573 " :type sphere_radius: sphere_radius\n" 00574 " :return: The intersection points as a pair of vectors or None when there is no intersection\n" 00575 " :rtype: A tuple pair containing :class:`mathutils.Vector` or None\n" 00576 ); 00577 static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObject *args) 00578 { 00579 VectorObject *line_a, *line_b, *sphere_co; 00580 float sphere_radius; 00581 int clip = TRUE; 00582 00583 float isect_a[3]; 00584 float isect_b[3]; 00585 00586 if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere", 00587 &vector_Type, &line_a, 00588 &vector_Type, &line_b, 00589 &vector_Type, &sphere_co, 00590 &sphere_radius, &clip)) 00591 { 00592 return NULL; 00593 } 00594 00595 if ( BaseMath_ReadCallback(line_a) == -1 || 00596 BaseMath_ReadCallback(line_b) == -1 || 00597 BaseMath_ReadCallback(sphere_co) == -1) 00598 { 00599 return NULL; 00600 } 00601 00602 if (ELEM3(2, line_a->size, line_b->size, sphere_co->size)) { 00603 PyErr_SetString(PyExc_ValueError, 00604 "geometry.intersect_line_sphere(...): " 00605 " can't use 2D Vectors"); 00606 return NULL; 00607 } 00608 else { 00609 short use_a = TRUE; 00610 short use_b = TRUE; 00611 float lambda; 00612 00613 PyObject *ret = PyTuple_New(2); 00614 00615 switch (isect_line_sphere_v3(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) { 00616 case 1: 00617 if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE; 00618 use_b = FALSE; 00619 break; 00620 case 2: 00621 if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE; 00622 if (!(!clip || (((lambda = line_point_factor_v3(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = FALSE; 00623 break; 00624 default: 00625 use_a = FALSE; 00626 use_b = FALSE; 00627 } 00628 00629 if (use_a) { PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_a, 3, Py_NEW, NULL)); } 00630 else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); } 00631 00632 if (use_b) { PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_b, 3, Py_NEW, NULL)); } 00633 else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); } 00634 00635 return ret; 00636 } 00637 } 00638 00639 /* keep in sync with M_Geometry_intersect_line_sphere */ 00640 PyDoc_STRVAR(M_Geometry_intersect_line_sphere_2d_doc, 00641 ".. function:: intersect_line_sphere_2d(line_a, line_b, sphere_co, sphere_radius, clip=True)\n" 00642 "\n" 00643 " Takes a lines (as 2 vectors), a sphere as a point and a radius and\n" 00644 " returns the intersection\n" 00645 "\n" 00646 " :arg line_a: First point of the first line\n" 00647 " :type line_a: :class:`mathutils.Vector`\n" 00648 " :arg line_b: Second point of the first line\n" 00649 " :type line_b: :class:`mathutils.Vector`\n" 00650 " :arg sphere_co: The center of the sphere\n" 00651 " :type sphere_co: :class:`mathutils.Vector`\n" 00652 " :arg sphere_radius: Radius of the sphere\n" 00653 " :type sphere_radius: sphere_radius\n" 00654 " :return: The intersection points as a pair of vectors or None when there is no intersection\n" 00655 " :rtype: A tuple pair containing :class:`mathutils.Vector` or None\n" 00656 ); 00657 static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyObject *args) 00658 { 00659 VectorObject *line_a, *line_b, *sphere_co; 00660 float sphere_radius; 00661 int clip = TRUE; 00662 00663 float isect_a[3]; 00664 float isect_b[3]; 00665 00666 if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere_2d", 00667 &vector_Type, &line_a, 00668 &vector_Type, &line_b, 00669 &vector_Type, &sphere_co, 00670 &sphere_radius, &clip)) 00671 { 00672 return NULL; 00673 } 00674 00675 if ( BaseMath_ReadCallback(line_a) == -1 || 00676 BaseMath_ReadCallback(line_b) == -1 || 00677 BaseMath_ReadCallback(sphere_co) == -1) 00678 { 00679 return NULL; 00680 } 00681 else { 00682 short use_a = TRUE; 00683 short use_b = TRUE; 00684 float lambda; 00685 00686 PyObject *ret = PyTuple_New(2); 00687 00688 switch (isect_line_sphere_v2(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) { 00689 case 1: 00690 if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE; 00691 use_b = FALSE; 00692 break; 00693 case 2: 00694 if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE; 00695 if (!(!clip || (((lambda = line_point_factor_v2(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = FALSE; 00696 break; 00697 default: 00698 use_a = FALSE; 00699 use_b = FALSE; 00700 } 00701 00702 if (use_a) { PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_a, 2, Py_NEW, NULL)); } 00703 else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); } 00704 00705 if (use_b) { PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_b, 2, Py_NEW, NULL)); } 00706 else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); } 00707 00708 return ret; 00709 } 00710 } 00711 00712 PyDoc_STRVAR(M_Geometry_intersect_point_line_doc, 00713 ".. function:: intersect_point_line(pt, line_p1, line_p2)\n" 00714 "\n" 00715 " Takes a point and a line and returns a tuple with the closest point on the line and its distance from the first point of the line as a percentage of the length of the line.\n" 00716 "\n" 00717 " :arg pt: Point\n" 00718 " :type pt: :class:`mathutils.Vector`\n" 00719 " :arg line_p1: First point of the line\n" 00720 " :type line_p1: :class:`mathutils.Vector`\n" 00721 " :arg line_p1: Second point of the line\n" 00722 " :type line_p1: :class:`mathutils.Vector`\n" 00723 " :rtype: (:class:`mathutils.Vector`, float)\n" 00724 ); 00725 static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObject *args) 00726 { 00727 VectorObject *pt, *line_1, *line_2; 00728 float pt_in[3], pt_out[3], l1[3], l2[3]; 00729 float lambda; 00730 PyObject *ret; 00731 00732 if (!PyArg_ParseTuple(args, "O!O!O!:intersect_point_line", 00733 &vector_Type, &pt, 00734 &vector_Type, &line_1, 00735 &vector_Type, &line_2)) 00736 { 00737 return NULL; 00738 } 00739 00740 if ( BaseMath_ReadCallback(pt) == -1 || 00741 BaseMath_ReadCallback(line_1) == -1 || 00742 BaseMath_ReadCallback(line_2) == -1) 00743 { 00744 return NULL; 00745 } 00746 00747 /* accept 2d verts */ 00748 if (pt->size == 3) { copy_v3_v3(pt_in, pt->vec);} 00749 else { pt_in[2] = 0.0f; copy_v2_v2(pt_in, pt->vec); } 00750 00751 if (line_1->size == 3) { copy_v3_v3(l1, line_1->vec);} 00752 else { l1[2] = 0.0f; copy_v2_v2(l1, line_1->vec); } 00753 00754 if (line_2->size == 3) { copy_v3_v3(l2, line_2->vec);} 00755 else { l2[2] = 0.0f; copy_v2_v2(l2, line_2->vec); } 00756 00757 /* do the calculation */ 00758 lambda = closest_to_line_v3(pt_out, pt_in, l1, l2); 00759 00760 ret = PyTuple_New(2); 00761 PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(pt_out, 3, Py_NEW, NULL)); 00762 PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(lambda)); 00763 return ret; 00764 } 00765 00766 PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc, 00767 ".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n" 00768 "\n" 00769 " Takes 4 vectors (using only the x and y coordinates): one is the point and the next 3 define the triangle. Returns 1 if the point is within the triangle, otherwise 0.\n" 00770 "\n" 00771 " :arg pt: Point\n" 00772 " :type v1: :class:`mathutils.Vector`\n" 00773 " :arg tri_p1: First point of the triangle\n" 00774 " :type tri_p1: :class:`mathutils.Vector`\n" 00775 " :arg tri_p2: Second point of the triangle\n" 00776 " :type tri_p2: :class:`mathutils.Vector`\n" 00777 " :arg tri_p3: Third point of the triangle\n" 00778 " :type tri_p3: :class:`mathutils.Vector`\n" 00779 " :rtype: int\n" 00780 ); 00781 static PyObject *M_Geometry_intersect_point_tri_2d(PyObject *UNUSED(self), PyObject *args) 00782 { 00783 VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; 00784 00785 if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri_2d", 00786 &vector_Type, &pt_vec, 00787 &vector_Type, &tri_p1, 00788 &vector_Type, &tri_p2, 00789 &vector_Type, &tri_p3)) 00790 { 00791 return NULL; 00792 } 00793 00794 if ( BaseMath_ReadCallback(pt_vec) == -1 || 00795 BaseMath_ReadCallback(tri_p1) == -1 || 00796 BaseMath_ReadCallback(tri_p2) == -1 || 00797 BaseMath_ReadCallback(tri_p3) == -1) 00798 { 00799 return NULL; 00800 } 00801 00802 return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec)); 00803 } 00804 00805 PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc, 00806 ".. function:: intersect_point_quad_2d(pt, quad_p1, quad_p2, quad_p3, quad_p4)\n" 00807 "\n" 00808 " Takes 5 vectors (using only the x and y coordinates): one is the point and the next 4 define the quad, \n" 00809 " only the x and y are used from the vectors. Returns 1 if the point is within the quad, otherwise 0.\n" 00810 "\n" 00811 " :arg pt: Point\n" 00812 " :type pt: :class:`mathutils.Vector`\n" 00813 " :arg quad_p1: First point of the quad\n" 00814 " :type quad_p1: :class:`mathutils.Vector`\n" 00815 " :arg quad_p2: Second point of the quad\n" 00816 " :type quad_p2: :class:`mathutils.Vector`\n" 00817 " :arg quad_p3: Third point of the quad\n" 00818 " :type quad_p3: :class:`mathutils.Vector`\n" 00819 " :arg quad_p4: Forth point of the quad\n" 00820 " :type quad_p4: :class:`mathutils.Vector`\n" 00821 " :rtype: int\n" 00822 ); 00823 static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyObject *args) 00824 { 00825 VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4; 00826 00827 if (!PyArg_ParseTuple(args, "O!O!O!O!O!:intersect_point_quad_2d", 00828 &vector_Type, &pt_vec, 00829 &vector_Type, &quad_p1, 00830 &vector_Type, &quad_p2, 00831 &vector_Type, &quad_p3, 00832 &vector_Type, &quad_p4)) 00833 { 00834 return NULL; 00835 } 00836 00837 if ( BaseMath_ReadCallback(pt_vec) == -1 || 00838 BaseMath_ReadCallback(quad_p1) == -1 || 00839 BaseMath_ReadCallback(quad_p2) == -1 || 00840 BaseMath_ReadCallback(quad_p3) == -1 || 00841 BaseMath_ReadCallback(quad_p4) == -1) 00842 { 00843 return NULL; 00844 } 00845 00846 return PyLong_FromLong(isect_point_quad_v2(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec)); 00847 } 00848 00849 PyDoc_STRVAR(M_Geometry_distance_point_to_plane_doc, 00850 ".. function:: distance_point_to_plane(pt, plane_co, plane_no)\n" 00851 "\n" 00852 " Returns the signed distance between a point and a plane " 00853 " (negative when below the normal).\n" 00854 "\n" 00855 " :arg pt: Point\n" 00856 " :type pt: :class:`mathutils.Vector`\n" 00857 " :arg plane_co: First point of the quad\n" 00858 " :type plane_co: :class:`mathutils.Vector`\n" 00859 " :arg plane_no: Second point of the quad\n" 00860 " :type plane_no: :class:`mathutils.Vector`\n" 00861 " :rtype: float\n" 00862 ); 00863 static PyObject *M_Geometry_distance_point_to_plane(PyObject *UNUSED(self), PyObject *args) 00864 { 00865 VectorObject *pt, *plene_co, *plane_no; 00866 00867 if (!PyArg_ParseTuple(args, "O!O!O!:distance_point_to_plane", 00868 &vector_Type, &pt, 00869 &vector_Type, &plene_co, 00870 &vector_Type, &plane_no)) 00871 { 00872 return NULL; 00873 } 00874 00875 if ( BaseMath_ReadCallback(pt) == -1 || 00876 BaseMath_ReadCallback(plene_co) == -1 || 00877 BaseMath_ReadCallback(plane_no) == -1) 00878 { 00879 return NULL; 00880 } 00881 00882 return PyFloat_FromDouble(dist_to_plane_v3(pt->vec, plene_co->vec, plane_no->vec)); 00883 } 00884 00885 PyDoc_STRVAR(M_Geometry_barycentric_transform_doc, 00886 ".. function:: barycentric_transform(point, tri_a1, tri_a2, tri_a3, tri_b1, tri_b2, tri_b3)\n" 00887 "\n" 00888 " Return a transformed point, the transformation is defined by 2 triangles.\n" 00889 "\n" 00890 " :arg point: The point to transform.\n" 00891 " :type point: :class:`mathutils.Vector`\n" 00892 " :arg tri_a1: source triangle vertex.\n" 00893 " :type tri_a1: :class:`mathutils.Vector`\n" 00894 " :arg tri_a2: source triangle vertex.\n" 00895 " :type tri_a2: :class:`mathutils.Vector`\n" 00896 " :arg tri_a3: source triangle vertex.\n" 00897 " :type tri_a3: :class:`mathutils.Vector`\n" 00898 " :arg tri_a1: target triangle vertex.\n" 00899 " :type tri_a1: :class:`mathutils.Vector`\n" 00900 " :arg tri_a2: target triangle vertex.\n" 00901 " :type tri_a2: :class:`mathutils.Vector`\n" 00902 " :arg tri_a3: target triangle vertex.\n" 00903 " :type tri_a3: :class:`mathutils.Vector`\n" 00904 " :return: The transformed point\n" 00905 " :rtype: :class:`mathutils.Vector`'s\n" 00906 ); 00907 static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObject *args) 00908 { 00909 VectorObject *vec_pt; 00910 VectorObject *vec_t1_tar, *vec_t2_tar, *vec_t3_tar; 00911 VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src; 00912 float vec[3]; 00913 00914 if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!:barycentric_transform", 00915 &vector_Type, &vec_pt, 00916 &vector_Type, &vec_t1_src, 00917 &vector_Type, &vec_t2_src, 00918 &vector_Type, &vec_t3_src, 00919 &vector_Type, &vec_t1_tar, 00920 &vector_Type, &vec_t2_tar, 00921 &vector_Type, &vec_t3_tar)) 00922 { 00923 return NULL; 00924 } 00925 00926 if ( vec_pt->size != 3 || 00927 vec_t1_src->size != 3 || 00928 vec_t2_src->size != 3 || 00929 vec_t3_src->size != 3 || 00930 vec_t1_tar->size != 3 || 00931 vec_t2_tar->size != 3 || 00932 vec_t3_tar->size != 3) 00933 { 00934 PyErr_SetString(PyExc_ValueError, 00935 "One of more of the vector arguments wasn't a 3D vector"); 00936 return NULL; 00937 } 00938 00939 barycentric_transform(vec, vec_pt->vec, 00940 vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec, 00941 vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec); 00942 00943 return Vector_CreatePyObject(vec, 3, Py_NEW, NULL); 00944 } 00945 00946 #ifndef MATH_STANDALONE 00947 00948 PyDoc_STRVAR(M_Geometry_interpolate_bezier_doc, 00949 ".. function:: interpolate_bezier(knot1, handle1, handle2, knot2, resolution)\n" 00950 "\n" 00951 " Interpolate a bezier spline segment.\n" 00952 "\n" 00953 " :arg knot1: First bezier spline point.\n" 00954 " :type knot1: :class:`mathutils.Vector`\n" 00955 " :arg handle1: First bezier spline handle.\n" 00956 " :type handle1: :class:`mathutils.Vector`\n" 00957 " :arg handle2: Second bezier spline handle.\n" 00958 " :type handle2: :class:`mathutils.Vector`\n" 00959 " :arg knot2: Second bezier spline point.\n" 00960 " :type knot2: :class:`mathutils.Vector`\n" 00961 " :arg resolution: Number of points to return.\n" 00962 " :type resolution: int\n" 00963 " :return: The interpolated points\n" 00964 " :rtype: list of :class:`mathutils.Vector`'s\n" 00965 ); 00966 static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject *args) 00967 { 00968 VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2; 00969 int resolu; 00970 int dims; 00971 int i; 00972 float *coord_array, *fp; 00973 PyObject *list; 00974 00975 float k1[4] = {0.0, 0.0, 0.0, 0.0}; 00976 float h1[4] = {0.0, 0.0, 0.0, 0.0}; 00977 float k2[4] = {0.0, 0.0, 0.0, 0.0}; 00978 float h2[4] = {0.0, 0.0, 0.0, 0.0}; 00979 00980 00981 if (!PyArg_ParseTuple(args, "O!O!O!O!i:interpolate_bezier", 00982 &vector_Type, &vec_k1, 00983 &vector_Type, &vec_h1, 00984 &vector_Type, &vec_h2, 00985 &vector_Type, &vec_k2, &resolu)) 00986 { 00987 return NULL; 00988 } 00989 00990 if (resolu <= 1) { 00991 PyErr_SetString(PyExc_ValueError, 00992 "resolution must be 2 or over"); 00993 return NULL; 00994 } 00995 00996 if ( BaseMath_ReadCallback(vec_k1) == -1 || 00997 BaseMath_ReadCallback(vec_h1) == -1 || 00998 BaseMath_ReadCallback(vec_k2) == -1 || 00999 BaseMath_ReadCallback(vec_h2) == -1) 01000 { 01001 return NULL; 01002 } 01003 01004 dims = MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size); 01005 01006 for (i = 0; i < vec_k1->size; i++) k1[i] = vec_k1->vec[i]; 01007 for (i = 0; i < vec_h1->size; i++) h1[i] = vec_h1->vec[i]; 01008 for (i = 0; i < vec_k2->size; i++) k2[i] = vec_k2->vec[i]; 01009 for (i = 0; i < vec_h2->size; i++) h2[i] = vec_h2->vec[i]; 01010 01011 coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier"); 01012 for (i = 0; i < dims; i++) { 01013 forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array + i, resolu - 1, sizeof(float)*dims); 01014 } 01015 01016 list = PyList_New(resolu); 01017 fp = coord_array; 01018 for (i = 0; i < resolu; i++, fp = fp + dims) { 01019 PyList_SET_ITEM(list, i, Vector_CreatePyObject(fp, dims, Py_NEW, NULL)); 01020 } 01021 MEM_freeN(coord_array); 01022 return list; 01023 } 01024 01025 01026 PyDoc_STRVAR(M_Geometry_tesselate_polygon_doc, 01027 ".. function:: tesselate_polygon(veclist_list)\n" 01028 "\n" 01029 " Takes a list of polylines (each point a vector) and returns the point indices for a polyline filled with triangles.\n" 01030 "\n" 01031 " :arg veclist_list: list of polylines\n" 01032 " :rtype: list\n" 01033 ); 01034 /* PolyFill function, uses Blenders scanfill to fill multiple poly lines */ 01035 static PyObject *M_Geometry_tesselate_polygon(PyObject *UNUSED(self), PyObject *polyLineSeq) 01036 { 01037 PyObject *tri_list; /*return this list of tri's */ 01038 PyObject *polyLine, *polyVec; 01039 int i, len_polylines, len_polypoints, ls_error = 0; 01040 01041 /* display listbase */ 01042 ListBase dispbase = {NULL, NULL}; 01043 DispList *dl; 01044 float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ 01045 int index, *dl_face, totpoints = 0; 01046 01047 if (!PySequence_Check(polyLineSeq)) { 01048 PyErr_SetString(PyExc_TypeError, 01049 "expected a sequence of poly lines"); 01050 return NULL; 01051 } 01052 01053 len_polylines = PySequence_Size(polyLineSeq); 01054 01055 for (i = 0; i < len_polylines; i++) { 01056 polyLine = PySequence_GetItem(polyLineSeq, i); 01057 if (!PySequence_Check(polyLine)) { 01058 freedisplist(&dispbase); 01059 Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/ 01060 PyErr_SetString(PyExc_TypeError, 01061 "One or more of the polylines is not a sequence of mathutils.Vector's"); 01062 return NULL; 01063 } 01064 01065 len_polypoints = PySequence_Size(polyLine); 01066 if (len_polypoints > 0) { /* dont bother adding edges as polylines */ 01067 #if 0 01068 if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) { 01069 freedisplist(&dispbase); 01070 Py_DECREF(polyLine); 01071 PyErr_SetString(PyExc_TypeError, 01072 "A point in one of the polylines is not a mathutils.Vector type"); 01073 return NULL; 01074 } 01075 #endif 01076 dl = MEM_callocN(sizeof(DispList), "poly disp"); 01077 BLI_addtail(&dispbase, dl); 01078 dl->type = DL_INDEX3; 01079 dl->nr = len_polypoints; 01080 dl->type = DL_POLY; 01081 dl->parts = 1; /* no faces, 1 edge loop */ 01082 dl->col = 0; /* no material */ 01083 dl->verts = fp = MEM_callocN(sizeof(float) * 3 * len_polypoints, "dl verts"); 01084 dl->index = MEM_callocN(sizeof(int) * 3 * len_polypoints, "dl index"); 01085 01086 for (index = 0; index < len_polypoints; index++, fp += 3) { 01087 polyVec = PySequence_GetItem(polyLine, index); 01088 if (VectorObject_Check(polyVec)) { 01089 01090 if (BaseMath_ReadCallback((VectorObject *)polyVec) == -1) 01091 ls_error = 1; 01092 01093 fp[0] = ((VectorObject *)polyVec)->vec[0]; 01094 fp[1] = ((VectorObject *)polyVec)->vec[1]; 01095 if (((VectorObject *)polyVec)->size > 2) 01096 fp[2] = ((VectorObject *)polyVec)->vec[2]; 01097 else 01098 fp[2] = 0.0f; /* if its a 2d vector then set the z to be zero */ 01099 } 01100 else { 01101 ls_error = 1; 01102 } 01103 01104 totpoints++; 01105 Py_DECREF(polyVec); 01106 } 01107 } 01108 Py_DECREF(polyLine); 01109 } 01110 01111 if (ls_error) { 01112 freedisplist(&dispbase); /* possible some dl was allocated */ 01113 PyErr_SetString(PyExc_TypeError, 01114 "A point in one of the polylines " 01115 "is not a mathutils.Vector type"); 01116 return NULL; 01117 } 01118 else if (totpoints) { 01119 /* now make the list to return */ 01120 filldisplist(&dispbase, &dispbase, 0); 01121 01122 /* The faces are stored in a new DisplayList 01123 thats added to the head of the listbase */ 01124 dl = dispbase.first; 01125 01126 tri_list = PyList_New(dl->parts); 01127 if (!tri_list) { 01128 freedisplist(&dispbase); 01129 PyErr_SetString(PyExc_RuntimeError, 01130 "failed to make a new list"); 01131 return NULL; 01132 } 01133 01134 index = 0; 01135 dl_face = dl->index; 01136 while (index < dl->parts) { 01137 PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2])); 01138 dl_face += 3; 01139 index++; 01140 } 01141 freedisplist(&dispbase); 01142 } 01143 else { 01144 /* no points, do this so scripts dont barf */ 01145 freedisplist(&dispbase); /* possible some dl was allocated */ 01146 tri_list = PyList_New(0); 01147 } 01148 01149 return tri_list; 01150 } 01151 01152 01153 static int boxPack_FromPyObject(PyObject *value, boxPack **boxarray) 01154 { 01155 Py_ssize_t len, i; 01156 PyObject *list_item, *item_1, *item_2; 01157 boxPack *box; 01158 01159 01160 /* Error checking must already be done */ 01161 if (!PyList_Check(value)) { 01162 PyErr_SetString(PyExc_TypeError, 01163 "can only back a list of [x, y, w, h]"); 01164 return -1; 01165 } 01166 01167 len = PyList_GET_SIZE(value); 01168 01169 *boxarray = MEM_mallocN(len * sizeof(boxPack), "boxPack box"); 01170 01171 01172 for (i = 0; i < len; i++) { 01173 list_item = PyList_GET_ITEM(value, i); 01174 if (!PyList_Check(list_item) || PyList_GET_SIZE(list_item) < 4) { 01175 MEM_freeN(*boxarray); 01176 PyErr_SetString(PyExc_TypeError, 01177 "can only pack a list of [x, y, w, h]"); 01178 return -1; 01179 } 01180 01181 box = (*boxarray) + i; 01182 01183 item_1 = PyList_GET_ITEM(list_item, 2); 01184 item_2 = PyList_GET_ITEM(list_item, 3); 01185 01186 box->w = (float)PyFloat_AsDouble(item_1); 01187 box->h = (float)PyFloat_AsDouble(item_2); 01188 box->index = i; 01189 01190 /* accounts for error case too and overwrites with own error */ 01191 if (box->w < 0.0f || box->h < 0.0f) { 01192 MEM_freeN(*boxarray); 01193 PyErr_SetString(PyExc_TypeError, 01194 "error parsing width and height values from list: " 01195 "[x, y, w, h], not numbers or below zero"); 01196 return -1; 01197 } 01198 01199 /* verts will be added later */ 01200 } 01201 return 0; 01202 } 01203 01204 static void boxPack_ToPyObject(PyObject *value, boxPack **boxarray) 01205 { 01206 Py_ssize_t len, i; 01207 PyObject *list_item; 01208 boxPack *box; 01209 01210 len = PyList_GET_SIZE(value); 01211 01212 for (i = 0; i < len; i++) { 01213 box = (*boxarray) + i; 01214 list_item = PyList_GET_ITEM(value, box->index); 01215 PyList_SET_ITEM(list_item, 0, PyFloat_FromDouble(box->x)); 01216 PyList_SET_ITEM(list_item, 1, PyFloat_FromDouble(box->y)); 01217 } 01218 MEM_freeN(*boxarray); 01219 } 01220 01221 PyDoc_STRVAR(M_Geometry_box_pack_2d_doc, 01222 ".. function:: box_pack_2d(boxes)\n" 01223 "\n" 01224 " Returns the normal of the 3D tri or quad.\n" 01225 "\n" 01226 " :arg boxes: list of boxes, each box is a list where the first 4 items are [x, y, width, height, ...] other items are ignored.\n" 01227 " :type boxes: list\n" 01228 " :return: the width and height of the packed bounding box\n" 01229 " :rtype: tuple, pair of floats\n" 01230 ); 01231 static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlist) 01232 { 01233 float tot_width = 0.0f, tot_height = 0.0f; 01234 Py_ssize_t len; 01235 01236 PyObject *ret; 01237 01238 if (!PyList_Check(boxlist)) { 01239 PyErr_SetString(PyExc_TypeError, 01240 "expected a list of boxes [[x, y, w, h], ... ]"); 01241 return NULL; 01242 } 01243 01244 len = PyList_GET_SIZE(boxlist); 01245 if (len) { 01246 boxPack *boxarray = NULL; 01247 if (boxPack_FromPyObject(boxlist, &boxarray) == -1) { 01248 return NULL; /* exception set */ 01249 } 01250 01251 /* Non Python function */ 01252 boxPack2D(boxarray, len, &tot_width, &tot_height); 01253 01254 boxPack_ToPyObject(boxlist, &boxarray); 01255 } 01256 01257 ret = PyTuple_New(2); 01258 PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(tot_width)); 01259 PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(tot_width)); 01260 return ret; 01261 } 01262 01263 #endif /* MATH_STANDALONE */ 01264 01265 01266 static PyMethodDef M_Geometry_methods[] = { 01267 {"intersect_ray_tri", (PyCFunction) M_Geometry_intersect_ray_tri, METH_VARARGS, M_Geometry_intersect_ray_tri_doc}, 01268 {"intersect_point_line", (PyCFunction) M_Geometry_intersect_point_line, METH_VARARGS, M_Geometry_intersect_point_line_doc}, 01269 {"intersect_point_tri_2d", (PyCFunction) M_Geometry_intersect_point_tri_2d, METH_VARARGS, M_Geometry_intersect_point_tri_2d_doc}, 01270 {"intersect_point_quad_2d", (PyCFunction) M_Geometry_intersect_point_quad_2d, METH_VARARGS, M_Geometry_intersect_point_quad_2d_doc}, 01271 {"intersect_line_line", (PyCFunction) M_Geometry_intersect_line_line, METH_VARARGS, M_Geometry_intersect_line_line_doc}, 01272 {"intersect_line_line_2d", (PyCFunction) M_Geometry_intersect_line_line_2d, METH_VARARGS, M_Geometry_intersect_line_line_2d_doc}, 01273 {"intersect_line_plane", (PyCFunction) M_Geometry_intersect_line_plane, METH_VARARGS, M_Geometry_intersect_line_plane_doc}, 01274 {"intersect_plane_plane", (PyCFunction) M_Geometry_intersect_plane_plane, METH_VARARGS, M_Geometry_intersect_plane_plane_doc}, 01275 {"intersect_line_sphere", (PyCFunction) M_Geometry_intersect_line_sphere, METH_VARARGS, M_Geometry_intersect_line_sphere_doc}, 01276 {"intersect_line_sphere_2d", (PyCFunction) M_Geometry_intersect_line_sphere_2d, METH_VARARGS, M_Geometry_intersect_line_sphere_2d_doc}, 01277 {"distance_point_to_plane", (PyCFunction) M_Geometry_distance_point_to_plane, METH_VARARGS, M_Geometry_distance_point_to_plane_doc}, 01278 {"area_tri", (PyCFunction) M_Geometry_area_tri, METH_VARARGS, M_Geometry_area_tri_doc}, 01279 {"normal", (PyCFunction) M_Geometry_normal, METH_VARARGS, M_Geometry_normal_doc}, 01280 {"barycentric_transform", (PyCFunction) M_Geometry_barycentric_transform, METH_VARARGS, M_Geometry_barycentric_transform_doc}, 01281 #ifndef MATH_STANDALONE 01282 {"interpolate_bezier", (PyCFunction) M_Geometry_interpolate_bezier, METH_VARARGS, M_Geometry_interpolate_bezier_doc}, 01283 {"tesselate_polygon", (PyCFunction) M_Geometry_tesselate_polygon, METH_O, M_Geometry_tesselate_polygon_doc}, 01284 {"box_pack_2d", (PyCFunction) M_Geometry_box_pack_2d, METH_O, M_Geometry_box_pack_2d_doc}, 01285 #endif 01286 {NULL, NULL, 0, NULL} 01287 }; 01288 01289 static struct PyModuleDef M_Geometry_module_def = { 01290 PyModuleDef_HEAD_INIT, 01291 "mathutils.geometry", /* m_name */ 01292 M_Geometry_doc, /* m_doc */ 01293 0, /* m_size */ 01294 M_Geometry_methods, /* m_methods */ 01295 NULL, /* m_reload */ 01296 NULL, /* m_traverse */ 01297 NULL, /* m_clear */ 01298 NULL, /* m_free */ 01299 }; 01300 01301 /*----------------------------MODULE INIT-------------------------*/ 01302 PyMODINIT_FUNC PyInit_mathutils_geometry(void) 01303 { 01304 PyObject *submodule = PyModule_Create(&M_Geometry_module_def); 01305 return submodule; 01306 }