~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to source/blender/python/mathutils/mathutils_geometry.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 * ***** BEGIN GPL LICENSE BLOCK *****
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software Foundation,
 
17
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
18
 *
 
19
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 
20
 * All rights reserved.
 
21
 *
 
22
 * This is a new part of Blender.
 
23
 *
 
24
 * Contributor(s): Joseph Gilbert, Campbell Barton
 
25
 *
 
26
 * ***** END GPL LICENSE BLOCK *****
 
27
 */
 
28
 
 
29
/** \file blender/python/mathutils/mathutils_geometry.c
 
30
 *  \ingroup pymathutils
 
31
 */
 
32
 
 
33
 
 
34
#include <Python.h>
 
35
 
 
36
#include "mathutils_geometry.h"
 
37
 
 
38
/* Used for PolyFill */
 
39
#ifndef MATH_STANDALONE /* define when building outside blender */
 
40
#  include "MEM_guardedalloc.h"
 
41
#  include "BLI_blenlib.h"
 
42
#  include "BLI_boxpack2d.h"
 
43
#  include "BKE_displist.h"
 
44
#  include "BKE_curve.h"
 
45
#endif
 
46
 
 
47
#include "BLI_math.h"
 
48
#include "BLI_utildefines.h"
 
49
 
 
50
#define SWAP_FLOAT(a, b, tmp) tmp = a; a = b; b = tmp
 
51
 
 
52
/*-------------------------DOC STRINGS ---------------------------*/
 
53
PyDoc_STRVAR(M_Geometry_doc,
 
54
"The Blender geometry module"
 
55
);
 
56
 
 
57
//---------------------------------INTERSECTION FUNCTIONS--------------------
 
58
 
 
59
PyDoc_STRVAR(M_Geometry_intersect_ray_tri_doc,
 
60
".. function:: intersect_ray_tri(v1, v2, v3, ray, orig, clip=True)\n"
 
61
"\n"
 
62
"   Returns the intersection between a ray and a triangle, if possible, returns None otherwise.\n"
 
63
"\n"
 
64
"   :arg v1: Point1\n"
 
65
"   :type v1: :class:`mathutils.Vector`\n"
 
66
"   :arg v2: Point2\n"
 
67
"   :type v2: :class:`mathutils.Vector`\n"
 
68
"   :arg v3: Point3\n"
 
69
"   :type v3: :class:`mathutils.Vector`\n"
 
70
"   :arg ray: Direction of the projection\n"
 
71
"   :type ray: :class:`mathutils.Vector`\n"
 
72
"   :arg orig: Origin\n"
 
73
"   :type orig: :class:`mathutils.Vector`\n"
 
74
"   :arg clip: When False, don't restrict the intersection to the area of the triangle, use the infinite plane defined by the triangle.\n"
 
75
"   :type clip: boolean\n"
 
76
"   :return: The point of intersection or None if no intersection is found\n"
 
77
"   :rtype: :class:`mathutils.Vector` or None\n"
 
78
);
 
79
static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args)
 
80
{
 
81
        VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
 
82
        float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
 
83
        float det, inv_det, u, v, t;
 
84
        int clip = 1;
 
85
 
 
86
        if (!PyArg_ParseTuple(args,
 
87
                              "O!O!O!O!O!|i:intersect_ray_tri",
 
88
                              &vector_Type, &vec1,
 
89
                              &vector_Type, &vec2,
 
90
                              &vector_Type, &vec3,
 
91
                              &vector_Type, &ray,
 
92
                              &vector_Type, &ray_off, &clip))
 
93
        {
 
94
                return NULL;
 
95
        }
 
96
        if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
 
97
                PyErr_SetString(PyExc_ValueError,
 
98
                                "only 3D vectors for all parameters");
 
99
                return NULL;
 
100
        }
 
101
 
 
102
        if (BaseMath_ReadCallback(vec1) == -1 ||
 
103
            BaseMath_ReadCallback(vec2) == -1 ||
 
104
            BaseMath_ReadCallback(vec3) == -1 ||
 
105
            BaseMath_ReadCallback(ray)  == -1 ||
 
106
            BaseMath_ReadCallback(ray_off) == -1)
 
107
        {
 
108
                return NULL;
 
109
        }
 
110
 
 
111
        copy_v3_v3(v1, vec1->vec);
 
112
        copy_v3_v3(v2, vec2->vec);
 
113
        copy_v3_v3(v3, vec3->vec);
 
114
 
 
115
        copy_v3_v3(dir, ray->vec);
 
116
        normalize_v3(dir);
 
117
 
 
118
        copy_v3_v3(orig, ray_off->vec);
 
119
 
 
120
        /* find vectors for two edges sharing v1 */
 
121
        sub_v3_v3v3(e1, v2, v1);
 
122
        sub_v3_v3v3(e2, v3, v1);
 
123
 
 
124
        /* begin calculating determinant - also used to calculated U parameter */
 
125
        cross_v3_v3v3(pvec, dir, e2);
 
126
 
 
127
        /* if determinant is near zero, ray lies in plane of triangle */
 
128
        det = dot_v3v3(e1, pvec);
 
129
 
 
130
        if (det > -0.000001f && det < 0.000001f) {
 
131
                Py_RETURN_NONE;
 
132
        }
 
133
 
 
134
        inv_det = 1.0f / det;
 
135
 
 
136
        /* calculate distance from v1 to ray origin */
 
137
        sub_v3_v3v3(tvec, orig, v1);
 
138
 
 
139
        /* calculate U parameter and test bounds */
 
140
        u = dot_v3v3(tvec, pvec) * inv_det;
 
141
        if (clip && (u < 0.0f || u > 1.0f)) {
 
142
                Py_RETURN_NONE;
 
143
        }
 
144
 
 
145
        /* prepare to test the V parameter */
 
146
        cross_v3_v3v3(qvec, tvec, e1);
 
147
 
 
148
        /* calculate V parameter and test bounds */
 
149
        v = dot_v3v3(dir, qvec) * inv_det;
 
150
 
 
151
        if (clip && (v < 0.0f || u + v > 1.0f)) {
 
152
                Py_RETURN_NONE;
 
153
        }
 
154
 
 
155
        /* calculate t, ray intersects triangle */
 
156
        t = dot_v3v3(e2, qvec) * inv_det;
 
157
 
 
158
        mul_v3_fl(dir, t);
 
159
        add_v3_v3v3(pvec, orig, dir);
 
160
 
 
161
        return Vector_CreatePyObject(pvec, 3, Py_NEW, NULL);
 
162
}
 
163
 
 
164
/* Line-Line intersection using algorithm from mathworld.wolfram.com */
 
165
 
 
166
PyDoc_STRVAR(M_Geometry_intersect_line_line_doc,
 
167
".. function:: intersect_line_line(v1, v2, v3, v4)\n"
 
168
"\n"
 
169
"   Returns a tuple with the points on each line respectively closest to the other.\n"
 
170
"\n"
 
171
"   :arg v1: First point of the first line\n"
 
172
"   :type v1: :class:`mathutils.Vector`\n"
 
173
"   :arg v2: Second point of the first line\n"
 
174
"   :type v2: :class:`mathutils.Vector`\n"
 
175
"   :arg v3: First point of the second line\n"
 
176
"   :type v3: :class:`mathutils.Vector`\n"
 
177
"   :arg v4: Second point of the second line\n"
 
178
"   :type v4: :class:`mathutils.Vector`\n"
 
179
"   :rtype: tuple of :class:`mathutils.Vector`'s\n"
 
180
);
 
181
static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject *args)
 
182
{
 
183
        PyObject *tuple;
 
184
        VectorObject *vec1, *vec2, *vec3, *vec4;
 
185
        float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
 
186
 
 
187
        if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line",
 
188
                              &vector_Type, &vec1,
 
189
                              &vector_Type, &vec2,
 
190
                              &vector_Type, &vec3,
 
191
                              &vector_Type, &vec4))
 
