Skip to content

Commit 193071a

Browse files
committed
optimized the Line.project method made it METH_FASTCALL and removed sqrt calls
1 parent e2001dd commit 193071a

File tree

1 file changed

+25
-50
lines changed

1 file changed

+25
-50
lines changed

src_c/line.c

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -201,30 +201,28 @@ _length_of_vector(double *vector)
201201
}
202202

203203
static PyObject *
204-
_line_project_helper(pgLineBase *line, double *point, int do_clamp)
204+
_line_project_helper(pgLineBase *line, double *point, int clamp)
205205
{
206206
// this is a vector that goes from one point of the line to another
207207
double line_vector[2] = {line->bx - line->ax, line->by - line->ay};
208-
double line_length = _length_of_vector(line_vector);
209-
210-
// this is a unit vector that points in the direction of the line
211-
double normalized_line_vector[2] = {line_vector[0], line_vector[1]};
212-
_normalize_vector(normalized_line_vector);
213208

214209
// this is a vector that goes from the start of the line to the point we
215210
// are projecting onto the line
216211
double vector_from_line_start_to_point[2] = {point[0] - line->ax,
217212
point[1] - line->ay};
218213

219214
double dot_product =
220-
vector_from_line_start_to_point[0] * normalized_line_vector[0] +
221-
vector_from_line_start_to_point[1] * normalized_line_vector[1];
215+
(vector_from_line_start_to_point[0] * line_vector[0] +
216+
vector_from_line_start_to_point[1] * line_vector[1]) /
217+
(line_vector[0] * line_vector[0] + line_vector[1] * line_vector[1]);
222218

223-
double projection[2] = {dot_product * normalized_line_vector[0],
224-
dot_product * normalized_line_vector[1]};
219+
double projection[2] = {dot_product * line_vector[0],
220+
dot_product * line_vector[1]};
225221

226-
if (do_clamp) {
227-
if (dot_product > line_length) {
222+
if (clamp) {
223+
if (projection[0] * projection[0] + projection[1] * projection[1] >
224+
line_vector[0] * line_vector[0] +
225+
line_vector[1] * line_vector[1]) {
228226
projection[0] = line_vector[0];
229227
projection[1] = line_vector[1];
230228
}
@@ -237,10 +235,8 @@ _line_project_helper(pgLineBase *line, double *point, int do_clamp)
237235
double projected_point[2] = {line->ax + projection[0],
238236
line->ay + projection[1]};
239237

240-
PyObject *projected_tuple =
241-
Py_BuildValue("(dd)", projected_point[0], projected_point[1]);
242-
243-
return projected_tuple;
238+
return pg_tuple_couple_from_values_double(projected_point[0],
239+
projected_point[1]);
244240
}
245241

246242
static PyObject *
@@ -284,47 +280,26 @@ pg_line_scale_ip(pgLineObject *self, PyObject *const *args, Py_ssize_t nargs)
284280
}
285281

286282
static PyObject *
287-
pg_line_project(pgLineObject *self, PyObject *args, PyObject *kwnames)
283+
pg_line_project(pgLineObject *self, PyObject *const *args, Py_ssize_t nargs,
284+
PyObject *kwnames)
288285
{
289-
PyObject *point_obj = NULL;
290-
int do_clamp = 0;
286+
double point[2] = {0.f, 0.f};
287+
int clamp = 0;
291288

292-
static char *kwlist[] = {"point", "do_clamp", NULL};
293-
294-
if (!PyArg_ParseTupleAndKeywords(args, kwnames, "O|p:project", kwlist,
295-
&point_obj, &do_clamp)) {
296-
return RAISE(
297-
PyExc_TypeError,
298-
"project requires a sequence(point) and an optional clamp flag");
299-
}
300-
301-
PyObject *item;
302-
double point[2];
303-
304-
if (!PySequence_Check(point_obj) || PySequence_Size(point_obj) != 2) {
305-
return RAISE(
306-
PyExc_ValueError,
307-
"project requires the point to be a sequence of 2 elements");
308-
}
309-
310-
item = PySequence_GetItem(point_obj, 0);
311-
point[0] = PyFloat_AsDouble(item);
312-
313-
PyObject *error_type;
314-
if ((error_type = PyErr_Occurred())) {
315-
return NULL;
289+
if (nargs >= 1) {
290+
if (!pg_TwoDoublesFromObj(args[0], &point[0], &point[1])) {
291+
return RAISE(PyExc_TypeError,
292+
"project requires a sequence of two numbers");
293+
}
316294
}
317295

318-
item = PySequence_GetItem(point_obj, 1);
319-
point[1] = PyFloat_AsDouble(item);
320-
321-
if ((error_type = PyErr_Occurred())) {
322-
return NULL;
296+
if (kwnames != NULL) {
297+
clamp = PyObject_IsTrue(args[nargs]);
323298
}
324299

325300
PyObject *projected_point;
326301
if (!(projected_point =
327-
_line_project_helper(&pgLine_AsLine(self), point, do_clamp))) {
302+
_line_project_helper(&pgLine_AsLine(self), point, clamp))) {
328303
return NULL;
329304
}
330305

@@ -343,7 +318,7 @@ static struct PyMethodDef pg_line_methods[] = {
343318
{"scale", (PyCFunction)pg_line_scale, METH_FASTCALL, DOC_LINE_SCALE},
344319
{"scale_ip", (PyCFunction)pg_line_scale_ip, METH_FASTCALL,
345320
DOC_LINE_SCALEIP},
346-
{"project", (PyCFunction)pg_line_project, METH_VARARGS | METH_KEYWORDS,
321+
{"project", (PyCFunction)pg_line_project, METH_FASTCALL | METH_KEYWORDS,
347322
DOC_LINE_PROJECT},
348323
{NULL, NULL, 0, NULL}};
349324

0 commit comments

Comments
 (0)