Code

GSoC C++-ificiation merge and cleanup.
[inkscape.git] / src / vanishing-point.h
index b7f3d12a1f8ec322d35f8e5481bdb36c11f0a54d..9fcb6bb46d6440a0e35bf8b67311add2df68d78f 100644 (file)
 #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 {
 
@@ -22,148 +31,182 @@ enum VPState {
     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 */