Blender V2.61 - r43446

mathutils_geometry.c

Go to the documentation of this file.
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 }