From 428cd4b47a96c3f9e4074fd356ef95d09adbf58c Mon Sep 17 00:00:00 2001 From: cilix42 Date: Wed, 4 Jul 2007 10:26:36 +0000 Subject: [PATCH] New/updated 3D box auxiliary/convenience functions (e.g., allow (un)constrained movement of corners, too; determine midpoints of edges) --- src/box3d.cpp | 41 +++++++++++++++++++++++++++++++++++++--- src/box3d.h | 9 +++++++-- src/object-edit.cpp | 3 +-- src/perspective-line.cpp | 1 + src/vanishing-point.cpp | 3 +++ src/vanishing-point.h | 21 ++++++++++++++++++++ 6 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/box3d.cpp b/src/box3d.cpp index 258c65879..aefa620cd 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -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 +sp_3dbox_get_center (SP3DBox *box) +{ + return sp_3dbox_get_midpoint_between_corners (box, 0, 7); +} + +NR::Maybe +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 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: diff --git a/src/box3d.h b/src/box3d.h index 1fb8280ee..8fe90dc3b 100644 --- a/src/box3d.h +++ b/src/box3d.h @@ -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 sp_3dbox_get_center (SP3DBox *box); +NR::Maybe 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 diff --git a/src/object-edit.cpp b/src/object-edit.cpp index c597f3a26..684c4404f 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -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])); } diff --git a/src/perspective-line.cpp b/src/perspective-line.cpp index 158ddd47b..e5596cc1b 100644 --- a/src/perspective-line.cpp +++ b/src/perspective-line.cpp @@ -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); diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 21bb7fa76..bd1c8f5b0 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -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; } } diff --git a/src/vanishing-point.h b/src/vanishing-point.h index b94193adc..cc11f9749 100644 --- a/src/vanishing-point.h +++ b/src/vanishing-point.h @@ -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 { -- 2.30.2