From: cilix42 Date: Wed, 19 Mar 2008 10:37:50 +0000 (+0000) Subject: Make grouped 3D boxes work correctly when transformed (fixes: LP 188991) X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=71dea9c6fbd2fd6d73cce6f1ed96151d51ada58f;p=inkscape.git Make grouped 3D boxes work correctly when transformed (fixes: LP 188991) --- diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index 9ee920c1b..7414fcd77 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -186,10 +186,6 @@ static void sp_box3d_context_selection_changed(Inkscape::Selection *selection, g ec->shape_repr = 0; } - SPDocument *doc = sp_desktop_document(bc->desktop); - doc->persps_sel.clear(); - doc->persps_sel = persp3d_currently_selected_persps(); - SPItem *item = selection->singleItem(); if (item) { ec->shape_knot_holder = sp_item_knot_holder(item, ec->desktop); @@ -201,9 +197,9 @@ static void sp_box3d_context_selection_changed(Inkscape::Selection *selection, g } } - if (doc->persps_sel.size() == 1) { + if (selection->perspList().size() == 1) { // selecting a single box changes the current perspective - doc->current_persp3d = *(doc->persps_sel.begin()); + ec->desktop->doc()->current_persp3d = selection->perspList().front(); } } @@ -509,7 +505,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven ret = TRUE; } if (MOD__SHIFT_ONLY) { - persp3d_toggle_VPs(persp3d_currently_selected_persps(), Proj::X); + persp3d_toggle_VPs(selection->perspList(), Proj::X); bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; } @@ -518,7 +514,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven case GDK_y: case GDK_Y: if (MOD__SHIFT_ONLY) { - persp3d_toggle_VPs(persp3d_currently_selected_persps(), Proj::Y); + persp3d_toggle_VPs(selection->perspList(), Proj::Y); bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; } @@ -527,7 +523,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven case GDK_z: case GDK_Z: if (MOD__SHIFT_ONLY) { - persp3d_toggle_VPs(persp3d_currently_selected_persps(), Proj::Z); + persp3d_toggle_VPs(selection->perspList(), Proj::Z); bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; } diff --git a/src/box3d-side.cpp b/src/box3d-side.cpp index c20b7a864..4cd3765c9 100644 --- a/src/box3d-side.cpp +++ b/src/box3d-side.cpp @@ -35,8 +35,7 @@ static void box3d_side_update (SPObject *object, SPCtx *ctx, guint flags); static void box3d_side_set_shape (SPShape *shape); -static Proj::Pt3 box3d_side_corner (Box3DSide *side, guint index); -static std::vector box3d_side_corners (Box3DSide *side); +static void box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]); static SPShapeClass *parent_class; @@ -210,10 +209,12 @@ box3d_side_set_shape (SPShape *shape) return; } - if (!SP_IS_BOX3D(SP_OBJECT(side)->parent)) { + SPObject *parent = SP_OBJECT(side)->parent; + if (!SP_IS_BOX3D(parent)) { g_warning ("Parent of 3D box side is not a 3D box.\n"); return; } + SPBox3D *box = SP_BOX3D(parent); Persp3D *persp = box3d_side_perspective(side); if (!persp) { @@ -226,15 +227,13 @@ box3d_side_set_shape (SPShape *shape) // compute the coordinates of the corners in P^3, project them onto the canvas, and draw the // resulting path. - std::vector corners = box3d_side_corners (side); + unsigned int corners[4]; + box3d_side_compute_corner_ids(side, corners); - NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(shape))); - - // FIXME: This can better be implemented by using box3d_get_corner - sp_curve_moveto (c, persp->tmat.image(corners[0]).affine() * i2d); - sp_curve_lineto (c, persp->tmat.image(corners[1]).affine() * i2d); - sp_curve_lineto (c, persp->tmat.image(corners[2]).affine() * i2d); - sp_curve_lineto (c, persp->tmat.image(corners[3]).affine() * i2d); + sp_curve_moveto (c, box3d_get_corner_screen(box, corners[0])); + sp_curve_lineto (c, box3d_get_corner_screen(box, corners[1])); + sp_curve_lineto (c, box3d_get_corner_screen(box, corners[2])); + sp_curve_lineto (c, box3d_get_corner_screen(box, corners[3])); sp_curve_closepath (c); sp_shape_perform_path_effect(c, SP_SHAPE (side)); @@ -284,29 +283,14 @@ box3d_side_axes_string(Box3DSide *side) return pstring->str; } -static Proj::Pt3 -box3d_side_corner (Box3DSide *side, guint index) { - SPBox3D *box = SP_BOX3D(SP_OBJECT_PARENT(side)); - return Proj::Pt3 ((index & 0x1) ? box->orig_corner7[Proj::X] : box->orig_corner0[Proj::X], - (index & 0x2) ? box->orig_corner7[Proj::Y] : box->orig_corner0[Proj::Y], - (index & 0x4) ? box->orig_corner7[Proj::Z] : box->orig_corner0[Proj::Z], - 1.0); -} - -static std::vector -box3d_side_corners (Box3DSide *side) { - std::vector corners; +static void +box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]) { Box3D::Axis orth = Box3D::third_axis_direction (side->dir1, side->dir2); - unsigned int i0 = (side->front_or_rear ? orth : 0); - unsigned int i1 = i0 ^ side->dir1; - unsigned int i2 = i0 ^ side->dir1 ^ side->dir2; - unsigned int i3 = i0 ^ side->dir2; - - corners.push_back (box3d_side_corner (side, i0)); - corners.push_back (box3d_side_corner (side, i1)); - corners.push_back (box3d_side_corner (side, i2)); - corners.push_back (box3d_side_corner (side, i3)); - return corners; + + corners[0] = (side->front_or_rear ? orth : 0); + corners[1] = corners[0] ^ side->dir1; + corners[2] = corners[0] ^ side->dir1 ^ side->dir2; + corners[3] = corners[0] ^ side->dir2; } Persp3D * diff --git a/src/box3d.cpp b/src/box3d.cpp index 5beee4acc..f57452101 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -37,6 +37,7 @@ #include "prefs-utils.h" #include "desktop.h" +#include "desktop-handles.h" #include "macros.h" static void box3d_class_init(SPBox3DClass *klass); @@ -337,12 +338,12 @@ box3d_set_transform(SPItem *item, NR::Matrix const &xform) Persp3D *transf_persp; if (!persp3d_has_all_boxes_in_selection (persp)) { - std::list sel = persp3d_selected_boxes (persp); + std::list selboxes = sp_desktop_selection(inkscape_active_desktop())->box3DList(); /* create a new perspective as a copy of the current one and link the selected boxes to it */ transf_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp); - for (std::list::iterator b = sel.begin(); b != sel.end(); ++b) { + for (std::list::iterator b = selboxes.begin(); b != selboxes.end(); ++b) { box3d_switch_perspectives(*b, persp, transf_persp); } } else { @@ -404,12 +405,17 @@ box3d_get_proj_corner (SPBox3D const *box, guint id) { } NR::Point -box3d_get_corner_screen (SPBox3D const *box, guint id) { +box3d_get_corner_screen (SPBox3D const *box, guint id, bool item_coords) { Proj::Pt3 proj_corner (box3d_get_proj_corner (box, id)); if (!box3d_get_perspective(box)) { return NR::Point (NR_HUGE, NR_HUGE); } - return box3d_get_perspective(box)->tmat.image(proj_corner).affine(); + NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(box))); + if (item_coords) { + return box3d_get_perspective(box)->tmat.image(proj_corner).affine() * i2d.inverse(); + } else { + return box3d_get_perspective(box)->tmat.image(proj_corner).affine(); + } } Proj::Pt3 @@ -428,7 +434,8 @@ box3d_get_center_screen (SPBox3D *box) { if (!box3d_get_perspective(box)) { return NR::Point (NR_HUGE, NR_HUGE); } - return box3d_get_perspective(box)->tmat.image(proj_center).affine(); + NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(box))); + return box3d_get_perspective(box)->tmat.image(proj_center).affine() * i2d.inverse(); } /* @@ -700,8 +707,8 @@ static bool box3d_XY_axes_are_swapped (SPBox3D *box) { Persp3D *persp = box3d_get_perspective(box); g_return_val_if_fail(persp, false); - Box3D::PerspectiveLine l1(box3d_get_corner_screen(box, 3), Proj::X, persp); - Box3D::PerspectiveLine l2(box3d_get_corner_screen(box, 3), Proj::Y, persp); + Box3D::PerspectiveLine l1(box3d_get_corner_screen(box, 3, false), Proj::X, persp); + Box3D::PerspectiveLine l2(box3d_get_corner_screen(box, 3, false), Proj::Y, persp); NR::Point v1(l1.direction()); NR::Point v2(l2.direction()); v1.normalize(); @@ -861,7 +868,7 @@ static void box3d_set_new_z_orders_case2 (SPBox3D *box, int z_orders[6], Box3D::Axis central_axis, Box3D::Axis /*infinite_axis*/) { Persp3D *persp = box3d_get_perspective(box); - NR::Point c3(box3d_get_corner_screen(box, 3)); + NR::Point c3(box3d_get_corner_screen(box, 3, false)); NR::Point xdir(persp3d_get_PL_dir_from_pt(persp, c3, Proj::X)); NR::Point ydir(persp3d_get_PL_dir_from_pt(persp, c3, Proj::Y)); NR::Point zdir(persp3d_get_PL_dir_from_pt(persp, c3, Proj::Z)); @@ -996,7 +1003,7 @@ box3d_recompute_z_orders (SPBox3D *box) { int z_orders[6]; - NR::Point c3(box3d_get_corner_screen(box, 3)); + NR::Point c3(box3d_get_corner_screen(box, 3, false)); // determine directions from corner3 to the VPs int num_finite = 0; @@ -1051,7 +1058,7 @@ box3d_recompute_z_orders (SPBox3D *box) { Geom::Point vpy(vp_y[NR::X], vp_y[NR::Y]); Geom::Point vpz(vp_z[NR::X], vp_z[NR::Y]); - NR::Point c3 = box3d_get_corner_screen(box, 3); + NR::Point c3 = box3d_get_corner_screen(box, 3, false); Geom::Point corner3(c3[NR::X], c3[NR::Y]); if (box3d_half_line_crosses_joining_line (corner3, vpx, vpy, vpz)) { @@ -1070,9 +1077,9 @@ box3d_recompute_z_orders (SPBox3D *box) { central_corner = central_corner ^ Box3D::XYZ; } - NR::Point c1(box3d_get_corner_screen(box, 1)); - NR::Point c2(box3d_get_corner_screen(box, 2)); - NR::Point c7(box3d_get_corner_screen(box, 7)); + NR::Point c1(box3d_get_corner_screen(box, 1, false)); + NR::Point c2(box3d_get_corner_screen(box, 2, false)); + NR::Point c7(box3d_get_corner_screen(box, 7, false)); Geom::Point corner1(c1[NR::X], c1[NR::Y]); Geom::Point corner2(c2[NR::X], c2[NR::Y]); @@ -1185,8 +1192,8 @@ box3d_pt_lies_in_PL_sector (SPBox3D const *box, NR::Point const &pt, int id1, in Persp3D *persp = box3d_get_perspective(box); // the two corners - NR::Point c1(box3d_get_corner_screen(box, id1)); - NR::Point c2(box3d_get_corner_screen(box, id2)); + NR::Point c1(box3d_get_corner_screen(box, id1, false)); + NR::Point c2(box3d_get_corner_screen(box, id2, false)); int ret = 0; if (persp3d_VP_is_finite(persp, Box3D::toProj(axis))) { @@ -1201,7 +1208,7 @@ box3d_pt_lies_in_PL_sector (SPBox3D const *box, NR::Point const &pt, int id1, in if (pl1.lie_on_same_side(pt, c2) && pl2.lie_on_same_side(pt, c1)) { // test whether pt lies "towards" or "away from" the VP Box3D::Line edge(c1,c2); - NR::Point c3(box3d_get_corner_screen(box, id1 ^ axis)); + NR::Point c3(box3d_get_corner_screen(box, id1 ^ axis, false)); if (edge.lie_on_same_side(pt, c3)) { ret = 1; } else { @@ -1304,6 +1311,24 @@ box3d_mark_transformed(SPBox3D *box) { persp3d_set_box_transformed(persp, box, true); } +static void +box3d_extract_boxes_rec(SPObject *obj, std::list &boxes) { + if (SP_IS_BOX3D(obj)) { + boxes.push_back(SP_BOX3D(obj)); + } else if (SP_IS_GROUP(obj)) { + for (SPObject *child = sp_object_first_child(obj); child != NULL; child = SP_OBJECT_NEXT(child) ) { + box3d_extract_boxes_rec(child, boxes); + } + } +} + +std::list +box3d_extract_boxes(SPObject *obj) { + std::list boxes; + box3d_extract_boxes_rec(obj, boxes); + return boxes; +} + Persp3D * box3d_get_perspective(SPBox3D const *box) { return box->persp_ref->getObject(); @@ -1316,8 +1341,8 @@ box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp, box->orig_corner7.normalize(); double z0 = box->orig_corner0[Proj::Z]; double z7 = box->orig_corner7[Proj::Z]; - NR::Point corner0_screen = box3d_get_corner_screen(box, 0); - NR::Point corner7_screen = box3d_get_corner_screen(box, 7); + NR::Point corner0_screen = box3d_get_corner_screen(box, 0, false); + NR::Point corner7_screen = box3d_get_corner_screen(box, 7, false); box->orig_corner0 = new_persp->tmat.preimage(corner0_screen, z0, Proj::Z); box->orig_corner7 = new_persp->tmat.preimage(corner7_screen, z7, Proj::Z); @@ -1383,8 +1408,8 @@ box3d_convert_to_group(SPBox3D *box) { static inline void box3d_push_back_corner_pair(SPBox3D *box, std::list > &pts, int c1, int c2) { - pts.push_back(std::make_pair(box3d_get_corner_screen(box, c1).to_2geom(), - box3d_get_corner_screen(box, c2).to_2geom())); + pts.push_back(std::make_pair(box3d_get_corner_screen(box, c1, false).to_2geom(), + box3d_get_corner_screen(box, c2, false).to_2geom())); } void diff --git a/src/box3d.h b/src/box3d.h index d9fd540b6..bc88e6257 100644 --- a/src/box3d.h +++ b/src/box3d.h @@ -54,7 +54,7 @@ GType box3d_get_type (void); void box3d_position_set (SPBox3D *box); Proj::Pt3 box3d_get_proj_corner (SPBox3D const *box, guint id); -NR::Point box3d_get_corner_screen (SPBox3D const *box, guint id); +NR::Point box3d_get_corner_screen (SPBox3D const *box, guint id, bool item_coords = true); Proj::Pt3 box3d_get_proj_center (SPBox3D *box); NR::Point box3d_get_center_screen (SPBox3D *box); @@ -74,6 +74,8 @@ void box3d_add_to_selection(SPBox3D *box); void box3d_remove_from_selection(SPBox3D *box); void box3d_mark_transformed(SPBox3D *box); +std::list box3d_extract_boxes(SPObject *obj); + Persp3D *box3d_get_perspective(SPBox3D const *box); void box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp, bool recompute_corners = false); diff --git a/src/document.h b/src/document.h index 8a4e65bb3..b0d6afecb 100644 --- a/src/document.h +++ b/src/document.h @@ -107,7 +107,6 @@ struct SPDocument : public Inkscape::GC::Managed<>, GSList *perspectives; Persp3D *current_persp3d; // "currently active" perspective (e.g., newly created boxes are attached to this one) - std::set persps_sel; // perspectives associated to currently selected boxes void add_persp3d (Persp3D * const persp); void remove_persp3d (Persp3D * const persp); diff --git a/src/object-edit.cpp b/src/object-edit.cpp index da5672ca2..b3d661586 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -530,11 +530,7 @@ static SPKnotHolder *sp_rect_knot_holder(SPItem *item, SPDesktop *desktop) static NR::Point box3d_knot_get(SPItem *item, guint knot_id) { - g_assert(item != NULL); - SPBox3D *box = SP_BOX3D(item); - - NR::Matrix const i2d (sp_item_i2d_affine (item)); - return box3d_get_corner_screen(box, knot_id) * i2d; + return box3d_get_corner_screen(SP_BOX3D(item), knot_id); } static void box3d_knot_set(SPItem *item, guint knot_id, NR::Point const &new_pos, NR::Point const &/*origin*/, guint state) @@ -559,8 +555,7 @@ static void box3d_knot_set(SPItem *item, guint knot_id, NR::Point const &new_pos static NR::Point box3d_knot_center_get (SPItem *item) { - NR::Matrix const i2d (sp_item_i2d_affine (item)); - return box3d_get_center_screen (SP_BOX3D(item)) * i2d; + return box3d_get_center_screen (SP_BOX3D(item)); } static void box3d_knot_center_set(SPItem *item, NR::Point const &new_pos, NR::Point const &origin, guint state) diff --git a/src/persp3d.cpp b/src/persp3d.cpp index e5cade661..e647af698 100644 --- a/src/persp3d.cpp +++ b/src/persp3d.cpp @@ -337,8 +337,8 @@ persp3d_toggle_VP (Persp3D *persp, Proj::Axis axis, bool set_undo) { /* toggle VPs for the same axis in all perspectives of a given list */ void -persp3d_toggle_VPs (std::set p, Proj::Axis axis) { - for (std::set::iterator i = p.begin(); i != p.end(); ++i) { +persp3d_toggle_VPs (std::list p, Proj::Axis axis) { + for (std::list::iterator i = p.begin(); i != p.end(); ++i) { persp3d_toggle_VP((*i), axis, false); } sp_document_done(sp_desktop_document(inkscape_active_desktop()), SP_VERB_CONTEXT_3DBOX, @@ -563,27 +563,13 @@ persp3d_on_repr_attr_changed ( Inkscape::XML::Node * /*repr*/, persp3d_update_box_displays (persp); } -/* returns a std::set() of all perspectives of the currently selected boxes */ -std::set -persp3d_currently_selected_persps () { - Inkscape::Selection *selection = sp_desktop_selection(inkscape_active_desktop()); - - std::set p; - for (GSList *i = (GSList *) selection->itemList(); i != NULL; i = i->next) { - if (SP_IS_BOX3D (i->data)) { - p.insert(box3d_get_perspective(SP_BOX3D(i->data))); - } - } - return p; -} - /* checks whether all boxes linked to this perspective are currently selected */ bool persp3d_has_all_boxes_in_selection (Persp3D *persp) { - const GSList *selection = sp_desktop_selection (inkscape_active_desktop())->itemList(); + std::list selboxes = sp_desktop_selection(inkscape_active_desktop())->box3DList(); for (std::vector::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) { - if (g_slist_find((GSList *) selection, *i) == NULL) { + if (std::find(selboxes.begin(), selboxes.end(), *i) == selboxes.end()) { // we have an unselected box in the perspective return false; } @@ -591,17 +577,48 @@ persp3d_has_all_boxes_in_selection (Persp3D *persp) { return true; } -std::list -persp3d_selected_boxes (Persp3D *persp) { - const GSList *selection = sp_desktop_selection (inkscape_active_desktop())->itemList(); - std::list sel; +// TODO: Check where we can use pass-by-reference (or so) instead of recreating all the lists afresh. +std::map > +persp3d_unselected_boxes(Inkscape::Selection *selection) { + std::list plist = selection->perspList(); + std::map > punsel; + + std::list::iterator i; + std::vector::iterator j; + // for all perspectives in the list ... + for (i = plist.begin(); i != plist.end(); ++i) { + Persp3D *persp = *i; + // ... and each box associated to it ... + for (j = persp->boxes.begin(); j != persp->boxes.end(); ++j) { + SPBox3D *box = *j; + // ... check whether it is unselected, and if so add it to the list + if (persp->boxes_transformed.find(box) == persp->boxes_transformed.end()) { + punsel[persp].push_back(box); + } + } + } + return punsel; +} - for (std::vector::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) { - if (g_slist_find((GSList *) selection, *i) != NULL) { - sel.push_back(SP_BOX3D(*i)); +void +persp3d_split_perspectives_according_to_selection(Inkscape::Selection *selection) { + std::map > punsel = persp3d_unselected_boxes(selection); + + std::map >::iterator i; + std::list::iterator j; + // for all perspectives in the list ... + for (i = punsel.begin(); i != punsel.end(); ++i) { + Persp3D *persp = (*i).first; + // ... if the perspective has unselected boxes ... + if (!(*i).second.empty()) { + // create a new perspective and move these boxes over + Persp3D * new_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp); + for (j = (*i).second.begin(); j != (*i).second.end(); ++j) { + SPBox3D *box = *j; + box3d_switch_perspectives(box, persp, new_persp); + } } } - return sel; } /* some debugging stuff follows */ @@ -645,9 +662,9 @@ persp3d_print_all_selected() { g_print ("\n======================================\n"); g_print ("Selected perspectives and their boxes:\n"); - std::set sel_persps = persp3d_currently_selected_persps(); + std::list sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList(); - for (std::set::iterator j = sel_persps.begin(); j != sel_persps.end(); ++j) { + for (std::list::iterator j = sel_persps.begin(); j != sel_persps.end(); ++j) { Persp3D *persp = SP_PERSP3D(*j); g_print (" %s (%d): ", SP_OBJECT_REPR(persp)->attribute("id"), persp->my_counter); for (std::map::iterator i = persp->boxes_transformed.begin(); diff --git a/src/persp3d.h b/src/persp3d.h index 4819a52e9..271b42459 100644 --- a/src/persp3d.h +++ b/src/persp3d.h @@ -18,7 +18,7 @@ #define SP_IS_PERSP3D(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_PERSP3D)) #define SP_IS_PERSP3D_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_PERSP3D)) -#include +#include #include #include #include "sp-item.h" @@ -62,7 +62,7 @@ NR::Point persp3d_get_infinite_dir (Persp3D *persp, Proj::Axis axis); double persp3d_get_infinite_angle (Persp3D *persp, Proj::Axis axis); bool persp3d_VP_is_finite (Persp3D *persp, Proj::Axis axis); void persp3d_toggle_VP (Persp3D *persp, Proj::Axis axis, bool set_undo = true); -void persp3d_toggle_VPs (std::set, Proj::Axis axis); +void persp3d_toggle_VPs (std::list, Proj::Axis axis); void persp3d_set_VP_state (Persp3D *persp, Proj::Axis axis, Proj::VPState state); void persp3d_rotate_VP (Persp3D *persp, Proj::Axis axis, double angle, bool alt_pressed); // angle is in degrees void persp3d_update_with_point (Persp3D *persp, Proj::Axis const axis, Proj::Pt2 const &new_image); @@ -92,9 +92,9 @@ void persp3d_absorb(Persp3D *persp1, Persp3D *persp2); Persp3D * persp3d_create_xml_element (SPDocument *document, Persp3D *dup = NULL); Persp3D * persp3d_document_first_persp (SPDocument *document); -std::set persp3d_currently_selected_persps(); bool persp3d_has_all_boxes_in_selection (Persp3D *persp); -std::list persp3d_selected_boxes (Persp3D *persp); +std::map > persp3d_unselected_boxes(Inkscape::Selection *selection); +void persp3d_split_perspectives_according_to_selection(Inkscape::Selection *selection); void persp3d_print_debugging_info (Persp3D *persp); void persp3d_print_debugging_info_all(SPDocument *doc); diff --git a/src/selection.cpp b/src/selection.cpp index d3b667a12..41540c95c 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -30,6 +30,8 @@ #include "sp-path.h" #include "sp-item-group.h" #include "box3d.h" +#include "box3d.h" +#include "persp3d.h" #include @@ -159,6 +161,27 @@ void Selection::add(SPObject *obj, bool persist_selection_context/* = false */) _emitChanged(persist_selection_context); } +void Selection::add_box_perspective(SPBox3D *box) { + Persp3D *persp = box3d_get_perspective(box); + std::map::iterator p = _persps.find(persp); + if (p != _persps.end()) { + (*p).second++; + } else { + _persps[persp] = 1; + } +} + +void Selection::add_3D_boxes_recursively(SPObject *obj) { + std::list boxes = box3d_extract_boxes(obj); + + for (std::list::iterator i = boxes.begin(); i != boxes.end(); ++i) { + SPBox3D *box = *i; + box3d_add_to_selection(box); + _3dboxes.push_back(box); + add_box_perspective(box); + } +} + void Selection::_add(SPObject *obj) { // unselect any of the item's ancestors and descendants which may be selected // (to prevent double-selection) @@ -167,10 +190,7 @@ void Selection::_add(SPObject *obj) { _objs = g_slist_prepend(_objs, obj); - if (SP_IS_BOX3D(obj)) { - // keep track of selected boxes for transformations - box3d_add_to_selection(SP_BOX3D(obj)); - } + add_3D_boxes_recursively(obj); _release_connections[obj] = obj->connectRelease(sigc::mem_fun(*this, (void (Selection::*)(SPObject *))&Selection::remove)); _modified_connections[obj] = obj->connectModified(sigc::mem_fun(*this, &Selection::_schedule_modified)); @@ -199,6 +219,36 @@ void Selection::remove(SPObject *obj) { _emitChanged(); } +void Selection::remove_box_perspective(SPBox3D *box) { + Persp3D *persp = box3d_get_perspective(box); + std::map::iterator p = _persps.find(persp); + if (p == _persps.end()) { + g_print ("Warning! Trying to remove unselected perspective from selection!\n"); + return; + } + if ((*p).second > 1) { + _persps[persp]--; + } else { + _persps.erase(p); + } +} + +void Selection::remove_3D_boxes_recursively(SPObject *obj) { + std::list boxes = box3d_extract_boxes(obj); + + for (std::list::iterator i = boxes.begin(); i != boxes.end(); ++i) { + SPBox3D *box = *i; + box3d_remove_from_selection(box); + std::list::iterator b = std::find(_3dboxes.begin(), _3dboxes.end(), box); + if (b == _3dboxes.end()) { + g_print ("Warning! Trying to remove unselected box from selection.\n"); + return; + } + _3dboxes.erase(b); + remove_box_perspective(box); + } +} + void Selection::_remove(SPObject *obj) { _modified_connections[obj].disconnect(); _modified_connections.erase(obj); @@ -206,10 +256,7 @@ void Selection::_remove(SPObject *obj) { _release_connections[obj].disconnect(); _release_connections.erase(obj); - if (SP_IS_BOX3D(obj)) { - // keep track of selected boxes for transformations - box3d_remove_from_selection(SP_BOX3D(obj)); - } + remove_3D_boxes_recursively(obj); _objs = g_slist_remove(_objs, obj); } @@ -294,6 +341,18 @@ GSList const *Selection::reprList() { return _reprs; } +std::list const Selection::perspList() { + std::list pl; + for (std::map::iterator p = _persps.begin(); p != _persps.end(); ++p) { + pl.push_back((*p).first); + } + return pl; +} + +std::list const Selection::box3DList() { + return _3dboxes; +} + SPObject *Selection::single() { if ( _objs != NULL && _objs->next == NULL ) { return reinterpret_cast(_objs->data); diff --git a/src/selection.h b/src/selection.h index 58204160b..3d45c171d 100644 --- a/src/selection.h +++ b/src/selection.h @@ -18,6 +18,7 @@ #include #include +#include #include #include "libnr/nr-rect.h" @@ -31,6 +32,8 @@ #include "sp-item.h" class SPItem; +class SPBox3D; +class Persp3D; namespace Inkscape { namespace XML { @@ -225,6 +228,12 @@ public: /// method for that GSList const *reprList(); + /* list of all perspectives which have a 3D box in the current selection + (these may also be nested in groups) */ + std::list const perspList(); + + std::list const box3DList(); + /** @brief Returns the number of layers in which there are selected objects */ guint numberOfLayers(); @@ -336,6 +345,14 @@ private: mutable GSList *_reprs; mutable GSList *_items; + void add_box_perspective(SPBox3D *box); + void add_3D_boxes_recursively(SPObject *obj); + void remove_box_perspective(SPBox3D *box); + void remove_3D_boxes_recursively(SPObject *obj); + + std::map _persps; + std::list _3dboxes; + GC::soft_ptr _desktop; SPObject* _selection_context; guint _flags; diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 5ae5713ca..7969c1bc1 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -38,6 +38,10 @@ #include "sp-mask.h" #include "sp-path.h" #include "box3d.h" +#include "persp3d.h" +#include "inkscape.h" +#include "desktop-handles.h" +#include "selection.h" static void sp_group_class_init (SPGroupClass *klass); static void sp_group_init (SPGroup *group); @@ -56,6 +60,7 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value); static void sp_group_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags); static void sp_group_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_group_description (SPItem * item); +static NR::Matrix sp_group_set_transform(SPItem *item, NR::Matrix const &xform); static NRArenaItem *sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_group_hide (SPItem * item, unsigned int key); static void sp_group_snappoints (SPItem const *item, SnapPointsIter p); @@ -112,6 +117,7 @@ sp_group_class_init (SPGroupClass *klass) item_class->bbox = sp_group_bbox; item_class->print = sp_group_print; item_class->description = sp_group_description; + item_class->set_transform = sp_group_set_transform; item_class->show = sp_group_show; item_class->hide = sp_group_hide; item_class->snappoints = sp_group_snappoints; @@ -264,6 +270,26 @@ static gchar * sp_group_description (SPItem * item) return SP_GROUP(item)->group->getDescription(); } +static NR::Matrix +sp_group_set_transform(SPItem *item, NR::Matrix const &xform) +{ + SPGroup *group = SP_GROUP(item); + + Inkscape::Selection *selection = sp_desktop_selection(inkscape_active_desktop()); + persp3d_split_perspectives_according_to_selection(selection); + + NR::Matrix last_trans; + sp_svg_transform_read(SP_OBJECT_REPR(item)->attribute("transform"), &last_trans); + NR::Matrix inc_trans = last_trans.inverse()*xform; + + std::list plist = selection->perspList(); + for (std::list::iterator i = plist.begin(); i != plist.end(); ++i) { + persp3d_apply_affine_transformation(*i, inc_trans); + } + + return xform; +} + static void sp_group_set(SPObject *object, unsigned key, char const *value) { SPGroup *group=SP_GROUP(object); diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 8ac019cb7..5718c6cf2 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -2614,12 +2614,12 @@ box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis ax g_object_set_data(dataKludge, "freeze_angle", GINT_TO_POINTER(TRUE)); //Persp3D *persp = document->current_persp3d; - std::set sel_persps = persp3d_currently_selected_persps(); + std::list sel_persps = sp_desktop_selection(desktop)->perspList(); if (sel_persps.empty()) { // this can happen when the document is created; we silently ignore it return; } - Persp3D *persp = *(sel_persps.begin()); + Persp3D *persp = sel_persps.front(); persp->tmat.set_infinite_direction (axis, adj->value); SP_OBJECT(persp)->updateRepr(); @@ -2653,12 +2653,12 @@ box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge) static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction */*box3d_angle*/, Proj::Axis axis ) { // TODO: Take all selected perspectives into account - std::set sel_persps = persp3d_currently_selected_persps(); + std::list sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList(); if (sel_persps.empty()) { // this can happen when the document is created; we silently ignore it return; } - Persp3D *persp = *(sel_persps.begin()); + Persp3D *persp = sel_persps.front(); bool set_infinite = gtk_toggle_action_get_active(act); persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);