192
        {
 
193
                return NULL;
 
194
        }
 
195
 
 
196
        if (vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) {
 
197
                PyErr_SetString(PyExc_ValueError,
 
198
                                "vectors must be of the same size");
 
199
                return NULL;
 
200
        }
 
201
 
 
202
        if (BaseMath_ReadCallback(vec1) == -1 ||
 
203
            BaseMath_ReadCallback(vec2) == -1 ||
 
204
            BaseMath_ReadCallback(vec3) == -1 ||
 
205
            BaseMath_ReadCallback(vec4) == -1)
 
206
        {
 
207
                return NULL;
 
208
        }
 
209
 
 
210
        if (vec1->size == 3 || vec1->size == 2) {
 
211
                int result;
 
212
 
 
213
                if (vec1->size == 3) {
 
214
                        copy_v3_v3(v1, vec1->vec);
 
215
                        copy_v3_v3(v2, vec2->vec);
 
216
                        copy_v3_v3(v3, vec3->vec);
 
217
                        copy_v3_v3(v4, vec4->vec);
 
218
                }
 
219
                else {
 
220
                        v1[0] = vec1->vec[0];
 
221
                        v1[1] = vec1->vec[1];
 
222
                        v1[2] = 0.0f;
 
223
 
 
224
                        v2[0] = vec2->vec[0];
 
225
                        v2[1] = vec2->vec[1];
 
226
                        v2[2] = 0.0f;
 
227
 
 
228
                        v3[0] = vec3->vec[0];
 
229
                        v3[1] = vec3->vec[1];
 
230
                        v3[2] = 0.0f;
 
231
 
 
232
                        v4[0] = vec4->vec[0];
 
233
                        v4[1] = vec4->vec[1];
 
234
                        v4[2] = 0.0f;
 
235
                }
 
236
 
 
237
                result = isect_line_line_v3(v1, v2, v3, v4, i1, i2);
 
238
 
 
239
                if (result == 0) {
 
240
                        /* colinear */
 
241
                        Py_RETURN_NONE;
 
242
                }
 
243
                else {
 
244
                        tuple = PyTuple_New(2);
 
245
                        PyTuple_SET_ITEM(tuple, 0, Vector_CreatePyObject(i1, vec1->size, Py_NEW, NULL));
 
246
                        PyTuple_SET_ITEM(tuple, 1, Vector_CreatePyObject(i2, vec1->size, Py_NEW, NULL));
 
247
                        return tuple;
 
248
                }
 
249
        }
 
250
        else {
 
251
                PyErr_SetString(PyExc_ValueError,
 
252
                                "2D/3D vectors only");
 
253
                return NULL;
 
254
        }
 
255
}
 
256
 
 
257
 
 
258
 
 
259
 
 
260
//----------------------------geometry.normal() -------------------
 
261
PyDoc_STRVAR(M_Geometry_normal_doc,
 
262
".. function:: normal(v1, v2, v3, v4=None)\n"
 
263
"\n"
 
264
"   Returns the normal of the 3D tri or quad.\n"
 
265
"\n"
 
266
"   :arg v1: Point1\n"
 
267
"   :type v1: :class:`mathutils.Vector`\n"
 
268
"   :arg v2: Point2\n"
 
269
"   :type v2: :class:`mathutils.Vector`\n"
 
270
"   :arg v3: Point3\n"
 
271
"   :type v3: :class:`mathutils.Vector`\n"
 
272
"   :arg v4: Point4 (optional)\n"
 
273
"   :type v4: :class:`mathutils.Vector`\n"
 
274
"   :rtype: :class:`mathutils.Vector`\n"
 
275
);
 
276
static PyObject *M_Geometry_normal(PyObject *UNUSED(self), PyObject *args)
 
277
{
 
278
        VectorObject *vec1, *vec2, *vec3, *vec4;
 
279
        float n[3];
 
280
 
 
281
        if (PyTuple_GET_SIZE(args) == 3) {
 
282
                if (!PyArg_ParseTuple(args, "O!O!O!:normal",
 
283
                                      &vector_Type, &vec1,
 
284
                                      &vector_Type, &vec2,
 
285
                                      &vector_Type, &vec3))
 
286
                {
 
287
                        return NULL;
 
288
                }
 
289
 
 
290
                if (vec1->size != vec2->size || vec1->size != vec3->size) {
 
291
                        PyErr_SetString(PyExc_ValueError,
 
292
                                        "vectors must be of the same size");
 
293
                        return NULL;
 
294
                }
 
295
                if (vec1->size < 3) {
 
296
                        PyErr_SetString(PyExc_ValueError,
 
297
                                        "2D vectors unsupported");
 
298
                        return NULL;
 
299
                }
 
300
 
 
301
                if (BaseMath_ReadCallback(vec1) == -1 ||
 
302
                    BaseMath_ReadCallback(vec2) == -1 ||
 
303
                    BaseMath_ReadCallback(vec3) == -1)
 
304
                {
 
305
                        return NULL;
 
306
                }
 
307
 
 
308
                normal_tri_v3(n, vec1->vec, vec2->vec, vec3->vec);
 
309
        }
 
310
        else {
 
311
                if (!PyArg_ParseTuple(args, "O!O!O!O!:normal",
 
312
                                      &vector_Type, &vec1,
 
313
                                      &vector_Type, &vec2,
 
314
                                      &vector_Type, &vec3,
 
315
                                      &vector_Type, &vec4))
 
316
                {
 
317
                        return NULL;
 
318
                }
 
319
                if (vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) {
 
320
                        PyErr_SetString(PyExc_ValueError,
 
321
                                        "vectors must be of the same size");
 
322
                        return NULL;
 
323
                }
 
324
                if (vec1->size < 3) {
 
325
                        PyErr_SetString(PyExc_ValueError,
 
326
                                        "2D vectors unsupported");
 
327
                        return NULL;
 
328
                }
 
329
 
 
330
                if (BaseMath_ReadCallback(vec1) == -1 ||
 
331
                    BaseMath_ReadCallback(vec2) == -1 ||
 
332
                    BaseMath_ReadCallback(vec3) == -1 ||
 
333
                    BaseMath_ReadCallback(vec4) == -1)
 
334
                {
 
335
                        return NULL;
 
336
                }
 
337
 
 
338
                normal_quad_v3(n, vec1->vec, vec2->vec, vec3->vec, vec4->vec);
 
339
        }
 
340
 
 
341
        return Vector_CreatePyObject(n, 3, Py_NEW, NULL);
 
342
}
 
343
 
 
344
//--------------------------------- AREA FUNCTIONS--------------------
 
345
 
 
346
PyDoc_STRVAR(M_Geometry_area_tri_doc,
 
347
".. function:: area_tri(v1, v2, v3)\n"
 
348
"\n"
 
349
"   Returns the area size of the 2D or 3D triangle defined.\n"
 
350
"\n"
 
351
"   :arg v1: Point1\n"
 
352
"   :type v1: :class:`mathutils.Vector`\n"
 
353
"   :arg v2: Point2\n"
 
354
"   :type v2: :class:`mathutils.Vector`\n"
 
355
"   :arg v3: Point3\n"
 
356
"   :type v3: :class:`mathutils.Vector`\n"
 
357
"   :rtype: float\n"
 
358
);
 
359
static PyObject *M_Geometry_area_tri(PyObject *UNUSED(self), PyObject *args)
 
