diff options
| author | su_v <suv-sf@users.sourceforge.net> | 2013-08-29 21:06:10 +0000 |
|---|---|---|
| committer | ~suv <suv-sf@users.sourceforge.net> | 2013-08-29 21:06:10 +0000 |
| commit | 4d331e73a76dce7d703716093923ca01b3cc5936 (patch) | |
| tree | b444657ba269b25f60684e66858a138b74fe240d /src/splivarot.cpp | |
| parent | Fix compiler warnings (diff) | |
| parent | Updating outdated test. Fixes bug #1202271. (diff) | |
| download | inkscape-4d331e73a76dce7d703716093923ca01b3cc5936.tar.gz inkscape-4d331e73a76dce7d703716093923ca01b3cc5936.zip | |
merge from trunk (r12487)
(bzr r11668.1.75)
Diffstat (limited to 'src/splivarot.cpp')
| -rw-r--r-- | src/splivarot.cpp | 126 |
1 files changed, 81 insertions, 45 deletions
diff --git a/src/splivarot.cpp b/src/splivarot.cpp index d07de51e3..8a57fa98a 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -34,6 +34,7 @@ #include "style.h" #include "document.h" #include "document-undo.h" +#include "layer-model.h" #include "message-stack.h" #include "selection.h" #include "desktop-handles.h" @@ -59,56 +60,67 @@ using Inkscape::DocumentUndo; bool 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=""); +void sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb=SP_VERB_NONE, const Glib::ustring description=""); void sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset); void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updating); void -sp_selected_path_union(SPDesktop *desktop) +sp_selected_path_union(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_union, SP_VERB_SELECTION_UNION, _("Union")); + sp_selected_path_boolop(selection, desktop, bool_op_union, SP_VERB_SELECTION_UNION, _("Union")); } void -sp_selected_path_union_skip_undo(SPDesktop *desktop) +sp_selected_path_union_skip_undo(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_union, SP_VERB_NONE, _("Union")); + sp_selected_path_boolop(selection, desktop, bool_op_union, SP_VERB_NONE, _("Union")); } void -sp_selected_path_intersect(SPDesktop *desktop) +sp_selected_path_intersect(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_inters, SP_VERB_SELECTION_INTERSECT, _("Intersection")); + sp_selected_path_boolop(selection, desktop, bool_op_inters, SP_VERB_SELECTION_INTERSECT, _("Intersection")); } void -sp_selected_path_diff(SPDesktop *desktop) +sp_selected_path_diff(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_diff, SP_VERB_SELECTION_DIFF, _("Difference")); + sp_selected_path_boolop(selection, desktop, bool_op_diff, SP_VERB_SELECTION_DIFF, _("Difference")); } void -sp_selected_path_diff_skip_undo(SPDesktop *desktop) +sp_selected_path_diff_skip_undo(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_diff, SP_VERB_NONE, _("Difference")); + sp_selected_path_boolop(selection, desktop, bool_op_diff, SP_VERB_NONE, _("Difference")); } void -sp_selected_path_symdiff(SPDesktop *desktop) +sp_selected_path_symdiff(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_symdiff, SP_VERB_SELECTION_SYMDIFF, _("Exclusion")); + sp_selected_path_boolop(selection, desktop, bool_op_symdiff, SP_VERB_SELECTION_SYMDIFF, _("Exclusion")); } void -sp_selected_path_cut(SPDesktop *desktop) +sp_selected_path_cut(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_cut, SP_VERB_SELECTION_CUT, _("Division")); + sp_selected_path_boolop(selection, desktop, bool_op_cut, SP_VERB_SELECTION_CUT, _("Division")); } void -sp_selected_path_slice(SPDesktop *desktop) +sp_selected_path_slice(Inkscape::Selection *selection, SPDesktop *desktop) { - sp_selected_path_boolop(desktop, bool_op_slice, SP_VERB_SELECTION_SLICE, _("Cut path")); + sp_selected_path_boolop(selection, desktop, bool_op_slice, SP_VERB_SELECTION_SLICE, _("Cut path")); } +// helper for printing error messages, regardless of whether we have a GUI or not +// If desktop == NULL, errors will be shown on stderr +static void +boolop_display_error_message(SPDesktop *desktop, Glib::ustring const &msg) +{ + if (desktop) { + desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, msg); + } else { + g_printerr("%s\n", msg.c_str()); + } +} // boolean operations PathVectors A,B -> PathVector result. // This is derived from sp_selected_path_boolop @@ -311,25 +323,24 @@ Geom::PathVector pathliv_to_pathvector(Path *pathliv){ // boolean operations on the desktop // take the source paths from the file, do the operation, delete the originals and add the results void -sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb, const Glib::ustring description) +sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb, const Glib::ustring description) { - Inkscape::Selection *selection = sp_desktop_selection(desktop); - + SPDocument *doc = selection->layers()->getDocument(); GSList *il = (GSList *) selection->itemList(); // allow union on a single object for the purpose of removing self overlapse (svn log, revision 13334) if ( (g_slist_length(il) < 2) && (bop != bool_op_union)) { - desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Select <b>at least 2 paths</b> to perform a boolean operation.")); + boolop_display_error_message(desktop, _("Select <b>at least 2 paths</b> to perform a boolean operation.")); return; } else if ( g_slist_length(il) < 1 ) { - desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Select <b>at least 1 path</b> to perform a boolean union.")); + boolop_display_error_message(desktop, _("Select <b>at least 1 path</b> to perform a boolean union.")); return; } if (g_slist_length(il) > 2) { if (bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice ) { - desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Select <b>exactly 2 paths</b> to perform difference, division, or path cut.")); + boolop_display_error_message(desktop, _("Select <b>exactly 2 paths</b> to perform difference, division, or path cut.")); return; } } @@ -345,7 +356,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb Inkscape::XML::Node *b = reinterpret_cast<SPObject *>(il->next->data)->getRepr(); if (a == NULL || b == NULL) { - 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.")); + boolop_display_error_message(desktop, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut.")); return; } @@ -360,7 +371,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb // find their lowest common ancestor Inkscape::XML::Node *dad = LCA(a, b); if (dad == NULL) { - 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.")); + boolop_display_error_message(desktop, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut.")); return; } @@ -390,7 +401,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb SPItem *item = SP_ITEM(l->data); if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item) && !SP_IS_FLOWTEXT(item)) { - desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("One of the objects is <b>not a path</b>, cannot perform boolean operation.")); + boolop_display_error_message(desktop, _("One of the objects is <b>not a path</b>, cannot perform boolean operation.")); g_slist_free(il); return; } @@ -465,11 +476,38 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb theShapeB->ConvertToShape(theShape, origWind[curOrig]); - if (theShapeA->numberOfEdges() == 0) { - Shape *swap = theShapeB; - theShapeB = theShapeA; - theShapeA = swap; - } else if (theShapeB->numberOfEdges() > 0) { + /* Due to quantization of the input shape coordinates, we may end up with A or B being empty. + * If this is a union or symdiff operation, we just use the non-empty shape as the result: + * A=0 => (0 or B) == B + * B=0 => (A or 0) == A + * A=0 => (0 xor B) == B + * B=0 => (A xor 0) == A + * If this is an intersection operation, we just use the empty shape as the result: + * A=0 => (0 and B) == 0 == A + * B=0 => (A and 0) == 0 == B + * If this a difference operation, and the upper shape (A) is empty, we keep B. + * If the lower shape (B) is empty, we still keep B, as it's empty: + * A=0 => (B - 0) == B + * B=0 => (0 - A) == 0 == B + * + * In any case, the output from this operation is stored in shape A, so we may apply + * the above rules simply by judicious use of swapping A and B where necessary. + */ + bool zeroA = theShapeA->numberOfEdges() == 0; + bool zeroB = theShapeB->numberOfEdges() == 0; + if (zeroA || zeroB) { + // We might need to do a swap. Apply the above rules depending on operation type. + bool resultIsB = ((bop == bool_op_union || bop == bool_op_symdiff) && zeroA) + || ((bop == bool_op_inters) && zeroB) + || (bop == bool_op_diff); + if (resultIsB) { + // Swap A and B to use B as the result + Shape *swap = theShapeB; + theShapeB = theShapeA; + theShapeA = swap; + } + } else { + // Just do the Boolean operation as usual // les elements arrivent en ordre inverse dans la liste theShape->Booleen(theShapeB, theShapeA, bop); Shape *swap = theShape; @@ -631,8 +669,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb { SP_OBJECT(l->data)->deleteObject(); } - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_NONE, - description); + DocumentUndo::done(doc, SP_VERB_NONE, description); selection->clear(); delete res; @@ -654,8 +691,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb sorted = g_slist_sort(sorted, (GCompareFunc) sp_repr_compare_position); - source = sp_desktop_document(desktop)-> - getObjectByRepr((Inkscape::XML::Node *)sorted->data); + source = doc->getObjectByRepr((Inkscape::XML::Node *)sorted->data); g_slist_free(sorted); } @@ -695,7 +731,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb g_slist_free(il); // premultiply by the inverse of parent's repr - SPItem *parent_item = SP_ITEM(sp_desktop_document(desktop)->getObjectByRepr(parent)); + SPItem *parent_item = SP_ITEM(doc->getObjectByRepr(parent)); Geom::Affine local (parent_item->i2doc_affine()); gchar *transform = sp_svg_transform_write(local.inverse()); @@ -725,7 +761,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb for (int i=0;i<nbRP;i++) { gchar *d = resPath[i]->svg_dump_path(); - Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); repr->setAttribute("style", style); if (mask) @@ -771,7 +807,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb } else { gchar *d = res->svg_dump_path(); - Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); repr->setAttribute("style", style); @@ -789,10 +825,10 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb repr->setAttribute("id", id); parent->appendChild(repr); if (title) { - sp_desktop_document(desktop)->getObjectByRepr(repr)->setTitle(title); + doc->getObjectByRepr(repr)->setTitle(title); } if (desc) { - sp_desktop_document(desktop)->getObjectByRepr(repr)->setDesc(desc); + doc->getObjectByRepr(repr)->setDesc(desc); } repr->setPosition(pos > 0 ? pos : 0); @@ -805,7 +841,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb if (desc) g_free(desc); if (verb != SP_VERB_NONE) { - DocumentUndo::done(sp_desktop_document(desktop), verb, description); + DocumentUndo::done(doc, verb, description); } delete res; @@ -1764,12 +1800,12 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) float o_width = 0; float o_miter = 0; JoinType o_join = join_straight; - ButtType o_butt = butt_straight; + //ButtType o_butt = butt_straight; { SPStyle *i_style = item->style; int jointype = i_style->stroke_linejoin.value; - int captype = i_style->stroke_linecap.value; + //int captype = i_style->stroke_linecap.value; o_width = i_style->stroke_width.computed; @@ -1785,7 +1821,7 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) break; } - switch (captype) { + /*switch (captype) { case SP_STROKE_LINECAP_SQUARE: o_butt = butt_square; break; @@ -1795,7 +1831,7 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) default: o_butt = butt_straight; break; - } + }*/ o_width = prefOffset; |
