1 /* 2 * Copyright 2012, 2013 Thomas Schöps 3 * Copyright 2015-2017 Kai Pastor 4 * 5 * This file is part of OpenOrienteering. 6 * 7 * OpenOrienteering is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * OpenOrienteering is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with OpenOrienteering. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #ifndef OPENORIENTEERING_OBJECT_MOVER_H 22 #define OPENORIENTEERING_OBJECT_MOVER_H 23 24 #include <unordered_map> 25 #include <unordered_set> 26 #include <utility> 27 #include <vector> 28 29 #include <QtGlobal> 30 31 #include "core/map_coord.h" 32 33 namespace OpenOrienteering { 34 35 class Map; 36 class Object; 37 class PathObject; 38 class TextObject; 39 40 using SelectionInfoVector = std::vector<std::pair<int, Object*>>; 41 42 43 /** 44 * Implements the logic to move sets of objects and / or object points for edit tools. 45 */ 46 class ObjectMover 47 { 48 public: 49 enum HandleOpMode { 50 Never, ///< Never move opposite curve handles 51 Click, ///< Move opposite handles once they get aligned in line, move them 52 ///< together from that point on 53 }; 54 55 /** Creates a mover for the map with the given cursor start position. */ 56 ObjectMover(Map* map, const MapCoordF& start_pos); 57 58 /** Sets the start position. */ 59 void setStartPos(const MapCoordF& start_pos); 60 61 /** Sets corner point tolerance. A curve anchor point is considered a corner 62 * point during editing when the moving curve handle is more than 63 * corner_tolerance away from the direction line set by the opposite handle. 64 * 65 * @param corner_tolerance Maximum difference in vector directions 66 * in millimeters. 67 */ 68 void setCornerTolerance(qreal corner_tolerance); 69 70 /** Adds an object to the set of elements to move. */ 71 void addObject(Object* object); 72 73 /** Adds a point to the set of elements to move. */ 74 void addPoint(PathObject* object, MapCoordVector::size_type point_index); 75 76 /** Adds a line to the set of elements to move. */ 77 void addLine(PathObject* object, MapCoordVector::size_type start_point_index); 78 79 /** Adds a text handle to the set of elements to move. */ 80 void addTextHandle(TextObject* text, MapCoordVector::size_type handle); 81 82 /** 83 * Moves the elements. 84 * @param move_opposite_handles Opposite curve handles either operate 85 * in "click in" mode or move independently. 86 * @param out_dx returns the move along the x coordinate in map units 87 * @param out_dy returns the move along the y coordinate in map units 88 */ 89 void move(const MapCoordF& cursor_pos, HandleOpMode move_opposite_handles, 90 qint32* out_dx = nullptr, qint32* out_dy = nullptr); 91 92 /** Overload of move() taking delta values. */ 93 void move(qint32 dx, qint32 dy, HandleOpMode move_opposite_handles); 94 95 private: 96 using ObjectSet = std::unordered_set<Object*>; 97 using CoordIndexSet = std::unordered_set<MapCoordVector::size_type>; 98 99 CoordIndexSet* insertPointObject(PathObject* object); 100 void calculateConstraints(); 101 102 // Basic information 103 MapCoordF start_position; 104 qreal corner_tolerance {}; 105 qint32 prev_drag_x {}; 106 qint32 prev_drag_y {}; 107 ObjectSet objects; 108 std::unordered_map<PathObject*, CoordIndexSet> points; 109 std::unordered_map<TextObject*, MapCoordVector::size_type> text_handles; 110 111 /** Constraints calculated from the basic information */ 112 struct OppositeHandleConstraint 113 { 114 /** Object to which the constraint applies */ 115 PathObject* object; 116 /** Index of moved handle */ 117 MapCoordVector::size_type moved_handle_index; 118 /** Index of opposite handle */ 119 MapCoordVector::size_type opposite_handle_index; 120 /** Index of center point in the middle of the handles */ 121 MapCoordVector::size_type curve_anchor_index; 122 /** Middle point is a corner point */ 123 bool anchor_is_corner; 124 /** Distance of opposite handle to center point */ 125 qreal opposite_handle_dist; 126 /** Original position of the opposite handle */ 127 MapCoord opposite_handle_original_position; 128 }; 129 std::vector<OppositeHandleConstraint> handle_constraints; 130 bool constraints_calculated {true}; 131 }; 132 133 134 } // namespace OpenOrienteering 135 136 #endif 137