Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / persp3d.cpp
index 27701c80deff7fd642a531997ba4f10881238b5e..74208444b04418be0e1b862fffad32cb71c8f6d0 100644 (file)
@@ -1,10 +1,10 @@
-#define __PERSP3D_C__
-
 /*
  * Class modelling a 3D perspective as an SPObject
  *
  * Authors:
  *   Maximilian Albert <Anhalter42@gmx.de>
+ *   Jon A. Cruz <jon@joncruz.org>
+ *   Abhishek Sharma
  *
  * Copyright (C) 2007 authors
  *
 #include "desktop-handles.h"
 #include <glibmm/i18n.h>
 
+using Inkscape::DocumentUndo;
+
 static void persp3d_class_init(Persp3DClass *klass);
-static void persp3d_init(Persp3D *stop);
+static void persp3d_init(Persp3D *persp);
 
 static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
 static void persp3d_release(SPObject *object);
 static void persp3d_set(SPObject *object, unsigned key, gchar const *value);
 static void persp3d_update(SPObject *object, SPCtx *ctx, guint flags);
-static Inkscape::XML::Node *persp3d_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+static Inkscape::XML::Node *persp3d_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 
 static void persp3d_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
 
+static void persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj::Pt2 const &new_image);
+static gchar * persp3d_pt_to_str (Persp3DImpl *persp_impl, Proj::Axis const axis);
+
 static SPObjectClass *persp3d_parent_class;
 
 static int global_counter = 0;
 
+/* Constructor/destructor for the internal class */
+
+Persp3DImpl::Persp3DImpl() {
+    tmat = Proj::TransfMat3x4 ();
+    document = NULL;
+
+    my_counter = global_counter++;
+}
+
 /**
  * Registers Persp3d class and returns its type.
  */
@@ -91,13 +105,7 @@ static void persp3d_class_init(Persp3DClass *klass)
 static void
 persp3d_init(Persp3D *persp)
 {
-    persp->tmat = Proj::TransfMat3x4 ();
-
-    //persp->boxes = NULL;
-    persp->boxes_transformed.clear();
-    persp->document = NULL;
-
-    persp->my_counter = global_counter++;
+    persp->perspective_impl = new Persp3DImpl();
 }
 
 /**
@@ -110,35 +118,23 @@ static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML:
 
     /* calls sp_object_set for the respective attributes */
     // The transformation matrix is updated according to the values we read for the VPs
-    sp_object_read_attr(object, "inkscape:vp_x");
-    sp_object_read_attr(object, "inkscape:vp_y");
-    sp_object_read_attr(object, "inkscape:vp_z");
-    sp_object_read_attr(object, "inkscape:persp3d-origin");
+    object->readAttr( "inkscape:vp_x" );
+    object->readAttr( "inkscape:vp_y" );
+    object->readAttr( "inkscape:vp_z" );
+    object->readAttr( "inkscape:persp3d-origin" );
 
     if (repr) {
         repr->addListener (&persp3d_repr_events, object);
     }
-
-    // FIXME: What precisely does this do and is it necessary for perspectives?
-    /* Register ourselves */
-    //sp_document_add_resource(document, "persp3d", object);
 }
 
 /**
  * Virtual release of Persp3D members before destruction.
  */
 static void persp3d_release(SPObject *object) {
-    //Persp3D *persp = (Persp3D *) object;
-
+    Persp3D *persp = SP_PERSP3D(object);
+    delete persp->perspective_impl;
     SP_OBJECT_REPR(object)->removeListenerByData(object);
-
-    // FIXME: What precisely does this do and is it necessary for perspectives?
-    /**
-    if (SP_OBJECT_DOCUMENT(object)) {
-        // Unregister ourselves
-        sp_document_remove_resource(SP_OBJECT_DOCUMENT(object), "persp3d", SP_OBJECT(object));
-    }
-    **/
 }
 
 
