Skip to content

Commit 2c4f186

Browse files
authored
Create triangulation.c
triangulation.c provides fast implementations for some of the functions in learner/triangulation.py
1 parent 7647ee8 commit 2c4f186

File tree

1 file changed

+272
-0
lines changed

1 file changed

+272
-0
lines changed

adaptive/learner/triangulation.c

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
#include "Python.h"
2+
#include "numpy/arrayobject.h"
3+
#include <math.h>
4+
#include <stdio.h>
5+
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
6+
7+
static PyObject *
8+
fast_norm(PyObject *self, PyObject *args)
9+
{
10+
PyObject* vect;
11+
if (!PyArg_ParseTuple(args, "O", &vect))
12+
return NULL;
13+
14+
if (PyList_Check(vect)) {
15+
Py_ssize_t numElements = PyObject_Length(vect);
16+
if (numElements <= 0) {
17+
PyErr_SetString(PyExc_ValueError, "fast_norm requires a list of length 1 or greater.");
18+
return NULL;
19+
}
20+
double sum = 0;
21+
for (Py_ssize_t i = 0; i < numElements; ++i) {
22+
double val = PyFloat_AsDouble(PyList_GetItem(vect, i));
23+
if (PyErr_Occurred()) {
24+
return NULL;
25+
}
26+
sum += val * val;
27+
}
28+
return Py_BuildValue("f", sqrt(sum));
29+
}
30+
31+
if (PyTuple_Check(vect)) {
32+
Py_ssize_t numElements = PyTuple_Size(vect);
33+
if (numElements <= 0) {
34+
PyErr_SetString(PyExc_ValueError, "fast_norm requires a list of length 1 or greater.");
35+
return NULL;
36+
}
37+
double sum = 0;
38+
for (Py_ssize_t i = 0; i < numElements; ++i) {
39+
double val = PyFloat_AsDouble(PyTuple_GetItem(vect, i));
40+
if (PyErr_Occurred()) {
41+
return NULL;
42+
}
43+
sum += val * val;
44+
}
45+
return Py_BuildValue("f", sqrt(sum));
46+
}
47+
48+
if (PyArray_Check(vect)) {
49+
PyObject *npArray = PyArray_FROM_OTF(vect, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
50+
if (npArray == NULL)
51+
return NULL;
52+
int nd = PyArray_NDIM(npArray);
53+
if (nd != 1)
54+
return NULL;
55+
npy_intp * shape = PyArray_DIMS(npArray);
56+
Py_ssize_t numElements = PyArray_SIZE(npArray);
57+
double* data = (double *) PyArray_DATA(npArray);
58+
double sum = 0;
59+
for (Py_ssize_t i = 0; i < numElements; ++i) {
60+
double val = data[i];
61+
sum += val * val;
62+
}
63+
return Py_BuildValue("f", sqrt(sum));
64+
}
65+
66+
}
67+
68+
static int get_tuple_elems(PyObject * tuple, double * first, double * second) {
69+
PyObject * elem = PyTuple_GetItem(tuple, 0);
70+
if (elem == NULL)
71+
return 0;
72+
*first = PyFloat_AsDouble(elem);
73+
elem = PyTuple_GetItem(tuple, 1);
74+
if (elem == NULL)
75+
return 0;
76+
*second = PyFloat_AsDouble(elem);
77+
return 1;
78+
}
79+
80+
static int get_triple_tuple_elems(PyObject * tuple, double * first, double * second, double* third) {
81+
PyObject * elem = PyTuple_GetItem(tuple, 0);
82+
if (elem == NULL)
83+
return 0;
84+
*first = PyFloat_AsDouble(elem);
85+
elem = PyTuple_GetItem(tuple, 1);
86+
if (elem == NULL)
87+
return 0;
88+
*second = PyFloat_AsDouble(elem);
89+
elem = PyTuple_GetItem(tuple, 2);
90+
if (elem == NULL)
91+
return 0;
92+
*third = PyFloat_AsDouble(elem);
93+
return 1;
94+
}
95+
96+
static PyObject *
97+
fast_2d_point_in_simplex(PyObject *self, PyObject *args, PyObject *kwargs)
98+
{
99+
PyObject* point, * simplex;
100+
double eps = 0.00000001;
101+
102+
// SystemError: bad format char passed to Py_BuildValue ??
103+
static char *kwlist[] = {"point", "simplex", "eps", NULL};
104+
105+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|d", kwlist, &point, &simplex, &eps))
106+
return NULL;
107+
108+
109+
if (!PyTuple_Check(point))
110+
return NULL;
111+
112+
if (!PyList_Check(simplex))
113+
return NULL;
114+
115+
double px, py, p0x, p0y, p1x, p1y, p2x, p2y;
116+
if (!get_tuple_elems(point, &px, &py))
117+
return NULL;
118+
119+
point = PyList_GetItem(simplex, 0);
120+
if (point == NULL)
121+
return NULL;
122+
123+
if (!get_tuple_elems(point, &p0x, &p0y))
124+
return NULL;
125+
126+
point = PyList_GetItem(simplex, 1);
127+
if (point == NULL)
128+
return NULL;
129+
130+
if (!get_tuple_elems(point, &p1x, &p1y))
131+
return NULL;
132+
133+
point = PyList_GetItem(simplex, 2);
134+
if (point == NULL)
135+
return NULL;
136+
137+
if (!get_tuple_elems(point, &p2x, &p2y))
138+
return NULL;
139+
140+
double area = 0.5 * (-p1y * p2x + p0y * (p2x - p1x) + p1x * p2y + p0x * (p1y - p2y));
141+
double s = 1 / (2 * area) * (p0y * p2x + (p2y - p0y) * px - p0x * p2y + (p0x - p2x) * py);
142+
if ((s < -eps) || (s > 1 + eps))
143+
return Py_BuildValue("O", Py_False);
144+
double t = 1 / (2 * area) * (p0x * p1y + (p0y - p1y) * px - p0y * p1x + (p1x - p0x) * py);
145+
return Py_BuildValue("O", (t >= -eps) && (s + t <= 1 + eps) ? Py_True : Py_False);
146+
}
147+
148+
static PyObject *
149+
fast_2d_circumcircle(PyObject *self, PyObject *args)
150+
{
151+
PyObject* points;
152+
if (!PyArg_ParseTuple(args, "O", &points))
153+
return NULL;
154+
155+
if (PyList_Check(points)) {
156+
Py_ssize_t numElements = PyObject_Length(points);
157+
if (numElements <= 0) {
158+
PyErr_SetString(PyExc_ValueError, "fast_2d_circumcircle requires a list of length 1 or greater.");
159+
return NULL;
160+
}
161+
double x0, y0, x1, y1, x2, y2;
162+
if (!get_tuple_elems(PyList_GetItem(points, 0), &x0, &y0))
163+
return NULL;
164+
if (!get_tuple_elems(PyList_GetItem(points, 1), &x1, &y1))
165+
return NULL;
166+
if (!get_tuple_elems(PyList_GetItem(points, 2), &x2, &y2))
167+
return NULL;
168+
169+
x1 -= x0;
170+
y1 -= y0;
171+
172+
x2 -= x0;
173+
y2 -= y0;
174+
175+
double l1 = x1 * x1 + y1 * y1;
176+
double l2 = x2 * x2 + y2 * y2;
177+
double dx = l1 * y2 - l2 * y1;
178+
double dy = -l1 * x2 + l2 * x1;
179+
180+
double aa = 2 * (x1 * y2 - x2 * y1);
181+
double x = dx / aa;
182+
double y = dy / aa;
183+
return Py_BuildValue("(ff)f", x + x0, y + y0, sqrt(x * x + y * y));
184+
}
185+
return NULL;
186+
}
187+
188+
static PyObject *
189+
fast_3d_circumcircle(PyObject *self, PyObject *args)
190+
{
191+
PyObject* points;
192+
if (!PyArg_ParseTuple(args, "O", &points))
193+
return NULL;
194+
195+
if (PyList_Check(points)) {
196+
Py_ssize_t numElements = PyObject_Length(points);
197+
if (numElements <= 0) {
198+
PyErr_SetString(PyExc_ValueError, "fast_2d_circumcircle requires a list of length 1 or greater.");
199+
return NULL;
200+
}
201+
double x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3;
202+
if (!get_triple_tuple_elems(PyList_GetItem(points, 0), &x0, &y0, &z0))
203+
return NULL;
204+
if (!get_triple_tuple_elems(PyList_GetItem(points, 1), &x1, &y1, &z1))
205+
return NULL;
206+
if (!get_triple_tuple_elems(PyList_GetItem(points, 2), &x2, &y2, &z2))
207+
return NULL;
208+
if (!get_triple_tuple_elems(PyList_GetItem(points, 3), &x3, &y3, &z3))
209+
return NULL;
210+
211+
x1 -= x0;
212+
y1 -= y0;
213+
z1 -= z0;
214+
215+
x2 -= x0;
216+
y2 -= y0;
217+
z2 -= z0;
218+
219+
x3 -= x0;
220+
y3 -= y0;
221+
z3 -= z0;
222+
223+
double l1 = x1 * x1 + y1 * y1 + z1 * z1;
224+
double l2 = x2 * x2 + y2 * y2 + z2 * z2;
225+
double l3 = x3 * x3 + y3 * y3 + z3 * z3;
226+
double dx = l1 * (y2 * z3 - z2 * y3) - l2 * (y1 * z3 - z1 * y3) + l3 * (y1 * z2 - z1 * y2);
227+
double dy = -l1 * (x2 * z3 - z2 * x3) - l2 * (x1 * z3 - z1 * x3) + l3 * (x1 * z2 - z1 * x2);
228+
double dz = l1 * (x2 * y3 - y2 * x3) - l2 * (x1 * y3 - y1 * x3) + l3 * (x1 * y2 - y1 * x2);
229+
230+
double aa = 2 * (x1 * (y2 * z3 - z2 * y3) - x2 * (y1 * z3 - z1 * y3) + x3 * (y1 * z2 - z1 * y2));
231+
double x = dx / aa;
232+
double y = dy / aa;
233+
double z = dz / aa;
234+
return Py_BuildValue("(fff)f", x + x0, y + y0, z + z0, sqrt(x * x + y * y + z * z));
235+
}
236+
return NULL;
237+
}
238+
239+
240+
static PyMethodDef triangulation_functions[] = {
241+
{"fast_norm", fast_norm, METH_VARARGS,
242+
"Returns the norm of the given array."},
243+
{"fast_2d_circumcircle", fast_2d_circumcircle, METH_VARARGS,
244+
"Returns the norm of the given array."},
245+
{"fast_3d_circumcircle", fast_3d_circumcircle, METH_VARARGS,
246+
"Returns the norm of the given array."},
247+
{"fast_2d_point_in_simplex", (PyCFunction) fast_2d_point_in_simplex, METH_VARARGS | METH_KEYWORDS,
248+
"Refer to docs."},
249+
{NULL}
250+
};
251+
252+
PyDoc_STRVAR(module_doc, "Fast implementations of triangulation functions.");
253+
254+
static struct PyModuleDef moduledef = {
255+
PyModuleDef_HEAD_INIT,
256+
"triangulation",
257+
module_doc,
258+
-1, /* m_size */
259+
triangulation_functions, /* m_methods */
260+
NULL, /* m_reload (unused) */
261+
NULL, /* m_traverse */
262+
NULL, /* m_clear */
263+
NULL /* m_free */
264+
};
265+
266+
PyObject *
267+
PyInit_triangulation(void)
268+
{
269+
if(PyArray_API == NULL)
270+
import_array();
271+
return PyModule_Create(&moduledef);
272+
}

0 commit comments

Comments
 (0)