Beispiel #1
0
static PyObject *Polygon_new(PyObject *self, PyObject *args) {
    PyObject *O = NULL, *TMP = NULL;
    int hole = 0;
    Polygon *p = Polygon_NEW(NULL);
    if (! PyArg_ParseTuple(args, "|Oi", &O, &hole))
        Polygon_Raise(ERR_ARG);
    if (O != NULL) {
        if ((PyTypeObject *)PyObject_Type(O) == &Polygon_Type) {
            if (poly_p_clone(((Polygon *)O)->p, p->p) != 0) {
                Polygon_dealloc(p);
                return Polygon_Raise(ERR_MEM);
            }
        } else if (PyString_Check(O)) {
            TMP = Polygon_read(p, args);
        } else if (PySequence_Check(O)) {
            TMP = Polygon_addContour(p, args);
        } else if (PyFile_Check(O)) {
            TMP = Polygon_read(p, args);
        } else return Polygon_Raise(ERR_ARG);
        if (TMP) Py_DECREF(TMP);
        if (PyErr_Occurred()) {
            Polygon_dealloc(p);
            return NULL;
        }
    }
    return (PyObject *)p;
}
Beispiel #2
0
static PyObject *Polygon_opUnion(Polygon *self, Polygon *other) {
    gpc_polygon *ret;
    if (! Polygon_Check(other)) return Polygon_Raise(ERR_TYP);
    if (! (ret = poly_p_new())) return Polygon_Raise(ERR_MEM);
    gpc_polygon_clip(GPC_UNION, self->p, other->p, ret);
    return (PyObject *)Polygon_NEW(ret);
}
Beispiel #3
0
static int Polygon_init(Polygon *self, PyObject *args, PyObject *kwds) {
    PyObject *O = NULL, *TMP = NULL;
    int hole;
    static char *kwlist[] = {"contour", "hole", NULL};
    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|Oi", kwlist, &O, &hole))
        return -1; 
    if (O != NULL) {
        if ((PyTypeObject *)PyObject_Type(O) == &Polygon_Type) {
            if (poly_p_clone(((Polygon *)O)->gpc_p, self->gpc_p) != 0) {
                Polygon_dealloc(self);
                Polygon_Raise(ERR_MEM);
                return -1;
            }
        } else if (PyString_Check(O)) {
            TMP = Polygon_read(self, args);
        } else if (PySequence_Check(O)) {
            TMP = Polygon_addContour(self, args);
        } else if (PyFile_Check(O)) {
            TMP = Polygon_read(self, args);
        } else {
            Polygon_Raise(ERR_ARG);
            return -1;
        }
        if (TMP) {
            Py_DECREF(TMP);
        }
    }
    return 0;
}
Beispiel #4
0
static PyObject *Polygon_getitem(PyObject *self, int item) {
    PyObject *R;
    gpc_vertex_list * vl = NULL;
    gpc_vertex *v;
    int i, imax;
    gpc_polygon *p = ((Polygon *)self)->p;
    if (item < 0) item += p->num_contours;
    if ((item >= p->num_contours) || (item < 0))
        return Polygon_Raise(ERR_IND);
    vl = (p->contour)+item;
    imax = vl->num_vertices;
    switch (dataStyle) {
    case STYLE_TUPLE: {
        PyObject *XY;
        v = vl->vertex;
        R = PyTuple_New(imax);
        for (i=0; i < imax; i++) {
            XY = PyTuple_New(2);
            PyTuple_SetItem(XY, 0, PyFloat_FromDouble(v->x));
            PyTuple_SetItem(XY, 1, PyFloat_FromDouble(v->y));
            PyTuple_SetItem(R, i, XY);
            v++;
        }
    }
    break;
    case STYLE_LIST: {
        PyObject *XY;
        v = vl->vertex;
        R = PyList_New(imax);
        for (i=0; i < imax; i++) {
            XY = PyTuple_New(2);
            PyTuple_SetItem(XY, 0, PyFloat_FromDouble(v->x));
            PyTuple_SetItem(XY, 1, PyFloat_FromDouble(v->y));
            PyList_SetItem(R, i, XY);
            v++;
        }
    }
    break;
#ifdef WITH_NUMERIC
    case STYLE_ARRAY: {
        int dims[2] = {0, 2};
        PyArrayObject *a;
        dims[0] = imax;
        R = PyArray_FromDims(2, dims, PyArray_DOUBLE);
        a = (PyArrayObject *)R;
        memcpy(a->data, vl->vertex, sizeof(gpc_vertex)*vl->num_vertices);
    }
    break;
#endif /* WITH_NUMERIC */
    default:
        return Polygon_Raise(PolyError, "Unknown data style");
    }
    return Py_BuildValue("O", R);
}
Beispiel #5
0
static PyObject *Polygon_area(Polygon *self, PyObject *args) {
    int i=INDEF;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->p->num_contours))
            return Py_BuildValue("d", poly_c_area(self->p->contour+i));
        else
            return Polygon_Raise(ERR_IND);
    }
    return Py_BuildValue("d",  poly_p_area(self->p));
}
Beispiel #6
0
static PyObject *Polygon_nPoints(Polygon *self, PyObject *args) {
    int i=INDEF, n=0;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->p->num_contours))
            return Py_BuildValue("i",  self->p->contour[i].num_vertices);
        else
            return Polygon_Raise(ERR_IND);
    }
    for (i=0; i < self->p->num_contours; i++) n += self->p->contour[i].num_vertices;
    return Py_BuildValue("i", n);
}
Beispiel #7
0
static PyObject *Polygon_simplify(Polygon *self, PyObject *args) {
    gpc_polygon *ret, *lop, *rop, *tmp, *p = self->p;
    int i;
    if (p->num_contours <= 0) {
        Py_INCREF(Py_None);
        return Py_None;
    }
    if (! (lop = poly_p_new())) return Polygon_Raise(ERR_MEM);
    if (! (rop = poly_p_new())) return Polygon_Raise(ERR_MEM);
    if (! (ret = poly_p_new())) return Polygon_Raise(ERR_MEM);
    /* find first contour which is not a hole */
    i = 0;
    while ((i < p->num_contours) && (p->hole[i] == 1))
        i++;
    if (i < p->num_contours)
        gpc_add_contour(lop, p->contour+i, 1);
    /* then try to add other contours */
    for (i++; i < p->num_contours; i++) {
        if (p->hole[i] == 0) {
            gpc_free_polygon(rop);
            gpc_free_polygon(ret);
            gpc_add_contour(rop, (p->contour+i), 0);
            gpc_polygon_clip(GPC_UNION, lop, rop, ret);
            tmp = lop;
            lop = ret;
            ret = tmp;
        }
    }
    /* then try to cut out holes */
    for (i = 0; i < p->num_contours; i++) {
        if (p->hole[i] == 1) {
            gpc_free_polygon(rop);
            gpc_free_polygon(ret);
            gpc_add_contour(rop, (p->contour+i), 0);
            gpc_polygon_clip(GPC_DIFF, lop, rop, ret);
            tmp = lop;
            lop = ret;
            ret = tmp;
        }
    }
    gpc_free_polygon(self->p);
    free(self->p);
    self->p = lop;
    gpc_free_polygon(ret);
    free(ret);
    gpc_free_polygon(rop);
    free(rop);
    self->bbValid = 0;
    return Py_BuildValue("O", Py_None);
}
Beispiel #8
0
static PyObject *Polygon_boundingBox(Polygon *self, PyObject *args) {
    int i=INDEF;
    double x0, x1, y0, y1;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->p->num_contours))
            poly_c_boundingbox(self->p->contour+i, &x0, &x1, &y0, &y1);
        else
            return Polygon_Raise(ERR_IND);
    } else
        Polygon_getBoundingBox(self, &x0, &x1, &y0, &y1);
    return Py_BuildValue("dddd", x0, x1,y0,y1);
}
Beispiel #9
0
static PyObject *Polygon_aspectRatio(Polygon *self, PyObject *args) {
    int i=INDEF;
    double x0, x1, y0, y1;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->gpc_p->num_contours))
            poly_c_boundingbox(self->gpc_p->contour+i, &x0, &x1, &y0, &y1);
        else
            return Polygon_Raise(ERR_IND);
    } else
        Polygon_getBoundingBox(self, &x0, &x1, &y0, &y1);
    return Py_BuildValue("d", ((x0 != x1) ? fabs((y1-y0)/(x1-x0)) : 0.0));
}
Beispiel #10
0
static PyObject *Polygon_orientation(Polygon *self, PyObject *args) {
    int i=INDEF;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->p->num_contours))
            return Py_BuildValue("i", poly_c_orientation(self->p->contour+i));
        else
            return Polygon_Raise(ERR_IND);
    } else {
        PyObject *OL;
        OL = PyTuple_New(self->p->num_contours);
        for (i = 0; i < self->p->num_contours; i++)
            PyTuple_SetItem(OL, i, PyFloat_FromDouble(poly_c_orientation(self->p->contour+i)));
        return Py_BuildValue("O", OL);
    }
}
Beispiel #11
0
static PyObject *Polygon_read(Polygon *self, PyObject *args) {
    PyObject *O;
    int hflag = 1;
    if (! PyArg_ParseTuple(args, "O|i", &O, &hflag))
        return Polygon_Raise(ERR_ARG);
    if (PyFile_Check(O))
        gpc_read_polygon(PyFile_AsFile(O), hflag, self->gpc_p);
    else if (PyString_Check(O)) {
        FILE *f = fopen(PyString_AsString(O), "r");
        if (!f)
            return Polygon_Raise(PyExc_IOError, "Could not open file for reading!");
        gpc_read_polygon(f, hflag, self->gpc_p);
        fclose(f);
    } else
        return Polygon_Raise(ERR_ARG);
    Py_RETURN_NONE;
}
Beispiel #12
0
static PyObject *Polygon_center(Polygon *self, PyObject *args) {
    int i=INDEF;
    double cx, cy;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->p->num_contours)) {
            if (poly_c_center(self->p->contour+i, &cx, &cy) !=0)
                return Polygon_Raise(ERR_INV);
        } else
            return Polygon_Raise(ERR_IND);
    } else {
        if (poly_p_center(self->p, &cx, &cy) != 0)
            return Polygon_Raise(ERR_INV);
    }
    return Py_BuildValue("dd", cx, cy);
}
Beispiel #13
0
static PyObject *Polygon_isSolid(Polygon *self, PyObject *args) {
    int i=INDEF;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->p->num_contours))
            return Py_BuildValue("i", (self->p->hole[i] > 0) ? 0 : 1);
        else
            return Polygon_Raise(ERR_IND);
    } else {
        PyObject *O;
        O = PyTuple_New(self->p->num_contours);
        for (i = 0; i < self->p->num_contours; i++)
            PyTuple_SetItem(O, i, PyInt_FromLong((self->p->hole[i] > 0) ? 0 : 1));
        return Py_BuildValue("O", O);
    }
}
Beispiel #14
0
static PyObject *Polygon_isInside(Polygon *self, PyObject *args) {
    int i=INDEF, r=0;
    double x, y;
    if (! PyArg_ParseTuple(args, "dd|i", &x, &y, &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->p->num_contours)) {
            if ((r = poly_c_point_inside(self->p->contour+i, x, y)) == -1)
                return Polygon_Raise(ERR_INV);
        } else
            return Polygon_Raise(ERR_IND);
    } else {
        if ((r = poly_p_point_inside(self->p, x, y)) == -1)
            return Polygon_Raise(ERR_INV);
    }
    return Py_BuildValue("i",  r);
}
Beispiel #15
0
static PyObject *Polygon_shift(Polygon *self, PyObject *args) {
    double x, y;
    if (! PyArg_ParseTuple(args, "dd", &x, &y))
        return Polygon_Raise(ERR_ARG);
    if ((x != 0.0) || (y != 0.0))
        poly_p_shift(self->p, x, y);
    self->bbValid = 0;
    return Py_BuildValue("O", Py_None);
}
Beispiel #16
0
static PyObject *Polygon_shift(Polygon *self, PyObject *args) {
    double x, y;
    if (! PyArg_ParseTuple(args, "dd", &x, &y))
        return Polygon_Raise(ERR_ARG);
    if ((x != 0.0) || (y != 0.0))
        poly_p_shift(self->gpc_p, x, y);
    self->bbValid = 0;
    Py_RETURN_NONE;
}
Beispiel #17
0
static PyObject *Polygon_write(Polygon *self, PyObject *args) {
    PyObject *O;
    int hflag = 1;
    if (! PyArg_ParseTuple(args, "O|i", &O, &hflag))
        return Polygon_Raise(ERR_ARG);
    if (PyFile_Check(O))
        gpc_write_polygon(PyFile_AsFile(O), hflag, self->p);
    else if (PyString_Check(O)) {
        FILE *f = fopen(PyString_AsString(O), "w");
        if (!f)
            return Polygon_Raise(PyExc_IOError, "Could not open file for writing!");
        gpc_write_polygon(f, hflag, self->p);
        fclose(f);
    } else
        return Polygon_Raise(ERR_ARG);
    Py_INCREF(Py_None);
    return Py_None;
}
Beispiel #18
0
static PyObject *Polygon_overlaps(Polygon *self, Polygon *other) {
    double x0, x1, y0, y1, X0, X1, Y0, Y1;
    gpc_polygon * pres;
    int r;
    if (! Polygon_Check(other))
        return Polygon_Raise(ERR_ARG);
    Polygon_getBoundingBox(self,  &x0, &x1, &y0, &y1);
    Polygon_getBoundingBox(other, &X0, &X1, &Y0, &Y1);
    /* first test if bounding box overlaps other boundingbox */
    if ((X0 > x1) || (x0 > X1) || (Y0 > y1) || (y0 > Y1))
        return Py_BuildValue("i",  0);
    /* still there? Let's do the full test... */
    if (! (pres = poly_p_new())) return Polygon_Raise(ERR_MEM);
    gpc_polygon_clip(GPC_INT, other->p, self->p, pres);
    r = pres->num_contours;
    gpc_free_polygon(pres);
    free(pres);
    return Py_BuildValue("i",  ((r > 0) ? 1 : 0));
}
Beispiel #19
0
static PyObject * setEpsilon(PyObject *self, PyObject *arg) {
    if (PyFloat_Check(arg))
        GPC_EPSILON = PyFloat_AsDouble(arg);
    else if (PyInt_Check(arg))
        GPC_EPSILON = PyInt_AsLong(arg);
    else if (PyLong_Check(arg))
        GPC_EPSILON = PyLong_AsLong(arg);
    else
        return Polygon_Raise(ERR_ARG);
    return Py_BuildValue("O",  Py_None);
}
Beispiel #20
0
static PyObject *Polygon_warpToBox(Polygon *self, PyObject *args) {
    double x0, x1, y0, y1;
    if (! PyArg_ParseTuple(args, "dddd", &x0, &x1, &y0, &y1))
        return Polygon_Raise(ERR_ARG);
    if (self->bbValid)
        poly_p_warpToBox(self->p, x0, x1, y0, y1, self->boundingBox);
    else
        poly_p_warpToBox(self->p, x0, x1, y0, y1, NULL);
    self->bbValid = 0;
    return Py_BuildValue("O", Py_None);
}
Beispiel #21
0
static PyObject *Polygon_isSolid(Polygon *self, PyObject *args) {
    int i=INDEF;
    if (! PyArg_ParseTuple(args, "|i", &i))
        return Polygon_Raise(ERR_ARG);
    if (i!=INDEF) {
        if ((i >= 0) && (i < self->gpc_p->num_contours))
            if (self->gpc_p->hole[i] > 0)
                Py_RETURN_FALSE;
            else 
                Py_RETURN_TRUE;
        else 
            return Polygon_Raise(ERR_IND);
    } else {
        PyObject *O;
        O = PyTuple_New(self->gpc_p->num_contours);
        for (i = 0; i < self->gpc_p->num_contours; i++)
            PyTuple_SetItem(O, i, PyBool_FromLong((self->gpc_p->hole[i] > 0) ? 0 : 1));
        return O;
    }
}
Beispiel #22
0
static PyObject *Polygon_warpToBox(Polygon *self, PyObject *args) {
    double x0, x1, y0, y1;
    if (! PyArg_ParseTuple(args, "dddd", &x0, &x1, &y0, &y1))
        return Polygon_Raise(ERR_ARG);
    if (self->bbValid)
        poly_p_warpToBox(self->gpc_p, x0, x1, y0, y1, self->boundingBox);
    else
        poly_p_warpToBox(self->gpc_p, x0, x1, y0, y1, NULL);
    self->bbValid = 0;
    Py_RETURN_NONE;
}
Beispiel #23
0
static PyObject * setEpsilon(PyObject *self, PyObject *arg) {
    if (PyFloat_Check(arg))
        GPC_EPSILON = PyFloat_AsDouble(arg);
    else if (PyInt_Check(arg))
        GPC_EPSILON = PyInt_AsLong(arg);
    else if (PyLong_Check(arg))
        GPC_EPSILON = PyLong_AsLong(arg);
    else
        return Polygon_Raise(ERR_ARG);
    Py_RETURN_NONE;
}
Beispiel #24
0
static PyObject *Polygon_addContour(Polygon *self, PyObject *args) {
#ifdef WITH_NUMERIC
    PyObject *a=NULL;
    gpc_vertex_list *vl;
    int hole = 0;
    if (! PyArg_ParseTuple(args, "O|i", &a, &hole))
        return Polygon_Raise(ERR_ARG);
    if ((a = PyArray_ContiguousFromObject(a, PyArray_DOUBLE, 2, 2)) == NULL)
        return Polygon_Raise(ERR_ARG);
    if (((PyArrayObject *)a)->nd != 2)            return Polygon_Raise(ERR_ARG);
    if (((PyArrayObject *)a)->dimensions[1] != 2) return Polygon_Raise(ERR_ARG);
    vl = PyMem_New(gpc_vertex_list, 1);
    vl->num_vertices = ((PyArrayObject *)a)->dimensions[0];
    vl->vertex = PyMem_New(gpc_vertex, vl->num_vertices);
    memcpy((vl->vertex), (((PyArrayObject *)a)->data), 2*vl->num_vertices*sizeof(double));
    Py_DECREF(a);
#else
    PyObject *list=NULL, *flist, *point=NULL, *X, *Y;
    gpc_vertex_list *vl;
    gpc_vertex *v;
    int i, imax, hole = 0;
    if (! PyArg_ParseTuple(args, "O|i", &list, &hole))
        return Polygon_Raise(ERR_ARG);
    if (! PySequence_Check(list))
        return Polygon_Raise(ERR_ARG);
    flist = PySequence_Fast(list, "this is not a sequence");
    if ((! flist) || ((imax = PySequence_Length(flist)) <= 2))
        return Polygon_Raise(ERR_INV);
    vl = PyMem_New(gpc_vertex_list, 1);
    vl->num_vertices = imax;
    vl->vertex = v = PyMem_New(gpc_vertex, imax);
    for (i=0; i<imax; i++) {
        point = PySequence_Fast(PySequence_Fast_GET_ITEM(flist, i), "this is not a point");
        if ((!point) || (PySequence_Length(point) != 2))
            return Polygon_Raise(ERR_INV);
        v->x = PyFloat_AsDouble(X = PyNumber_Float(PySequence_Fast_GET_ITEM(point, 0)));
        v->y = PyFloat_AsDouble(Y = PyNumber_Float(PySequence_Fast_GET_ITEM(point, 1)));
        v++;
        Py_DECREF(X);
        Py_DECREF(Y);
        Py_DECREF(point);
    }
    Py_DECREF(flist);
#endif /* WITH_NUMERIC */
    gpc_add_contour(self->p, vl, hole);
    self->bbValid = 0;
    PyMem_Free(vl->vertex);
    PyMem_Free(vl);
    Py_INCREF(Py_None);
    return Py_None;
}
Beispiel #25
0
/* make a new Polygon, using gpc_p if not NULL */
static Polygon *Polygon_NEW(gpc_polygon *gpc_p) {
    Polygon *obj = PyObject_NEW(Polygon, &Polygon_Type);
    if (gpc_p != NULL)
        obj->gpc_p = gpc_p;
    else {
        if (! (obj->gpc_p = poly_p_new()))
            return (Polygon *)Polygon_Raise(ERR_MEM);
    }
    obj->bbValid = 0;
    obj->attr = NULL;
    return obj;
}
Beispiel #26
0
static PyObject *Polygon_flip(Polygon *self, PyObject *args) {
    double x = DNDEF;
    if (! PyArg_ParseTuple(args, "|d", &x))
        return Polygon_Raise(ERR_ARG);
    if (x == DNDEF) {
        double x0, x1, y0, y1;
        Polygon_getBoundingBox(self, &x0, &x1, &y0, &y1);
        x = 0.5 * (x0+x1);
    } else
        self->bbValid = 0;
    poly_p_flip(self->gpc_p, x);
    Py_RETURN_NONE;
}
Beispiel #27
0
static PyObject *Polygon_covers(Polygon *self, Polygon *other) {
    double x0, x1, y0, y1, X0, X1, Y0, Y1;
    gpc_polygon * pres;
    int r;
    if (! Polygon_Check(other))
        return Polygon_Raise(ERR_ARG);
    Polygon_getBoundingBox(self,  &x0, &x1, &y0, &y1);
    Polygon_getBoundingBox(other, &X0, &X1, &Y0, &Y1);
    /* first test if bounding box covers other boundingbox */ 
    if ((X0 < x0) || (X1 > x1) || (Y0 < y0) || (Y1 > y1))
        Py_RETURN_FALSE;
    /* still there? Let's do the full test... */  
    if (! (pres = poly_p_new())) return Polygon_Raise(ERR_MEM);
    gpc_polygon_clip(GPC_DIFF, other->gpc_p, self->gpc_p, pres);
    r = pres->num_contours;
    gpc_free_polygon(pres);
    free(pres);
    if (r > 0)
        Py_RETURN_FALSE;
    else
        Py_RETURN_TRUE;
}
Beispiel #28
0
static PyObject *Polygon_flop(Polygon *self, PyObject *args) {
    double y = DNDEF;
    if (! PyArg_ParseTuple(args, "|d", &y))
        return Polygon_Raise(ERR_ARG);
    if (y == DNDEF) {
        double x0, x1, y0, y1;
        Polygon_getBoundingBox(self, &x0, &x1, &y0, &y1);
        y = 0.5 * (y0+y1);
    } else
        self->bbValid = 0;
    poly_p_flop(self->p, y);
    return Py_BuildValue("O", Py_None);
}
Beispiel #29
0
static Polygon *Polygon_NEW(void *ptr) {
    Polygon *obj = PyObject_NEW(Polygon, &Polygon_Type);
    if (ptr != NULL)
        /* create from existing gpc_polygon struct */
        obj->p = (gpc_polygon *)ptr;
    else {
        /* create a new struct */
        if (! (obj->p = poly_p_new()))
            return (Polygon *)Polygon_Raise(ERR_MEM);
    }
    obj->bbValid = 0;
    obj->attr = NULL;
    return obj;
}
Beispiel #30
0
static PyObject *Polygon_cloneContour(Polygon *self, PyObject *args) {
    int con, i, hole=-1;
    double xs=1.0, ys=1.0;
    gpc_vertex_list *vl = NULL, *vlnew = NULL;
    gpc_polygon *p = ((Polygon *)self)->gpc_p;
    if (! PyArg_ParseTuple(args, "i|ddi", &con, &xs, &ys, &hole))
        return Polygon_Raise(ERR_ARG);
    if (con < 0) con += p->num_contours;
    if ((con >= p->num_contours) || (con < 0))
        return Polygon_Raise(ERR_IND);
    vl = (p->contour)+con;
    vlnew = PyMem_New(gpc_vertex_list, 1);
    vlnew->num_vertices = vl->num_vertices;
    vlnew->vertex = PyMem_New(gpc_vertex, vlnew->num_vertices);
    for (i=0; i < vl->num_vertices; i++) {
        vlnew->vertex[i].x = vl->vertex[i].x + xs;
        vlnew->vertex[i].y = vl->vertex[i].y + ys;
    }
    gpc_add_contour(p, vlnew, p->hole[con]);
    self->bbValid = 0;
    PyMem_Free(vlnew->vertex);
    PyMem_Free(vlnew);
    return Py_BuildValue("i", (p->num_contours)-1);
}