Code

Make grouped 3D boxes work correctly when transformed (fixes: LP 188991)
authorcilix42 <cilix42@users.sourceforge.net>
Wed, 19 Mar 2008 10:37:50 +0000 (10:37 +0000)
committercilix42 <cilix42@users.sourceforge.net>
Wed, 19 Mar 2008 10:37:50 +0000 (10:37 +0000)
12 files changed:
src/box3d-context.cpp
src/box3d-side.cpp
src/box3d.cpp
src/box3d.h
src/document.h
src/object-edit.cpp
src/persp3d.cpp
src/persp3d.h
src/selection.cpp
src/selection.h
src/sp-item-group.cpp
src/widgets/toolbox.cpp

index 9ee920c1b21ab5c26823b75b1d60791798489a7d..7414fcd770e406977c1b858096008c7649023c35 100644 (file)
@@ -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;
             }
index c20b7a8646f2172603aba0cb15463a2daa6771c6..4cd3765c90967aeda7cbb4adf28988a263ccf7b4 100644 (file)
@@ -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<Proj::Pt3> 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<Proj::Pt3> 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<Proj::Pt3>
-box3d_side_corners (Box3DSide *side) {
-    std::vector<Proj::Pt3> 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 *
index 5beee4accab9e3fb439ddb846bdadb88c99ea5fd..f5745210171ed19dc8d9c940177817d4b7f51559 100644 (file)
@@ -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<SPBox3D *> sel = persp3d_selected_boxes (persp);
+        std::list<SPBox3D *> 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<SPBox3D *>::iterator b = sel.begin(); b != sel.end(); ++b) {
+        for (std::list<SPBox3D *>::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<SPBox3D *> &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<SPBox3D *>
+box3d_extract_boxes(SPObject *obj) {
+    std::list<SPBox3D *> 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<std::pair<Geom::Point, Geom::Point> > &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
index d9fd540b68d9217087a11b6c89678f44a9032fb6..bc88e6257931375ae667bf50abd4fe96c7ba0ee9 100644 (file)
@@ -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<SPBox3D *> 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);
 
index 8a4e65bb373fe57541f868a79aca6c9aafcf1838..b0d6afecb1be9b8dafce41b7afe1c778ac4af2be 100644 (file)
@@ -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<Persp3D *> persps_sel; // perspectives associated to currently selected boxes
 
     void add_persp3d (Persp3D * const persp);
     void remove_persp3d (Persp3D * const persp);
index da5672ca261de302afa06c558f0e90eb575d2b7a..b3d661586a2b08b2f2e012052f8779e6706bb1e7 100644 (file)
@@ -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)
index e5cade661d151f3efb1c12e6417fdc221ca529ab..e647af6987499fd793c039b99d3e13cf51cfa0de 100644 (file)
@@ -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<Persp3D *> p, Proj::Axis axis) {
-    for (std::set<Persp3D *>::iterator i = p.begin(); i != p.end(); ++i) {
+persp3d_toggle_VPs (std::list<Persp3D *> p, Proj::Axis axis) {
+    for (std::list<Persp3D *>::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 *>
-persp3d_currently_selected_persps () {
-    Inkscape::Selection *selection = sp_desktop_selection(inkscape_active_desktop());
-
-    std::set<Persp3D *> 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<SPBox3D *> selboxes = sp_desktop_selection(inkscape_active_desktop())->box3DList();
 
     for (std::vector<SPBox3D *>::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<SPBox3D *>
-persp3d_selected_boxes (Persp3D *persp) {
-    const GSList *selection = sp_desktop_selection (inkscape_active_desktop())->itemList();
-    std::list<SPBox3D *> sel;
+// TODO: Check where we can use pass-by-reference (or so) instead of recreating all the lists afresh.
+std::map<Persp3D *, std::list<SPBox3D *> >
+persp3d_unselected_boxes(Inkscape::Selection *selection) {
+    std::list<Persp3D *> plist = selection->perspList();
+    std::map<Persp3D *, std::list<SPBox3D *> > punsel;
+
+    std::list<Persp3D *>::iterator i;
+    std::vector<SPBox3D *>::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<SPBox3D *>::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<Persp3D *, std::list<SPBox3D *> > punsel = persp3d_unselected_boxes(selection);
+
+    std::map<Persp3D *, std::list<SPBox3D *> >::iterator i;
+    std::list<SPBox3D *>::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<Persp3D *> sel_persps = persp3d_currently_selected_persps();
+    std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList();
 
-    for (std::set<Persp3D *>::iterator j = sel_persps.begin(); j != sel_persps.end(); ++j) {
+    for (std::list<Persp3D *>::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<SPBox3D *, bool>::iterator i = persp->boxes_transformed.begin();
index 4819a52e997073aa29131d4a76b69310dbb3bc35..271b42459fd971caf6874b96a965a37b0c17f598 100644 (file)
@@ -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 <set>
+#include <list>
 #include <vector>
 #include <map>
 #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<Persp3D *>, Proj::Axis axis);
+void persp3d_toggle_VPs (std::list<Persp3D *>, 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 *> persp3d_currently_selected_persps();
 bool persp3d_has_all_boxes_in_selection (Persp3D *persp);
-std::list<SPBox3D *> persp3d_selected_boxes (Persp3D *persp);
+std::map<Persp3D *, std::list<SPBox3D *> > 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);
index d3b667a128a0e76cdd5650ed276898bc41af71ba..41540c95c99b982333230c8fbafd614b8da70113 100644 (file)
@@ -30,6 +30,8 @@
 #include "sp-path.h"
 #include "sp-item-group.h"
 #include "box3d.h"
+#include "box3d.h"
+#include "persp3d.h"
 
 #include <sigc++/functors/mem_fun.h>
 
@@ -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<Persp3D *, unsigned int>::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<SPBox3D *> boxes = box3d_extract_boxes(obj);
+
+    for (std::list<SPBox3D *>::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<Persp3D *, unsigned int>::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<SPBox3D *> boxes = box3d_extract_boxes(obj);
+
+    for (std::list<SPBox3D *>::iterator i = boxes.begin(); i != boxes.end(); ++i) {
+        SPBox3D *box = *i;
+        box3d_remove_from_selection(box);
+        std::list<SPBox3D *>::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<Persp3D *> const Selection::perspList() {
+    std::list<Persp3D *> pl;
+    for (std::map<Persp3D *, unsigned int>::iterator p = _persps.begin(); p != _persps.end(); ++p) {
+        pl.push_back((*p).first);
+    }
+    return pl;
+}
+
+std::list<SPBox3D *> const Selection::box3DList() {
+    return _3dboxes;
+}
+
 SPObject *Selection::single() {
     if ( _objs != NULL && _objs->next == NULL ) {
         return reinterpret_cast<SPObject *>(_objs->data);
index 58204160b7de9e1972728912f3f4e27c7a4670bc..3d45c171d95021093c98eba4aef4c098a1f61777 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <vector>
 #include <map>
+#include <list>
 #include <sigc++/sigc++.h>
 
 #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<Persp3D *> const perspList();
+
+    std::list<SPBox3D *> 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<Persp3D *, unsigned int> _persps;
+    std::list<SPBox3D *> _3dboxes;
+
     GC::soft_ptr<SPDesktop> _desktop;
     SPObject* _selection_context;
     guint _flags;
index 5ae5713ca429fcac4a87b29ba05b02fc77ca38bf..7969c1bc106c5e66168c77ab89473c6d8bf5b66d 100644 (file)
 #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<Persp3D *> plist = selection->perspList();
+    for (std::list<Persp3D *>::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);
 
index 8ac019cb7921b5b829de8ec2d1ec215ec7f10828..5718c6cf272ea16188d2f51e4dbb5c7c3b6030c3 100644 (file)
@@ -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<Persp3D *> sel_persps = persp3d_currently_selected_persps();
+    std::list<Persp3D *> 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<Persp3D *> sel_persps = persp3d_currently_selected_persps();
+    std::list<Persp3D *> 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);