Code

Write/read perspectives to/from SVG; store ratios of the distances from corners to...
authorcilix42 <cilix42@users.sourceforge.net>
Mon, 6 Aug 2007 06:51:01 +0000 (06:51 +0000)
committercilix42 <cilix42@users.sourceforge.net>
Mon, 6 Aug 2007 06:51:01 +0000 (06:51 +0000)
13 files changed:
src/attributes.cpp
src/attributes.h
src/box3d-context.cpp
src/box3d.cpp
src/box3d.h
src/desktop.cpp
src/desktop.h
src/knotholder.cpp
src/knotholder.h
src/perspective3d.cpp
src/perspective3d.h
src/vanishing-point.cpp
src/vanishing-point.h

index ee7ebff69fb23108a22f4266e2642daae577cdde..90f3e0280ee63df8adccc1b5a8c88d92aeba5676 100644 (file)
@@ -113,6 +113,7 @@ static SPStyleProp const props[] = {
     {SP_ATTR_INKSCAPE_3DBOX_CORNER_A, "inkscape:box3dcornerA"}, // "upper left front" corner
     {SP_ATTR_INKSCAPE_3DBOX_CORNER_B, "inkscape:box3dcornerB"}, // "lower right front" corner
     {SP_ATTR_INKSCAPE_3DBOX_CORNER_C, "inkscape:box3dcornerC"}, // "lower right rear" corner
+    {SP_ATTR_INKSCAPE_3DBOX_PERSPECTIVE, "inkscape:perspective"},
     /* SPEllipse */
     {SP_ATTR_R, "r"},
     {SP_ATTR_CX, "cx"},
index 5eb906320bec59993dc42259c0e3abc19f458c92..9a969dc8cbdde73f7577bba1edf0a878597f60ba 100644 (file)
@@ -113,6 +113,7 @@ enum SPAttributeEnum {
     SP_ATTR_INKSCAPE_3DBOX_CORNER_A, // "upper left front" corner
     SP_ATTR_INKSCAPE_3DBOX_CORNER_B, // "lower right front" corner
     SP_ATTR_INKSCAPE_3DBOX_CORNER_C, // "lower right rear" corner
+    SP_ATTR_INKSCAPE_3DBOX_PERSPECTIVE,
     /* SPEllipse */
     SP_ATTR_R,
     SP_ATTR_CX,
index fc4e7462934f66914201db5e7c3a649f842b7860..c82728c9760131f0f4826609aa96d27baefe3b32 100644 (file)
@@ -554,6 +554,7 @@ static void sp_3dbox_finish(SP3DBoxContext *bc)
         desktop = SP_EVENT_CONTEXT_DESKTOP(bc);
 
         SP_OBJECT(bc->item)->updateRepr();
+        sp_3dbox_set_ratios(SP_3DBOX(bc->item));
 
         sp_canvas_end_forced_full_redraws(desktop->canvas);
 
index 76dad605b9f5fa60f5284d45493cec954aa92305..44b2c9bbef9ab2ec697da06dbee636f83ed3e56d 100644 (file)
@@ -32,11 +32,13 @@ static Inkscape::XML::Node *sp_3dbox_write(SPObject *object, Inkscape::XML::Node
 static gchar *sp_3dbox_description(SPItem *item);
 
 //static void sp_3dbox_set_shape(SPShape *shape);
-static void sp_3dbox_set_shape(SP3DBox *box3d);
+//static void sp_3dbox_set_shape(SP3DBox *box3d);
 
 static void sp_3dbox_update_corner_with_value_from_svg (SPObject *object, guint corner_id, const gchar *value);
+static void sp_3dbox_update_perspective (Box3D::Perspective3D *persp, const gchar *value);
 static gchar * sp_3dbox_get_corner_coords_string (SP3DBox *box, guint id);
 static std::pair<gdouble, gdouble> sp_3dbox_get_coord_pair_from_string (const gchar *);
+static gchar * sp_3dbox_get_perspective_string (SP3DBox *box);
 
 static SPGroupClass *parent_class;
 
@@ -97,7 +99,33 @@ sp_3dbox_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr
 
     SP3DBox *box = SP_3DBOX (object);
 
-    Box3D::Perspective3D::current_perspective->add_box (box);
+    if (repr->attribute ("inkscape:perspective") == NULL) {
+        // we are creating a new box; link it to the current perspective
+        Box3D::Perspective3D::current_perspective->add_box (box);
+    } else {
+        // create a new perspective that we can compare with existing ones
+        Box3D::Perspective3D *persp = new Box3D::Perspective3D (Box3D::VanishingPoint (0,0),
+                                                                Box3D::VanishingPoint (0,0),
+                                                                Box3D::VanishingPoint (0,0));
+        sp_3dbox_update_perspective (persp, repr->attribute ("inkscape:perspective"));
+        SPDesktop *desktop = inkscape_active_desktop();
+        Box3D::Perspective3D *comp = desktop->find_perspective (persp);
+        if (comp == NULL) {
+            // perspective doesn't exist yet
+            desktop->add_perspective (persp);
+            persp->add_box (box);
+        } else {
+            // link the box to the existing perspective and delete the temporary one
+            comp->add_box (box);
+            delete persp;
+            //g_assert (Box3D::get_persp_of_box (box) == comp);
+
+            // FIXME: If the paths of the box's faces do not correspond to the svg representation of the perspective
+            //        the box is shown with a "wrong" initial shape that is only corrected after dragging.
+            //        Should we "repair" this by updating the paths at the end of sp_3dbox_build()?
+            //        Maybe it would be better to simply destroy and rebuild them in sp_3dbox_link_to_existing_paths().
+        }
+    }
 
     sp_object_read_attr(object, "inkscape:box3dcornerA");
     sp_object_read_attr(object, "inkscape:box3dcornerB");
@@ -127,6 +155,8 @@ sp_3dbox_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr
     // Check whether the paths of the faces of the box need to be linked to existing paths in the
     // document (e.g., after a 'redo' operation or after opening a file) and do so if necessary.
     sp_3dbox_link_to_existing_paths (box, repr);
+
+    sp_3dbox_set_ratios (box);
 }
 
 static void
@@ -160,6 +190,9 @@ static void sp_3dbox_set(SPObject *object, unsigned int key, const gchar *value)
         case SP_ATTR_INKSCAPE_3DBOX_CORNER_C:
             sp_3dbox_update_corner_with_value_from_svg (object, 5, value);
             break;
+        case SP_ATTR_INKSCAPE_3DBOX_PERSPECTIVE:
+            sp_3dbox_update_perspective (Box3D::get_persp_of_box (SP_3DBOX (object)), value);
+            break;
        default:
             if (((SPObjectClass *) (parent_class))->set) {
                 ((SPObjectClass *) (parent_class))->set(object, key, value);
@@ -206,17 +239,21 @@ static Inkscape::XML::Node *sp_3dbox_write(SPObject *object, Inkscape::XML::Node
     }
 
     if (flags & SP_OBJECT_WRITE_EXT) {
-        gchar *coords;
-        coords = sp_3dbox_get_corner_coords_string (box, 2);
-        repr->setAttribute("inkscape:box3dcornerA", coords);
+        gchar *str;
+        str = sp_3dbox_get_corner_coords_string (box, 2);
+        repr->setAttribute("inkscape:box3dcornerA", str);
+
+        str = sp_3dbox_get_corner_coords_string (box, 1);
+        repr->setAttribute("inkscape:box3dcornerB", str);
 
-        coords = sp_3dbox_get_corner_coords_string (box, 1);
-        repr->setAttribute("inkscape:box3dcornerB", coords);
+        str = sp_3dbox_get_corner_coords_string (box, 5);
+        repr->setAttribute("inkscape:box3dcornerC", str);
 
-        coords = sp_3dbox_get_corner_coords_string (box, 5);
-        repr->setAttribute("inkscape:box3dcornerC", coords);
+        str = sp_3dbox_get_perspective_string (box);
+        repr->setAttribute("inkscape:perspective", str);
+        sp_3dbox_set_ratios (box);
 
-        g_free ((void *) coords);
+        g_free ((void *) str);
     }
 
     if (((SPObjectClass *) (parent_class))->write) {
@@ -234,6 +271,27 @@ sp_3dbox_description(SPItem *item)
     return g_strdup(_("<b>3D Box</b>"));
 }
 
+void sp_3dbox_set_ratios (SP3DBox *box, Box3D::Axis axes)
+{
+    Box3D::Perspective3D *persp = Box3D::get_persp_of_box (box);
+    NR::Point pt;
+
+    if (axes & Box3D::X) {
+        pt = persp->get_vanishing_point (Box3D::X)->get_pos();
+        box->ratio_x = NR::L2 (pt - box->corners[2]) / NR::L2 (pt - box->corners[3]);
+    }
+
+    if (axes & Box3D::Y) {
+        pt = persp->get_vanishing_point (Box3D::Y)->get_pos();
+        box->ratio_y = NR::L2 (pt - box->corners[2]) / NR::L2 (pt - box->corners[0]);
+    }
+
+    if (axes & Box3D::Z) {
+        pt = persp->get_vanishing_point (Box3D::Z)->get_pos();
+        box->ratio_z = NR::L2 (pt - box->corners[4]) / NR::L2 (pt - box->corners[0]);
+    }
+}
+
 void
 sp_3dbox_position_set (SP3DBoxContext &bc)
 {
@@ -255,12 +313,13 @@ sp_3dbox_position_set (SP3DBoxContext &bc)
     ***/
 }
 
-static void
+//static
+void
 // FIXME: Note that this is _not_ the virtual set_shape() method inherited from SPShape,
 //        since SP3DBox is inherited from SPGroup. The following method is "artificially"
 //        called from sp_3dbox_update().
 //sp_3dbox_set_shape(SPShape *shape)
-sp_3dbox_set_shape(SP3DBox *box3d)
+sp_3dbox_set_shape(SP3DBox *box3d, bool use_previous_corners)
 {
     // FIXME: How to handle other contexts???
     // FIXME: Is tools_isactive(..) more recommended to check for the current context/tool?
@@ -270,7 +329,11 @@ sp_3dbox_set_shape(SP3DBox *box3d)
 
     /* Only update the curves during dragging; setting the svg representations 
        is expensive and only done once at the end */
-    sp_3dbox_recompute_corners (box3d, bc->drag_origin, bc->drag_ptB, bc->drag_ptC);
+    if (!use_previous_corners) {
+        sp_3dbox_recompute_corners (box3d, bc->drag_origin, bc->drag_ptB, bc->drag_ptC);
+    } else {
+        sp_3dbox_recompute_corners (box3d, box3d->corners[2], box3d->corners[1], box3d->corners[5]);
+    }
     if (bc->extruded) {
         box3d->faces[0]->set_corners (box3d->corners[0], box3d->corners[4], box3d->corners[6], box3d->corners[2]);
         box3d->faces[1]->set_corners (box3d->corners[1], box3d->corners[5], box3d->corners[7], box3d->corners[3]);
@@ -457,7 +520,50 @@ sp_3dbox_get_coord_pair_from_string (const gchar *coords)
     return std::make_pair(coord1, coord2);
 }
 
-// auxiliary function
+static gchar *
+sp_3dbox_get_perspective_string (SP3DBox *box)
+{
+    
+    return sp_3dbox_get_svg_descr_of_persp (Box3D::get_persp_of_box (box));
+}
+  
+gchar *
+sp_3dbox_get_svg_descr_of_persp (Box3D::Perspective3D *persp)
+{
+    // FIXME: We should move this code to perspective3d.cpp, but this yields compiler errors. Why?
+    Inkscape::SVGOStringStream os;
+
+    Box3D::VanishingPoint vp = *(persp->get_vanishing_point (Box3D::X));
+    os << vp[NR::X] << "," << vp[NR::Y] << ",";
+    os << vp.v_dir[NR::X] << "," << vp.v_dir[NR::Y] << ",";
+    if (vp.is_finite()) {
+        os << "finite,";
+    } else {
+        os << "infinite,";
+    }
+
+    vp = *(persp->get_vanishing_point (Box3D::Y));
+    os << vp[NR::X] << "," << vp[NR::Y] << ",";
+    os << vp.v_dir[NR::X] << "," << vp.v_dir[NR::Y] << ",";
+    if (vp.is_finite()) {
+        os << "finite,";
+    } else {
+        os << "infinite,";
+    }
+
+    vp = *(persp->get_vanishing_point (Box3D::Z));
+    os << vp[NR::X] << "," << vp[NR::Y] << ",";
+    os << vp.v_dir[NR::X] << "," << vp.v_dir[NR::Y] << ",";
+    if (vp.is_finite()) {
+        os << "finite";
+    } else {
+        os << "infinite";
+    }
+
+    return g_strdup(os.str().c_str());
+}
+
+// auxiliary functions
 static void
 sp_3dbox_update_corner_with_value_from_svg (SPObject *object, guint corner_id, const gchar *value)
 {
@@ -470,6 +576,36 @@ sp_3dbox_update_corner_with_value_from_svg (SPObject *object, guint corner_id, c
     object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
+static void
+sp_3dbox_update_perspective (Box3D::Perspective3D *persp, const gchar *value)
+{
+    // WARNING! This function changes the perspective associated to 'box'. Since there may be
+    // many other boxes linked to the same perspective, their perspective is also changed.
+    // If this behaviour is not desired in all cases, we need a different function.
+    if (value == NULL) return;
+
+    gchar **vps = g_strsplit( value, ",", 0);
+    for (int i = 0; i < 15; ++i) {
+        if (vps[i] == NULL) {
+            g_warning ("Malformed svg attribute 'perspective'\n");
+            return;
+        }
+    }
+
+    persp->set_vanishing_point (Box3D::X, g_ascii_strtod (vps[0], NULL), g_ascii_strtod (vps[1], NULL),
+                                          g_ascii_strtod (vps[2], NULL), g_ascii_strtod (vps[3], NULL),
+                                          Box3D::VP_FINITE);
+    persp->set_vanishing_point (Box3D::Y, g_ascii_strtod (vps[5], NULL), g_ascii_strtod (vps[6], NULL),
+                                          g_ascii_strtod (vps[7], NULL), g_ascii_strtod (vps[8], NULL),
+                                          Box3D::VP_FINITE);
+    persp->set_vanishing_point (Box3D::Z, g_ascii_strtod (vps[10], NULL), g_ascii_strtod (vps[11], NULL),
+                                          g_ascii_strtod (vps[12], NULL), g_ascii_strtod (vps[13], NULL),
+                                          Box3D::VP_FINITE);
+
+    // update the other boxes linked to the same perspective
+    persp->reshape_boxes (Box3D::XYZ);
+}
+
 /*
   Local Variables:
   mode:c++
index ee0f30c8169c7c5375595337bcf6926758285d13..1b40afa760ea79de7f53296879ee9ca928a17806 100644 (file)
 struct SP3DBox : public SPGroup {
     NR::Point corners[8];
     Box3DFace *faces[6];
+
+    // TODO: Keeping/updating the ratios works reasonably well but is still an ad hoc implementation.
+    //       Use a mathematically correct model to update the boxes.
+    double ratio_x;
+    double ratio_y;
+    double ratio_z;
 };
 
 struct SP3DBoxClass {
@@ -45,14 +51,18 @@ struct SP3DBoxClass {
 GType sp_3dbox_get_type (void);
 
 void sp_3dbox_position_set (SP3DBoxContext &bc);
+void sp_3dbox_set_shape(SP3DBox *box3d, bool use_previous_corners = false);
 void sp_3dbox_recompute_corners (SP3DBox *box, NR::Point const pt1, NR::Point const pt2, NR::Point const pt3);
 void sp_3dbox_update_curves (SP3DBox *box);
 void sp_3dbox_link_to_existing_paths (SP3DBox *box, Inkscape::XML::Node *repr);
+void sp_3dbox_set_ratios (SP3DBox *box, Box3D::Axis axes = Box3D::XYZ);
 void sp_3dbox_move_corner_in_XY_plane (SP3DBox *box, guint id, NR::Point pt, Box3D::Axis axes = Box3D::XY);
 void sp_3dbox_move_corner_in_Z_direction (SP3DBox *box, guint id, NR::Point pt, bool constrained = true);
 NR::Maybe<NR::Point> sp_3dbox_get_center (SP3DBox *box);
 NR::Maybe<NR::Point> sp_3dbox_get_midpoint_between_corners (SP3DBox *box, guint id_corner1, guint id_corner2);
 
+gchar * sp_3dbox_get_svg_descr_of_persp (Box3D::Perspective3D *persp);
+
 inline NR::Point sp_3dbox_get_corner (SP3DBox *box, guint id) { return box->corners[id]; }
 inline bool sp_3dbox_corners_are_adjacent (guint id_corner1, guint id_corner2) {
   return Box3D::is_single_axis_direction ((Box3D::Axis) (id_corner1 ^ id_corner2));
index 6314621c14e146805075c28fae13c2d916a893df..f58864955d01641cbc2c4bbf52c27592349caa09 100644 (file)
@@ -720,7 +720,13 @@ void SPDesktop::set_display_area(NR::Rect const &a, NR::Coord b, bool log)
 void
 SPDesktop::add_perspective (Box3D::Perspective3D * const persp)
 {
+    // check that the perspective is not yet linked to another desktop
+    if (persp->desktop != NULL) {
+        g_assert (persp->desktop == this);
+    }
+
     // FIXME: Should we handle the case that the perspectives have equal VPs but are not identical?
+    //        If so, we need to take care of relinking the boxes, etc.
     if (persp == NULL || g_slist_find (this->perspectives, persp)) return;
     this->perspectives = g_slist_prepend (this->perspectives, persp);
     persp->desktop = this;
@@ -729,15 +735,24 @@ SPDesktop::add_perspective (Box3D::Perspective3D * const persp)
 void SPDesktop::remove_perspective (Box3D::Perspective3D * const persp)
 {
     if (persp == NULL) return;
-
     if (!g_slist_find (this->perspectives, persp)) {
         g_warning ("Could not find perspective in current desktop. Not removed.\n");
         return;
     }
-
     this->perspectives = g_slist_remove (this->perspectives, persp);
 }
 
+// find an existing perspective whose VPs are equal to those of persp
+Box3D::Perspective3D * SPDesktop::find_perspective (Box3D::Perspective3D * const persp)
+{
+    for (GSList *p = this->perspectives; p != NULL; p = p->next) {
+        if (*((Box3D::Perspective3D *) p->data) == *persp) {
+            return ((Box3D::Perspective3D *) p->data);
+        }
+    }
+    return NULL; // perspective was not found
+}
+
 /**
  * Return viewbox dimensions.
  */
index fa6602651bc1b8c8dd2b8fc4ade2a99146e7fe22..5f4e2cfab63a110d31fd5518da44fb91dd5642d7 100644 (file)
@@ -209,6 +209,7 @@ struct SPDesktop : public Inkscape::UI::View::View
     // Methods to handle 3D perspective
     void add_perspective (Box3D::Perspective3D * const persp);
     void remove_perspective (Box3D::Perspective3D * const persp);
+    Box3D::Perspective3D * find_perspective (Box3D::Perspective3D * const persp); // find an existing perspective whose VPs are equal to those of persp
 
     NR::Rect get_display_area() const;
     void set_display_area (double x0, double y0, double x1, double y1, double border, bool log = true);
index a24bb16259d0bcf2b70d7459e0f9436e67448810..d8776cca7219db5a91f417fbdd32f7c55bd28c9d 100644 (file)
@@ -195,7 +195,8 @@ void sp_knot_holder_add_full(
  * \param p In desktop coordinates.
  */
 
-static void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item)
+//static
+void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item)
 {
     NR::Matrix const i2d(sp_item_i2d_affine(item));
 
index 971dae3b0747a2036ebe338ea6d32ef74bb47957..18b6c4165241b38fa6de694a62a238bb2d95f871 100644 (file)
@@ -68,6 +68,9 @@ void sp_knot_holder_add_full(SPKnotHolder *knot_holder,
 
 GType sp_knot_holder_get_type();
 
+// For testing. What is the right way to update the knots from Perspective3D::reshape_boxes() ?
+void knotholder_update_knots(SPKnotHolder *knot_holder, SPItem *item);
+
 #define SP_TYPE_KNOT_HOLDER      (sp_knot_holder_get_type())
 
 #endif /* !__SP_KNOTHOLDER_H__ */
index 27366e564203e9134009adad5c7a40ed852861ec..d4990fd397b5b99ad9d8c5b901dfd0b15c2e943e 100644 (file)
@@ -11,6 +11,7 @@
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
 
+#include "box3d.h"
 #include "box3d-context.h"
 #include "perspective-line.h"
 #include <iostream>
@@ -18,6 +19,7 @@
 
 // can probably be removed later
 #include "inkscape.h"
+#include "knotholder.h"
 
 namespace Box3D {
 
@@ -80,8 +82,10 @@ Perspective3D::Perspective3D (Perspective3D &other)
 
 Perspective3D::~Perspective3D ()
 {
-    g_assert (desktop != NULL);
-    desktop->remove_perspective (this);
+    // we can have desktop == NULL when building a box whose attribute "inkscape:perspective" is set
+    if (desktop != NULL) {
+        desktop->remove_perspective (this);
+    }
 
     delete vp_x;
     delete vp_y;
@@ -90,6 +94,12 @@ Perspective3D::~Perspective3D ()
     g_slist_free (boxes);
 }
 
+bool
+Perspective3D::operator==(Perspective3D const &other)
+{
+    // 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);
+}
 
 VanishingPoint *
 Perspective3D::get_vanishing_point (Box3D::Axis const dir)
@@ -134,6 +144,30 @@ Perspective3D::set_vanishing_point (Box3D::Axis const dir, VanishingPoint const
     }
 }
 
+void
+Perspective3D::set_vanishing_point (Box3D::Axis const dir, gdouble pt_x, gdouble pt_y, gdouble dir_x, gdouble dir_y, VPState st)
+{
+    VanishingPoint *vp;
+    switch (dir) {
+        case X:
+            vp = vp_x;
+            break;
+        case Y:
+            vp = vp_y;
+            break;
+        case Z:
+            vp = vp_z;
+            break;
+        case NONE:
+            // no vanishing point to set
+            return;
+    }
+
+    vp->set_pos (pt_x, pt_y);
+    vp->v_dir = NR::Point (dir_x, dir_y);
+    vp->state = st;
+}
+
 void
 Perspective3D::add_box (SP3DBox *box)
 {
@@ -160,6 +194,60 @@ Perspective3D::has_box (const SP3DBox *box)
     return (g_slist_find (this->boxes, box) != NULL);
 }
 
+/**
+ * Update the shape of a box after a handle was dragged or a VP was changed, according to the stored ratios.
+ */
+void
+Perspective3D::reshape_boxes (Box3D::Axis axes)
+{
+    // TODO: Leave the "correct" corner fixed according to which face is supposed to be on front.
+    NR::Point new_pt;
+    VanishingPoint *vp;
+    for (const GSList *i = this->boxes; i != NULL; i = i->next) {
+        SP3DBox *box = SP_3DBOX (i->data);
+        if (axes & Box3D::X) {
+            vp = this->get_vanishing_point (Box3D::X);
+            new_pt = vp->get_pos() + box->ratio_x * (box->corners[3] - vp->get_pos());
+            sp_3dbox_move_corner_in_XY_plane (box, 2, new_pt);
+        }
+        if (axes & Box3D::Y) {
+            vp = this->get_vanishing_point (Box3D::Y);
+            new_pt = vp->get_pos() + box->ratio_y * (box->corners[0] - vp->get_pos());
+            sp_3dbox_move_corner_in_XY_plane (box, 2, new_pt);
+        }
+        if (axes & Box3D::Z) {
+            vp = this->get_vanishing_point (Box3D::Z);
+            new_pt = vp->get_pos() + box->ratio_z * (box->corners[0] - vp->get_pos());
+            sp_3dbox_move_corner_in_Z_direction (box, 4, new_pt);
+        }                
+
+        sp_3dbox_set_shape (box, true);
+        // FIXME: Is there a way update the knots without accessing the
+        //        statically linked function knotholder_update_knots?
+        SPEventContext *ec = inkscape_active_event_context();
+        g_assert (ec != NULL);
+        if (ec->shape_knot_holder != NULL) {
+            knotholder_update_knots(ec->shape_knot_holder, (SPItem *) box);
+        }
+    }
+}
+
+void
+Perspective3D::update_box_reprs ()
+{
+    for (GSList *i = this->boxes; i != NULL; i = i->next) {
+        SP_OBJECT(SP_3DBOX (i->data))->updateRepr(SP_OBJECT_WRITE_EXT);
+    }
+}
+
+// FIXME: We get compiler errors when we try to move the code from sp_3dbox_get_perspective_string to this function
+/***
+gchar *
+Perspective3D::svg_string ()
+{
+}
+***/
+
 } // namespace Box3D 
  
 /*
index afecb2e48b88489d479b5ed35fc5c6fe8f3bc543..2cffd3419cbd0c20d2295f30a84f0bd353423e6e 100644 (file)
@@ -13,6 +13,7 @@
 #define SEEN_PERSPECTIVE3D_H
 
 #include "vanishing-point.h"
+#include "svg/stringstream.h"
 
 class SP3DBox;
 
@@ -26,11 +27,16 @@ public:
     Perspective3D(Perspective3D &other);
     ~Perspective3D();
 
+    bool operator== (Perspective3D const &other);
+
     VanishingPoint *get_vanishing_point (Box3D::Axis const dir);
     void set_vanishing_point (Box3D::Axis const dir, VanishingPoint const &pt);
+    void set_vanishing_point (Box3D::Axis const dir, gdouble pt_x, gdouble pt_y, gdouble dir_x, gdouble dir_y, VPState st);
     void add_box (SP3DBox *box);
     void remove_box (const SP3DBox *box);
     bool has_box (const SP3DBox *box);
+    void reshape_boxes (Box3D::Axis axes);
+    void update_box_reprs ();
 
     static Perspective3D * current_perspective; // should current_perspective be moved to desktop.h?
 
index 20c67cb28d1d9c37956be9b7000ac5093699afe6..5f40936cf5ca637da07e98c252eb15b223274a43 100644 (file)
@@ -45,6 +45,15 @@ VanishingPoint::VanishingPoint(VanishingPoint const &rhs) : NR::Point (rhs)
     this->v_dir = rhs.v_dir;
 }
 
+bool VanishingPoint::operator== (VanishingPoint const &other)
+{
+    // Should we compare the parent perspectives, too? Probably not.
+    if ((*this)[NR::X] == other[NR::X] && (*this)[NR::Y] == other[NR::Y]
+        && this->state == other.state && this->v_dir == other.v_dir) {
+        return true;
+    }
+    return false;
+}
 
 bool VanishingPoint::is_finite() const
 {
index 85b7434e2dc6be07b1ff7712ac880c43fa44836b..918b27fc76876c79bc20bec4507af2d2d18c0b92 100644 (file)
@@ -47,6 +47,14 @@ public:
     VanishingPoint(NR::Coord x, NR::Coord y, NR::Coord dir_x, NR::Coord dir_y);
     VanishingPoint(VanishingPoint const &rhs);
 
+    bool operator== (VanishingPoint const &other);
+
+    inline NR::Point get_pos() const { return NR::Point ((*this)[NR::X], (*this)[NR::Y]); }
+    inline void set_pos(NR::Point const &pt) { (*this)[NR::X] = pt[NR::X];
+                                               (*this)[NR::Y] = pt[NR::Y]; }
+    inline void set_pos(const double pt_x, const double pt_y) { (*this)[NR::X] = pt_x;
+                                                                (*this)[NR::Y] = pt_y; }
+
     bool is_finite() const;
     VPState toggle_parallel();
     void draw(Box3D::Axis const axis); // Draws a point on the canvas if state == VP_FINITE