@@ -150,34 +146,34 @@ static void persp3d_release(SPObject *object) {
 static void
 persp3d_set(SPObject *object, unsigned key, gchar const *value)
 {
-    Persp3D *persp = SP_PERSP3D (object);
+    Persp3DImpl *persp_impl = SP_PERSP3D(object)->perspective_impl;
 
     switch (key) {
         case SP_ATTR_INKSCAPE_PERSP3D_VP_X: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::X, new_image);
+                persp3d_update_with_point (persp_impl, Proj::X, new_image);
             }
             break;
         }
         case SP_ATTR_INKSCAPE_PERSP3D_VP_Y: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::Y, new_image);
+                persp3d_update_with_point (persp_impl, Proj::Y, new_image);
                 break;
             }
         }
         case SP_ATTR_INKSCAPE_PERSP3D_VP_Z: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::Z, new_image);
+                persp3d_update_with_point (persp_impl, Proj::Z, new_image);
                 break;
             }
         }
         case SP_ATTR_INKSCAPE_PERSP3D_ORIGIN: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::W, new_image);
+                persp3d_update_with_point (persp_impl, Proj::W, new_image);
                 break;
             }
         }
@@ -202,7 +198,7 @@ persp3d_set(SPObject *object, unsigned key, gchar const *value)
 static void
 persp3d_update(SPObject *object, SPCtx *ctx, guint flags)
 {
-    if (flags & SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG) {
+    if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
 
         /* TODO: Should we update anything here? */
 
@@ -212,124 +208,156 @@ persp3d_update(SPObject *object, SPCtx *ctx, guint flags)
         ((SPObjectClass *) persp3d_parent_class)->update(object, ctx, flags);
 }
 
-Persp3D *
-persp3d_create_xml_element (SPDocument *document, Persp3D *dup) {// if dup is given, copy the attributes over
+Persp3D *persp3d_create_xml_element(SPDocument *document, Persp3DImpl *dup) {// if dup is given, copy the attributes over
     SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
-    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
+    Inkscape::XML::Document *xml_doc = document->getReprDoc();
     Inkscape::XML::Node *repr;
+
+    /* if no perspective is given, create a default one */
+    repr = xml_doc->createElement("inkscape:perspective");
+    repr->setAttribute("sodipodi:type", "inkscape:persp3d");
+
+    Proj::Pt2 proj_vp_x = Proj::Pt2 (0.0, document->getHeight()/2, 1.0);
+    Proj::Pt2 proj_vp_y = Proj::Pt2 (0.0, 1000.0, 0.0);
+    Proj::Pt2 proj_vp_z = Proj::Pt2 (document->getWidth(), document->getHeight()/2, 1.0);
+    Proj::Pt2 proj_origin = Proj::Pt2 (document->getWidth()/2, document->getHeight()/3, 1.0);
+
     if (dup) {
-        repr = SP_OBJECT_REPR(dup)->duplicate (xml_doc);
-    } else {
-        repr = xml_doc->createElement("inkscape:perspective");
-        repr->setAttribute("sodipodi:type", "inkscape:persp3d");
-    }
+        proj_vp_x = dup->tmat.column (Proj::X);
+        proj_vp_y = dup->tmat.column (Proj::Y);
+        proj_vp_z = dup->tmat.column (Proj::Z);
+        proj_origin = dup->tmat.column (Proj::W);
+    }
+
+    gchar *str = NULL;
+    str = proj_vp_x.coord_string();
+    repr->setAttribute("inkscape:vp_x", str);
+    g_free (str);
+    str = proj_vp_y.coord_string();
+    repr->setAttribute("inkscape:vp_y", str);
+    g_free (str);
+    str = proj_vp_z.coord_string();
+    repr->setAttribute("inkscape:vp_z", str);
+    g_free (str);
+    str = proj_origin.coord_string();
+    repr->setAttribute("inkscape:persp3d-origin", str);
+    g_free (str);
 
     /* Append the new persp3d to defs */
     SP_OBJECT_REPR(defs)->addChild(repr, NULL);
     Inkscape::GC::release(repr);
 
-    return (Persp3D *) sp_object_get_child_by_repr (SP_OBJECT(defs), repr);
+    return (Persp3D *) SP_OBJECT(defs)->get_child_by_repr (repr);
+}
+
+Persp3D *persp3d_document_first_persp(SPDocument *document)
+{
+    Persp3D *first = 0;
+    for ( SPObject *child = SP_DOCUMENT_DEFS(document)->firstChild(); child && !first; child = child->getNext() ) {
+        if (SP_IS_PERSP3D(child)) {
+            first = SP_PERSP3D(child);
+        }
+    }
+    return first;
 }
 
 /**
  * Virtual write: write object attributes to repr.
  */
 static Inkscape::XML::Node *
-persp3d_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+persp3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
-    Persp3D *persp = SP_PERSP3D(object);
+    Persp3DImpl *persp_impl = SP_PERSP3D(object)->perspective_impl;
 
-    if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
+    if ((flags & SP_OBJECT_WRITE_BUILD & SP_OBJECT_WRITE_EXT) && !repr) {
         // this is where we end up when saving as plain SVG (also in other circumstances?);
         // hence we don't set the sodipodi:type attribute
-        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
         repr = xml_doc->createElement("inkscape:perspective");
     }
 
     if (flags & SP_OBJECT_WRITE_EXT) {
         gchar *str = NULL; // FIXME: Should this be freed each time we set an attribute or only in the end or at all?
-        str = persp3d_pt_to_str (persp, Proj::X);
+        str = persp3d_pt_to_str (persp_impl, Proj::X);
         repr->setAttribute("inkscape:vp_x", str);
 
-        str = persp3d_pt_to_str (persp, Proj::Y);
+        str = persp3d_pt_to_str (persp_impl, Proj::Y);
         repr->setAttribute("inkscape:vp_y", str);
 
-        str = persp3d_pt_to_str (persp, Proj::Z);
+        str = persp3d_pt_to_str (persp_impl, Proj::Z);
         repr->setAttribute("inkscape:vp_z", str);
 
-        str = persp3d_pt_to_str (persp, Proj::W);
+        str = persp3d_pt_to_str (persp_impl, Proj::W);
         repr->setAttribute("inkscape:persp3d-origin", str);
     }
 
     if (((SPObjectClass *) persp3d_parent_class)->write)
-        (* ((SPObjectClass *) persp3d_parent_class)->write)(object, repr, flags);
+        (* ((SPObjectClass *) persp3d_parent_class)->write)(object, xml_doc, repr, flags);
 
     return repr;
 }
 
 /* convenience wrapper around persp3d_get_finite_dir() and persp3d_get_infinite_dir() */
