Code

(Un-)Snapping of VPs by Shift-dragging; this makes it possible to separate perspectiv...
[inkscape.git] / src / perspective3d.cpp
index dd05ec7c7cef6ca7563e75782a2a78ce25200908..2137449373735c8a62dfec0f67fb6b95b37692f1 100644 (file)
@@ -38,6 +38,23 @@ get_persp_of_box (const SP3DBox *box)
     g_assert_not_reached();
 }
 
+Perspective3D *
+get_persp_of_VP (const VanishingPoint *vp)
+{
+    Perspective3D *persp;
+    for (GSList *p = Perspective3D::perspectives; p != NULL; p = p->next) {
+        persp = (Perspective3D *) p->data;
+        // we compare the pointers, not the position/state of the VPs; is this correct?
+        if (persp->get_vanishing_point (Box3D::X) == vp ||
+            persp->get_vanishing_point (Box3D::Y) == vp ||
+            persp->get_vanishing_point (Box3D::Z) == vp)
+            return persp;
+    }
+
+    g_warning ("Stray vanishing point!\n");
+    g_assert_not_reached();
+}
+
 /**
  * Computes the intersection of the two perspective lines from pt1 and pt2 to the respective
  * vanishing points in the given directions.
@@ -88,6 +105,37 @@ Perspective3D::~Perspective3D ()
 {
     Perspective3D::remove_perspective (this);
 
+    // Remove the VPs from their draggers
+    SPEventContext *ec = inkscape_active_event_context();
+    if (SP_IS_3DBOX_CONTEXT (ec)) {
+        SP3DBoxContext *bc = SP_3DBOX_CONTEXT (ec);
+        // we need to check if there are any draggers because the selection
+        // is temporarily empty during duplication of boxes, e.g.
+        if (bc->_vpdrag->draggers != NULL) {
+            /***
+            g_assert (bc->_vpdrag->getDraggerFor (*vp_x) != NULL);
+            g_assert (bc->_vpdrag->getDraggerFor (*vp_y) != NULL);
+            g_assert (bc->_vpdrag->getDraggerFor (*vp_z) != NULL);
+            bc->_vpdrag->getDraggerFor (*vp_x)->removeVP (vp_x);
+            bc->_vpdrag->getDraggerFor (*vp_y)->removeVP (vp_y);
+            bc->_vpdrag->getDraggerFor (*vp_z)->removeVP (vp_z);
+            ***/
+            // TODO: the temporary perspective created when building boxes is not linked to any dragger, hence
+            //       we need to do the following checks. Maybe it would be better to not create a temporary
+            //       perspective at all but simply compare the VPs manually in sp_3dbox_build.
+            VPDragger * dragger;
+            dragger = bc->_vpdrag->getDraggerFor (*vp_x);
+            if (dragger)
+                dragger->removeVP (vp_x);
+            dragger = bc->_vpdrag->getDraggerFor (*vp_y);
+            if (dragger)
+                dragger->removeVP (vp_y);
+            dragger = bc->_vpdrag->getDraggerFor (*vp_z);
+            if (dragger)
+                dragger->removeVP (vp_z);
+        }
+    }
+
     delete vp_x;
     delete vp_y;
     delete vp_z;
@@ -96,12 +144,18 @@ Perspective3D::~Perspective3D ()
 }
 
 bool
-Perspective3D::operator==(Perspective3D const &other)
+Perspective3D::operator==(Perspective3D const &other) const
 {
     // Two perspectives are equal iff their vanishing points coincide and have identical states
     return (*vp_x == *other.vp_x && *vp_y == *other.vp_y && *vp_z == *other.vp_z);
 }
 
+bool
+Perspective3D::has_vanishing_point (VanishingPoint *vp)
+{
+    return (vp == vp_x || vp == vp_y || vp == vp_z);
+}
+
 VanishingPoint *
 Perspective3D::get_vanishing_point (Box3D::Axis const dir)
 {
@@ -145,6 +199,17 @@ Perspective3D::set_vanishing_point (Box3D::Axis const dir, VanishingPoint const
     }
 }
 
+Axis
+Perspective3D::get_axis_of_VP (VanishingPoint *vp)
+{
+    if (vp == vp_x) return X;
+    if (vp == vp_y) return Y;
+    if (vp == vp_z) return Z;
+
+    g_warning ("Vanishing point not present in the perspective.\n");
+    return NONE;
+}
+
 void
 Perspective3D::set_vanishing_point (Box3D::Axis const dir, gdouble pt_x, gdouble pt_y, gdouble dir_x, gdouble dir_y, VPState st)
 {
@@ -190,11 +255,35 @@ Perspective3D::remove_box (const SP3DBox *box)
 }
 
 bool
-Perspective3D::has_box (const SP3DBox *box)
+Perspective3D::has_box (const SP3DBox *box) const
 {
     return (g_slist_find (this->boxes, box) != NULL);
 }
 
+bool
+Perspective3D::all_boxes_occur_in_list (GSList *boxes_to_do)
+{
+    for (GSList *i = boxes; i != NULL; i = i->next) {
+        if (!g_slist_find (boxes_to_do, i->data)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+GSList *
+Perspective3D::boxes_occurring_in_list (GSList * list_of_boxes)
+{
+    GSList * result = NULL;
+    for (GSList *i = list_of_boxes; i != NULL; i = i->next) {
+        if (this->has_box (SP_3DBOX (i->data))) {
+            result = g_slist_prepend (result, i->data);
+        }
+    }
+    // we reverse so as to retain the same order as in list_of_boxes
+    return g_slist_reverse (result);
+}
+
 /**
  * Update the shape of a box after a handle was dragged or a VP was changed, according to the stored ratios.
  */
@@ -241,6 +330,20 @@ Perspective3D::update_box_reprs ()
     }
 }
 
+// swallow the list of boxes from the other perspective and delete it
+void
+Perspective3D::absorb (Perspective3D *other)
+{
+    g_return_if_fail (*this == *other);
+
+    // FIXME: Is copying necessary? Is other->boxes invalidated when other is deleted below?
+    this->boxes = g_slist_concat (this->boxes, g_slist_copy (other->boxes));
+
+    // Should we delete the other perspective here or at the place from where absorb() is called?
+    delete other;
+    other = NULL;
+}
+
 // FIXME: We get compiler errors when we try to move the code from sp_3dbox_get_perspective_string to this function
 /***
 gchar *