Py::Object _path_module::path_in_path(const Py::Tuple& args) { args.verify_length(4); PathIterator a(args[0]); agg::trans_affine atrans = py_to_agg_transformation_matrix(args[1], false); PathIterator b(args[2]); agg::trans_affine btrans = py_to_agg_transformation_matrix(args[3], false); return Py::Int(::path_in_path(a, atrans, b, btrans)); }
Py::Object _path_module::convert_path_to_polygons(const Py::Tuple& args) { typedef agg::conv_transform<PathIterator> transformed_path_t; typedef SimplifyPath<transformed_path_t> simplify_t; typedef agg::conv_curve<simplify_t> curve_t; typedef std::vector<double> vertices_t; args.verify_length(4); PathIterator path(args[0]); agg::trans_affine trans = py_to_agg_transformation_matrix(args[1], false); double width = Py::Float(args[2]); double height = Py::Float(args[3]); bool simplify = path.should_simplify() && width != 0.0 && height != 0.0; transformed_path_t tpath(path, trans); simplify_t simplified(tpath, false, simplify, width, height); curve_t curve(simplified); Py::List polygons; vertices_t polygon; double x, y; unsigned code; polygon.reserve(path.total_vertices() * 2); while ((code = curve.vertex(&x, &y)) != agg::path_cmd_stop) { if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) { if (polygon.size() >= 2) { polygon.push_back(polygon[0]); polygon.push_back(polygon[1]); _add_polygon(polygons, polygon); } polygon.clear(); } else { if (code == agg::path_cmd_move_to) { _add_polygon(polygons, polygon); polygon.clear(); } polygon.push_back(x); polygon.push_back(y); } } _add_polygon(polygons, polygon); return polygons; }
Py::Object _path_module::point_in_path(const Py::Tuple& args) { args.verify_length(4); double x = Py::Float(args[0]); double y = Py::Float(args[1]); PathIterator path(args[2]); agg::trans_affine trans = py_to_agg_transformation_matrix(args[3], false); if (::point_in_path(x, y, path, trans)) return Py::Int(1); return Py::Int(0); }
void* get_path_iterator( PyObject* path, PyObject* trans, int remove_nans, int do_clip, double rect[4], e_snap_mode snap_mode, double stroke_width, int do_simplify) { agg::trans_affine agg_trans = py_to_agg_transformation_matrix(trans, false); agg::rect_base<double> clip_rect(rect[0], rect[1], rect[2], rect[3]); PathCleanupIterator* pipeline = new PathCleanupIterator( path, agg_trans, remove_nans != 0, do_clip != 0, clip_rect, snap_mode, stroke_width, do_simplify != 0); return (void*)pipeline; }
Py::Object _path_module::get_path_extents(const Py::Tuple& args) { args.verify_length(2); PathIterator path(args[0]); agg::trans_affine trans = py_to_agg_transformation_matrix(args[1].ptr(), false); npy_intp extent_dims[] = { 2, 2, 0 }; double* extents_data = NULL; double xm, ym; PyArrayObject* extents = NULL; try { extents = (PyArrayObject*)PyArray_SimpleNew (2, extent_dims, PyArray_DOUBLE); if (extents == NULL) { throw Py::MemoryError("Could not allocate result array"); } extents_data = (double*)PyArray_DATA(extents); extents_data[0] = std::numeric_limits<double>::infinity(); extents_data[1] = std::numeric_limits<double>::infinity(); extents_data[2] = -std::numeric_limits<double>::infinity(); extents_data[3] = -std::numeric_limits<double>::infinity(); /* xm and ym are the minimum positive values in the data, used by log scaling */ xm = std::numeric_limits<double>::infinity(); ym = std::numeric_limits<double>::infinity(); ::get_path_extents(path, trans, &extents_data[0], &extents_data[1], &extents_data[2], &extents_data[3], &xm, &ym); } catch (...) { Py_XDECREF(extents); throw; } return Py::Object((PyObject*)extents, true); }
Py::Object _path_module::point_in_path_collection(const Py::Tuple& args) { args.verify_length(9); //segments, trans, clipbox, colors, linewidths, antialiaseds double x = Py::Float(args[0]); double y = Py::Float(args[1]); double radius = Py::Float(args[2]); agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[3].ptr()); Py::SeqBase<Py::Object> paths = args[4]; Py::SeqBase<Py::Object> transforms_obj = args[5]; Py::SeqBase<Py::Object> offsets_obj = args[6]; agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7].ptr()); bool filled = Py::Boolean(args[8]); PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject( offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); if (!offsets || (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) != 2) || (PyArray_NDIM(offsets) == 1 && PyArray_DIM(offsets, 0) != 0)) { Py_XDECREF(offsets); throw Py::ValueError("Offsets array must be Nx2"); } size_t Npaths = paths.length(); size_t Noffsets = offsets->dimensions[0]; size_t N = std::max(Npaths, Noffsets); size_t Ntransforms = std::min(transforms_obj.length(), N); size_t i; // Convert all of the transforms up front typedef std::vector<agg::trans_affine> transforms_t; transforms_t transforms; transforms.reserve(Ntransforms); for (i = 0; i < Ntransforms; ++i) { agg::trans_affine trans = py_to_agg_transformation_matrix (transforms_obj[i].ptr(), false); trans *= master_transform; transforms.push_back(trans); } Py::List result; agg::trans_affine trans; for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); if (Ntransforms) { trans = transforms[i % Ntransforms]; } else { trans = master_transform; } if (Noffsets) { double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); offset_trans.transform(&xo, &yo); trans *= agg::trans_affine_translation(xo, yo); } if (filled) { if (::point_in_path(x, y, path, trans)) result.append(Py::Int((int)i)); } else { if (::point_on_path(x, y, radius, path, trans)) result.append(Py::Int((int)i)); } } return result; }
Py::Object _path_module::get_path_collection_extents(const Py::Tuple& args) { args.verify_length(5); //segments, trans, clipbox, colors, linewidths, antialiaseds agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0].ptr()); Py::SeqBase<Py::Object> paths = args[1]; Py::SeqBase<Py::Object> transforms_obj = args[2]; Py::Object offsets_obj = args[3]; agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[4].ptr(), false); PyArrayObject* offsets = NULL; double x0, y0, x1, y1, xm, ym; try { offsets = (PyArrayObject*)PyArray_FromObject( offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); if (!offsets || (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) != 2) || (PyArray_NDIM(offsets) == 1 && PyArray_DIM(offsets, 0) != 0)) { throw Py::ValueError("Offsets array must be Nx2"); } size_t Npaths = paths.length(); size_t Noffsets = offsets->dimensions[0]; size_t N = std::max(Npaths, Noffsets); size_t Ntransforms = std::min(transforms_obj.length(), N); size_t i; // Convert all of the transforms up front typedef std::vector<agg::trans_affine> transforms_t; transforms_t transforms; transforms.reserve(Ntransforms); for (i = 0; i < Ntransforms; ++i) { agg::trans_affine trans = py_to_agg_transformation_matrix (transforms_obj[i].ptr(), false); trans *= master_transform; transforms.push_back(trans); } // The offset each of those and collect the mins/maxs x0 = std::numeric_limits<double>::infinity(); y0 = std::numeric_limits<double>::infinity(); x1 = -std::numeric_limits<double>::infinity(); y1 = -std::numeric_limits<double>::infinity(); xm = std::numeric_limits<double>::infinity(); ym = std::numeric_limits<double>::infinity(); agg::trans_affine trans; for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); if (Ntransforms) { trans = transforms[i % Ntransforms]; } else { trans = master_transform; } if (Noffsets) { double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); offset_trans.transform(&xo, &yo); trans *= agg::trans_affine_translation(xo, yo); } ::get_path_extents(path, trans, &x0, &y0, &x1, &y1, &xm, &ym); } } catch (...) { Py_XDECREF(offsets); throw; } Py_XDECREF(offsets); Py::Tuple result(4); result[0] = Py::Float(x0); result[1] = Py::Float(y0); result[2] = Py::Float(x1); result[3] = Py::Float(y1); return result; }
Py::Object _path_module::update_path_extents(const Py::Tuple& args) { args.verify_length(5); double x0, y0, x1, y1; PathIterator path(args[0]); agg::trans_affine trans = py_to_agg_transformation_matrix( args[1].ptr(), false); if (!py_convert_bbox(args[2].ptr(), x0, y0, x1, y1)) { throw Py::ValueError( "Must pass Bbox object as arg 3 of update_path_extents"); } Py::Object minpos_obj = args[3]; bool ignore = Py::Boolean(args[4]); double xm, ym; PyArrayObject* input_minpos = NULL; try { input_minpos = (PyArrayObject*)PyArray_FromObject( minpos_obj.ptr(), PyArray_DOUBLE, 1, 1); if (!input_minpos || PyArray_DIM(input_minpos, 0) != 2) { throw Py::TypeError( "Argument 4 to update_path_extents must be a length-2 numpy array."); } xm = *(double*)PyArray_GETPTR1(input_minpos, 0); ym = *(double*)PyArray_GETPTR1(input_minpos, 1); } catch (...) { Py_XDECREF(input_minpos); throw; } Py_XDECREF(input_minpos); npy_intp extent_dims[] = { 2, 2, 0 }; double* extents_data = NULL; npy_intp minpos_dims[] = { 2, 0 }; double* minpos_data = NULL; PyArrayObject* extents = NULL; PyArrayObject* minpos = NULL; bool changed = false; try { extents = (PyArrayObject*)PyArray_SimpleNew (2, extent_dims, PyArray_DOUBLE); if (extents == NULL) { throw Py::MemoryError("Could not allocate result array"); } minpos = (PyArrayObject*)PyArray_SimpleNew (1, minpos_dims, PyArray_DOUBLE); if (minpos == NULL) { throw Py::MemoryError("Could not allocate result array"); } extents_data = (double*)PyArray_DATA(extents); minpos_data = (double*)PyArray_DATA(minpos); if (ignore) { extents_data[0] = std::numeric_limits<double>::infinity(); extents_data[1] = std::numeric_limits<double>::infinity(); extents_data[2] = -std::numeric_limits<double>::infinity(); extents_data[3] = -std::numeric_limits<double>::infinity(); minpos_data[0] = std::numeric_limits<double>::infinity(); minpos_data[1] = std::numeric_limits<double>::infinity(); } else { if (x0 > x1) { extents_data[0] = std::numeric_limits<double>::infinity(); extents_data[2] = -std::numeric_limits<double>::infinity(); } else { extents_data[0] = x0; extents_data[2] = x1; } if (y0 > y1) { extents_data[1] = std::numeric_limits<double>::infinity(); extents_data[3] = -std::numeric_limits<double>::infinity(); } else { extents_data[1] = y0; extents_data[3] = y1; } minpos_data[0] = xm; minpos_data[1] = ym; } ::get_path_extents(path, trans, &extents_data[0], &extents_data[1], &extents_data[2], &extents_data[3], &minpos_data[0], &minpos_data[1]); changed = (extents_data[0] != x0 || extents_data[1] != y0 || extents_data[2] != x1 || extents_data[3] != y1 || minpos_data[0] != xm || minpos_data[1] != ym); } catch (...) { Py_XDECREF(extents); Py_XDECREF(minpos); throw; } Py::Tuple result(3); result[0] = Py::Object((PyObject*) extents); result[1] = Py::Object((PyObject*) minpos); result[2] = Py::Int(changed ? 1 : 0); Py_XDECREF(extents); Py_XDECREF(minpos); return result; }
Py::Object _path_module::convert_to_svg(const Py::Tuple& args) { args.verify_length(5); PathIterator path(args[0]); agg::trans_affine trans = py_to_agg_transformation_matrix(args[1].ptr(), false); Py::Object clip_obj = args[2]; bool do_clip; agg::rect_base<double> clip_rect(0, 0, 0, 0); if (clip_obj.isNone() || !clip_obj.isTrue()) { do_clip = false; } else { double x1, y1, x2, y2; Py::Tuple clip_tuple(clip_obj); x1 = Py::Float(clip_tuple[0]); y1 = Py::Float(clip_tuple[1]); x2 = Py::Float(clip_tuple[2]); y2 = Py::Float(clip_tuple[3]); clip_rect.init(x1, y1, x2, y2); do_clip = true; } bool simplify; Py::Object simplify_obj = args[3]; if (simplify_obj.isNone()) { simplify = path.should_simplify(); } else { simplify = simplify_obj.isTrue(); } int precision = Py::Int(args[4]); #if PY_VERSION_HEX < 0x02070000 char format[64]; snprintf(format, 64, "%s.%dg", "%", precision); #endif typedef agg::conv_transform<PathIterator> transformed_path_t; typedef PathNanRemover<transformed_path_t> nan_removal_t; typedef PathClipper<nan_removal_t> clipped_t; typedef PathSimplifier<clipped_t> simplify_t; transformed_path_t tpath(path, trans); nan_removal_t nan_removed(tpath, true, path.has_curves()); clipped_t clipped(nan_removed, do_clip, clip_rect); simplify_t simplified(clipped, simplify, path.simplify_threshold()); size_t buffersize = path.total_vertices() * (precision + 5) * 4; char* buffer = (char *)malloc(buffersize); char* p = buffer; const char codes[] = {'M', 'L', 'Q', 'C'}; const int waits[] = { 1, 1, 2, 3}; int wait = 0; unsigned code; double x = 0, y = 0; while ((code = simplified.vertex(&x, &y)) != agg::path_cmd_stop) { if (wait == 0) { *p++ = '\n'; if (code == 0x4f) { *p++ = 'z'; *p++ = '\n'; continue; } *p++ = codes[code-1]; wait = waits[code-1]; } else { *p++ = ' '; } #if PY_VERSION_HEX >= 0x02070000 char* str; str = PyOS_double_to_string(x, 'g', precision, 0, NULL); p += snprintf(p, buffersize - (p - buffer), str); PyMem_Free(str); *p++ = ' '; str = PyOS_double_to_string(y, 'g', precision, 0, NULL); p += snprintf(p, buffersize - (p - buffer), str); PyMem_Free(str); #else char str[64]; PyOS_ascii_formatd(str, 64, format, x); p += snprintf(p, buffersize - (p - buffer), str); *p++ = ' '; PyOS_ascii_formatd(str, 64, format, y); p += snprintf(p, buffersize - (p - buffer), str); #endif --wait; } #if PY3K PyObject* result = PyUnicode_FromStringAndSize(buffer, p - buffer); #else PyObject* result = PyString_FromStringAndSize(buffer, p - buffer); #endif free(buffer); return Py::Object(result, true); }
Py::Object _path_module::cleanup_path(const Py::Tuple& args) { args.verify_length(8); PathIterator path(args[0]); agg::trans_affine trans = py_to_agg_transformation_matrix(args[1].ptr(), false); bool remove_nans = args[2].isTrue(); Py::Object clip_obj = args[3]; bool do_clip; agg::rect_base<double> clip_rect; if (clip_obj.isNone()) { do_clip = false; } else { double x1, y1, x2, y2; Py::Tuple clip_tuple(clip_obj); x1 = Py::Float(clip_tuple[0]); y1 = Py::Float(clip_tuple[1]); x2 = Py::Float(clip_tuple[2]); y2 = Py::Float(clip_tuple[3]); clip_rect.init(x1, y1, x2, y2); do_clip = true; } Py::Object snap_obj = args[4]; e_snap_mode snap_mode; if (snap_obj.isNone()) { snap_mode = SNAP_AUTO; } else if (snap_obj.isTrue()) { snap_mode = SNAP_TRUE; } else { snap_mode = SNAP_FALSE; } double stroke_width = Py::Float(args[5]); bool simplify; Py::Object simplify_obj = args[6]; if (simplify_obj.isNone()) { simplify = path.should_simplify(); } else { simplify = simplify_obj.isTrue(); } bool return_curves = args[7].isTrue(); std::vector<double> vertices; std::vector<npy_uint8> codes; _cleanup_path(path, trans, remove_nans, do_clip, clip_rect, snap_mode, stroke_width, simplify, return_curves, vertices, codes); npy_intp length = codes.size(); npy_intp dims[] = { length, 2, 0 }; PyArrayObject* vertices_obj = NULL; PyArrayObject* codes_obj = NULL; Py::Tuple result(2); try { vertices_obj = (PyArrayObject*)PyArray_SimpleNew (2, dims, PyArray_DOUBLE); if (vertices_obj == NULL) { throw Py::MemoryError("Could not allocate result array"); } codes_obj = (PyArrayObject*)PyArray_SimpleNew (1, dims, PyArray_UINT8); if (codes_obj == NULL) { throw Py::MemoryError("Could not allocate result array"); } memcpy(PyArray_DATA(vertices_obj), &vertices[0], sizeof(double) * 2 * length); memcpy(PyArray_DATA(codes_obj), &codes[0], sizeof(npy_uint8) * length); result[0] = Py::Object((PyObject*)vertices_obj, true); result[1] = Py::Object((PyObject*)codes_obj, true); } catch (...) { Py_XDECREF(vertices_obj); Py_XDECREF(codes_obj); throw; } return result; }