1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Vanishing point for 3D perspectives 4 * 5 * Authors: 6 * Maximilian Albert <Anhalter42@gmx.de> 7 * 8 * Copyright (C) 2007 authors 9 * 10 * Released under GNU GPL v2+, read the file 'COPYING' for more information. 11 */ 12 13 #ifndef SEEN_VANISHING_POINT_H 14 #define SEEN_VANISHING_POINT_H 15 16 #include <2geom/point.h> 17 #include <list> 18 #include <set> 19 20 #include "selection.h" 21 22 #include "display/control/canvas-item-enums.h" 23 24 #include "object/persp3d.h" 25 26 class SPBox3D; 27 class SPKnot; 28 29 namespace Inkscape { 30 class CanvasItemCurve; 31 } 32 33 namespace Box3D { 34 35 enum VPState { 36 VP_FINITE = 0, // perspective lines meet in the VP 37 VP_INFINITE // perspective lines are parallel 38 }; 39 40 /* VanishingPoint is a simple wrapper class to easily extract VP data from perspectives. 41 * A VanishingPoint represents a VP in a certain direction (X, Y, Z) of a single perspective. 42 * In particular, it can potentially have more than one box linked to it (although in facth they 43 * are rather linked to the parent perspective). 44 */ 45 // FIXME: Don't store the box in the VP but rather the perspective (and link the box to it)!! 46 class VanishingPoint { 47 public: VanishingPoint()48 VanishingPoint() : my_counter(VanishingPoint::global_counter++), _persp(nullptr), _axis(Proj::NONE) {} VanishingPoint(Persp3D * persp,Proj::Axis axis)49 VanishingPoint(Persp3D *persp, Proj::Axis axis) : my_counter(VanishingPoint::global_counter++), _persp(persp), _axis(axis) {} VanishingPoint(const VanishingPoint & other)50 VanishingPoint(const VanishingPoint &other) : my_counter(VanishingPoint::global_counter++), _persp(other._persp), _axis(other._axis) {} 51 52 inline VanishingPoint &operator=(VanishingPoint const &rhs) = default; 53 inline bool operator==(VanishingPoint const &rhs) const { 54 /* vanishing points coincide if they belong to the same perspective */ 55 return (_persp == rhs._persp && _axis == rhs._axis); 56 } 57 58 inline bool operator<(VanishingPoint const &rhs) const { 59 return my_counter < rhs.my_counter; 60 } 61 set(Persp3D * persp,Proj::Axis axis)62 inline void set(Persp3D *persp, Proj::Axis axis) { 63 _persp = persp; 64 _axis = axis; 65 } 66 void set_pos(Proj::Pt2 const &pt); is_finite()67 inline bool is_finite() const { 68 g_return_val_if_fail (_persp, false); 69 return _persp->get_VP (_axis).is_finite(); 70 } get_pos()71 inline Geom::Point get_pos() const { 72 g_return_val_if_fail (_persp, Geom::Point (Geom::infinity(), Geom::infinity())); 73 return _persp->get_VP (_axis).affine(); 74 } get_perspective()75 inline Persp3D * get_perspective() const { 76 return _persp; 77 } set_perspective(Persp3D * persp)78 inline Persp3D * set_perspective(Persp3D *persp) { 79 return _persp = persp; 80 } 81 hasBox(SPBox3D * box)82 inline bool hasBox (SPBox3D *box) { 83 return _persp->has_box(box); 84 } numberOfBoxes()85 inline unsigned int numberOfBoxes() const { 86 return _persp->num_boxes(); 87 } 88 89 /* returns all selected boxes sharing this perspective */ 90 std::list<SPBox3D *> selectedBoxes(Inkscape::Selection *sel); 91 updateBoxDisplays()92 inline void updateBoxDisplays() const { 93 g_return_if_fail (_persp); 94 _persp->update_box_displays(); 95 } updateBoxReprs()96 inline void updateBoxReprs() const { 97 g_return_if_fail (_persp); 98 _persp->update_box_reprs(); 99 } updatePerspRepr()100 inline void updatePerspRepr() const { 101 g_return_if_fail (_persp); 102 SP_OBJECT(_persp)->updateRepr(SP_OBJECT_WRITE_EXT); 103 } printPt()104 inline void printPt() const { 105 g_return_if_fail (_persp); 106 _persp->get_VP (_axis).print(""); 107 } axisString()108 inline char const *axisString () { return Proj::string_from_axis(_axis); } 109 110 unsigned int my_counter; 111 static unsigned int global_counter; // FIXME: Only to implement operator< so that we can merge lists. Do this in a better way!! 112 private: 113 Persp3D *_persp; 114 Proj::Axis _axis; 115 }; 116 117 struct VPDrag; 118 119 struct VPDragger { 120 public: 121 VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp); 122 ~VPDragger(); 123 124 VPDrag *parent; 125 SPKnot *knot; 126 127 // position of the knot, desktop coords 128 Geom::Point point; 129 // position of the knot before it began to drag; updated when released 130 Geom::Point point_original; 131 132 bool dragging_started; 133 134 std::list<VanishingPoint> vps; 135 136 void addVP(VanishingPoint &vp, bool update_pos = false); 137 void removeVP(const VanishingPoint &vp); 138 139 void updateTip(); 140 141 unsigned int numberOfBoxes(); // the number of boxes linked to all VPs of the dragger 142 VanishingPoint *findVPWithBox(SPBox3D *box); 143 std::set<VanishingPoint*> VPsOfSelectedBoxes(); 144 145 bool hasPerspective(const Persp3D *persp); 146 void mergePerspectives(); // remove duplicate perspectives 147 148 void updateBoxDisplays(); 149 void updateVPs(Geom::Point const &pt); 150 void updateZOrders(); 151 152 void printVPs(); 153 154 private: 155 sigc::connection _moved_connection; 156 sigc::connection _grabbed_connection; 157 sigc::connection _ungrabbed_connection; 158 }; 159 160 struct VPDrag { 161 public: 162 VPDrag(SPDocument *document); 163 ~VPDrag(); 164 165 VPDragger *getDraggerFor (VanishingPoint const &vp); 166 167 bool dragging; 168 169 SPDocument *document; 170 std::vector<VPDragger *> draggers; 171 std::vector<Inkscape::CanvasItemCurve *> item_curves; 172 173 void printDraggers(); // convenience for debugging 174 /* 175 * FIXME: Should the following functions be merged? 176 * Also, they should make use of the info in a VanishingPoint structure (regarding boxes 177 * and perspectives) rather than each time iterating over the whole list of selected items? 178 */ 179 void updateDraggers (); 180 void updateLines (); 181 void updateBoxHandles (); 182 void updateBoxReprs (); 183 void updateBoxDisplays (); 184 void drawLinesForFace (const SPBox3D *box, Proj::Axis axis); //, guint corner1, guint corner2, guint corner3, guint corner4); 185 bool show_lines; /* whether perspective lines are drawn at all */ 186 unsigned int front_or_rear_lines; /* whether we draw perspective lines from all corners or only the 187 front/rear corners (indicated by the first/second bit, respectively */ 188 189 hasEmptySelectionVPDrag190 inline bool hasEmptySelection() { return this->selection->isEmpty(); } 191 bool allBoxesAreSelected (VPDragger *dragger); 192 193 // FIXME: Should this be private? (It's the case with the corresponding function in gradient-drag.h) 194 // But vp_knot_grabbed_handler 195 void addDragger (VanishingPoint &vp); 196 197 void swap_perspectives_of_VPs(Persp3D *persp2, Persp3D *persp1); 198 199 private: 200 //void deselect_all(); 201 202 /** 203 * Create a line from p1 to p2 and add it to the item_curves list. 204 */ 205 void addCurve(Geom::Point const &p1, Geom::Point const &p2, Inkscape::CanvasItemColor color); 206 207 Inkscape::Selection *selection; 208 sigc::connection sel_changed_connection; 209 sigc::connection sel_modified_connection; 210 }; 211 212 } // namespace Box3D 213 214 215 #endif /* !SEEN_VANISHING_POINT_H */ 216 217 /* 218 Local Variables: 219 mode:c++ 220 c-file-style:"stroustrup" 221 c-file-offsets:((innamespace . 0)(inline-open . 0)) 222 indent-tabs-mode:nil 223 fill-column:99 224 End: 225 */ 226 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 227