/* * 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; }
/** * Returns a list of new curves corresponding to the subpaths in \a curve. * 2geomified */ GSList * SPCurve::split() const { GSList *l = NULL; for (Geom::PathVector::const_iterator path_it = _pathv.begin(); path_it != _pathv.end(); ++path_it) { Geom::PathVector newpathv; newpathv.push_back(*path_it); SPCurve * newcurve = new SPCurve(newpathv); l = g_slist_prepend(l, newcurve); } return l; }
/* * 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; }
/// @todo investigate why Geom::Point p is passed in but ignored. void Inkscape::ObjectSnapper::_collectPaths(Geom::Point /*p*/, SnapSourceType const source_type, bool const &first_point) const { // Now, let's first collect all paths to snap to. If we have a whole bunch of points to snap, // e.g. when translating an item using the selector tool, then we will only do this for the // first point and store the collection for later use. This significantly improves the performance if (first_point) { _clear_paths(); // Determine the type of bounding box we should snap to SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX; bool p_is_a_node = source_type & SNAPSOURCE_NODE_CATEGORY; bool p_is_a_bbox = source_type & SNAPSOURCE_BBOX_CATEGORY; bool p_is_other = (source_type & SNAPSOURCE_OTHERS_CATEGORY) || (source_type & SNAPSOURCE_DATUMS_CATEGORY); if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE)) { Preferences *prefs = Preferences::get(); int prefs_bbox = prefs->getBool("/tools/bounding_box", 0); bbox_type = !prefs_bbox ? SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; } // Consider the page border for snapping if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PAGE_BORDER) && _snapmanager->snapprefs.isAnyCategorySnappable()) { Geom::PathVector *border_path = _getBorderPathv(); if (border_path != NULL) { _paths_to_snap_to->push_back(SnapCandidatePath(border_path, SNAPTARGET_PAGE_BORDER, Geom::OptRect())); } } for (std::vector<SnapCandidateItem>::const_iterator i = _candidates->begin(); i != _candidates->end(); ++i) { /* Transform the requested snap point to this item's coordinates */ Geom::Affine i2doc(Geom::identity()); SPItem *root_item = NULL; /* We might have a clone at hand, so make sure we get the root item */ if (SP_IS_USE((*i).item)) { i2doc = SP_USE((*i).item)->get_root_transform(); root_item = SP_USE((*i).item)->root(); g_return_if_fail(root_item); } else { i2doc = (*i).item->i2doc_affine(); root_item = (*i).item; } //Build a list of all paths considered for snapping to //Add the item's path to snap to if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH, SNAPTARGET_PATH_INTERSECTION, SNAPTARGET_TEXT_BASELINE)) { if (p_is_other || p_is_a_node || (!_snapmanager->snapprefs.getStrictSnapping() && p_is_a_bbox)) { if (SP_IS_TEXT(root_item) || SP_IS_FLOWTEXT(root_item)) { if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_TEXT_BASELINE)) { // Snap to the text baseline Text::Layout const *layout = te_get_layout(static_cast<SPItem *>(root_item)); if (layout != NULL && layout->outputExists()) { Geom::PathVector *pv = new Geom::PathVector(); pv->push_back(layout->baseline() * root_item->i2dt_affine() * (*i).additional_affine * _snapmanager->getDesktop()->doc2dt()); _paths_to_snap_to->push_back(SnapCandidatePath(pv, SNAPTARGET_TEXT_BASELINE, Geom::OptRect())); } } } else { // Snapping for example to a traced bitmap is very stressing for // the CPU, so we'll only snap to paths having no more than 500 nodes // This also leads to a lag of approx. 500 msec (in my lousy test set-up). bool very_complex_path = false; if (SP_IS_PATH(root_item)) { very_complex_path = SP_PATH(root_item)->nodesInPath() > 500; } if (!very_complex_path && root_item && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH, SNAPTARGET_PATH_INTERSECTION)) { SPCurve *curve = NULL; if (SP_IS_SHAPE(root_item)) { curve = SP_SHAPE(root_item)->getCurve(); }/* else if (SP_IS_TEXT(root_item) || SP_IS_FLOWTEXT(root_item)) { curve = te_get_layout(root_item)->convertToCurves(); }*/ if (curve) { // We will get our own copy of the pathvector, which must be freed at some point // Geom::PathVector *pv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine); Geom::PathVector *pv = new Geom::PathVector(curve->get_pathvector()); (*pv) *= root_item->i2dt_affine() * (*i).additional_affine * _snapmanager->getDesktop()->doc2dt(); // (_edit_transform * _i2d_transform); _paths_to_snap_to->push_back(SnapCandidatePath(pv, SNAPTARGET_PATH, Geom::OptRect())); // Perhaps for speed, get a reference to the Geom::pathvector, and store the transformation besides it. curve->unref(); } } } } } //Add the item's bounding box to snap to if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE)) { if (p_is_other || p_is_a_bbox || (!_snapmanager->snapprefs.getStrictSnapping() && p_is_a_node)) { // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox // of the item AND the bbox of the clipping path at the same time if (!(*i).clip_or_mask) { Geom::OptRect rect = root_item->bounds(bbox_type, i2doc); if (rect) { Geom::PathVector *path = _getPathvFromRect(*rect); rect = root_item->desktopBounds(bbox_type); _paths_to_snap_to->push_back(SnapCandidatePath(path, SNAPTARGET_BBOX_EDGE, rect)); } } } } } } }