path.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. /*
  2. * The Python Imaging Library.
  3. *
  4. * 2D path utilities
  5. *
  6. * history:
  7. * 1996-11-04 fl Added to PIL (incomplete)
  8. * 1996-11-05 fl Added sequence semantics
  9. * 1997-02-28 fl Fixed getbbox
  10. * 1997-06-12 fl Added id attribute
  11. * 1997-06-14 fl Added slicing and setitem
  12. * 1998-12-29 fl Improved sequence handling (from Richard Jones)
  13. * 1999-01-10 fl Fixed IndexError test for 1.5 (from Fred Drake)
  14. * 2000-10-12 fl Added special cases for tuples and lists
  15. * 2002-10-27 fl Added clipping boilerplate
  16. * 2004-09-19 fl Added tolist(flat) variant
  17. * 2005-05-06 fl Added buffer interface support to path constructor
  18. *
  19. * notes:
  20. * FIXME: fill in remaining slots in the sequence api
  21. *
  22. * Copyright (c) 1997-2005 by Secret Labs AB
  23. * Copyright (c) 1997-2005 by Fredrik Lundh
  24. *
  25. * See the README file for information on usage and redistribution.
  26. */
  27. #include "Python.h"
  28. #include "libImaging/Imaging.h"
  29. #include <math.h>
  30. /* compatibility wrappers (defined in _imaging.c) */
  31. extern int
  32. PyImaging_CheckBuffer(PyObject *buffer);
  33. extern int
  34. PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view);
  35. /* -------------------------------------------------------------------- */
  36. /* Class */
  37. /* -------------------------------------------------------------------- */
  38. typedef struct {
  39. PyObject_HEAD Py_ssize_t count;
  40. double *xy;
  41. int index; /* temporary use, e.g. in decimate */
  42. } PyPathObject;
  43. static PyTypeObject PyPathType;
  44. static double *
  45. alloc_array(Py_ssize_t count) {
  46. double *xy;
  47. if (count < 0) {
  48. return ImagingError_MemoryError();
  49. }
  50. if ((unsigned long long)count > (SIZE_MAX / (2 * sizeof(double))) - 1) {
  51. return ImagingError_MemoryError();
  52. }
  53. xy = calloc(2 * count + 1, sizeof(double));
  54. if (!xy) {
  55. ImagingError_MemoryError();
  56. }
  57. return xy;
  58. }
  59. static PyPathObject *
  60. path_new(Py_ssize_t count, double *xy, int duplicate) {
  61. PyPathObject *path;
  62. if (duplicate) {
  63. /* duplicate path */
  64. double *p = alloc_array(count);
  65. if (!p) {
  66. return NULL;
  67. }
  68. memcpy(p, xy, count * 2 * sizeof(double));
  69. xy = p;
  70. }
  71. if (PyType_Ready(&PyPathType) < 0) {
  72. free(xy);
  73. return NULL;
  74. }
  75. path = PyObject_New(PyPathObject, &PyPathType);
  76. if (path == NULL) {
  77. free(xy);
  78. return NULL;
  79. }
  80. path->count = count;
  81. path->xy = xy;
  82. return path;
  83. }
  84. static void
  85. path_dealloc(PyPathObject *path) {
  86. free(path->xy);
  87. PyObject_Del(path);
  88. }
  89. /* -------------------------------------------------------------------- */
  90. /* Helpers */
  91. /* -------------------------------------------------------------------- */
  92. #define PyPath_Check(op) (Py_TYPE(op) == &PyPathType)
  93. Py_ssize_t
  94. PyPath_Flatten(PyObject *data, double **pxy) {
  95. Py_ssize_t i, j, n;
  96. double *xy;
  97. if (PyPath_Check(data)) {
  98. /* This was another path object. */
  99. PyPathObject *path = (PyPathObject *)data;
  100. xy = alloc_array(path->count);
  101. if (!xy) {
  102. return -1;
  103. }
  104. memcpy(xy, path->xy, 2 * path->count * sizeof(double));
  105. *pxy = xy;
  106. return path->count;
  107. }
  108. if (PyImaging_CheckBuffer(data)) {
  109. /* Assume the buffer contains floats */
  110. Py_buffer buffer;
  111. if (PyImaging_GetBuffer(data, &buffer) == 0) {
  112. float *ptr = (float *)buffer.buf;
  113. n = buffer.len / (2 * sizeof(float));
  114. xy = alloc_array(n);
  115. if (!xy) {
  116. return -1;
  117. }
  118. for (i = 0; i < n + n; i++) {
  119. xy[i] = ptr[i];
  120. }
  121. *pxy = xy;
  122. PyBuffer_Release(&buffer);
  123. return n;
  124. }
  125. PyErr_Clear();
  126. }
  127. if (!PySequence_Check(data)) {
  128. PyErr_SetString(PyExc_TypeError, "argument must be sequence");
  129. return -1;
  130. }
  131. j = 0;
  132. n = PyObject_Length(data);
  133. /* Just in case __len__ breaks (or doesn't exist) */
  134. if (PyErr_Occurred()) {
  135. return -1;
  136. }
  137. /* Allocate for worst case */
  138. xy = alloc_array(n);
  139. if (!xy) {
  140. return -1;
  141. }
  142. #define assign_item_to_array(op, decref) \
  143. if (PyFloat_Check(op)) { \
  144. xy[j++] = PyFloat_AS_DOUBLE(op); \
  145. } else if (PyLong_Check(op)) { \
  146. xy[j++] = (float)PyLong_AS_LONG(op); \
  147. } else if (PyNumber_Check(op)) { \
  148. xy[j++] = PyFloat_AsDouble(op); \
  149. } else if (PyArg_ParseTuple(op, "dd", &x, &y)) { \
  150. xy[j++] = x; \
  151. xy[j++] = y; \
  152. } else { \
  153. PyErr_SetString(PyExc_ValueError, "incorrect coordinate type"); \
  154. if (decref) { \
  155. Py_DECREF(op); \
  156. } \
  157. free(xy); \
  158. return -1; \
  159. }
  160. /* Copy table to path array */
  161. if (PyList_Check(data)) {
  162. for (i = 0; i < n; i++) {
  163. double x, y;
  164. PyObject *op = PyList_GET_ITEM(data, i);
  165. assign_item_to_array(op, 0);
  166. }
  167. } else if (PyTuple_Check(data)) {
  168. for (i = 0; i < n; i++) {
  169. double x, y;
  170. PyObject *op = PyTuple_GET_ITEM(data, i);
  171. assign_item_to_array(op, 0);
  172. }
  173. } else {
  174. for (i = 0; i < n; i++) {
  175. double x, y;
  176. PyObject *op = PySequence_GetItem(data, i);
  177. if (!op) {
  178. /* treat IndexError as end of sequence */
  179. if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_IndexError)) {
  180. PyErr_Clear();
  181. break;
  182. } else {
  183. free(xy);
  184. return -1;
  185. }
  186. }
  187. assign_item_to_array(op, 1);
  188. Py_DECREF(op);
  189. }
  190. }
  191. if (j & 1) {
  192. PyErr_SetString(PyExc_ValueError, "wrong number of coordinates");
  193. free(xy);
  194. return -1;
  195. }
  196. *pxy = xy;
  197. return j / 2;
  198. }
  199. /* -------------------------------------------------------------------- */
  200. /* Factories */
  201. /* -------------------------------------------------------------------- */
  202. PyObject *
  203. PyPath_Create(PyObject *self, PyObject *args) {
  204. PyObject *data;
  205. Py_ssize_t count;
  206. double *xy;
  207. if (PyArg_ParseTuple(args, "n:Path", &count)) {
  208. /* number of vertices */
  209. xy = alloc_array(count);
  210. if (!xy) {
  211. return NULL;
  212. }
  213. } else {
  214. /* sequence or other path */
  215. PyErr_Clear();
  216. if (!PyArg_ParseTuple(args, "O", &data)) {
  217. return NULL;
  218. }
  219. count = PyPath_Flatten(data, &xy);
  220. if (count < 0) {
  221. return NULL;
  222. }
  223. }
  224. return (PyObject *)path_new(count, xy, 0);
  225. }
  226. /* -------------------------------------------------------------------- */
  227. /* Methods */
  228. /* -------------------------------------------------------------------- */
  229. static PyObject *
  230. path_compact(PyPathObject *self, PyObject *args) {
  231. /* Simple-minded method to shorten path. A point is removed if
  232. the city block distance to the previous point is less than the
  233. given distance */
  234. Py_ssize_t i, j;
  235. double *xy;
  236. double cityblock = 2.0;
  237. if (!PyArg_ParseTuple(args, "|d:compact", &cityblock)) {
  238. return NULL;
  239. }
  240. xy = self->xy;
  241. /* remove bogus vertices */
  242. for (i = j = 1; i < self->count; i++) {
  243. if (fabs(xy[j + j - 2] - xy[i + i]) + fabs(xy[j + j - 1] - xy[i + i + 1]) >=
  244. cityblock) {
  245. xy[j + j] = xy[i + i];
  246. xy[j + j + 1] = xy[i + i + 1];
  247. j++;
  248. }
  249. }
  250. i = self->count - j;
  251. self->count = j;
  252. /* shrink coordinate array */
  253. /* malloc check ok, self->count is smaller than it was before */
  254. self->xy = realloc(self->xy, 2 * self->count * sizeof(double));
  255. return Py_BuildValue("i", i); /* number of removed vertices */
  256. }
  257. static PyObject *
  258. path_getbbox(PyPathObject *self, PyObject *args) {
  259. /* Find bounding box */
  260. Py_ssize_t i;
  261. double *xy;
  262. double x0, y0, x1, y1;
  263. if (!PyArg_ParseTuple(args, ":getbbox")) {
  264. return NULL;
  265. }
  266. xy = self->xy;
  267. if (self->count == 0) {
  268. x0 = x1 = 0;
  269. y0 = y1 = 0;
  270. } else {
  271. x0 = x1 = xy[0];
  272. y0 = y1 = xy[1];
  273. for (i = 1; i < self->count; i++) {
  274. if (xy[i + i] < x0) {
  275. x0 = xy[i + i];
  276. }
  277. if (xy[i + i] > x1) {
  278. x1 = xy[i + i];
  279. }
  280. if (xy[i + i + 1] < y0) {
  281. y0 = xy[i + i + 1];
  282. }
  283. if (xy[i + i + 1] > y1) {
  284. y1 = xy[i + i + 1];
  285. }
  286. }
  287. }
  288. return Py_BuildValue("dddd", x0, y0, x1, y1);
  289. }
  290. static PyObject *
  291. path_getitem(PyPathObject *self, Py_ssize_t i) {
  292. if (i < 0) {
  293. i = self->count + i;
  294. }
  295. if (i < 0 || i >= self->count) {
  296. PyErr_SetString(PyExc_IndexError, "path index out of range");
  297. return NULL;
  298. }
  299. return Py_BuildValue("dd", self->xy[i + i], self->xy[i + i + 1]);
  300. }
  301. static PyObject *
  302. path_getslice(PyPathObject *self, Py_ssize_t ilow, Py_ssize_t ihigh) {
  303. /* adjust arguments */
  304. if (ilow < 0) {
  305. ilow = 0;
  306. } else if (ilow >= self->count) {
  307. ilow = self->count;
  308. }
  309. if (ihigh < 0) {
  310. ihigh = 0;
  311. }
  312. if (ihigh < ilow) {
  313. ihigh = ilow;
  314. } else if (ihigh > self->count) {
  315. ihigh = self->count;
  316. }
  317. return (PyObject *)path_new(ihigh - ilow, self->xy + ilow * 2, 1);
  318. }
  319. static Py_ssize_t
  320. path_len(PyPathObject *self) {
  321. return self->count;
  322. }
  323. static PyObject *
  324. path_map(PyPathObject *self, PyObject *args) {
  325. /* Map coordinate set through function */
  326. Py_ssize_t i;
  327. double *xy;
  328. PyObject *function;
  329. if (!PyArg_ParseTuple(args, "O:map", &function)) {
  330. return NULL;
  331. }
  332. xy = self->xy;
  333. /* apply function to coordinate set */
  334. for (i = 0; i < self->count; i++) {
  335. double x = xy[i + i];
  336. double y = xy[i + i + 1];
  337. PyObject *item = PyObject_CallFunction(function, "dd", x, y);
  338. if (!item || !PyArg_ParseTuple(item, "dd", &x, &y)) {
  339. Py_XDECREF(item);
  340. return NULL;
  341. }
  342. xy[i + i] = x;
  343. xy[i + i + 1] = y;
  344. Py_DECREF(item);
  345. }
  346. Py_INCREF(Py_None);
  347. return Py_None;
  348. }
  349. static int
  350. path_setitem(PyPathObject *self, Py_ssize_t i, PyObject *op) {
  351. double *xy;
  352. if (i < 0 || i >= self->count) {
  353. PyErr_SetString(PyExc_IndexError, "path assignment index out of range");
  354. return -1;
  355. }
  356. if (op == NULL) {
  357. PyErr_SetString(PyExc_TypeError, "cannot delete from path");
  358. return -1;
  359. }
  360. xy = &self->xy[i + i];
  361. if (!PyArg_ParseTuple(op, "dd", &xy[0], &xy[1])) {
  362. return -1;
  363. }
  364. return 0;
  365. }
  366. static PyObject *
  367. path_tolist(PyPathObject *self, PyObject *args) {
  368. PyObject *list;
  369. Py_ssize_t i;
  370. int flat = 0;
  371. if (!PyArg_ParseTuple(args, "|i:tolist", &flat)) {
  372. return NULL;
  373. }
  374. if (flat) {
  375. list = PyList_New(self->count * 2);
  376. if (list == NULL) {
  377. return NULL;
  378. }
  379. for (i = 0; i < self->count * 2; i++) {
  380. PyObject *item;
  381. item = PyFloat_FromDouble(self->xy[i]);
  382. if (!item) {
  383. goto error;
  384. }
  385. PyList_SetItem(list, i, item);
  386. }
  387. } else {
  388. list = PyList_New(self->count);
  389. if (list == NULL) {
  390. return NULL;
  391. }
  392. for (i = 0; i < self->count; i++) {
  393. PyObject *item;
  394. item = Py_BuildValue("dd", self->xy[i + i], self->xy[i + i + 1]);
  395. if (!item) {
  396. goto error;
  397. }
  398. PyList_SetItem(list, i, item);
  399. }
  400. }
  401. return list;
  402. error:
  403. Py_DECREF(list);
  404. return NULL;
  405. }
  406. static PyObject *
  407. path_transform(PyPathObject *self, PyObject *args) {
  408. /* Apply affine transform to coordinate set */
  409. Py_ssize_t i;
  410. double *xy;
  411. double a, b, c, d, e, f;
  412. double wrap = 0.0;
  413. if (!PyArg_ParseTuple(
  414. args, "(dddddd)|d:transform", &a, &b, &c, &d, &e, &f, &wrap)) {
  415. return NULL;
  416. }
  417. xy = self->xy;
  418. /* transform the coordinate set */
  419. if (b == 0.0 && d == 0.0) {
  420. /* scaling */
  421. for (i = 0; i < self->count; i++) {
  422. xy[i + i] = a * xy[i + i] + c;
  423. xy[i + i + 1] = e * xy[i + i + 1] + f;
  424. }
  425. } else {
  426. /* affine transform */
  427. for (i = 0; i < self->count; i++) {
  428. double x = xy[i + i];
  429. double y = xy[i + i + 1];
  430. xy[i + i] = a * x + b * y + c;
  431. xy[i + i + 1] = d * x + e * y + f;
  432. }
  433. }
  434. /* special treatment of geographical map data */
  435. if (wrap != 0.0) {
  436. for (i = 0; i < self->count; i++) {
  437. xy[i + i] = fmod(xy[i + i], wrap);
  438. }
  439. }
  440. Py_INCREF(Py_None);
  441. return Py_None;
  442. }
  443. static struct PyMethodDef methods[] = {
  444. {"getbbox", (PyCFunction)path_getbbox, METH_VARARGS},
  445. {"tolist", (PyCFunction)path_tolist, METH_VARARGS},
  446. {"compact", (PyCFunction)path_compact, METH_VARARGS},
  447. {"map", (PyCFunction)path_map, METH_VARARGS},
  448. {"transform", (PyCFunction)path_transform, METH_VARARGS},
  449. {NULL, NULL} /* sentinel */
  450. };
  451. static PyObject *
  452. path_getattr_id(PyPathObject *self, void *closure) {
  453. return Py_BuildValue("n", (Py_ssize_t)self->xy);
  454. }
  455. static struct PyGetSetDef getsetters[] = {{"id", (getter)path_getattr_id}, {NULL}};
  456. static PyObject *
  457. path_subscript(PyPathObject *self, PyObject *item) {
  458. if (PyIndex_Check(item)) {
  459. Py_ssize_t i;
  460. i = PyNumber_AsSsize_t(item, PyExc_IndexError);
  461. if (i == -1 && PyErr_Occurred()) {
  462. return NULL;
  463. }
  464. return path_getitem(self, i);
  465. }
  466. if (PySlice_Check(item)) {
  467. int len = 4;
  468. Py_ssize_t start, stop, step, slicelength;
  469. if (PySlice_GetIndicesEx(item, len, &start, &stop, &step, &slicelength) < 0) {
  470. return NULL;
  471. }
  472. if (slicelength <= 0) {
  473. double *xy = alloc_array(0);
  474. return (PyObject *)path_new(0, xy, 0);
  475. } else if (step == 1) {
  476. return path_getslice(self, start, stop);
  477. } else {
  478. PyErr_SetString(PyExc_TypeError, "slice steps not supported");
  479. return NULL;
  480. }
  481. } else {
  482. PyErr_Format(
  483. PyExc_TypeError,
  484. "Path indices must be integers, not %.200s",
  485. Py_TYPE(item)->tp_name);
  486. return NULL;
  487. }
  488. }
  489. static PySequenceMethods path_as_sequence = {
  490. (lenfunc)path_len, /*sq_length*/
  491. (binaryfunc)0, /*sq_concat*/
  492. (ssizeargfunc)0, /*sq_repeat*/
  493. (ssizeargfunc)path_getitem, /*sq_item*/
  494. (ssizessizeargfunc)path_getslice, /*sq_slice*/
  495. (ssizeobjargproc)path_setitem, /*sq_ass_item*/
  496. (ssizessizeobjargproc)0, /*sq_ass_slice*/
  497. };
  498. static PyMappingMethods path_as_mapping = {
  499. (lenfunc)path_len, (binaryfunc)path_subscript, NULL};
  500. static PyTypeObject PyPathType = {
  501. PyVarObject_HEAD_INIT(NULL, 0) "Path", /*tp_name*/
  502. sizeof(PyPathObject), /*tp_basicsize*/
  503. 0, /*tp_itemsize*/
  504. /* methods */
  505. (destructor)path_dealloc, /*tp_dealloc*/
  506. 0, /*tp_vectorcall_offset*/
  507. 0, /*tp_getattr*/
  508. 0, /*tp_setattr*/
  509. 0, /*tp_as_async*/
  510. 0, /*tp_repr*/
  511. 0, /*tp_as_number*/
  512. &path_as_sequence, /*tp_as_sequence*/
  513. &path_as_mapping, /*tp_as_mapping*/
  514. 0, /*tp_hash*/
  515. 0, /*tp_call*/
  516. 0, /*tp_str*/
  517. 0, /*tp_getattro*/
  518. 0, /*tp_setattro*/
  519. 0, /*tp_as_buffer*/
  520. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  521. 0, /*tp_doc*/
  522. 0, /*tp_traverse*/
  523. 0, /*tp_clear*/
  524. 0, /*tp_richcompare*/
  525. 0, /*tp_weaklistoffset*/
  526. 0, /*tp_iter*/
  527. 0, /*tp_iternext*/
  528. methods, /*tp_methods*/
  529. 0, /*tp_members*/
  530. getsetters, /*tp_getset*/
  531. };