Code

New/updated 3D box auxiliary/convenience functions (e.g., allow (un)constrained movem...
authorcilix42 <cilix42@users.sourceforge.net>
Wed, 4 Jul 2007 10:26:36 +0000 (10:26 +0000)
committercilix42 <cilix42@users.sourceforge.net>
Wed, 4 Jul 2007 10:26:36 +0000 (10:26 +0000)
src/box3d.cpp
src/box3d.h
src/object-edit.cpp
src/perspective-line.cpp
src/vanishing-point.cpp
src/vanishing-point.h

index 258c658791084c66f11b9d2ecec287a9cc5edc0b..aefa620cd9f39dd1050c776202e06b06a49f2c22 100644 (file)
@@ -228,7 +228,7 @@ void sp_3dbox_recompute_corners (SP3DBox *box, NR::Point const A, NR::Point cons
 {
     sp_3dbox_move_corner_in_XY_plane (box, 2, A);
     sp_3dbox_move_corner_in_XY_plane (box, 1, B);
-    sp_3dbox_move_corner_in_constrained_Z_direction (box, 5, C);
+    sp_3dbox_move_corner_in_Z_direction (box, 5, C);
 }
 
 void
@@ -239,9 +239,12 @@ sp_3dbox_update_curves (SP3DBox *box) {
 }
 
 void
-sp_3dbox_move_corner_in_XY_plane (SP3DBox *box, guint id, NR::Point pt)
+sp_3dbox_move_corner_in_XY_plane (SP3DBox *box, guint id, NR::Point pt, Box3D::Axis axes)
 {
     NR::Point A (box->corners[id ^ Box3D::XY]);
+    if (Box3D::is_single_axis_direction (axes)) {
+        pt = Box3D::PerspectiveLine (box->corners[id], axes).closest_to(pt);
+    }
 
     /* set the 'front' corners */
     box->corners[id] = pt;
@@ -272,8 +275,10 @@ sp_3dbox_move_corner_in_XY_plane (SP3DBox *box, guint id, NR::Point pt)
 }
 
 void
-sp_3dbox_move_corner_in_constrained_Z_direction (SP3DBox *box, guint id, NR::Point pt)
+sp_3dbox_move_corner_in_Z_direction (SP3DBox *box, guint id, NR::Point pt, bool constrained)
 {
+    if (!constrained) sp_3dbox_move_corner_in_XY_plane (box, id, pt, Box3D::XY);
+
     /* set the four corners of the face containing corners[id] */
     box->corners[id] = Box3D::PerspectiveLine (box->corners[id], Box3D::Z).closest_to(pt);
 
@@ -290,6 +295,36 @@ sp_3dbox_move_corner_in_constrained_Z_direction (SP3DBox *box, guint id, NR::Poi
     box->corners[id ^ Box3D::Y] = pl_one.meet(pl_two);
 }
 
+NR::Maybe<NR::Point>
+sp_3dbox_get_center (SP3DBox *box)
+{
+    return sp_3dbox_get_midpoint_between_corners (box, 0, 7);
+}
+
+NR::Maybe<NR::Point>
+sp_3dbox_get_midpoint_between_corners (SP3DBox *box, guint id_corner1, guint id_corner2)
+{
+    Box3D::Axis corner_axes = (Box3D::Axis) (id_corner1 ^ id_corner2);
+
+    // Is all this sufficiently precise also for degenerate cases?
+    if (sp_3dbox_corners_are_adjacent (id_corner1, id_corner2)) {
+        Box3D::Axis orth_dir = get_perpendicular_axis_direction (corner_axes);
+
+        Box3D::Line diag1 (box->corners[id_corner1], box->corners[id_corner2 ^ orth_dir]);
+        Box3D::Line diag2 (box->corners[id_corner1 ^ orth_dir], box->corners[id_corner2]);
+        NR::Maybe<NR::Point> adjacent_face_center = diag1.intersect(diag2);
+
+        if (!adjacent_face_center) return NR::Nothing();
+
+        Box3D::PerspectiveLine pl (*adjacent_face_center, orth_dir);
+        return pl.intersect(Box3D::PerspectiveLine(box->corners[id_corner1], corner_axes));
+    } else {
+        Box3D::Axis dir = Box3D::extract_single_axis_direction (corner_axes);
+        Box3D::Line diag1 (box->corners[id_corner1], box->corners[id_corner2]);
+        Box3D::Line diag2 (box->corners[id_corner1 ^ dir], box->corners[id_corner2 ^ dir]);
+        return diag1.intersect(diag2);
+    }
+}
 
 /*
   Local Variables:
index 1fb8280eed9ae4acfbc94974cb0ccfb833137897..8fe90dc3bdd5389319bf428c6a94d2cd453f928e 100644 (file)
@@ -47,9 +47,14 @@ GType sp_3dbox_get_type (void);
 void sp_3dbox_position_set (SP3DBoxContext &bc);
 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_move_corner_in_XY_plane (SP3DBox *box, guint id, NR::Point pt);
-void sp_3dbox_move_corner_in_constrained_Z_direction (SP3DBox *box, guint id, NR::Point pt);
+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);
 
 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));
+}
 
 #endif
index c597f3a265f7b748912b3e55a938386af825f698..684c4404f3bd51193682885d34f158ea78d64690 100644 (file)
@@ -539,8 +539,7 @@ static void sp_3dbox_knot_set(SPItem *item, guint knot_id, Box3D::Axis direction
     gdouble height = sp_document_height(doc);
 
     if (direction == Box3D::Z) {
-        sp_3dbox_move_corner_in_constrained_Z_direction (box, knot_id,
-                                                         NR::Point (new_pos[NR::X], height - new_pos[NR::Y]));
+        sp_3dbox_move_corner_in_Z_direction (box, knot_id, NR::Point (new_pos[NR::X], height - new_pos[NR::Y]));
     } else {
         sp_3dbox_move_corner_in_XY_plane (box, knot_id, NR::Point (new_pos[NR::X], height - new_pos[NR::Y]));
     }
index 158ddd47bd2a2b7be83a0c77a51704622d3cc600..e5596cc1b5704a09d024ea58802cccb75a8b54c5 100644 (file)
@@ -19,6 +19,7 @@ PerspectiveLine::PerspectiveLine (NR::Point const &pt, Box3D::Axis const axis, P
         Line (pt, *(perspective->get_vanishing_point(axis)), true)
 {
     g_assert (perspective != NULL);
+    g_assert (Box3D::is_single_axis_direction (axis));
 
     if (perspective->get_vanishing_point(axis)->state == VP_INFINITE) {
         this->set_direction(perspective->get_vanishing_point(axis)->v_dir);
index 21bb7fa769e352f76eb52f1e7b2a15bc81859a74..bd1c8f5b0cbdd187310748dba73b28f47753cd19 100644 (file)
@@ -84,6 +84,9 @@ void VanishingPoint::draw(Box3D::Axis const axis)
             else
                 create_canvas_point(*this, 6.0, 0xffffff00);
             break;
+        default:
+            g_assert_not_reached();
+            break;
     }
 }
 
index b94193adcba70b56af1841cc6c202320dee459e7..cc11f9749e643a1be07e844ea2d01de3f801ee80 100644 (file)
@@ -36,11 +36,32 @@ enum Axis {
 };
 
 
+inline bool is_single_axis_direction (Box3D::Axis dir) {
+    // tests whether dir is nonzero and a power of 2
+    return (!(dir & (dir - 1)) && dir);
+}
+
 /** Given two axis directions out of {X, Y, Z}, returns the remaining one */
 inline Box3D::Axis third_axis_direction (Box3D::Axis dir1, Box3D::Axis dir2) {
     return (Box3D::Axis) ((dir1 + dir2) ^ 0x7);
 }
 
+/* returns the first axis direction occuring in the (possibly compound) expression 'dirs' */
+inline Box3D::Axis extract_single_axis_direction (Box3D::Axis dirs) {
+    if (dirs & Box3D::X) return Box3D::X;
+    if (dirs & Box3D::Y) return Box3D::Y;
+    if (dirs & Box3D::Z) return Box3D::Z;
+    return Box3D::NONE;
+}
+
+/* returns an axis direction perpendicular to the ones occuring in the (possibly compound) expression 'dirs' */
+inline Box3D::Axis get_perpendicular_axis_direction (Box3D::Axis dirs) {
+    if (!(dirs & Box3D::X)) return Box3D::X;
+    if (!(dirs & Box3D::Y)) return Box3D::Y;
+    if (!(dirs & Box3D::Z)) return Box3D::Z;
+    return Box3D::NONE;
+}
+
 
 // FIXME: Store the Axis of the VP inside the class
 class VanishingPoint : public NR::Point {