Esempio n. 1
0
static PyObject *image_fromarray(PyObject *self, PyObject *args, PyObject *kwds)
{
    PyObject *array;
    int isoutput;
    const char *names[] = { "array", "isoutput", NULL };

    if (!PyArg_ParseTupleAndKeywords(
             args, kwds, "O|i:fromarray", (char **)names, &array, &isoutput)) {
        return NULL;
    }

    numpy::array_view<const double, 3> color_array;
    numpy::array_view<const double, 2> grey_array;
    Image *result = NULL;

    if (color_array.converter(array, &color_array)) {
        CALL_CPP("fromarray", result = from_color_array(color_array, isoutput));
    } else if (grey_array.converter(array, &grey_array)) {
        CALL_CPP("fromarray", result = from_grey_array(grey_array, isoutput));
    } else {
        PyErr_SetString(PyExc_ValueError, "invalid array");
        return NULL;
    }

    return PyImage_cnew(result);
}
Esempio n. 2
0
static PyObject *Py_affine_transform(PyObject *self, PyObject *args, PyObject *kwds)
{
    PyObject *vertices_obj;
    agg::trans_affine trans;

    if (!PyArg_ParseTuple(args,
                          "OO&:affine_transform",
                          &vertices_obj,
                          &convert_trans_affine,
                          &trans)) {
        return NULL;
    }

    try {
        numpy::array_view<double, 2> vertices(vertices_obj);
        npy_intp dims[] = { (npy_intp)vertices.size(), 2 };
        numpy::array_view<double, 2> result(dims);
        CALL_CPP("affine_transform", (affine_transform_2d(vertices, trans, result)));
        return result.pyobj();
    } catch (py::exception &) {
        PyErr_Clear();
        try {
            numpy::array_view<double, 1> vertices(vertices_obj);
            npy_intp dims[] = { (npy_intp)vertices.size() };
            numpy::array_view<double, 1> result(dims);
            CALL_CPP("affine_transform", (affine_transform_1d(vertices, trans, result)));
            return result.pyobj();
        } catch (py::exception &) {
            return NULL;
        }
    }
}
static PyObject *PyRendererAgg_restore_region(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    PyBufferRegion *regobj;
    int xx1 = 0, yy1 = 0, xx2 = 0, yy2 = 0, x = 0, y = 0;

    if (!PyArg_ParseTuple(args,
                          "O!|iiiiii:restore_region",
                          &PyBufferRegionType,
                          &regobj,
                          &xx1,
                          &yy1,
                          &xx2,
                          &yy2,
                          &x,
                          &y)) {
        return 0;
    }

    if (PySequence_Size(args) == 1) {
        CALL_CPP("restore_region", (self->x->restore_region(*(regobj->x))));
    } else {
        CALL_CPP("restore_region", self->x->restore_region(*(regobj->x), xx1, yy1, xx2, yy2, x, y));
    }

    Py_RETURN_NONE;
}
Esempio n. 4
0
static PyObject *Py_convert_path_to_polygons(PyObject *self, PyObject *args, PyObject *kwds)
{
    py::PathIterator path;
    agg::trans_affine trans;
    double width = 0.0, height = 0.0;
    int closed_only = 1;
    std::vector<Polygon> result;
    const char *names[] = { "path", "transform", "width", "height", "closed_only", NULL };

    if (!PyArg_ParseTupleAndKeywords(args,
                                     kwds,
                                     "O&O&|ddi:convert_path_to_polygons",
                                     (char **)names,
                                     &convert_path,
                                     &path,
                                     &convert_trans_affine,
                                     &trans,
                                     &width,
                                     &height,
                                     &closed_only)) {
        return NULL;
    }

    CALL_CPP("convert_path_to_polygons",
             (convert_path_to_polygons(path, trans, width, height, closed_only, result)));

    return convert_polygon_vector(result);
}
Esempio n. 5
0
static PyObject *Py_points_in_path(PyObject *self, PyObject *args, PyObject *kwds)
{
    numpy::array_view<const double, 2> points;
    double r;
    py::PathIterator path;
    agg::trans_affine trans;

    if (!PyArg_ParseTuple(args,
                          "O&dO&O&:points_in_path",
                          &convert_points,
                          &points,
                          &r,
                          &convert_path,
                          &path,
                          &convert_trans_affine,
                          &trans)) {
        return NULL;
    }

    npy_intp dims[] = { (npy_intp)points.size() };
    numpy::array_view<uint8_t, 1> results(dims);

    CALL_CPP("points_in_path", (points_in_path(points, r, path, trans, results)));

    return results.pyobj();
}
Esempio n. 6
0
static PyObject *Py_point_on_path(PyObject *self, PyObject *args, PyObject *kwds)
{
    double x, y, r;
    py::PathIterator path;
    agg::trans_affine trans;
    bool result;

    if (!PyArg_ParseTuple(args,
                          "dddO&O&:point_on_path",
                          &x,
                          &y,
                          &r,
                          &convert_path,
                          &path,
                          &convert_trans_affine,
                          &trans)) {
        return NULL;
    }

    CALL_CPP("point_on_path", (result = point_on_path(x, y, r, path, trans)));

    if (result) {
        Py_RETURN_TRUE;
    } else {
        Py_RETURN_FALSE;
    }
}
Esempio n. 7
0
static PyObject *Py_path_in_path(PyObject *self, PyObject *args, PyObject *kwds)
{
    py::PathIterator a;
    agg::trans_affine atrans;
    py::PathIterator b;
    agg::trans_affine btrans;
    bool result;

    if (!PyArg_ParseTuple(args,
                          "O&O&O&O&:path_in_path",
                          &convert_path,
                          &a,
                          &convert_trans_affine,
                          &atrans,
                          &convert_path,
                          &b,
                          &convert_trans_affine,
                          &btrans)) {
        return NULL;
    }

    CALL_CPP("path_in_path", (result = path_in_path(a, atrans, b, btrans)));

    if (result) {
        Py_RETURN_TRUE;
    } else {
        Py_RETURN_FALSE;
    }
}
Esempio n. 8
0
static PyObject *Py_path_intersects_rectangle(PyObject *self, PyObject *args, PyObject *kwds)
{
    py::PathIterator path;
    double rect_x1, rect_y1, rect_x2, rect_y2;
    bool filled = false;
    const char *names[] = { "path", "rect_x1", "rect_y1", "rect_x2", "rect_y2", "filled", NULL };
    bool result;

    if (!PyArg_ParseTupleAndKeywords(args,
                                     kwds,
                                     "O&dddd|O&:path_intersects_rectangle",
                                     (char **)names,
                                     &convert_path,
                                     &path,
                                     &rect_x1,
                                     &rect_y1,
                                     &rect_x2,
                                     &rect_y2,
                                     &convert_bool,
                                     &filled)) {
        return NULL;
    }

    CALL_CPP("path_intersects_rectangle", (result = path_intersects_rectangle(path, rect_x1, rect_y1, rect_x2, rect_y2, filled)));

    if (result) {
        Py_RETURN_TRUE;
    } else {
        Py_RETURN_FALSE;
    }
}
Esempio n. 9
0
static PyObject *image_pcolor2(PyObject *self, PyObject *args, PyObject *kwds)
{
    numpy::array_view<const double, 1> x;
    numpy::array_view<const double, 1> y;
    numpy::array_view<const agg::int8u, 3> d;
    unsigned int rows;
    unsigned int cols;
    float bounds[4];
    numpy::array_view<const agg::int8u, 1> bg;
    Image *result;

    if (!PyArg_ParseTuple(args,
                          "O&O&O&II(ffff)O&:pcolor2",
                          &x.converter,
                          &x,
                          &y.converter,
                          &y,
                          &d.converter_contiguous,
                          &d,
                          &rows,
                          &cols,
                          &bounds[0],
                          &bounds[1],
                          &bounds[2],
                          &bounds[3],
                          &bg.converter,
                          &bg)) {
        return NULL;
    }

    CALL_CPP("pcolor2", (result = pcolor2(x, y, d, rows, cols, bounds, bg)));

    return PyImage_cnew(result);
}
static PyObject *
PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    GCAgg gc;
    numpy::array_view<const double, 3> points;
    numpy::array_view<const double, 3> colors;
    agg::trans_affine trans;

    if (!PyArg_ParseTuple(args,
                          "O&O&O&O&|O:draw_gouraud_triangles",
                          &convert_gcagg,
                          &gc,
                          &points.converter,
                          &points,
                          &colors.converter,
                          &colors,
                          &convert_trans_affine,
                          &trans)) {
        return NULL;
    }

    CALL_CPP("draw_gouraud_triangles", self->x->draw_gouraud_triangles(gc, points, colors, trans));

    Py_RETURN_NONE;
}
PyObject *PyRendererAgg_draw_markers(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    GCAgg gc;
    py::PathIterator marker_path;
    agg::trans_affine marker_path_trans;
    py::PathIterator path;
    agg::trans_affine trans;
    PyObject *faceobj = NULL;
    agg::rgba face;

    if (!PyArg_ParseTuple(args,
                          "O&O&O&O&O&|O:draw_markers",
                          &convert_gcagg,
                          &gc,
                          &convert_path,
                          &marker_path,
                          &convert_trans_affine,
                          &marker_path_trans,
                          &convert_path,
                          &path,
                          &convert_trans_affine,
                          &trans,
                          &faceobj)) {
        return NULL;
    }

    if (!convert_face(faceobj, gc, &face)) {
        return NULL;
    }

    CALL_CPP("draw_markers",
             (self->x->draw_markers(gc, marker_path, marker_path_trans, path, trans, face)));

    Py_RETURN_NONE;
}
static PyObject *PyRendererAgg_draw_image(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    GCAgg gc;
    double x;
    double y;
    numpy::array_view<agg::int8u, 3> image;

    if (!PyArg_ParseTuple(args,
                          "O&ddO&:draw_image",
                          &convert_gcagg,
                          &gc,
                          &x,
                          &y,
                          &image.converter_contiguous,
                          &image)) {
        return NULL;
    }

    x = mpl_round(x);
    y = mpl_round(y);

    gc.alpha = 1.0;
    CALL_CPP("draw_image", (self->x->draw_image(gc, x, y, image)));

    Py_RETURN_NONE;
}
Esempio n. 13
0
static PyObject *Py_point_in_path_collection(PyObject *self, PyObject *args, PyObject *kwds)
{
    double x, y, radius;
    agg::trans_affine master_transform;
    PyObject *pathsobj;
    numpy::array_view<const double, 3> transforms;
    numpy::array_view<const double, 2> offsets;
    agg::trans_affine offset_trans;
    int filled;
    e_offset_position offset_position;
    std::vector<size_t> result;

    if (!PyArg_ParseTuple(args,
                          "dddO&OO&O&O&iO&:point_in_path_collection",
                          &x,
                          &y,
                          &radius,
                          &convert_trans_affine,
                          &master_transform,
                          &pathsobj,
                          &transforms.converter,
                          &transforms,
                          &offsets.converter,
                          &offsets,
                          &convert_trans_affine,
                          &offset_trans,
                          &filled,
                          &convert_offset_position,
                          &offset_position)) {
        return NULL;
    }

    try
    {
        py::PathGenerator paths(pathsobj);

        CALL_CPP("point_in_path_collection",
                 (point_in_path_collection(x,
                                           y,
                                           radius,
                                           master_transform,
                                           paths,
                                           transforms,
                                           offsets,
                                           offset_trans,
                                           filled,
                                           offset_position,
                                           result)));
    }
    catch (py::exception &e)
    {
        return NULL;
    }

    npy_intp dims[] = {(npy_intp)result.size() };
    numpy::array_view<size_t, 1> pyresult(dims);
    memcpy(pyresult.data(), &result[0], result.size() * sizeof(size_t));
    return pyresult.pyobj();
}
Esempio n. 14
0
static PyObject *image_from_images(PyObject *self, PyObject *args, PyObject *kwds)
{
    unsigned int numrows;
    unsigned int numcols;
    PyObject *images;
    size_t numimages;

    if (!PyArg_ParseTuple(args, "IIO:from_images", &numrows, &numcols, &images)) {
        return NULL;
    }

    if (!PySequence_Check(images)) {
        return NULL;
    }

    Image *im = new Image(numrows, numcols, true);
    im->clear();

    numimages = PySequence_Size(images);

    for (size_t i = 0; i < numimages; ++i) {
        PyObject *entry = PySequence_GetItem(images, i);
        if (entry == NULL) {
            delete im;
            return NULL;
        }

        PyObject *subimage;
        unsigned int x;
        unsigned int y;
        PyObject *alphaobj = NULL;
        double alpha = 0.0;

        if (!PyArg_ParseTuple(entry, "O!II|O", &PyImageType, &subimage, &x, &y, &alphaobj)) {
            Py_DECREF(entry);
            delete im;
            return NULL;
        }

        bool has_alpha = false;
        if (alphaobj != NULL && alphaobj != Py_None) {
            has_alpha = true;
            alpha = PyFloat_AsDouble(alphaobj);
            if (PyErr_Occurred()) {
                Py_DECREF(entry);
                delete im;
                return NULL;
            }
        }

        CALL_CPP("from_images",
                 (im->blend_image(*((PyImage *)subimage)->x, x, y, has_alpha, alpha)));

        Py_DECREF(entry);
    }

    return PyImage_cnew(im);
}
static PyObject *
PyRendererAgg_get_content_extents(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    agg::rect_i extents;

    CALL_CPP("get_content_extents", (extents = self->x->get_content_extents()));

    return Py_BuildValue(
        "iiii", extents.x1, extents.y1, extents.x2 - extents.x1, extents.y2 - extents.y1);
}
Esempio n. 16
0
static PyObject *PyImage_apply_translation(PyImage *self, PyObject *args, PyObject *kwds)
{
    double tx, ty;
    if (!PyArg_ParseTuple(args, "dd:apply_translation", &tx, &ty)) {
        return NULL;
    }

    CALL_CPP("apply_translation", self->x->apply_translation(tx, ty));

    Py_RETURN_NONE;
}
Esempio n. 17
0
static PyObject* PyTriContourGenerator_create_contour(PyTriContourGenerator* self, PyObject* args, PyObject* kwds)
{
    double level;
    if (!PyArg_ParseTuple(args, "d:create_contour", &level)) {
        return NULL;
    }

    PyObject* result;
    CALL_CPP("create_contour", (result = self->ptr->create_contour(level)));
    return result;
}
Esempio n. 18
0
static PyObject* PyTriangulation_get_neighbors(PyTriangulation* self, PyObject* args, PyObject* kwds)
{
    Triangulation::NeighborArray* result;
    CALL_CPP("get_neighbors", (result = &self->ptr->get_neighbors()));

    if (result->empty()) {
        Py_RETURN_NONE;
    }
    else
        return result->pyobj();
}
Esempio n. 19
0
static PyObject *PyImage_set_bg(PyImage *self, PyObject *args, PyObject *kwds)
{
    double r, g, b, a;

    if (!PyArg_ParseTuple(args, "dddd:set_bg", &r, &g, &b, &a)) {
        return NULL;
    }

    CALL_CPP("set_bg", (self->x->set_bg(r, g, b, a)));

    Py_RETURN_NONE;
}
Esempio n. 20
0
static PyObject *PyImage_apply_rotation(PyImage *self, PyObject *args, PyObject *kwds)
{
    double r;

    if (!PyArg_ParseTuple(args, "d:apply_rotation", &r)) {
        return NULL;
    }

    CALL_CPP("apply_rotation", (self->x->apply_rotation(r)));

    Py_RETURN_NONE;
}
Esempio n. 21
0
static PyObject *PyImage_apply_scaling(PyImage *self, PyObject *args, PyObject *kwds)
{
    double sx, sy;

    if (!PyArg_ParseTuple(args, "dd:apply_scaling", &sx, &sy)) {
        return NULL;
    }

    CALL_CPP("apply_scaling", (self->x->apply_scaling(sx, sy)));

    Py_RETURN_NONE;
}
Esempio n. 22
0
static PyObject *Py_path_intersects_path(PyObject *self, PyObject *args, PyObject *kwds)
{
    py::PathIterator p1;
    py::PathIterator p2;
    agg::trans_affine t1;
    agg::trans_affine t2;
    int filled = 0;
    const char *names[] = { "p1", "p2", "filled", NULL };
    bool result;

    if (!PyArg_ParseTupleAndKeywords(args,
                                     kwds,
                                     "O&O&i:path_intersects_path",
                                     (char **)names,
                                     &convert_path,
                                     &p1,
                                     &convert_path,
                                     &p2,
                                     &filled)) {
        return NULL;
    }

    CALL_CPP("path_intersects_path", (result = path_intersects_path(p1, p2)));
    if (filled) {
        if (!result) {
            CALL_CPP("path_intersects_path",
                     (result = path_in_path(p1, t1, p2, t2)));
        }
        if (!result) {
            CALL_CPP("path_intersects_path",
                     (result = path_in_path(p2, t1, p1, t2)));
        }
    }

    if (result) {
        Py_RETURN_TRUE;
    } else {
        Py_RETURN_FALSE;
    }
}
static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    GCAgg gc;
    agg::trans_affine master_transform;
    unsigned int mesh_width;
    unsigned int mesh_height;
    numpy::array_view<const double, 3> coordinates;
    numpy::array_view<const double, 2> offsets;
    agg::trans_affine offset_trans;
    numpy::array_view<const double, 2> facecolors;
    bool antialiased;
    numpy::array_view<const double, 2> edgecolors;

    if (!PyArg_ParseTuple(args,
                          "O&O&IIO&O&O&O&O&O&:draw_quad_mesh",
                          &convert_gcagg,
                          &gc,
                          &convert_trans_affine,
                          &master_transform,
                          &mesh_width,
                          &mesh_height,
                          &coordinates.converter,
                          &coordinates,
                          &convert_points,
                          &offsets,
                          &convert_trans_affine,
                          &offset_trans,
                          &convert_colors,
                          &facecolors,
                          &convert_bool,
                          &antialiased,
                          &convert_colors,
                          &edgecolors)) {
        return NULL;
    }

    CALL_CPP("draw_quad_mesh",
             (self->x->draw_quad_mesh(gc,
                                      master_transform,
                                      mesh_width,
                                      mesh_height,
                                      coordinates,
                                      offsets,
                                      offset_trans,
                                      facecolors,
                                      antialiased,
                                      edgecolors)));

    Py_RETURN_NONE;
}
Esempio n. 24
0
static PyObject* PyQuadContourGenerator_create_filled_contour(PyQuadContourGenerator* self, PyObject* args, PyObject* kwds)
{
    double lower_level, upper_level;
    if (!PyArg_ParseTuple(args, "dd:create_filled_contour",
                          &lower_level, &upper_level)) {
        return NULL;
    }

    PyObject* result;
    CALL_CPP("create_filled_contour",
             (result = self->ptr->create_filled_contour(lower_level,
                                                        upper_level)));
    return result;
}
Esempio n. 25
0
static PyObject *Py_get_path_extents(PyObject *self, PyObject *args, PyObject *kwds)
{
    py::PathIterator path;
    agg::trans_affine trans;

    if (!PyArg_ParseTuple(
             args, "O&O&:get_path_extents", &convert_path, &path, &convert_trans_affine, &trans)) {
        return NULL;
    }

    extent_limits e;

    CALL_CPP("get_path_extents", (reset_limits(e)));
    CALL_CPP("get_path_extents", (update_path_extents(path, trans, e)));

    npy_intp dims[] = { 2, 2 };
    numpy::array_view<double, 2> extents(dims);
    extents(0, 0) = e.x0;
    extents(0, 1) = e.y0;
    extents(1, 0) = e.x1;
    extents(1, 1) = e.y1;

    return extents.pyobj();
}
Esempio n. 26
0
static PyObject* PyTriangulation_set_mask(PyTriangulation* self, PyObject* args, PyObject* kwds)
{
    Triangulation::MaskArray mask;

    if (!PyArg_ParseTuple(args, "O&:set_mask", &mask.converter, &mask)) {
        return NULL;
    }

    if (!mask.empty() && mask.dim(0) != self->ptr->get_ntri()) {
        PyErr_SetString(PyExc_ValueError,
            "mask must be a 1D array with the same length as the triangles array");
    }

    CALL_CPP("set_mask", (self->ptr->set_mask(mask)));
    Py_RETURN_NONE;
}
static PyObject *
PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    GCAgg gc;
    numpy::array_view<const double, 3> points;
    numpy::array_view<const double, 3> colors;
    agg::trans_affine trans;

    if (!PyArg_ParseTuple(args,
                          "O&O&O&O&|O:draw_gouraud_triangles",
                          &convert_gcagg,
                          &gc,
                          &points.converter,
                          &points,
                          &colors.converter,
                          &colors,
                          &convert_trans_affine,
                          &trans)) {
        return NULL;
    }

    if (points.size() != 0 && (points.dim(1) != 3 || points.dim(2) != 2)) {
        PyErr_Format(PyExc_ValueError,
                     "points must be a Nx3x2 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT,
                     points.dim(0), points.dim(1), points.dim(2));
        return NULL;
    }

    if (colors.size() != 0 && (colors.dim(1) != 3 || colors.dim(2) != 4)) {
        PyErr_Format(PyExc_ValueError,
                     "colors must be a Nx3x4 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT,
                     colors.dim(0), colors.dim(1), colors.dim(2));
        return NULL;
    }

    if (points.size() != colors.size()) {
        PyErr_Format(PyExc_ValueError,
                     "points and colors arrays must be the same length, got %" NPY_INTP_FMT " and %" NPY_INTP_FMT,
                     points.dim(0), colors.dim(0));
        return NULL;
    }

    CALL_CPP("draw_gouraud_triangles", self->x->draw_gouraud_triangles(gc, points, colors, trans));

    Py_RETURN_NONE;
}
static PyObject *PyRendererAgg_copy_from_bbox(PyRendererAgg *self, PyObject *args, PyObject *kwds)
{
    agg::rect_d bbox;
    BufferRegion *reg;
    PyObject *regobj;

    if (!PyArg_ParseTuple(args, "O&:copy_from_bbox", &convert_rect, &bbox)) {
        return 0;
    }

    CALL_CPP("copy_from_bbox", (reg = self->x->copy_from_bbox(bbox)));

    regobj = PyBufferRegion_new(&PyBufferRegionType, NULL, NULL);
    ((PyBufferRegion *)regobj)->x = reg;

    return regobj;
}
Esempio n. 29
0
static PyObject *PyImage_resize(PyImage *self, PyObject *args, PyObject *kwds)
{
    double width;
    double height;
    double norm;
    double radius;
    const char *names[] = { "width", "height", "norm", "radius", NULL };

    if (!PyArg_ParseTupleAndKeywords(
             args, kwds, "dd|dd:resize", (char **)names, &width, &height, &norm, &radius)) {
        return NULL;
    }

    CALL_CPP("resize", (self->x->resize(width, height, norm, radius)));

    Py_RETURN_NONE;
}
Esempio n. 30
0
static PyObject *Py_get_path_collection_extents(PyObject *self, PyObject *args, PyObject *kwds)
{
    agg::trans_affine master_transform;
    PyObject *pathsobj;
    numpy::array_view<const double, 3> transforms;
    numpy::array_view<const double, 2> offsets;
    agg::trans_affine offset_trans;
    extent_limits e;

    if (!PyArg_ParseTuple(args,
                          "O&OO&O&O&:get_path_collection_extents",
                          &convert_trans_affine,
                          &master_transform,
                          &pathsobj,
                          &convert_transforms,
                          &transforms,
                          &convert_points,
                          &offsets,
                          &convert_trans_affine,
                          &offset_trans)) {
        return NULL;
    }

    try
    {
        py::PathGenerator paths(pathsobj);

        CALL_CPP("get_path_collection_extents",
                 (get_path_collection_extents(
                     master_transform, paths, transforms, offsets, offset_trans, e)));
    }
    catch (const py::exception &)
    {
        return NULL;
    }

    npy_intp dims[] = { 2, 2 };
    numpy::array_view<double, 2> extents(dims);
    extents(0, 0) = e.x0;
    extents(0, 1) = e.y0;
    extents(1, 0) = e.x1;
    extents(1, 1) = e.y1;

    return extents.pyobj();
}