360
{
 
361
        VectorObject *vec1, *vec2, *vec3;
 
362
 
 
363
        if (!PyArg_ParseTuple(args, "O!O!O!:area_tri",
 
364
                              &vector_Type, &vec1,
 
365
                              &vector_Type, &vec2,
 
366
                              &vector_Type, &vec3))
 
367
        {
 
368
                return NULL;
 
369
        }
 
370
 
 
371
        if (vec1->size != vec2->size || vec1->size != vec3->size) {
 
372
                PyErr_SetString(PyExc_ValueError,
 
373
                                "vectors must be of the same size");
 
374
                return NULL;
 
375
        }
 
376
 
 
377
        if (BaseMath_ReadCallback(vec1) == -1 ||
 
378
            BaseMath_ReadCallback(vec2) == -1 ||
 
379
            BaseMath_ReadCallback(vec3) == -1)
 
380
        {
 
381
                return NULL;
 
382
        }
 
383
 
 
384
        if (vec1->size == 3) {
 
385
                return PyFloat_FromDouble(area_tri_v3(vec1->vec, vec2->vec, vec3->vec));
 
386
        }
 
387
        else if (vec1->size == 2) {
 
388
                return PyFloat_FromDouble(area_tri_v2(vec1->vec, vec2->vec, vec3->vec));
 
389
        }
 
390
        else {
 
391
                PyErr_SetString(PyExc_ValueError,
 
392
                                "only 2D,3D vectors are supported");
 
393
                return NULL;
 
394
        }
 
395
}
 
396
 
 
397
 
 
398
PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc,
 
399
".. function:: intersect_line_line_2d(lineA_p1, lineA_p2, lineB_p1, lineB_p2)\n"
 
400
"\n"
 
401
"   Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n"
 
402
"\n"
 
403
"   :arg lineA_p1: First point of the first line\n"
 
404
"   :type lineA_p1: :class:`mathutils.Vector`\n"
 
405
"   :arg lineA_p2: Second point of the first line\n"
 
406
"   :type lineA_p2: :class:`mathutils.Vector`\n"
 
407
"   :arg lineB_p1: First point of the second line\n"
 
408
"   :type lineB_p1: :class:`mathutils.Vector`\n"
 
409
"   :arg lineB_p2: Second point of the second line\n"
 
410
"   :type lineB_p2: :class:`mathutils.Vector`\n"
 
411
"   :return: The point of intersection or None when not found\n"
 
412
"   :rtype: :class:`mathutils.Vector` or None\n"
 
413
);
 
414
static PyObject *M_Geometry_intersect_line_line_2d(PyObject *UNUSED(self), PyObject *args)
 
415
{
 
416
        VectorObject *line_a1, *line_a2, *line_b1, *line_b2;
 
417
        float vi[2];
 
418
        if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line_2d",
 
419
                              &vector_Type, &line_a1,
 
420
                              &vector_Type, &line_a2,
 
421
                              &vector_Type, &line_b1,
 
422
                              &vector_Type, &line_b2))
 
423
        {
 
424
                return NULL;
 
425
        }
 
426
        
 
427
        if (BaseMath_ReadCallback(line_a1) == -1 ||
 
428
            BaseMath_ReadCallback(line_a2) == -1 ||
 
429
            BaseMath_ReadCallback(line_b1) == -1 ||
 
430
            BaseMath_ReadCallback(line_b2) == -1)
 
431
        {
 
432
                return NULL;
 
433
        }
 
434
 
 
435
        if (isect_seg_seg_v2_point(line_a1->vec, line_a2->vec, line_b1->vec, line_b2->vec, vi) == 1) {
 
436
                return Vector_CreatePyObject(vi, 2, Py_NEW, NULL);
 
437
        }
 
438
        else {
 
439
                Py_RETURN_NONE;
 
440
        }
 
441
}
 
442
 
 
443
 
 
444
PyDoc_STRVAR(M_Geometry_intersect_line_plane_doc,
 
445
".. function:: intersect_line_plane(line_a, line_b, plane_co, plane_no, no_flip=False)\n"
 
446
"\n"
 
447
"   Calculate the intersection between a line (as 2 vectors) and a plane.\n"
 
448
"   Returns a vector for the intersection or None.\n"
 
449
"\n"
 
450
"   :arg line_a: First point of the first line\n"
 
451
"   :type line_a: :class:`mathutils.Vector`\n"
 
452
"   :arg line_b: Second point of the first line\n"
 
453
"   :type line_b: :class:`mathutils.Vector`\n"
 
454
"   :arg plane_co: A point on the plane\n"
 
455
"   :type plane_co: :class:`mathutils.Vector`\n"
 
456
"   :arg plane_no: The direction the plane is facing\n"
 
457
"   :type plane_no: :class:`mathutils.Vector`\n"
 
458
"   :arg no_flip: Always return an intersection on the directon defined bt line_a -> line_b\n"
 
459
"   :type no_flip: :boolean\n"
 
460
"   :return: The point of intersection or None when not found\n"
 
461
"   :rtype: :class:`mathutils.Vector` or None\n"
 
462
);
 
463
static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObject *args)
 
464
{
 
465
        VectorObject *line_a, *line_b, *plane_co, *plane_no;
 
466
        int no_flip = 0;
 
467
        float isect[3];
 
468
        if (!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_line_plane",
 
469
                              &vector_Type, &line_a,
 
470
                              &vector_Type, &line_b,
 
471
                              &vector_Type, &plane_co,
 
472
                              &vector_Type, &plane_no,
 
473
                              &no_flip))
 
474
        {
 
475
                return NULL;
 
476
        }
 
477
 
 
478
        if (BaseMath_ReadCallback(line_a) == -1 ||
 
479
            BaseMath_ReadCallback(line_b) == -1 ||
 
480
            BaseMath_ReadCallback(plane_co) == -1 ||
 
481
            BaseMath_ReadCallback(plane_no) == -1)
 
482
        {
 
483
                return NULL;
 
484
        }
 
485
 
 
486
        if (ELEM4(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) {
 
487
                PyErr_SetString(PyExc_ValueError,
 
488
                                "geometry.intersect_line_plane(...): "
 
489
                                " can't use 2D Vectors");
 
490
                return NULL;
 
491
        }
 
492
 
 
493
        if (isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec, no_flip) == 1) {
 
494
                return Vector_CreatePyObject(isect, 3, Py_NEW, NULL);
 
495
        }
 
496
        else {
 
497
                Py_RETURN_NONE;
 
498
        }
 
499
}
 
500
 
 
501
PyDoc_STRVAR(M_Geometry_intersect_plane_plane_doc,
 
502
".. function:: intersect_plane_plane(plane_a_co, plane_a_no, plane_b_co, plane_b_no)\n"
 
503
"\n"
 
504
"   Return the intersection between two planes\n"
 
505
"\n"
 
506
"   :arg plane_a_co: Point on the first plane\n"
 
507
"   :type plane_a_co: :class:`mathutils.Vector`\n"
 
508
"   :arg plane_a_no: Normal of the first plane\n"
 
509
"   :type plane_a_no: :class:`mathutils.Vector`\n"
 
510
"   :arg plane_b_co: Point on the second plane\n"
 
511
"   :type plane_b_co: :class:`mathutils.Vector`\n"
 
512
"   :arg plane_b_no: Normal of the second plane\n"
 
513
"   :type plane_b_no: :class:`mathutils.Vector`\n"
 
514
"   :return: The line of the intersection represented as a point and a vector\n"
 
515
"   :rtype: tuple pair of :class:`mathutils.Vector`\n"
 
516
);
 
517
static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObject *args)
 
518
{
 
519
        PyObject *ret;
 
520
        VectorObject *plane_a_co, *plane_a_no, *plane_b_co, *plane_b_no;
 
521
 
 
522
        float isect_co[3];
 
523
        float isect_no[3];
 
524
 
 
525
        if (!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_plane_plane",
 
526
                              &vector_Type, &plane_a_co,
 
527
                              &vector_Type, &plane_a_no,
 
528
                              &vector_Type, &plane_b_co,
 
529
                              &vector_Type, &plane_b_no))
 