-NR::Point persp3d_get_PL_dir_from_pt (Persp3D *persp, NR::Point const &pt, Proj::Axis axis) {
-    if (persp3d_VP_is_finite(persp, axis)) {
+Geom::Point persp3d_get_PL_dir_from_pt (Persp3D *persp, Geom::Point const &pt, Proj::Axis axis) {
+    if (persp3d_VP_is_finite(persp->perspective_impl, axis)) {
         return persp3d_get_finite_dir(persp, pt, axis);
     } else {
         return persp3d_get_infinite_dir(persp, axis);
     }
 }
 
-NR::Point
-persp3d_get_finite_dir (Persp3D *persp, NR::Point const &pt, Proj::Axis axis) {
+Geom::Point
+persp3d_get_finite_dir (Persp3D *persp, Geom::Point const &pt, Proj::Axis axis) {
     Box3D::PerspectiveLine pl(pt, axis, persp);
     return pl.direction();
 }
 
-NR::Point
+Geom::Point
 persp3d_get_infinite_dir (Persp3D *persp, Proj::Axis axis) {
     Proj::Pt2 vp(persp3d_get_VP(persp, axis));
     if (vp[2] != 0.0) {
         g_print ("VP should be infinite but is (%f : %f : %f)\n", vp[0], vp[1], vp[2]);
-        g_return_val_if_fail(vp[2] != 0.0, NR::Point(0.0, 0.0));
+        g_return_val_if_fail(vp[2] != 0.0, Geom::Point(0.0, 0.0));
     }
-    return NR::Point(vp[0], vp[1]);
+    return Geom::Point(vp[0], vp[1]);
 }
 
 double
 persp3d_get_infinite_angle (Persp3D *persp, Proj::Axis axis) {
-    return persp->tmat.get_infinite_angle(axis);
+    return persp->perspective_impl->tmat.get_infinite_angle(axis);
 }
 
 bool
-persp3d_VP_is_finite (Persp3D *persp, Proj::Axis axis) {
-    return persp->tmat.has_finite_image(axis);
+persp3d_VP_is_finite (Persp3DImpl *persp_impl, Proj::Axis axis) {
+    return persp_impl->tmat.has_finite_image(axis);
 }
 
 void
 persp3d_toggle_VP (Persp3D *persp, Proj::Axis axis, bool set_undo) {
-    persp->tmat.toggle_finite(axis);
+    persp->perspective_impl->tmat.toggle_finite(axis);
     // FIXME: Remove this repr update and rely on vp_drag_sel_modified() to do this for us
     //        On the other hand, vp_drag_sel_modified() would update all boxes;
     //        here we can confine ourselves to the boxes of this particular perspective.
     persp3d_update_box_reprs (persp);
-    persp3d_update_z_orders (persp);
     SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT);
     if (set_undo) {
-        sp_document_done(sp_desktop_document(inkscape_active_desktop()), SP_VERB_CONTEXT_3DBOX,
-                         _("Toggle vanishing point"));
+        DocumentUndo::done(sp_desktop_document(inkscape_active_desktop()), SP_VERB_CONTEXT_3DBOX,
+                           _("Toggle vanishing point"));
     }
 }
 
 /* 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,
-                     _("Toggle multiple vanishing points"));
+    DocumentUndo::done(sp_desktop_document(inkscape_active_desktop()), SP_VERB_CONTEXT_3DBOX,
+                       _("Toggle multiple vanishing points"));
 }
 
 void
 persp3d_set_VP_state (Persp3D *persp, Proj::Axis axis, Proj::VPState state) {
-    if (persp3d_VP_is_finite(persp, axis) != (state == Proj::VP_FINITE)) {
+    if (persp3d_VP_is_finite(persp->perspective_impl, axis) != (state == Proj::VP_FINITE)) {
         persp3d_toggle_VP(persp, axis);
     }
 }
@@ -337,66 +365,67 @@ 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
     // FIXME: Most of this functionality should be moved to trans_mat_3x4.(h|cpp)
-    if (persp->tmat.has_finite_image(axis)) {
+    if (persp->perspective_impl->tmat.has_finite_image(axis)) {
         // don't rotate anything for finite VPs
         return;
     }
-    Proj::Pt2 v_dir_proj (persp->tmat.column(axis));
-    NR::Point v_dir (v_dir_proj[0], v_dir_proj[1]);
-    double a = NR::atan2 (v_dir) * 180/M_PI;
+    Proj::Pt2 v_dir_proj (persp->perspective_impl->tmat.column(axis));
+    Geom::Point v_dir (v_dir_proj[0], v_dir_proj[1]);
+    double a = Geom::atan2 (v_dir) * 180/M_PI;
     a += alt_pressed ? 0.5 * ((angle > 0 ) - (angle < 0)) : angle; // the r.h.s. yields +/-0.5 or angle
-    persp->tmat.set_infinite_direction (axis, a);
+    persp->perspective_impl->tmat.set_infinite_direction (axis, a);
 
     persp3d_update_box_reprs (persp);
-    persp3d_update_z_orders (persp);
     SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT);
 }
 
 void
-persp3d_update_with_point (Persp3D *persp, Proj::Axis const axis, Proj::Pt2 const &new_image) {
-    persp->tmat.set_image_pt (axis, new_image);
+persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj::Pt2 const &new_image) {
+    persp_impl->tmat.set_image_pt (axis, new_image);
 }
 
 void
-persp3d_apply_affine_transformation (Persp3D *persp, NR::Matrix const &xform) {
-    persp->tmat *= xform;
+persp3d_apply_affine_transformation (Persp3D *persp, Geom::Matrix const &xform) {
+    persp->perspective_impl->tmat *= xform;
     persp3d_update_box_reprs(persp);
     SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT);
 }
 
 gchar *
-persp3d_pt_to_str (Persp3D *persp, Proj::Axis const axis)
+persp3d_pt_to_str (Persp3DImpl *persp_impl, Proj::Axis const axis)
 {
-    return persp->tmat.pt_to_str(axis);
+    return persp_impl->tmat.pt_to_str(axis);
 }
 
 void
 persp3d_add_box (Persp3D *persp, SPBox3D *box) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
     if (!box) {
-        //g_warning ("Trying to add NULL box to perspective.\n");
         return;
     }
-    if (std::find (persp->boxes.begin(), persp->boxes.end(), box) != persp->boxes.end()) {
-        //g_warning ("Attempting to add already existent box to perspective.\n");
+    if (std::find (persp_impl->boxes.begin(), persp_impl->boxes.end(), box) != persp_impl->boxes.end()) {
         return;
     }
-    persp->boxes.push_back(box);
-    //SP_OBJECT_REPR(box)->setAttribute("inkscape:perspectiveID", SP_OBJECT_REPR(persp)->attribute("id"));
+    persp_impl->boxes.push_back(box);
 }
 
 void
 persp3d_remove_box (Persp3D *persp, SPBox3D *box) {
-    std::vector<SPBox3D *>::iterator i = std::find (persp->boxes.begin(), persp->boxes.end(), box);
-    if (i != persp->boxes.end()) {
-        persp->boxes.erase(i);
-    }
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
+    std::vector<SPBox3D *>::iterator i = std::find (persp_impl->boxes.begin(), persp_impl->boxes.end(), box);
+    if (i != persp_impl->boxes.end())
+        persp_impl->boxes.erase(i);
 }
 
 bool
 persp3d_has_box (Persp3D *persp, SPBox3D *box) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
     // FIXME: For some reason, std::find() does not seem to compare pointers "correctly" (or do we need to
     //        provide a proper comparison function?), so we manually traverse the list.
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         if ((*i) == box) {
             return true;
         }
@@ -405,97 +434,39 @@ persp3d_has_box (Persp3D *persp, SPBox3D *box) {
 }
 
 void
-persp3d_add_box_transform (Persp3D *persp, SPBox3D *box) {
-    std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed.find(box);
-    if (i != persp->boxes_transformed.end() && (*i).second == true) {
-        g_print ("Warning! In %s (%d): trying to add transform status for box %d twice when it's already listed as true.\n", SP_OBJECT_REPR(persp)->attribute("id"), persp->my_counter, box->my_counter);
-        return;
-    }
-    persp->boxes_transformed[box] = false;
-}
-
-void
-persp3d_remove_box_transform (Persp3D *persp, SPBox3D *box) {
-    persp->boxes_transformed.erase(box);
-}
+persp3d_update_box_displays (Persp3D *persp) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
 
-void
-persp3d_set_box_transformed (Persp3D *persp, SPBox3D *box, bool transformed) {
-    if (persp->boxes_transformed.find(box) == persp->boxes_transformed.end()) {
-        g_print ("Warning! In %s (%d): trying to set transform status for box %d, but it is not listed in the perspective!! Aborting.\n",
-                 SP_OBJECT_REPR(persp)->attribute("id"), persp->my_counter,
-                 box->my_counter);
+    if (persp_impl->boxes.empty())
         return;
-    }
-
-    persp->boxes_transformed[box] = transformed;
-}
-
-bool
-persp3d_was_transformed (Persp3D *persp) {
-    if (persp->boxes_transformed.size() == 1) {
-        /* either the transform has not been applied to the single box associated to this perspective yet
-           or the transform was already reset; in both cases we need to return false because upcoming
-           transforms need to be applied */
-        (*persp->boxes_transformed.begin()).second = false; // make sure the box is marked as untransformed (in case more boxes are added later)
-        return false;
-    }
-
-    for (std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed.begin();
-         i != persp->boxes_transformed.end(); ++i) {
-        if ((*i).second == true) {
-            // at least one of the boxes in the perspective has already been transformed;
-            return true;
-        }
-    }
-    return false; // all boxes in the perspective are still untransformed; a pending transformation should be applied
-}
-
-bool
-persp3d_all_transformed(Persp3D *persp) {
-    for (std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed.begin();
-         i != persp->boxes_transformed.end(); ++i) {
-        if ((*i).second == false) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void
-persp3d_unset_transforms(Persp3D *persp) {
-    for (std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed.begin();
-         i != persp->boxes_transformed.end(); ++i) {
-        (*i).second = false;
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
+        box3d_position_set(*i);
     }
 }
 
 void
-persp3d_update_box_displays (Persp3D *persp) {
-    if (persp->boxes.empty())
+persp3d_update_box_reprs (Persp3D *persp) {
+    if (!persp) {
+        // Hmm, is it an error if this happens?
         return;
-    //g_print ("Requesting display update for %d boxes in the perspective.\n", persp->boxes.size());
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
-        box3d_position_set(*i);
     }
-}
+    Persp3DImpl *persp_impl = persp->perspective_impl;
 
-void
-persp3d_update_box_reprs (Persp3D *persp) {
-    if (persp->boxes.empty())
+    if (persp_impl->boxes.empty())
         return;
-    //g_print ("Requesting repr update for %d boxes in the perspective.\n", persp->boxes.size());
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         SP_OBJECT(*i)->updateRepr(SP_OBJECT_WRITE_EXT);
+        box3d_set_z_orders(*i);
     }
 }
 
 void
 persp3d_update_z_orders (Persp3D *persp) {
-    if (persp->boxes.empty())
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
+    if (persp_impl->boxes.empty())
         return;
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         box3d_set_z_orders(*i);
     }
 }
@@ -505,8 +476,10 @@ persp3d_update_z_orders (Persp3D *persp) {
 //        obsolete. We should do this.
 std::list<SPBox3D *>
 persp3d_list_of_boxes(Persp3D *persp) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
     std::list<SPBox3D *> bx_lst;
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         bx_lst.push_back(*i);
     }
     return bx_lst;
@@ -515,7 +488,7 @@ persp3d_list_of_boxes(Persp3D *persp) {
 bool
 persp3d_perspectives_coincide(const Persp3D *lhs, const Persp3D *rhs)
 {
-    return lhs->tmat == rhs->tmat;
+    return lhs->perspective_impl->tmat == rhs->perspective_impl->tmat;
 }
 
 void
@@ -543,38 +516,22 @@ persp3d_on_repr_attr_changed ( Inkscape::XML::Node * /*repr*/,
                                bool /*is_interactive*/,
                                void * data )
 {
-    //g_print("persp3d_on_repr_attr_changed!!!! TODO: Do we need to trigger any further updates than the box reprs?");
-
     if (!data)
         return;
 
     Persp3D *persp = (Persp3D*) data;
     persp3d_update_box_displays (persp);
-
-    //lpeobj->requestModified(SP_OBJECT_MODIFIED_FLAG);
-}
-
-/* returns a std::set() of all perspectives of the currently selected boxes */
-std::set<Persp3D *>
-persp3d_currently_selected_persps (SPEventContext *ec) {
-    Inkscape::Selection *selection = sp_desktop_selection (ec->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();
+persp3d_has_all_boxes_in_selection (Persp3D *persp, Inkscape::Selection *selection) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
+    std::list<SPBox3D *> selboxes = selection->box3DList();
 
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
-        if (g_slist_find((GSList *) selection, *i) == NULL) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
+        if (std::find(selboxes.begin(), selboxes.end(), *i) == selboxes.end()) {
             // we have an unselected box in the perspective
             return false;
         }
@@ -582,22 +539,12 @@ 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;
-
-    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));
-        }
-    }
-    return sel;
-}
+/* some debugging stuff follows */
 
 void
 persp3d_print_debugging_info (Persp3D *persp) {
-    g_print ("=== Info for Persp3D %d ===\n", persp->my_counter);
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+    g_print ("=== Info for Persp3D %d ===\n", persp_impl->my_counter);
     gchar * cstr;
     for (int i = 0; i < 4; ++i) {
         cstr = persp3d_get_VP(persp, Proj::axes[i]).coord_string();
@@ -609,19 +556,16 @@ persp3d_print_debugging_info (Persp3D *persp) {
     g_free(cstr);
 
     g_print ("  Boxes: ");
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
-        g_print ("%d (%d)  ", (*i)->my_counter, box3d_get_perspective(*i)->my_counter);
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
+        g_print ("%d (%d)  ", (*i)->my_counter, box3d_get_perspective(*i)->perspective_impl->my_counter);
     }
     g_print ("\n");
     g_print ("========================\n");
 }
 
-void
-persp3d_print_debugging_info_all(SPDocument *document) {
-    SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
-    Inkscape::XML::Node *repr;
-    for (SPObject *child = sp_object_first_child(defs); child != NULL; child = SP_OBJECT_NEXT(child) ) {
-        repr = SP_OBJECT_REPR(child);
+void persp3d_print_debugging_info_all(SPDocument *document)
+{
+    for ( SPObject *child = SP_DOCUMENT_DEFS(document)->firstChild(); child; child = child->getNext() ) {
         if (SP_IS_PERSP3D(child)) {
             persp3d_print_debugging_info(SP_PERSP3D(child));
         }
@@ -631,29 +575,30 @@ persp3d_print_debugging_info_all(SPDocument *document) {
 
 void
 persp3d_print_all_selected() {
-    /**
-    if (persp3d->boxes_transformed.empty()) {
-        g_print ("No selected perspectives in document\n");
-        return;
-    }
-    **/
     g_print ("\n======================================\n");
     g_print ("Selected perspectives and their boxes:\n");
 
-    std::set<Persp3D *> sel_persps = persp3d_currently_selected_persps (inkscape_active_event_context());
+    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();
-             i != persp->boxes_transformed.end(); ++i) {
-            g_print ("<%d,%d> ", (*i).first->my_counter, (*i).second);
+        Persp3DImpl *persp_impl = persp->perspective_impl;
+        g_print ("  %s (%d):  ", SP_OBJECT_REPR(persp)->attribute("id"), persp->perspective_impl->my_counter);
+        for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin();
+             i != persp_impl->boxes.end(); ++i) {
+            g_print ("%d ", (*i)->my_counter);
         }
         g_print ("\n");
     }
     g_print ("======================================\n\n");
  }
 
+void print_current_persp3d(gchar *func_name, Persp3D *persp) {
+    g_print ("%s: current_persp3d is now %s\n",
+             func_name,
+             persp ? SP_OBJECT_REPR(persp)->attribute("id") : "NULL");
+}
+
 /*
   Local Variables:
   mode:c++
@@ -663,4 +608,4 @@ persp3d_print_all_selected() {
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :