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