path.c 17 KB

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