530
        {
 
531
                return NULL;
 
532
        }
 
533
 
 
534
        if (BaseMath_ReadCallback(plane_a_co) == -1 ||
 
535
            BaseMath_ReadCallback(plane_a_no) == -1 ||
 
536
            BaseMath_ReadCallback(plane_b_co) == -1 ||
 
537
            BaseMath_ReadCallback(plane_b_no) == -1)
 
538
        {
 
539
                return NULL;
 
540
        }
 
541
 
 
542
        if (ELEM4(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) {
 
543
                PyErr_SetString(PyExc_ValueError,
 
544
                                "geometry.intersect_plane_plane(...): "
 
545
                                " can't use 2D Vectors");
 
546
                return NULL;
 
547
        }
 
548
 
 
549
        isect_plane_plane_v3(isect_co, isect_no,
 
550
                             plane_a_co->vec, plane_a_no->vec,
 
551
                             plane_b_co->vec, plane_b_no->vec);
 
552
 
 
553
        normalize_v3(isect_no);
 
554
 
 
555
        ret = PyTuple_New(2);
 
556
        PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_co, 3, Py_NEW, NULL));
 
557
        PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_no, 3, Py_NEW, NULL));
 
558
        return ret;
 
559
}
 
560
 
 
561
PyDoc_STRVAR(M_Geometry_intersect_line_sphere_doc,
 
562
".. function:: intersect_line_sphere(line_a, line_b, sphere_co, sphere_radius, clip=True)\n"
 
563
"\n"
 
564
"   Takes a lines (as 2 vectors), a sphere as a point and a radius and\n"
 
565
"   returns the intersection\n"
 
566
"\n"
 
567
"   :arg line_a: First point of the first line\n"
 
568
"   :type line_a: :class:`mathutils.Vector`\n"
 
569
"   :arg line_b: Second point of the first line\n"
 
570
"   :type line_b: :class:`mathutils.Vector`\n"
 
571
"   :arg sphere_co: The center of the sphere\n"
 
572
"   :type sphere_co: :class:`mathutils.Vector`\n"
 
573
"   :arg sphere_radius: Radius of the sphere\n"
 
574
"   :type sphere_radius: sphere_radius\n"
 
575
"   :return: The intersection points as a pair of vectors or None when there is no intersection\n"
 
576
"   :rtype: A tuple pair containing :class:`mathutils.Vector` or None\n"
 
577
);
 
578
static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObject *args)
 
579
{
 
580
        VectorObject *line_a, *line_b, *sphere_co;
 
581
        float sphere_radius;
 
582
        int clip = TRUE;
 
583
 
 
584
        float isect_a[3];
 
585
        float isect_b[3];
 
586
 
 
587
        if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere",
 
588
                              &vector_Type, &line_a,
 
589
                              &vector_Type, &line_b,
 
590
                              &vector_Type, &sphere_co,
 
591
                              &sphere_radius, &clip))
 
592
        {
 
593
                return NULL;
 
594
        }
 
595
 
 
596
        if (BaseMath_ReadCallback(line_a) == -1 ||
 
597
            BaseMath_ReadCallback(line_b) == -1 ||
 
598
            BaseMath_ReadCallback(sphere_co) == -1)
 
599
        {
 
600
                return NULL;
 
601
        }
 
602
 
 
603
        if (ELEM3(2, line_a->size, line_b->size, sphere_co->size)) {
 
604
                PyErr_SetString(PyExc_ValueError,
 
605
                                "geometry.intersect_line_sphere(...): "
 
606
                                " can't use 2D Vectors");
 
607
                return NULL;
 
608
        }
 
