/* * Converts all segments in all paths to Geom::LineSegment or Geom::HLineSegment or * Geom::VLineSegment or Geom::CubicBezier. */ Geom::PathVector pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ) { Geom::PathVector output; for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { output.push_back( Geom::Path() ); output.back().start( pit->initialPoint() ); output.back().close( pit->closed() ); for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { if (is_straight_curve(*cit)) { Geom::LineSegment l(cit->initialPoint(), cit->finalPoint()); output.back().append(l); } else { Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&*cit); if (curve && curve->order() == 3) { Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); output.back().append(b); } else { // convert all other curve types to cubicbeziers Geom::Path cubicbezier_path = Geom::cubicbezierpath_from_sbasis(cit->toSBasis(), 0.1); output.back().append(cubicbezier_path); } } } } return output; }
static void sp_path_convert_to_guides(SPItem *item) { SPPath *path = SP_PATH(item); if (!path->_curve) { return; } std::list<std::pair<Geom::Point, Geom::Point> > pts; Geom::Affine const i2dt(path->i2dt_affine()); Geom::PathVector const & pv = path->_curve->get_pathvector(); for(Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { for(Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit) { // only add curves for straight line segments if( is_straight_curve(*cit) ) { pts.push_back(std::make_pair(cit->initialPoint() * i2dt, cit->finalPoint() * i2dt)); } } } sp_guide_pt_pairs_to_guides(item->document, pts); }
/* * Returns the number of segments of all paths summed * This count includes the closing line segment of a closed path. */ guint SPCurve::get_segment_count() const { guint nr = 0; for(Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) { nr += (*it).size(); if (it->closed()) nr += 1; } return nr; }
/* * Converts all segments in all paths to Geom::LineSegment. There is an intermediate * stage where some may be converted to beziers. maxdisp is the maximum displacement from * the line segment to the bezier curve; ** maxdisp is not used at this moment **. * * This is NOT a terribly fast method, but it should give a solution close to the one with the * fewest points. */ Geom::PathVector pathv_to_linear( Geom::PathVector const &pathv, double /*maxdisp*/) { Geom::PathVector output; Geom::PathVector tmppath = pathv_to_linear_and_cubic_beziers(pathv); // Now all path segments are either already lines, or they are beziers. for (Geom::PathVector::const_iterator pit = tmppath.begin(); pit != tmppath.end(); ++pit) { output.push_back( Geom::Path() ); output.back().start( pit->initialPoint() ); output.back().close( pit->closed() ); for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { if (is_straight_curve(*cit)) { Geom::LineSegment ls(cit->initialPoint(), cit->finalPoint()); output.back().append(ls); } else { /* all others must be Bezier curves */ Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&*cit); Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); std::vector<Geom::Point> bzrpoints = b.points(); Geom::Point A = bzrpoints[0]; Geom::Point B = bzrpoints[1]; Geom::Point C = bzrpoints[2]; Geom::Point D = bzrpoints[3]; std::vector<Geom::Point> pointlist; pointlist.push_back(A); recursive_bezier4( A[X], A[Y], B[X], B[Y], C[X], C[Y], D[X], D[Y], pointlist, 0); pointlist.push_back(D); Geom::Point r1 = pointlist[0]; for (unsigned int i=1; i<pointlist.size();i++){ Geom::Point prev_r1 = r1; r1 = pointlist[i]; Geom::LineSegment ls(prev_r1, r1); output.back().append(ls); } pointlist.clear(); } } } return output; }
/** * True iff all subpaths are closed. * Returns false if the curve is empty. */ bool SPCurve::is_closed() const { if (is_empty()) { return false; } else { bool closed = true; for (Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) { if ( ! it->closed() ) { closed = false; break; } } return closed; } }
static std::vector<Geom::Point> approxCurveWithPoints(SPCurve *curve) { // The number of segments to use for not straight curves approximation const unsigned NUM_SEGS = 4; const Geom::PathVector& curve_pv = curve->get_pathvector(); // The structure to hold the output std::vector<Geom::Point> poly_points; // Iterate over all curves, adding the endpoints for linear curves and // sampling the other curves double seg_size = 1.0 / NUM_SEGS; double at; at = 0; Geom::PathVector::const_iterator pit = curve_pv.begin(); while (pit != curve_pv.end()) { Geom::Path::const_iterator cit = pit->begin(); while (cit != pit->end()) { if (cit == pit->begin()) { poly_points.push_back(cit->initialPoint()); } if (dynamic_cast<Geom::CubicBezier const*>(&*cit)) { at += seg_size; if (at <= 1.0 ) poly_points.push_back(cit->pointAt(at)); else { at = 0.0; ++cit; } } else { poly_points.push_back(cit->finalPoint()); ++cit; } } ++pit; } return poly_points; }
/* * sp_svg_write_polygon: Write points attribute for polygon tag. * pathv may only contain paths with only straight line segments * Return value: points attribute string. */ static gchar *sp_svg_write_polygon(Geom::PathVector const & pathv) { Inkscape::SVGOStringStream os; for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit) { if ( is_straight_curve(*cit) ) { os << cit->finalPoint()[0] << "," << cit->finalPoint()[1] << " "; } else { g_error("sp_svg_write_polygon: polygon path contains non-straight line segments"); } } } return g_strdup(os.str().c_str()); }
Geom::OptRect bounds_exact_transformed(Geom::PathVector const & pv, Geom::Affine const & t) { if (pv.empty()) return Geom::OptRect(); Geom::Point initial = pv.front().initialPoint() * t; Geom::Rect bbox(initial, initial); // obtain well defined bbox as starting point to unionWith for (Geom::PathVector::const_iterator it = pv.begin(); it != pv.end(); ++it) { bbox.expandTo(it->initialPoint() * t); // don't loop including closing segment, since that segment can never increase the bbox for (Geom::Path::const_iterator cit = it->begin(); cit != it->end_open(); ++cit) { Geom::Curve const &c = *cit; unsigned order = 0; if (Geom::BezierCurve const* b = dynamic_cast<Geom::BezierCurve const*>(&c)) { order = b->order(); } if (order == 1) { // line segment bbox.expandTo(c.finalPoint() * t); // TODO: we can make the case for quadratics faster by degree elevating them to // cubic and then taking the bbox of that. } else if (order == 3) { // cubic bezier Geom::CubicBezier const &cubic_bezier = static_cast<Geom::CubicBezier const&>(c); Geom::Point c0 = cubic_bezier[0] * t; Geom::Point c1 = cubic_bezier[1] * t; Geom::Point c2 = cubic_bezier[2] * t; Geom::Point c3 = cubic_bezier[3] * t; cubic_bbox(c0[0], c0[1], c1[0], c1[1], c2[0], c2[1], c3[0], c3[1], bbox); } else { // should handle all not-so-easy curves: Geom::Curve *ctemp = cit->transformed(t); bbox.unionWith( ctemp->boundsExact()); delete ctemp; } } } //return Geom::bounds_exact(pv * t); return bbox; }
Geom::OptRect bounds_exact_transformed(Geom::PathVector const & pv, Geom::Affine const & t) { if (pv.empty()) return Geom::OptRect(); Geom::Point initial = pv.front().initialPoint() * t; Geom::Rect bbox(initial, initial); // obtain well defined bbox as starting point to unionWith for (Geom::PathVector::const_iterator it = pv.begin(); it != pv.end(); ++it) { bbox.expandTo(it->initialPoint() * t); // don't loop including closing segment, since that segment can never increase the bbox for (Geom::Path::const_iterator cit = it->begin(); cit != it->end_open(); ++cit) { Geom::Curve const &c = *cit; if( is_straight_curve(c) ) { bbox.expandTo( c.finalPoint() * t ); } else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const *>(&c)) { Geom::Point c0 = (*cubic_bezier)[0] * t; Geom::Point c1 = (*cubic_bezier)[1] * t; Geom::Point c2 = (*cubic_bezier)[2] * t; Geom::Point c3 = (*cubic_bezier)[3] * t; cubic_bbox( c0[0], c0[1], c1[0], c1[1], c2[0], c2[1], c3[0], c3[1], bbox ); } else { // should handle all not-so-easy curves: Geom::Curve *ctemp = cit->transformed(t); bbox.unionWith( ctemp->boundsExact()); delete ctemp; } } } //return Geom::bounds_exact(pv * t); return bbox; }
/* Calculates... and returns ... in *wind and the distance to ... in *dist. Returns bounding box in *bbox if bbox!=NULL. */ void pathv_matrix_point_bbox_wind_distance (Geom::PathVector const & pathv, Geom::Affine const &m, Geom::Point const &pt, Geom::Rect *bbox, int *wind, Geom::Coord *dist, Geom::Coord tolerance, Geom::Rect const *viewbox) { if (pathv.empty()) { if (wind) *wind = 0; if (dist) *dist = Geom::infinity(); return; } // remember last point of last curve Geom::Point p0(0,0); // remembering the start of subpath Geom::Point p_start(0,0); bool start_set = false; for (Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) { if (start_set) { // this is a new subpath if (wind && (p0 != p_start)) // for correct fill picking, each subpath must be closed geom_line_wind_distance (p0[X], p0[Y], p_start[X], p_start[Y], pt, wind, dist); } p0 = it->initialPoint() * m; p_start = p0; start_set = true; if (bbox) { bbox->expandTo(p0); } // loop including closing segment if path is closed for (Geom::Path::const_iterator cit = it->begin(); cit != it->end_default(); ++cit) { geom_curve_bbox_wind_distance(*cit, m, pt, bbox, wind, dist, tolerance, viewbox, p0); } } if (start_set) { if (wind && (p0 != p_start)) // for correct picking, each subpath must be closed geom_line_wind_distance (p0[X], p0[Y], p_start[X], p_start[Y], pt, wind, dist); } }
// FIXME: why is 'transform' argument not used? void PrintLatex::print_pathvector(SVGOStringStream &os, Geom::PathVector const &pathv_in, const Geom::Affine & /*transform*/) { if (pathv_in.empty()) return; // Geom::Affine tf=transform; // why was this here? Geom::Affine tf_stack=m_tr_stack.top(); // and why is transform argument not used? Geom::PathVector pathv = pathv_in * tf_stack; // generates new path, which is a bit slow, but this doesn't have to be performance optimized os << "\\newpath\n"; for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) { os << "\\moveto(" << it->initialPoint()[Geom::X] << "," << it->initialPoint()[Geom::Y] << ")\n"; for(Geom::Path::const_iterator cit = it->begin(); cit != it->end_open(); ++cit) { print_2geomcurve(os, *cit); } if (it->closed()) { os << "\\closepath\n"; } } }
/** * returns the number of nodes in a path, used for statusbar text when selecting an spcurve. * Sum of nodes in all the paths. When a path is closed, and its closing line segment is of zero-length, * this function will not count the closing knot double (so basically ignores the closing line segment when it has zero length) */ guint SPCurve::nodes_in_path() const { guint nr = 0; for(Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) { nr += (*it).size(); nr++; // count last node (this works also for closed paths because although they don't have a 'last node', they do have an extra segment // do not count closing knot double for zero-length closing line segments // however, if the path is only a moveto, and is closed, do not subtract 1 (otherwise the result will be zero nodes) if ( it->closed() && ((*it).size() != 0) ) { Geom::Curve const &c = it->back_closed(); if (are_near(c.initialPoint(), c.finalPoint())) { nr--; } } } return nr; }