diff --git a/src/vanishing-point.h b/src/vanishing-point.h
index b7f3d12a1f8ec322d35f8e5481bdb36c11f0a54d..9fcb6bb46d6440a0e35bf8b67311add2df68d78f 100644 (file)
--- a/src/vanishing-point.h
+++ b/src/vanishing-point.h
#ifndef SEEN_VANISHING_POINT_H
#define SEEN_VANISHING_POINT_H
-#include "libnr/nr-point.h"
-#include "line-geometry.h"
+#include <set>
+#include <2geom/point.h>
+#include "knot.h"
+#include "selection.h"
+#include "axis-manip.h"
+#include "inkscape.h"
+#include "persp3d.h"
+#include "box3d.h"
+#include "persp3d-reference.h"
+
+class SPBox3D;
namespace Box3D {
VP_INFINITE // perspective lines are parallel
};
-// The X-/Y-/Z-axis corresponds to the first/second/third digit
-// in binary representation, respectively.
-enum Axis {
- X = 1,
- Y = 2,
- Z = 4,
- XY = 3,
- XZ = 5,
- YZ = 6,
- XYZ = 7,
- NONE = 0
-};
+/* VanishingPoint is a simple wrapper class to easily extract VP data from perspectives.
+ * A VanishingPoint represents a VP in a certain direction (X, Y, Z) of a single perspective.
+ * In particular, it can potentially have more than one box linked to it (although in facth they
+ * are rather linked to the parent perspective).
+ */
+// FIXME: Don't store the box in the VP but rather the perspective (and link the box to it)!!
+class VanishingPoint {
+public:
+ VanishingPoint() : my_counter(VanishingPoint::global_counter++), _persp(NULL), _axis(Proj::NONE) {}
+ VanishingPoint(Persp3D *persp, Proj::Axis axis) : my_counter(VanishingPoint::global_counter++), _persp(persp), _axis(axis) {}
+ VanishingPoint(const VanishingPoint &other) : my_counter(VanishingPoint::global_counter++), _persp(other._persp), _axis(other._axis) {}
+
+ inline VanishingPoint &operator=(VanishingPoint const &rhs) {
+ _persp = rhs._persp;
+ _axis = rhs._axis;
+ return *this;
+ }
+ inline bool operator==(VanishingPoint const &rhs) const {
+ /* vanishing points coincide if they belong to the same perspective */
+ return (_persp == rhs._persp && _axis == rhs._axis);
+ }
-// We use the fourth bit in binary representation
-// to indicate whether a face is front or rear.
-enum FrontOrRear { // find a better name
- FRONT = 0,
- REAR = 8
-};
+ inline bool operator<(VanishingPoint const &rhs) const {
+ return my_counter < rhs.my_counter;
+ }
+
+ inline void set(Persp3D *persp, Proj::Axis axis) {
+ _persp = persp;
+ _axis = axis;
+ }
+ void set_pos(Proj::Pt2 const &pt);
+ inline bool is_finite() const {
+ g_return_val_if_fail (_persp, false);
+ return persp3d_get_VP (_persp, _axis).is_finite();
+ }
+ inline Geom::Point get_pos() const {
+ g_return_val_if_fail (_persp, Geom::Point (NR_HUGE, NR_HUGE));
+ return persp3d_get_VP (_persp,_axis).affine();
+ }
+ inline Persp3D * get_perspective() const {
+ return _persp;
+ }
+ inline Persp3D * set_perspective(Persp3D *persp) {
+ return _persp = persp;
+ }
-extern Axis axes[3];
-extern Axis planes[3];
-extern FrontOrRear face_positions [2];
-
-// Given a bit sequence that unambiguously specifies the face of a 3D box,
-// return a number between 0 and 5 corresponding to that particular face
-// (which is normally used to index an array). Return -1 if the bit sequence
-// does not specify a face. A face can either be given by its plane (e.g, XY)
-// or by the axis that is orthogonal to it (e.g., Z).
-inline gint face_to_int (guint face_id) {
- switch (face_id) {
- case 1: return 0;
- case 2: return 2;
- case 4: return 4;
- case 3: return 4;
- case 5: return 2;
- case 6: return 0;
-
- case 9: return 1;
- case 10: return 3;
- case 12: return 5;
- case 11: return 5;
- case 13: return 3;
- case 14: return 1;
-
- default: return -1;
+ inline bool hasBox (SPBox3D *box) {
+ return persp3d_has_box(_persp, box);
+ }
+ inline unsigned int numberOfBoxes() const {
+ return persp3d_num_boxes(_persp);
}
-}
-inline bool is_single_axis_direction (Box3D::Axis dir) {
- // tests whether dir is nonzero and a power of 2
- return (!(dir & (dir - 1)) && dir);
-}
+ /* returns all selected boxes sharing this perspective */
+ std::list<SPBox3D *> selectedBoxes(Inkscape::Selection *sel);
-/**
- * Given two axis directions out of {X, Y, Z} or the corresponding plane, return the remaining one
- * We don't check if 'plane' really specifies a plane (i.e., if it consists of precisely two directions).
- */
-inline Box3D::Axis third_axis_direction (Box3D::Axis dir1, Box3D::Axis dir2) {
- return (Box3D::Axis) ((dir1 + dir2) ^ 0x7);
-}
-inline Box3D::Axis third_axis_direction (Box3D::Axis plane) {
- return (Box3D::Axis) (plane ^ 0x7);
-}
-
-/* returns the first/second axis direction occuring in the (possibly compound) expression 'dirs' */
-inline Box3D::Axis extract_first_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;
-}
-inline Box3D::Axis extract_second_axis_direction (Box3D::Axis dirs) {
- return extract_first_axis_direction ((Box3D::Axis) (dirs ^ extract_first_axis_direction(dirs)));
-}
-
-inline Box3D::Axis orth_plane (Box3D::Axis axis) {
- return (Box3D::Axis) (Box3D::XYZ ^ axis);
-}
-
-/* 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;
-}
-
-inline gchar * string_from_axes (Box3D::Axis axes) {
- GString *pstring = g_string_new("");
- if (axes & Box3D::X) g_string_append_printf (pstring, "X");
- if (axes & Box3D::Y) g_string_append_printf (pstring, "Y");
- if (axes & Box3D::Z) g_string_append_printf (pstring, "Z");
- return pstring->str;
-}
-
-// FIXME: Store the Axis of the VP inside the class
-class VanishingPoint : public NR::Point {
-public:
- inline VanishingPoint() : NR::Point() {};
- /***
- inline VanishingPoint(NR::Point const &pt, NR::Point const &ref = NR::Point(0,0))
- : NR::Point (pt),
- ref_pt (ref),
- v_dir (pt[NR::X] - ref[NR::X], pt[NR::Y] - ref[NR::Y]) {}
- inline VanishingPoint(NR::Coord x, NR::Coord y, NR::Point const &ref = NR::Point(0,0))
- : NR::Point (x, y),
- ref_pt (ref),
- v_dir (x - ref[NR::X], y - ref[NR::Y]) {}
- ***/
- VanishingPoint(NR::Point const &pt, NR::Point const &inf_dir, VPState st);
- VanishingPoint(NR::Point const &pt);
- VanishingPoint(NR::Point const &dir, VPState const state);
- VanishingPoint(NR::Point const &pt, NR::Point const &direction);
- VanishingPoint(NR::Coord x, NR::Coord y);
- VanishingPoint(NR::Coord x, NR::Coord y, VPState const state);
- VanishingPoint(NR::Coord x, NR::Coord y, NR::Coord dir_x, NR::Coord dir_y);
- VanishingPoint(VanishingPoint const &rhs);
-
- bool is_finite();
- VPState toggle_parallel();
- void draw(Box3D::Axis const axis); // Draws a point on the canvas if state == VP_FINITE
- //inline VPState state() { return state; }
-
- VPState state;
- //NR::Point ref_pt; // point of reference to compute the direction of parallel lines
- NR::Point v_dir; // direction of perslective lines if the VP has state == VP_INFINITE
+ inline void updateBoxDisplays() const {
+ g_return_if_fail (_persp);
+ persp3d_update_box_displays(_persp);
+ }
+ inline void updateBoxReprs() const {
+ g_return_if_fail (_persp);
+ persp3d_update_box_reprs(_persp);
+ }
+ inline void updatePerspRepr() const {
+ g_return_if_fail (_persp);
+ SP_OBJECT(_persp)->updateRepr(SP_OBJECT_WRITE_EXT);
+ }
+ inline void printPt() const {
+ g_return_if_fail (_persp);
+ persp3d_get_VP (_persp, _axis).print("");
+ }
+ inline gchar const *axisString () { return Proj::string_from_axis(_axis); }
+ unsigned int my_counter;
+ static unsigned int global_counter; // FIXME: Only to implement operator< so that we can merge lists. Do this in a better way!!
private:
+ Persp3D *_persp;
+ Proj::Axis _axis;
};
+class VPDrag;
-} // namespace Box3D
+struct less_ptr : public std::binary_function<VanishingPoint *, VanishingPoint *, bool> {
+ bool operator()(VanishingPoint *vp1, VanishingPoint *vp2) {
+ return GPOINTER_TO_INT(vp1) < GPOINTER_TO_INT(vp2);
+ }
+};
+
+struct VPDragger {
+public:
+ VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp);
+ ~VPDragger();
+
+ VPDrag *parent;
+ SPKnot *knot;
+ // position of the knot, desktop coords
+ Geom::Point point;
+ // position of the knot before it began to drag; updated when released
+ Geom::Point point_original;
-/** A function to print out the VanishingPoint (prints the coordinates) **/
-/***
-inline std::ostream &operator<< (std::ostream &out_file, const VanishingPoint &vp) {
- out_file << vp;
- return out_file;
-}
-***/
+ bool dragging_started;
+
+ std::list<VanishingPoint> vps;
+
+ void addVP(VanishingPoint &vp, bool update_pos = false);
+ void removeVP(const VanishingPoint &vp);
+
+ void updateTip();
+
+ guint numberOfBoxes(); // the number of boxes linked to all VPs of the dragger
+ VanishingPoint *findVPWithBox(SPBox3D *box);
+ std::set<VanishingPoint*, less_ptr> VPsOfSelectedBoxes();
+
+ bool hasPerspective(const Persp3D *persp);
+ void mergePerspectives(); // remove duplicate perspectives
+
+ void updateBoxDisplays();
+ void updateVPs(Geom::Point const &pt);
+ void updateZOrders();
+
+ void printVPs();
+};
+
+struct VPDrag {
+public:
+ VPDrag(SPDocument *document);
+ ~VPDrag();
+
+ VPDragger *getDraggerFor (VanishingPoint const &vp);
+
+ bool dragging;
+
+ SPDocument *document;
+ GList *draggers;
+ GSList *lines;
+
+ void printDraggers(); // convenience for debugging
+ /*
+ * FIXME: Should the following functions be merged?
+ * Also, they should make use of the info in a VanishingPoint structure (regarding boxes
+ * and perspectives) rather than each time iterating over the whole list of selected items?
+ */
+ void updateDraggers ();
+ void updateLines ();
+ void updateBoxHandles ();
+ void updateBoxReprs ();
+ void updateBoxDisplays ();
+ void drawLinesForFace (const SPBox3D *box, Proj::Axis axis); //, guint corner1, guint corner2, guint corner3, guint corner4);
+ bool show_lines; /* whether perspective lines are drawn at all */
+ guint front_or_rear_lines; /* whether we draw perspective lines from all corners or only the
+ front/rear corners (indicated by the first/second bit, respectively */
+
+
+ inline bool hasEmptySelection() { return this->selection->isEmpty(); }
+ bool allBoxesAreSelected (VPDragger *dragger);
+ GSList * selectedBoxesWithVPinDragger (VPDragger *dragger);
+
+ // FIXME: Should this be private? (It's the case with the corresponding function in gradient-drag.h)
+ // But vp_knot_grabbed_handler
+ void addDragger (VanishingPoint &vp);
+
+ void swap_perspectives_of_VPs(Persp3D *persp2, Persp3D *persp1);
+
+private:
+ //void deselect_all();
+
+ void addLine (Geom::Point p1, Geom::Point p2, guint32 rgba);
+
+ Inkscape::Selection *selection;
+ sigc::connection sel_changed_connection;
+ sigc::connection sel_modified_connection;
+};
+
+} // namespace Box3D
#endif /* !SEEN_VANISHING_POINT_H */