~ubuntu-branches/ubuntu/wily/python-imaging/wily

« back to all changes in this revision

Viewing changes to .pc/git-updates.diff/path.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-01-31 20:49:20 UTC
  • mfrom: (1.1.4)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130131204920-7tnuhqhlsqdza4c2
Rewrite build dependencies to allow cross builds.

Show diffs side-by-side

added added

removed removed

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