summaryrefslogtreecommitdiffstats
path: root/src/box3d.cpp
diff options
context:
space:
mode:
authorMaximilian Albert <maximilian.albert@gmail.com>2007-08-07 06:56:36 +0000
committercilix42 <cilix42@users.sourceforge.net>2007-08-07 06:56:36 +0000
commitd8f7aa4697faeffccb32a45235378afc69f402fd (patch)
tree7074305d40ee73725f943aa84c41216ab487e170 /src/box3d.cpp
parentadd a way to set a radio toggle in aux toolbar via desktop, by the toggles id (diff)
downloadinkscape-d8f7aa4697faeffccb32a45235378afc69f402fd.tar.gz
inkscape-d8f7aa4697faeffccb32a45235378afc69f402fd.zip
Set z-orders of 3D box faces during dragging/resizing according to the perspective
(bzr r3409)
Diffstat (limited to 'src/box3d.cpp')
-rw-r--r--src/box3d.cpp109
1 files changed, 109 insertions, 0 deletions
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) {