summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/axis-manip.h4
-rw-r--r--src/box3d-context.cpp3
-rw-r--r--src/box3d-face.h2
-rw-r--r--src/box3d.cpp109
-rw-r--r--src/box3d.h4
-rw-r--r--src/object-edit.cpp2
-rw-r--r--src/perspective3d.cpp8
-rw-r--r--src/perspective3d.h1
-rw-r--r--src/vanishing-point.cpp10
-rw-r--r--src/vanishing-point.h1
10 files changed, 144 insertions, 0 deletions
diff --git a/src/axis-manip.h b/src/axis-manip.h
index 7461678d5..5690eedcb 100644
--- a/src/axis-manip.h
+++ b/src/axis-manip.h
@@ -66,6 +66,10 @@ inline gint face_to_int (guint face_id) {
}
}
+inline guint opposite_face (guint face_id) {
+ return face_id + ((face_id % 2 == 0) ? 1 : -1);
+}
+
inline bool is_single_axis_direction (Box3D::Axis dir) {
// tests whether dir is nonzero and a power of 2
return (!(dir & (dir - 1)) && dir);
diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp
index a753f5f50..388e2037d 100644
--- a/src/box3d-context.cpp
+++ b/src/box3d-context.cpp
@@ -581,6 +581,8 @@ static void sp_3dbox_drag(SP3DBoxContext &bc, guint state)
}
bc.item->updateRepr();
+ sp_3dbox_set_z_orders (SP_3DBOX (bc.item));
+
// TODO: It would be nice to show the VPs during dragging, but since there is no selection
// at this point (only after finishing the box), we must do this "manually"
bc._vpdrag->updateDraggers();
@@ -603,6 +605,7 @@ static void sp_3dbox_drag(SP3DBoxContext &bc, guint state)
NR::Point origin_w(ec->xp, ec->yp);
NR::Point origin(desktop->w2d(origin_w));
sp_3dbox_position_set(bc);
+ sp_3dbox_set_z_orders (SP_3DBOX (bc.item));
// status text
//GString *Ax = SP_PX_TO_METRIC_STRING(origin[NR::X], desktop->namedview->getDefaultMetric());
diff --git a/src/box3d-face.h b/src/box3d-face.h
index 61c13432d..0e911cccf 100644
--- a/src/box3d-face.h
+++ b/src/box3d-face.h
@@ -45,6 +45,8 @@ public:
void hook_path_to_3dbox(SPPath * existing_path = NULL);
void set_path_repr();
void set_curve();
+ inline void lower_to_bottom() { SP_ITEM (path)->lowerToBottom(); }
+ inline void raise_to_top() { SP_ITEM (path)->raiseToTop(); }
gchar * axes_string();
gchar * svg_repr_string();
diff --git a/src/box3d.cpp b/src/box3d.cpp
index e445ba3d0..7f04efde6 100644
--- a/src/box3d.cpp
+++ b/src/box3d.cpp
@@ -103,6 +103,11 @@ sp_3dbox_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr
box->my_counter = counter++;
+ /* we initialize the z-orders to zero so that they are updated during dragging */
+ for (int i = 0; i < 6; ++i) {
+ box->z_orders[i] = 0;
+ }
+
box->front_bits = 0x0;
if (repr->attribute ("inkscape:perspective") == NULL) {
@@ -368,6 +373,110 @@ void sp_3dbox_recompute_corners (SP3DBox *box, NR::Point const A, NR::Point cons
sp_3dbox_move_corner_in_Z_direction (box, 5, C);
}
+inline static double
+normalized_angle (double angle) {
+ if (angle < -M_PI) {
+ return angle + 2*M_PI;
+ } else if (angle > M_PI) {
+ return angle - 2*M_PI;
+ }
+ return angle;
+}
+
+static gdouble
+sp_3dbox_corner_angle_to_VP (SP3DBox *box, Box3D::Axis axis, guint extreme_corner)
+{
+ Box3D::VanishingPoint *vp = Box3D::get_persp_of_box (box)->get_vanishing_point (axis);
+ NR::Point dir;
+
+ if (vp->is_finite()) {
+ dir = NR::unit_vector (vp->get_pos() - box->corners[extreme_corner]);
+ } else {
+ dir = NR::unit_vector (vp->v_dir);
+ }
+
+ return atan2 (dir[NR::Y], dir[NR::X]);
+}
+
+
+bool sp_3dbox_recompute_z_orders (SP3DBox *box)
+{
+ guint new_z_orders[6];
+
+ Box3D::Perspective3D *persp = Box3D::get_persp_of_box (box);
+
+ // TODO: Determine the front corner depending on the distance from VPs and/or the user presets
+ guint front_corner = 1;
+
+ gdouble dir_1x = sp_3dbox_corner_angle_to_VP (box, Box3D::X, front_corner);
+ gdouble dir_3x = sp_3dbox_corner_angle_to_VP (box, Box3D::X, front_corner ^ Box3D::Y);
+
+ gdouble dir_1y = sp_3dbox_corner_angle_to_VP (box, Box3D::Y, front_corner);
+ gdouble dir_0y = sp_3dbox_corner_angle_to_VP (box, Box3D::Y, front_corner ^ Box3D::X);
+
+ gdouble dir_1z = sp_3dbox_corner_angle_to_VP (box, Box3D::Z, front_corner);
+ gdouble dir_3z = sp_3dbox_corner_angle_to_VP (box, Box3D::Z, front_corner ^ Box3D::Y);
+
+ // Still not perfect, but only fails in some rather degenerate cases.
+ // I suspect that there is a more elegant model, though. :)
+ new_z_orders[0] = Box3D::face_to_int (Box3D::XY ^ Box3D::FRONT);
+ if (normalized_angle (dir_1y - dir_1z) > 0) {
+ new_z_orders[1] = Box3D::face_to_int (Box3D::YZ ^ Box3D::REAR);
+ if (normalized_angle (dir_1x - dir_1z) > 0) {
+ new_z_orders[2] = Box3D::face_to_int (Box3D::XZ ^ Box3D::REAR);
+ } else {
+ new_z_orders[2] = Box3D::face_to_int (Box3D::XZ ^ Box3D::FRONT);
+ }
+ } else {
+ if (normalized_angle (dir_3x - dir_3z) > 0) {
+ new_z_orders[1] = Box3D::face_to_int (Box3D::XZ ^ Box3D::REAR);
+ new_z_orders[2] = Box3D::face_to_int (Box3D::YZ ^ Box3D::FRONT);
+ } else {
+ if (normalized_angle (dir_1x - dir_1z) > 0) {
+ new_z_orders[1] = Box3D::face_to_int (Box3D::YZ ^ Box3D::FRONT);
+ new_z_orders[2] = Box3D::face_to_int (Box3D::XZ ^ Box3D::FRONT);
+ } else {
+ new_z_orders[1] = Box3D::face_to_int (Box3D::XZ ^ Box3D::FRONT);
+ new_z_orders[2] = Box3D::face_to_int (Box3D::YZ ^ Box3D::FRONT);
+ }
+ }
+ }
+
+ new_z_orders[3] = Box3D::opposite_face (new_z_orders[2]);
+ new_z_orders[4] = Box3D::opposite_face (new_z_orders[1]);
+ new_z_orders[5] = Box3D::opposite_face (new_z_orders[0]);
+
+ /* We only need to look for changes among the topmost three faces because the order
+ of the other ones is just inverted. */
+ // Currently we can even skip the first test since the front face is always in the XY plane.
+ if (// (box->z_orders[0] != new_z_orders[0]) ||
+ (box->z_orders[1] != new_z_orders[1]) ||
+ (box->z_orders[2] != new_z_orders[2]))
+ {
+ for (int i = 0; i < 6; ++i) {
+ box->z_orders[i] = new_z_orders[i];
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void sp_3dbox_set_z_orders (SP3DBox *box)
+{
+ GSList *items = sp_item_group_item_list(SP_GROUP(box));
+
+ // For efficiency reasons, we only set the new z-orders if something really changed
+ if (sp_3dbox_recompute_z_orders (box)) {
+ box->faces[box->z_orders[0]]->lower_to_bottom ();
+ box->faces[box->z_orders[1]]->lower_to_bottom ();
+ box->faces[box->z_orders[2]]->lower_to_bottom ();
+ box->faces[box->z_orders[3]]->lower_to_bottom ();
+ box->faces[box->z_orders[4]]->lower_to_bottom ();
+ box->faces[box->z_orders[5]]->lower_to_bottom ();
+ }
+}
+
void
sp_3dbox_update_curves (SP3DBox *box) {
for (int i = 0; i < 6; ++i) {
diff --git a/src/box3d.h b/src/box3d.h
index ebf2a68bb..bca319e67 100644
--- a/src/box3d.h
+++ b/src/box3d.h
@@ -36,6 +36,7 @@
struct SP3DBox : public SPGroup {
NR::Point corners[8];
Box3DFace *faces[6];
+ guint z_orders[6]; // z_orders[i] holds the ID of the face at position #i in the group (from top to bottom)
// TODO: Keeping/updating the ratios works reasonably well but is still an ad hoc implementation.
// Use a mathematically correct model to update the boxes.
@@ -57,6 +58,9 @@ 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);
+bool sp_3dbox_recompute_z_orders (SP3DBox *box); /* returns true if there was a change in the z-orders
+ (which triggers an update of the repr) */
+void sp_3dbox_set_z_orders (SP3DBox *box);
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);
diff --git a/src/object-edit.cpp b/src/object-edit.cpp
index f9e5c64fb..a0a8d4218 100644
--- a/src/object-edit.cpp
+++ b/src/object-edit.cpp
@@ -548,6 +548,7 @@ static void sp_3dbox_knot_set(SPItem *item, guint knot_id, Box3D::Axis direction
sp_3dbox_update_curves (box);
sp_3dbox_set_ratios (box);
sp_3dbox_update_perspective_lines ();
+ sp_3dbox_set_z_orders (box);
}
static NR::Point sp_3dbox_knot_get(SPItem *item, guint knot_id)
@@ -619,6 +620,7 @@ static void sp_3dbox_knot_set_uniformly(SPItem *item, guint knot_id, Box3D::Axis
sp_3dbox_update_curves (box);
sp_3dbox_set_ratios (box);
sp_3dbox_update_perspective_lines ();
+ sp_3dbox_set_z_orders (box);
}
static void sp_3dbox_knot0_set_uniformly(SPItem *item, NR::Point const &new_pos, NR::Point const &origin, guint state)
diff --git a/src/perspective3d.cpp b/src/perspective3d.cpp
index d37c9f3a0..bb4963d11 100644
--- a/src/perspective3d.cpp
+++ b/src/perspective3d.cpp
@@ -322,6 +322,14 @@ Perspective3D::update_box_reprs ()
}
}
+void
+Perspective3D::update_z_orders ()
+{
+ for (GSList *i = this->boxes; i != NULL; i = i->next) {
+ sp_3dbox_set_z_orders (SP_3DBOX (i->data));
+ }
+}
+
// swallow the list of boxes from the other perspective and delete it
void
Perspective3D::absorb (Perspective3D *other)
diff --git a/src/perspective3d.h b/src/perspective3d.h
index 4134b3fc1..6c7e77446 100644
--- a/src/perspective3d.h
+++ b/src/perspective3d.h
@@ -41,6 +41,7 @@ public:
inline guint number_of_boxes () { return g_slist_length (boxes); }
void reshape_boxes (Box3D::Axis axes);
void update_box_reprs ();
+ void update_z_orders ();
/* convenience functions for interaction with dragging machinery: */
bool all_boxes_occur_in_list (GSList *boxes_to_do);
diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp
index ea3626dac..0b4140a8b 100644
--- a/src/vanishing-point.cpp
+++ b/src/vanishing-point.cpp
@@ -229,6 +229,7 @@ vp_knot_moved_handler (SPKnot *knot, NR::Point const *ppointer, guint state, gpo
d_new->reshapeBoxes (d_new->point, Box3D::XYZ);
d_new->updateBoxReprs ();
+ d_new->updateZOrders ();
drag->updateLines ();
@@ -248,6 +249,7 @@ vp_knot_moved_handler (SPKnot *knot, NR::Point const *ppointer, guint state, gpo
dragger->reshapeBoxes (p, Box3D::XYZ);
dragger->updateBoxReprs ();
+ dragger->updateZOrders ();
drag->updateLines ();
@@ -545,6 +547,14 @@ VPDragger::updateBoxReprs ()
}
}
+void
+VPDragger::updateZOrders ()
+{
+ for (GSList *i = this->vps; i != NULL; i = i->next) {
+ Box3D::get_persp_of_VP ((VanishingPoint *) i->data)->update_z_orders ();
+ }
+}
+
VPDrag::VPDrag (SPDesktop *desktop)
{
this->desktop = desktop;
diff --git a/src/vanishing-point.h b/src/vanishing-point.h
index 98788f512..516b4a51b 100644
--- a/src/vanishing-point.h
+++ b/src/vanishing-point.h
@@ -103,6 +103,7 @@ public:
void reshapeBoxes(NR::Point const &p, Box3D::Axis axes);
void updateBoxReprs();
+ void updateZOrders();
};
struct VPDrag {