splivarot.cpp revision d5ad05ac17abfd7d2eae333a8c1233971e1c1a8f
273e421813f295d65aab512f508e8fb575d997d4gouldtj * Created by fred on Fri Dec 05 2003.
273e421813f295d65aab512f508e8fb575d997d4gouldtj * tweaked endlessly by bulia byak <buliabyak@users.sf.net>
273e421813f295d65aab512f508e8fb575d997d4gouldtj * public domain
273e421813f295d65aab512f508e8fb575d997d4gouldtj * contains lots of stitched pieces of path-chemistry.c
273e421813f295d65aab512f508e8fb575d997d4gouldtjbool Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who);
void sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb=SP_VERB_NONE, const Glib::ustring description="");
sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb, const Glib::ustring description)
// allow union on a single object for the purpose of removing self overlapse (svn log, revision 13334)
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Select <b>at least 2 paths</b> to perform a boolean operation."));
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Select <b>at least 1 path</b> to perform a boolean union."));
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Select <b>exactly 2 paths</b> to perform difference, division, or path cut."));
bool reverseOrderForOp = false;
// check in the tree to find which element of the selection list is topmost (for 2-operand commands only)
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut."));
if (Ancetre(a, b)) {
} else if (Ancetre(b, a)) {
reverseOrderForOp = true;
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut."));
reverseOrderForOp = true;
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("One of the objects is <b>not a path</b>, cannot perform boolean operation."));
int curOrig;
curOrig = 0;
curOrig++;
if ( reverseOrderForOp ) {
int nbToCut=0;
if ( bop == bool_op_inters || bop == bool_op_union || bop == bool_op_diff || bop == bool_op_symdiff ) {
// get the polygons of each path, with the winding rule specified, and apply the operation iteratively
curOrig++;
theShapeB->ConvertToShape(theShape, fill_justDont); // fill_justDont doesn't computes winding numbers
originaux[1]->Fill(theShapeA, 1,true,false,false);// don't closeIfNeeded and just dump in the shape, don't reset it
int nbOrig=0;
int nbOther=0;
nbOrig++;
nbToCut++;
int nbNest=0;
// for later reconstruction in objects, you also need to extract which path is parent of holes (nesting info)
delete theShape;
delete theShapeA;
delete theShapeB;
delete res;
if (reverseOrderForOp) {
// delete it so that its clones don't get alerted; this object will be restored shortly, with the same id
int nbRP=0;
for (int i=0;i<nbRP;i++) {
if (mask)
if (clip_path)
g_free(d);
// we assign the same id on all pieces, but it on adding to document, it will be changed on all except one
delete resPath[i];
if ( mask )
if ( clip_path )
g_free(d);
if (title) {
if (desc) {
delete res;
if (marker_pathv) {
delete marker_pathv;
return ret_pathv;
return ret_pathv;
return ret_pathv;
case SP_STROKE_LINEJOIN_MITER:
case SP_STROKE_LINEJOIN_ROUND:
case SP_STROKE_LINECAP_SQUARE:
case SP_STROKE_LINECAP_ROUND:
// Livarots outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly.
// However Stroke adds lots of extra nodes _or_ makes the path crooked, so consider this a temporary workaround
delete theShape;
delete theRes;
delete theShape;
delete theRes;
delete res;
delete orig;
return ret_pathv;
ret_pathv );
if (!midmarker_obj) continue;
&& ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there
ret_pathv );
++curve_it1;
++curve_it2;
ret_pathv );
if (index > 0) {
index--;
ret_pathv );
delete res;
delete orig;
return ret_pathv;
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>stroked path(s)</b> to convert stroke to path."));
bool did = false;
if ( s_opac ) {
switch (jointype) {
case SP_STROKE_LINEJOIN_MITER:
case SP_STROKE_LINEJOIN_ROUND:
switch (captype) {
case SP_STROKE_LINECAP_SQUARE:
case SP_STROKE_LINECAP_ROUND:
// Livarots outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly.
// However Stroke adds lots of extra nodes _or_ makes the path crooked, so consider this a temporary workaround
delete theShape;
delete theRes;
delete theShape;
delete theRes;
delete res;
delete orig;
did = true;
if (mask)
if (clip_path)
if (title) {
if (desc) {
if (!midmarker_obj) continue;
&& ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there
++curve_it1;
++curve_it2;
if (index > 0) {
index--;
if (title) {
if (desc) {
delete res;
delete orig;
if (did) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No stroked paths</b> in the selection."));
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Selected object is <b>not a path</b>, cannot inset/outset."));
delete theShape;
delete theRes;
delete res;
delete orig;
? o_width
: expand < 0
? -o_width
if ( updating ) {
if ( updating ) {
delete res;
delete orig;
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to inset/outset."));
bool did = false;
switch (jointype) {
case SP_STROKE_LINEJOIN_MITER:
case SP_STROKE_LINEJOIN_ROUND:
switch (captype) {
case SP_STROKE_LINECAP_SQUARE:
case SP_STROKE_LINECAP_ROUND:
if (expand)
delete theShape;
delete theRes;
did = true;
delete orig;
delete res;
if (did) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No paths</b> to inset/outset in the selection."));
bool modifySelection);
if (!curve)
if (!curve)
if (modifySelection)
if ( justCoalesce ) {
if ( mask ) {
if ( clip_path ) {
if (patheffect)
if (title) {
if (desc) {
if (modifySelection)
bool modifySelection)
if (simplifyIndividualPaths) {
bool didSomething = false;
if (!selectionBbox) {
int pathsSimplified = 0;
if (simplifyIndividualPaths) {
if (itemBbox) {
simplifySize = 0;
desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, g_strdup_printf(_("<b>%d</b> paths simplified."), pathsSimplified));
return didSomething;
breakableAngles, true);
if (didSomething)
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No paths</b> to simplify in the selection."));
if (who == a)
Path *
return NULL;
Geom::PathVector *pathv = pathvector_for_curve(item, curve, doTransformation, transformFull, Geom::identity(), Geom::identity());
delete pathv;
return dest;
pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Matrix extraPreAffine, Geom::Matrix extraPostAffine)
return NULL;
if (doTransformation) {
if (transformFull) {
return dest;
if (!item)
return NULL;
boost::optional<Path::cut_position> get_nearest_position_on_Path(Path *path, Geom::Point p, unsigned seg)
return pos;