609
        else {
 
610
                short use_a = TRUE;
 
611
                short use_b = TRUE;
 
612
                float lambda;
 
613
 
 
614
                PyObject *ret = PyTuple_New(2);
 
615
 
 
616
                switch (isect_line_sphere_v3(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) {
 
617
                        case 1:
 
618
                                if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE;
 
619
                                use_b = FALSE;
 
620
                                break;
 
621
                        case 2:
 
622
                                if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE;
 
623
                                if (!(!clip || (((lambda = line_point_factor_v3(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = FALSE;
 
624
                                break;
 
625
                        default:
 
626
                                use_a = FALSE;
 
627
                                use_b = FALSE;
 
628
                }
 
629
 
 
630
                if (use_a) { PyTuple_SET_ITEM(ret, 0,  Vector_CreatePyObject(isect_a, 3, Py_NEW, NULL)); }
 
631
                else       { PyTuple_SET_ITEM(ret, 0,  Py_None); Py_INCREF(Py_None); }
 
632
 
 
633
                if (use_b) { PyTuple_SET_ITEM(ret, 1,  Vector_CreatePyObject(isect_b, 3, Py_NEW, NULL)); }
 
634
                else       { PyTuple_SET_ITEM(ret, 1,  Py_None); Py_INCREF(Py_None); }
 
635
 
 
636
                return ret;
 
637
        }
 
638
}
 
639
 
 
640
/* keep in sync with M_Geometry_intersect_line_sphere */
 
641
PyDoc_STRVAR(M_Geometry_intersect_line_sphere_2d_doc,
 
642
".. function:: intersect_line_sphere_2d(line_a, line_b, sphere_co, sphere_radius, clip=True)\n"
 
643
"\n"
 
644
"   Takes a lines (as 2 vectors), a sphere as a point and a radius and\n"
 
645
"   returns the intersection\n"
 
646
"\n"
 
647
"   :arg line_a: First point of the first line\n"
 
648
"   :type line_a: :class:`mathutils.Vector`\n"
 
649
"   :arg line_b: Second point of the first line\n"
 
650
"   :type line_b: :class:`mathutils.Vector`\n"
 
651
"   :arg sphere_co: The center of the sphere\n"
 
652
"   :type sphere_co: :class:`mathutils.Vector`\n"
 
653
"   :arg sphere_radius: Radius of the sphere\n"
 
654
"   :type sphere_radius: sphere_radius\n"
 
655
"   :return: The intersection points as a pair of vectors or None when there is no intersection\n"
 
656
"   :rtype: A tuple pair containing :class:`mathutils.Vector` or None\n"
 
657
);
 
658
static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyObject *args)
 
659
{
 
660
        VectorObject *line_a, *line_b, *sphere_co;
 
661
        float sphere_radius;
 
662
        int clip = TRUE;
 
663
 
 
664
        float isect_a[3];
 
665
        float isect_b[3];
 
666
 
 
667
        if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere_2d",
 
668
                              &vector_Type, &line_a,
 
669
                              &vector_Type, &line_b,
 
670
                              &vector_Type, &sphere_co,
 
671
                              &sphere_radius, &clip))
 
672
        {
 
673
                return NULL;
 
674
        }
 
675
 
 
676
        if (BaseMath_ReadCallback(line_a) == -1 ||
 
677
            BaseMath_ReadCallback(line_b) == -1 ||
 
678
            BaseMath_ReadCallback(sphere_co) == -1)
 
679
        {
 
680
                return NULL;
 
681
        }
 
682
        else {
 
683
                short use_a = TRUE;
 
684
                short use_b = TRUE;
 
685
                float lambda;
 
686
 
 
687
                PyObject *ret = PyTuple_New(2);
 
688
 
 
689
                switch (isect_line_sphere_v2(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) {
 
690
                        case 1:
 
691
                                if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE;
 
692
                                use_b = FALSE;
 
693
                                break;
 
694
                        case 2:
 
695
                                if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE;
 
696
                                if (!(!clip || (((lambda = line_point_factor_v2(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = FALSE;
 
697
                                break;
 
698
                        default:
 
699
                                use_a = FALSE;
 
700
                                use_b = FALSE;
 
701
                }
 
702
 
 
703
                if (use_a) { PyTuple_SET_ITEM(ret, 0,  Vector_CreatePyObject(isect_a, 2, Py_NEW, NULL)); }
 
704
                else       { PyTuple_SET_ITEM(ret, 0,  Py_None); Py_INCREF(Py_None); }
 
705
 
 
706
                if (use_b) { PyTuple_SET_ITEM(ret, 1,  Vector_CreatePyObject(isect_b, 2, Py_NEW, NULL)); }
 
707
                else       { PyTuple_SET_ITEM(ret, 1,  Py_None); Py_INCREF(Py_None); }
 
708
 
 
709
                return ret;
 
710
        }
 
711
}
 
712
 
 
713
PyDoc_STRVAR(M_Geometry_intersect_point_line_doc,
 
714
".. function:: intersect_point_line(pt, line_p1, line_p2)\n"
 
715
"\n"
 
716
"   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"
 
717
"\n"
 
718
"   :arg pt: Point\n"
 
719
"   :type pt: :class:`mathutils.Vector`\n"
 
720
"   :arg line_p1: First point of the line\n"
 
721
"   :type line_p1: :class:`mathutils.Vector`\n"
 
722
"   :arg line_p1: Second point of the line\n"
 
723
"   :type line_p1: :class:`mathutils.Vector`\n"
 
724
"   :rtype: (:class:`mathutils.Vector`, float)\n"
 
725
);
 
726
static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObject *args)
 
727
{
 
728
        VectorObject *pt, *line_1, *line_2;
 
729
        float pt_in[3], pt_out[3], l1[3], l2[3];
 
730
        float lambda;
 
731
        PyObject *ret;
 
732
        
 
733
        if (!PyArg_ParseTuple(args, "O!O!O!:intersect_point_line",
 
734
                              &vector_Type, &pt,
 
735
                              &vector_Type, &line_1,
 
736
                              &vector_Type, &line_2))
 
737
        {
 
738
                return NULL;
 
739
        }
 
740
 
 
741
        if (BaseMath_ReadCallback(pt) == -1 ||
 
742
            BaseMath_ReadCallback(line_1) == -1 ||
 
743
            BaseMath_ReadCallback(line_2) == -1)
 
744
        {
 
745
                return NULL;
 
746
        }
 
747
 
 
748
        /* accept 2d verts */
 
749
        if (pt->size == 3) {     copy_v3_v3(pt_in, pt->vec); }
 
750
        else { pt_in[2] = 0.0f;  copy_v2_v2(pt_in, pt->vec); }
 
751
        
 
752
        if (line_1->size == 3) { copy_v3_v3(l1, line_1->vec); }
 
753
        else { l1[2] = 0.0f;     copy_v2_v2(l1, line_1->vec); }
 
754
        
 
755
        if (line_2->size == 3) { copy_v3_v3(l2, line_2->vec); }
 
756
        else { l2[2] = 0.0f;     copy_v2_v2(l2, line_2->vec); }
 
757
        
 
758
        /* do the calculation */
 
759
        lambda = closest_to_line_v3(pt_out, pt_in, l1, l2);
 
760
        
 
761
        ret = PyTuple_New(2);
 
762
        PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(pt_out, 3, Py_NEW, NULL));
 
763
        PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(lambda));
 
764
        return ret;
 
765
}
 
766
 
 
767
PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc,
 
768
".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n"
 
769
"\n"
 
770
"   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"
 
771
"\n"
 
772
"   :arg pt: Point\n"
 
773
"   :type v1: :class:`mathutils.Vector`\n"
 
774
"   :arg tri_p1: First point of the triangle\n"
 
775
"   :type tri_p1: :class:`mathutils.Vector`\n"
 
776
"   :arg tri_p2: Second point of the triangle\n"
 
777
"   :type tri_p2: :class:`mathutils.Vector`\n"
 
778
"   :arg tri_p3: Third point of the triangle\n"
 
779
"   :type tri_p3: :class:`mathutils.Vector`\n"
 
780
"   :rtype: int\n"
 
781
);
 
782
static PyObject *M_Geometry_intersect_point_tri_2d(PyObject *UNUSED(self), PyObject *args)
 
783
{
 
784
        VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
 
785
        
 
786
        if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri_2d",
 
787
                              &vector_Type, &pt_vec,
 
788
                              &vector_Type, &tri_p1,
 
789
                              &vector_Type, &tri_p2,
 
790
                              &vector_Type, &tri_p3))
 
791
        {
 
792
                return NULL;
 
793
        }
 
794
        
 
795
        if (BaseMath_ReadCallback(pt_vec) == -1 ||
 
796
            BaseMath_ReadCallback(tri_p1) == -1 ||
 
797
            BaseMath_ReadCallback(tri_p2) == -1 ||
 
798
            BaseMath_ReadCallback(tri_p3) == -1)
 
799
        {
 
800
                return NULL;
 
801
        }
 
802
 
 
803
        return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec));
 
804
}
 
805
 
 
806
PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc,
 
807
".. function:: intersect_point_quad_2d(pt, quad_p1, quad_p2, quad_p3, quad_p4)\n"
 
808
"\n"
 
809
"   Takes 5 vectors (using only the x and y coordinates): one is the point and the next 4 define the quad, \n"
 
810
"   only the x and y are used from the vectors. Returns 1 if the point is within the quad, otherwise 0.\n"
 
811
"\n"
 
812
"   :arg pt: Point\n"
 
813
"   :type pt: :class:`mathutils.Vector`\n"
 
814
"   :arg quad_p1: First point of the quad\n"
 
815
"   :type quad_p1: :class:`mathutils.Vector`\n"
 
816
"   :arg quad_p2: Second point of the quad\n"
 
817
"   :type quad_p2: :class:`mathutils.Vector`\n"
 
818
"   :arg quad_p3: Third point of the quad\n"
 
819
"   :type quad_p3: :class:`mathutils.Vector`\n"
 
820
"   :arg quad_p4: Forth point of the quad\n"
 
821
"   :type quad_p4: :class:`mathutils.Vector`\n"
 
822
"   :rtype: int\n"
 
823
);
 
824
static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyObject *args)
 
825
{
 
826
        VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4;
 
827
        
 
828
        if (!PyArg_ParseTuple(args, "O!O!O!O!O!:intersect_point_quad_2d",
 
829
                              &vector_Type, &pt_vec,
 
830
                              &vector_Type, &quad_p1,
 
831
                              &vector_Type, &quad_p2,
 
832
                              &vector_Type, &quad_p3,
 
833
                              &vector_Type, &quad_p4))
 
834
        {
 
835
                return NULL;
 
836
        }
 
837
 
 
838
        if (BaseMath_ReadCallback(pt_vec)  == -1 ||
 
839
            BaseMath_ReadCallback(quad_p1) == -1 ||
 
840
            BaseMath_ReadCallback(quad_p2) == -1 ||
 
841
            BaseMath_ReadCallback(quad_p3) == -1 ||
 
842
            BaseMath_ReadCallback(quad_p4) == -1)
 
843
        {
 
844
                return NULL;
 
845
        }
 
846
 
 
847
        return PyLong_FromLong(isect_point_quad_v2(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec));
 
848
}
 
849
 
 
850
PyDoc_STRVAR(M_Geometry_distance_point_to_plane_doc,
 
851
".. function:: distance_point_to_plane(pt, plane_co, plane_no)\n"
 
852
"\n"
 
853
"   Returns the signed distance between a point and a plane "
 
854
"   (negative when below the normal).\n"
 
855
"\n"
 
856
"   :arg pt: Point\n"
 
857
"   :type pt: :class:`mathutils.Vector`\n"
 
858
"   :arg plane_co: First point of the quad\n"
 
859
"   :type plane_co: :class:`mathutils.Vector`\n"
 
860
"   :arg plane_no: Second point of the quad\n"
 
861
"   :type plane_no: :class:`mathutils.Vector`\n"
 
862
"   :rtype: float\n"
 
863
);
 
