summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 36e6eec)
raw | patch | inline | side by side (parent: 36e6eec)
author | cilix42 <cilix42@users.sourceforge.net> | |
Tue, 7 Aug 2007 06:56:36 +0000 (06:56 +0000) | ||
committer | cilix42 <cilix42@users.sourceforge.net> | |
Tue, 7 Aug 2007 06:56:36 +0000 (06:56 +0000) |
diff --git a/src/axis-manip.h b/src/axis-manip.h
index 7461678d5321f2dd4814e64eb799b02c09dd3958..5690eedcb79f564739f27cf2007f4af41bab7b70 100644 (file)
--- a/src/axis-manip.h
+++ b/src/axis-manip.h
}
}
+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 a753f5f5004ede9b660ef773870b9d2c885e73b9..388e2037d89578bf91877e5d6202fbef818a53c7 100644 (file)
--- a/src/box3d-context.cpp
+++ b/src/box3d-context.cpp
}
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();
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 61c13432d7bad100f1a7dfc498acdcbfe101e7b8..0e911cccfdbe84a1d18878ac63586d47767441e7 100644 (file)
--- a/src/box3d-face.h
+++ b/src/box3d-face.h
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 e445ba3d06cfe2092b8456a11644f7fd78472863..7f04efde65ef116cc53d21976f7ddc733edb4264 100644 (file)
--- 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 ebf2a68bbc1292985d1ea8ae46774c63d6042d10..bca319e678c6c01d461fa9fce6ace1429cd81190 100644 (file)
--- a/src/box3d.h
+++ b/src/box3d.h
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.
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 f9e5c64fb9591fedb706dc8f774c7de12e72841d..a0a8d42185ca3989bf5053c27a1a7c9d87a33de1 100644 (file)
--- 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 d37c9f3a0100be2e15debc5bab8791e66573b8d8..bb4963d119952f831efc4024b009ea0162453786 100644 (file)
--- a/src/perspective3d.cpp
+++ b/src/perspective3d.cpp
}
}
+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 4134b3fc1ffc59d970fa7914a26f6510efbc6bf8..6c7e774469fa0bc8cac0819017d2112ee587166e 100644 (file)
--- a/src/perspective3d.h
+++ b/src/perspective3d.h
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);
index ea3626dacb44ab1858f88a722d18b5791841296f..0b4140a8bc95a37dab705832202209a3a5d12aec 100644 (file)
--- 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 ();
}
}
+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 98788f51247a0f6aa6c969d9e7530f2d00b69ffa..516b4a51b2f2d0a2bcb749c01aff42557b5c98c7 100644 (file)
--- a/src/vanishing-point.h
+++ b/src/vanishing-point.h
void reshapeBoxes(NR::Point const &p, Box3D::Axis axes);
void updateBoxReprs();
+ void updateZOrders();
};
struct VPDrag {