864
static PyObject *M_Geometry_distance_point_to_plane(PyObject *UNUSED(self), PyObject *args)
 
865
{
 
866
        VectorObject *pt, *plene_co, *plane_no;
 
867
 
 
868
        if (!PyArg_ParseTuple(args, "O!O!O!:distance_point_to_plane",
 
869
                              &vector_Type, &pt,
 
870
                              &vector_Type, &plene_co,
 
871
                              &vector_Type, &plane_no))
 
872
        {
 
873
                return NULL;
 
874
        }
 
875
 
 
876
        if (BaseMath_ReadCallback(pt) == -1 ||
 
877
            BaseMath_ReadCallback(plene_co) == -1 ||
 
878
            BaseMath_ReadCallback(plane_no) == -1)
 
879
        {
 
880
                return NULL;
 
881
        }
 
882
 
 
883
        return PyFloat_FromDouble(dist_to_plane_v3(pt->vec, plene_co->vec, plane_no->vec));
 
884
}
 
885
 
 
886
PyDoc_STRVAR(M_Geometry_barycentric_transform_doc,
 
887
".. function:: barycentric_transform(point, tri_a1, tri_a2, tri_a3, tri_b1, tri_b2, tri_b3)\n"
 
888
"\n"
 
889
"   Return a transformed point, the transformation is defined by 2 triangles.\n"
 
890
"\n"
 
891
"   :arg point: The point to transform.\n"
 
892
"   :type point: :class:`mathutils.Vector`\n"
 
893
"   :arg tri_a1: source triangle vertex.\n"
 
894
"   :type tri_a1: :class:`mathutils.Vector`\n"
 
895
"   :arg tri_a2: source triangle vertex.\n"
 
896
"   :type tri_a2: :class:`mathutils.Vector`\n"
 
897
"   :arg tri_a3: source triangle vertex.\n"
 
898
"   :type tri_a3: :class:`mathutils.Vector`\n"
 
899
"   :arg tri_a1: target triangle vertex.\n"
 
900
"   :type tri_a1: :class:`mathutils.Vector`\n"
 
901
"   :arg tri_a2: target triangle vertex.\n"
 
902
"   :type tri_a2: :class:`mathutils.Vector`\n"
 
903
"   :arg tri_a3: target triangle vertex.\n"
 
904
"   :type tri_a3: :class:`mathutils.Vector`\n"
 
905
"   :return: The transformed point\n"
 
906
"   :rtype: :class:`mathutils.Vector`'s\n"
 
907
);
 
908
static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObject *args)
 
909
{
 
910
        VectorObject *vec_pt;
 
911
        VectorObject *vec_t1_tar, *vec_t2_tar, *vec_t3_tar;
 
912
        VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src;
 
913
        float vec[3];
 
914
 
 
915
        if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!:barycentric_transform",
 
916
                              &vector_Type, &vec_pt,
 
917
                              &vector_Type, &vec_t1_src,
 
918
                              &vector_Type, &vec_t2_src,
 
919
                              &vector_Type, &vec_t3_src,
 
920
                              &vector_Type, &vec_t1_tar,
 
921
                              &vector_Type, &vec_t2_tar,
 
922
                              &vector_Type, &vec_t3_tar))
 
923
        {
 
924
                return NULL;
 
925
        }
 
926
 
 
927
        if (vec_pt->size != 3 ||
 
928
            vec_t1_src->size != 3 ||
 
929
            vec_t2_src->size != 3 ||
 
930
            vec_t3_src->size != 3 ||
 
931
            vec_t1_tar->size != 3 ||
 
932
            vec_t2_tar->size != 3 ||
 
933
            vec_t3_tar->size != 3)
 
934
        {
 
935
                PyErr_SetString(PyExc_ValueError,
 
936
                                "One of more of the vector arguments wasn't a 3D vector");
 
937
                return NULL;
 
938
        }
 
939
 
 
940
        barycentric_transform(vec, vec_pt->vec,
 
941
                              vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec,
 
942
                              vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec);
 
943
 
 
944
        return Vector_CreatePyObject(vec, 3, Py_NEW, NULL);
 
945
}
 
946
 
 
947
#ifndef MATH_STANDALONE
 
948
 
 
949
PyDoc_STRVAR(M_Geometry_interpolate_bezier_doc,
 
950
".. function:: interpolate_bezier(knot1, handle1, handle2, knot2, resolution)\n"
 
951
"\n"
 
952
"   Interpolate a bezier spline segment.\n"
 
953
"\n"
 
954
"   :arg knot1: First bezier spline point.\n"
 
955
"   :type knot1: :class:`mathutils.Vector`\n"
 
956
"   :arg handle1: First bezier spline handle.\n"
 
957
"   :type handle1: :class:`mathutils.Vector`\n"
 
958
"   :arg handle2: Second bezier spline handle.\n"
 
959
"   :type handle2: :class:`mathutils.Vector`\n"
 
960
"   :arg knot2: Second bezier spline point.\n"
 
961
"   :type knot2: :class:`mathutils.Vector`\n"
 
962
"   :arg resolution: Number of points to return.\n"
 
963
"   :type resolution: int\n"
 
964
"   :return: The interpolated points\n"
 
965
"   :rtype: list of :class:`mathutils.Vector`'s\n"
 
966
);
 
967
static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject *args)
 
968
{
 
969
        VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2;
 
970
        int resolu;
 
971
        int dims;
 
972
        int i;
 
973
        float *coord_array, *fp;
 
974
        PyObject *list;
 
975
 
 
976
        float k1[4] = {0.0, 0.0, 0.0, 0.0};
 
977
        float h1[4] = {0.0, 0.0, 0.0, 0.0};
 
978
        float k2[4] = {0.0, 0.0, 0.0, 0.0};
 
979
        float h2[4] = {0.0, 0.0, 0.0, 0.0};
 
980
 
 
981
 
 
982
        if (!PyArg_ParseTuple(args, "O!O!O!O!i:interpolate_bezier",
 
983
                              &vector_Type, &vec_k1,
 
984
                              &vector_Type, &vec_h1,
 
985
                              &vector_Type, &vec_h2,
 
986
                              &vector_Type, &vec_k2, &resolu))
 
987
        {
 
988
                return NULL;
 
989
        }
 
990
 
 
991
        if (resolu <= 1) {
 
992
                PyErr_SetString(PyExc_ValueError,
 
993
                                "resolution must be 2 or over");
 
994
                return NULL;
 
995
        }
 
996
 
 
997
        if (BaseMath_ReadCallback(vec_k1) == -1 ||
 
998
            BaseMath_ReadCallback(vec_h1) == -1 ||
 
999
            BaseMath_ReadCallback(vec_k2) == -1 ||
 
1000
            BaseMath_ReadCallback(vec_h2) == -1)
 
1001
        {
 
1002
                return NULL;
 
1003
        }
 
1004
 
 
1005
        dims = MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size);
 
1006
 
 
1007
        for (i = 0; i < vec_k1->size; i++) k1[i] = vec_k1->vec[i];
 
1008
        for (i = 0; i < vec_h1->size; i++) h1[i] = vec_h1->vec[i];
 
1009
        for (i = 0; i < vec_k2->size; i++) k2[i] = vec_k2->vec[i];
 
1010
        for (i = 0; i < vec_h2->size; i++) h2[i] = vec_h2->vec[i];
 
1011
 
 
1012
        coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier");
 
1013
        for (i = 0; i < dims; i++) {
 
1014
                forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array + i, resolu - 1, sizeof(float) * dims);
 
1015
        }
 
1016
 
 
1017
        list = PyList_New(resolu);
 
1018
        fp = coord_array;
 
1019
        for (i = 0; i < resolu; i++, fp = fp + dims) {
 
1020
                PyList_SET_ITEM(list, i, Vector_CreatePyObject(fp, dims, Py_NEW, NULL));
 
1021
        }
 
1022
        MEM_freeN(coord_array);
 
1023
        return list;
 
1024
}
 
1025
 
 
1026
 
 
1027
PyDoc_STRVAR(M_Geometry_tessellate_polygon_doc,
 
1028
".. function:: tessellate_polygon(veclist_list)\n"
 
1029
"\n"
 
1030
"   Takes a list of polylines (each point a vector) and returns the point indices for a polyline filled with triangles.\n"
 
1031
"\n"
 
1032
"   :arg veclist_list: list of polylines\n"
 
1033
"   :rtype: list\n"
 
1034
);
 
1035
/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */
 
1036
static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject *polyLineSeq)
 
1037
{
 
1038
        PyObject *tri_list; /*return this list of tri's */
 
1039
        PyObject *polyLine, *polyVec;
 
1040
        int i, len_polylines, len_polypoints, ls_error = 0;
 
1041
 
 
1042
        /* display listbase */
 
1043
        ListBase dispbase = {NULL, NULL};
 
1044
        DispList *dl;
 
1045
        float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
 
1046
        int index, *dl_face, totpoints = 0;
 
1047
 
 
1048
        if (!PySequence_Check(polyLineSeq)) {
 
1049
                PyErr_SetString(PyExc_TypeError,
 
1050
                                "expected a sequence of poly lines");
 
1051
                return NULL;
 
1052
        }
 
1053
 
 
1054
        len_polylines = PySequence_Size(polyLineSeq);
 
1055
 
 
1056
        for (i = 0; i < len_polylines; i++) {
 
1057
                polyLine = PySequence_GetItem(polyLineSeq, i);
 
1058
                if (!PySequence_Check(polyLine)) {
 
1059
                        freedisplist(&dispbase);
 
1060
                        Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
 
1061
                        PyErr_SetString(PyExc_TypeError,
 
1062
                                        "One or more of the polylines is not a sequence of mathutils.Vector's");
 
1063
                        return NULL;
 
1064
                }
 
1065
 
 
1066
                len_polypoints = PySequence_Size(polyLine);
 
1067
                if (len_polypoints > 0) { /* don't bother adding edges as polylines */
 
1068
#if 0
 
1069
                        if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) {
 
1070
                                freedisplist(&dispbase);
 
1071
                                Py_DECREF(polyLine);
 
1072
                                PyErr_SetString(PyExc_TypeError,
 
1073
                                                "A point in one of the polylines is not a mathutils.Vector type");
 
1074
                                return NULL;
 
1075
                        }
 
1076
#endif
 
1077
                        dl = MEM_callocN(sizeof(DispList), "poly disp");
 
1078
                        BLI_addtail(&dispbase, dl);
 
1079
                        dl->type = DL_INDEX3;
 
1080
                        dl->nr = len_polypoints;
 
1081
                        dl->type = DL_POLY;
 
1082
                        dl->parts = 1; /* no faces, 1 edge loop */
 
1083
                        dl->col = 0; /* no material */
 
1084
                        dl->verts = fp = MEM_callocN(sizeof(float) * 3 * len_polypoints, "dl verts");
 
1085
                        dl->index = MEM_callocN(sizeof(int) * 3 * len_polypoints, "dl index");
 
1086
 
 
1087
                        for (index = 0; index < len_polypoints; index++, fp += 3) {
 
1088
                                polyVec = PySequence_GetItem(polyLine, index);
 
1089
                                if (VectorObject_Check(polyVec)) {
 
1090
 
 
1091
                                        if (BaseMath_ReadCallback((VectorObject *)polyVec) == -1)
 
1092
                                                ls_error = 1;
 
1093
 
 
1094
                                        fp[0] = ((VectorObject *)polyVec)->vec[0];
 
1095
                                        fp[1] = ((VectorObject *)polyVec)->vec[1];
 
1096
                                        if (((VectorObject *)polyVec)->size > 2)
 
1097
                                                fp[2] = ((VectorObject *)polyVec)->vec[2];
 
1098
                                        else
 
1099
                                                fp[2] = 0.0f;  /* if its a 2d vector then set the z to be zero */
 
1100
                                }
 
1101
                                else {
 
1102
                                        ls_error = 1;
 
1103
                                }
 
1104
 
 
1105
                                totpoints++;
 
1106
                                Py_DECREF(polyVec);
 
1107
                        }
 
1108
                }
 
1109
                Py_DECREF(polyLine);
 
1110
        }
 
1111
 
 
1112
        if (ls_error) {
 
1113
                freedisplist(&dispbase); /* possible some dl was allocated */
 
1114
                PyErr_SetString(PyExc_TypeError,
 
1115
                                "A point in one of the polylines "
 
1116
                                "is not a mathutils.Vector type");
 
1117
                return NULL;
 
1118
        }
 
1119
        else if (totpoints) {
 
1120
                /* now make the list to return */
 
1121
                filldisplist(&dispbase, &dispbase, 0);
 
1122
 
 
1123
                /* The faces are stored in a new DisplayList
 
1124
                 * thats added to the head of the listbase */
 
1125
                dl = dispbase.first;
 
1126
 
 
1127
                tri_list = PyList_New(dl->parts);
 
1128
                if (!tri_list) {
 
1129
                        freedisplist(&dispbase);
 
1130
                        PyErr_SetString(PyExc_RuntimeError,
 
1131
                                        "failed to make a new list");
 
1132
                        return NULL;
 
1133
                }
 
1134
 
 
1135
                index = 0;
 
1136
                dl_face = dl->index;
 
1137
                while (index < dl->parts) {
 
1138
                        PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]));
 
1139
                        dl_face += 3;
 
1140
                        index++;
 
1141
                }
 
1142
                freedisplist(&dispbase);
 
1143
        }
 
1144
        else {
 
1145
                /* no points, do this so scripts don't barf */
 
1146
                freedisplist(&dispbase); /* possible some dl was allocated */
 
1147
                tri_list = PyList_New(0);
 
1148
        }
 
1149
 
 
1150
        return tri_list;
 
1151
}
 
1152
 
 
1153
 
 
1154
static int boxPack_FromPyObject(PyObject *value, boxPack **boxarray)
 
1155
{
 
1156
        Py_ssize_t len, i;
 
1157
        PyObject *list_item, *item_1, *item_2;
 
1158
        boxPack *box;
 
1159
 
 
1160
 
 
1161
        /* Error checking must already be done */
 
1162
        if (!PyList_Check(value)) {
 
1163
                PyErr_SetString(PyExc_TypeError,
 
1164
                                "can only back a list of [x, y, w, h]");
 
1165
                return -1;
 
1166
        }
 
1167
 
 
1168
        len = PyList_GET_SIZE(value);
 
1169
 
 
1170
        *boxarray = MEM_mallocN(len * sizeof(boxPack), "boxPack box");
 
1171
 
 
1172
 
 
1173
        for (i = 0; i < len; i++) {
 
1174
                list_item = PyList_GET_ITEM(value, i);
 
1175
                if (!PyList_Check(list_item) || PyList_GET_SIZE(list_item) < 4) {
 
1176
                        MEM_freeN(*boxarray);
 
1177
                        PyErr_SetString(PyExc_TypeError,
 
1178
                                        "can only pack a list of [x, y, w, h]");
 
1179
                        return -1;
 
1180
                }
 
1181
 
 
1182
                box = (*boxarray) + i;
 
1183
 
 
1184
                item_1 = PyList_GET_ITEM(list_item, 2);
 
1185
                item_2 = PyList_GET_ITEM(list_item, 3);
 
1186
 
 
1187
                box->w =  (float)PyFloat_AsDouble(item_1);
 
1188
                box->h =  (float)PyFloat_AsDouble(item_2);
 
1189
                box->index = i;
 
1190
 
 
1191
                /* accounts for error case too and overwrites with own error */
 
1192
                if (box->w < 0.0f || box->h < 0.0f) {
 
1193
                        MEM_freeN(*boxarray);
 
1194
                        PyErr_SetString(PyExc_TypeError,
 
1195
                                        "error parsing width and height values from list: "
 
1196
                                        "[x, y, w, h], not numbers or below zero");
 
1197
                        return -1;
 
1198
                }
 
1199
 
 
1200
                /* verts will be added later */
 
1201
        }
 
1202
        return 0;
 
1203
}
 
1204
 
 
1205
static void boxPack_ToPyObject(PyObject *value, boxPack **boxarray)
 
1206
{
 
1207
        Py_ssize_t len, i;
 
1208
        PyObject *list_item;
 
1209
        boxPack *box;
 
1210
 
 
1211
        len = PyList_GET_SIZE(value);
 
1212
 
 
1213
        for (i = 0; i < len; i++) {
 
1214
                box = (*boxarray) + i;
 
1215
                list_item = PyList_GET_ITEM(value, box->index);
 
1216
                PyList_SET_ITEM(list_item, 0, PyFloat_FromDouble(box->x));
 
1217
                PyList_SET_ITEM(list_item, 1, PyFloat_FromDouble(box->y));
 
1218
        }
 
1219
        MEM_freeN(*boxarray);
 
1220
}
 
1221
 
 
1222
PyDoc_STRVAR(M_Geometry_box_pack_2d_doc,
 
1223
".. function:: box_pack_2d(boxes)\n"
 
1224
"\n"
 
1225
"   Returns the normal of the 3D tri or quad.\n"
 
1226
"\n"
 
1227
"   :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"
 
1228
"   :type boxes: list\n"
 
1229
"   :return: the width and height of the packed bounding box\n"
 
1230
"   :rtype: tuple, pair of floats\n"
 
1231
);
 
1232
static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlist)
 
1233
{
 
1234
        float tot_width = 0.0f, tot_height = 0.0f;
 
1235
        Py_ssize_t len;
 
1236
 
 
1237
        PyObject *ret;
 
1238
 
 
1239
        if (!PyList_Check(boxlist)) {
 
1240
                PyErr_SetString(PyExc_TypeError,
 
1241
                                "expected a list of boxes [[x, y, w, h], ... ]");
 
1242
                return NULL;
 
1243
        }
 
1244
 
 
1245
        len = PyList_GET_SIZE(boxlist);
 
1246
        if (len) {
 
1247
                boxPack *boxarray = NULL;
 
1248
                if (boxPack_FromPyObject(boxlist, &boxarray) == -1) {
 
1249
                        return NULL; /* exception set */
 
1250
                }
 
1251
 
 
1252
                /* Non Python function */
 
1253
                boxPack2D(boxarray, len, &tot_width, &tot_height);
 
1254
 
 
1255
                boxPack_ToPyObject(boxlist, &boxarray);
 
1256
        }
 
1257
 
 
1258
        ret = PyTuple_New(2);
 
1259
        PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(tot_width));
 
1260
        PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(tot_width));
 
1261
        return ret;
 
1262
}
 
1263
 
 
1264
#endif /* MATH_STANDALONE */
 
1265
 
 
1266
 
 
1267
static PyMethodDef M_Geometry_methods[] = {
 
1268
        {"intersect_ray_tri", (PyCFunction) M_Geometry_intersect_ray_tri, METH_VARARGS, M_Geometry_intersect_ray_tri_doc},
 
1269
        {"intersect_point_line", (PyCFunction) M_Geometry_intersect_point_line, METH_VARARGS, M_Geometry_intersect_point_line_doc},
 
1270
        {"intersect_point_tri_2d", (PyCFunction) M_Geometry_intersect_point_tri_2d, METH_VARARGS, M_Geometry_intersect_point_tri_2d_doc},
 
1271
        {"intersect_point_quad_2d", (PyCFunction) M_Geometry_intersect_point_quad_2d, METH_VARARGS, M_Geometry_intersect_point_quad_2d_doc},
 
1272
        {"intersect_line_line", (PyCFunction) M_Geometry_intersect_line_line, METH_VARARGS, M_Geometry_intersect_line_line_doc},
 
1273
        {"intersect_line_line_2d", (PyCFunction) M_Geometry_intersect_line_line_2d, METH_VARARGS, M_Geometry_intersect_line_line_2d_doc},
 
1274
        {"intersect_line_plane", (PyCFunction) M_Geometry_intersect_line_plane, METH_VARARGS, M_Geometry_intersect_line_plane_doc},
 
1275
        {"intersect_plane_plane", (PyCFunction) M_Geometry_intersect_plane_plane, METH_VARARGS, M_Geometry_intersect_plane_plane_doc},
 
1276
        {"intersect_line_sphere", (PyCFunction) M_Geometry_intersect_line_sphere, METH_VARARGS, M_Geometry_intersect_line_sphere_doc},
 
1277
        {"intersect_line_sphere_2d", (PyCFunction) M_Geometry_intersect_line_sphere_2d, METH_VARARGS, M_Geometry_intersect_line_sphere_2d_doc},
 
1278
        {"distance_point_to_plane", (PyCFunction) M_Geometry_distance_point_to_plane, METH_VARARGS, M_Geometry_distance_point_to_plane_doc},
 
1279
        {"area_tri", (PyCFunction) M_Geometry_area_tri, METH_VARARGS, M_Geometry_area_tri_doc},
 
1280
        {"normal", (PyCFunction) M_Geometry_normal, METH_VARARGS, M_Geometry_normal_doc},
 
1281
        {"barycentric_transform", (PyCFunction) M_Geometry_barycentric_transform, METH_VARARGS, M_Geometry_barycentric_transform_doc},
 
1282
#ifndef MATH_STANDALONE
 
1283
        {"interpolate_bezier", (PyCFunction) M_Geometry_interpolate_bezier, METH_VARARGS, M_Geometry_interpolate_bezier_doc},
 
1284
        {"tessellate_polygon", (PyCFunction) M_Geometry_tessellate_polygon, METH_O, M_Geometry_tessellate_polygon_doc},
 
1285
        {"box_pack_2d", (PyCFunction) M_Geometry_box_pack_2d, METH_O, M_Geometry_box_pack_2d_doc},
 
1286
#endif
 
1287
        {NULL, NULL, 0, NULL}
 
1288
};
 
1289
 
 
1290
static struct PyModuleDef M_Geometry_module_def = {
 
1291
        PyModuleDef_HEAD_INIT,
 
1292
        "mathutils.geometry",  /* m_name */
 
1293
        M_Geometry_doc,  /* m_doc */
 
1294
        0,  /* m_size */
 
1295
        M_Geometry_methods,  /* m_methods */
 
1296
        NULL,  /* m_reload */
 
1297
        NULL,  /* m_traverse */
 
1298
        NULL,  /* m_clear */
 
1299
        NULL,  /* m_free */
 
1300
};
 
1301
 
 
1302
/*----------------------------MODULE INIT-------------------------*/
 
1303
PyMODINIT_FUNC PyInit_mathutils_geometry(void)
 
1304
{
 
1305
        PyObject *submodule = PyModule_Create(&M_Geometry_module_def);
 
1306
        return submodule;
 
1307
}