]> Shamusworld >> Repos - guemap/blob - src/globals.cpp
Fix room adding to work properly, misc. small changes.
[guemap] / src / globals.cpp
1 //
2 // GUEmap
3 // (C) 1997-2007 Christopher J. Madsen
4 // (C) 2019 James Hammons
5 //
6 // GUEmap is licensed under either version 2 of the GPL, or (at your option)
7 // any later version.  See LICENSE file for details.
8 //
9
10 #include "globals.h"
11 #include <math.h>
12 #include "mathconstants.h"
13
14 //
15 // Class MapEdge:
16 //
17 // Member Variables:
18 //   end1:   The corner of room1 where this edge begins
19 //   end2:   The corner of room2 where this edge ends
20 //   room1:  The room where this edge begins
21 //   room2:  The room where this edge ends
22 //   type1:
23 //     The type of exit this is from room1
24 //     The etSpecial codes are only used with type1
25 //   type2:
26 //     The type2 of exit this is from room2
27 //
28 MapEdge::MapEdge(): room1(0), room2(0), end1(rcNone), end2(rcNone), type1(0), type2(0)
29 {
30 }
31
32 MapEdge::MapEdge(RoomNum r1, RoomNum r2, EdgeType t1, EdgeType t2, RoomCorner e1, RoomCorner e2): room1(r1), room2(r2), end1(e1), end2(e2), type1(t1), type2(t2)
33 {
34 }
35
36 void MapEdge::Clear(void)
37 {
38         room1 = room2 = 0;
39         end1 = end2 = rcNone;
40         type1 = type2 = 0;
41 }
42
43 //
44 // Actually swap the rooms for this edge
45 //
46 void MapEdge::Swap(void)
47 {
48         RoomNum tr1 = room1;
49         room1 = room2;
50         room2 = tr1;
51
52         EdgeType tt = type1;
53         type1 = type2;
54         type2 = tt;
55
56         RoomCorner tc = end1;
57         end1 = end2;
58         end2 = tc;
59 }
60
61 bool MapEdge::HasRoom(RoomNum r)
62 {
63         if ((room1 != r) && (room2 != r))
64                 return false;
65
66         return true;
67 }
68
69 //
70 // Return the MapEdge but with the RoomNums, EdgeTypes, & RoomCorners swapped
71 //
72 MapEdge MapEdge::Swapped(void) const
73 {
74         // Not sure why, but MapDoc::findEdge() keeps the etObstructed on room 1 for some reason...
75         return MapEdge(room2, room1, type2 | (type1 & etObstructed), type1 & ~etObstructed, end2, end1);
76 }
77
78 //
79 // Class MapRoom:
80 //
81 // Member Variables:
82 //   flags:
83 //     Bitmask of RoomFlags constants:
84 //       rfBorder:  Room has a border (default)
85 //       rfCorner:  Room is a corner connector (no name, one grid square)
86 //   pos:
87 //     The position of the top left corner of the room
88 //     Given in logical MM_HIMETRIC coordinates.
89 //   name:
90 //     The name of the room.
91 //
92 MapRoom::MapRoom(): flags(0)
93 {
94 }
95
96 MapRoom::MapRoom(const MapRoom & o)
97 {
98         *this = o;
99 }
100
101 MapRoom & MapRoom::operator=(const MapRoom & source)
102 {
103         pos = source.pos;
104         name = source.name;
105         note = source.note;
106         flags = source.flags;
107         return *this;
108 }
109
110 QRect MapRoom::getRect(void)
111 {
112         return QRect(pos,
113                 (flags & rfCorner ? QSize(gridX, gridY) : QSize(roomWidth, roomHeight)));
114 }
115
116 QRect MapRoom::getTranslatedRect(QPoint t)
117 {
118         return QRect(pos + t,
119                 (flags & rfCorner ? QSize(gridX, gridY) : QSize(roomWidth, roomHeight)));
120 }
121
122 QPoint MapRoom::GetCenter(void)
123 {
124         return QPoint(pos +
125                 (flags & rfCorner
126                         ? QPoint(gridX / 2, gridY / 2)
127                         : QPoint(roomWidth / 2, roomHeight / 2)));
128 }
129
130 RoomFlags MapRoom::isCorner() const
131 {
132         return (flags & rfCorner);
133 }
134
135 bool MapRoom::operator!=(const MapRoom & mr) const
136 {
137         if (pos != mr.pos)
138                 return false;
139
140         if (name != mr.name)
141                 return false;
142
143         if (note != mr.note)
144                 return false;
145
146         return true;
147 }
148
149 //
150 // Miscellaneous functions:
151 //--------------------------------------------------------------------
152 //
153 // Trim whitespace from left of string:
154 //
155 void trimLeft(string & s)
156 {
157         StrIdx  p = s.find_first_not_of("\n\r\t ");
158
159         if (p > 0)
160                 s.erase(0, p);
161 }
162
163 //
164 // Trim whitespace from right of string:
165 //
166 void trimRight(string & s)
167 {
168         StrIdx  p = s.find_last_not_of("\n\r\t ");
169
170         if (p < s.length())
171                 s.erase(p + 1);
172 }
173
174 //
175 // Consolidates action creation from a multi-step process to a single-step one.
176 //
177 QAction * CreateAction(QString name, QString tooltip,
178         QString statustip, QIcon icon, QKeySequence key, bool checkable/*= false*/, QObject * parent/*= 0*/)
179 {
180         QAction * action = new QAction(icon, name, parent);
181         action->setToolTip(tooltip);
182         action->setStatusTip(statustip);
183         action->setShortcut(key);
184         action->setCheckable(checkable);
185
186         return action;
187 }
188
189 //
190 // This is essentially the same as the previous function, but this allows more
191 // than one key sequence to be added as key shortcuts.
192 //
193 QAction * CreateAction(QString name, QString tooltip,
194         QString statustip, QIcon icon, QKeySequence key1, QKeySequence key2,
195         bool checkable/*= false*/, QObject * parent/*= 0*/)
196 {
197         QAction * action = new QAction(icon, name, parent);
198         action->setToolTip(tooltip);
199         action->setStatusTip(statustip);
200         QList<QKeySequence> keyList;
201         keyList.append(key1);
202         keyList.append(key2);
203         action->setShortcuts(keyList);
204         action->setCheckable(checkable);
205
206         return action;
207 }
208
209 //
210 // Miscellaneous geometrical helper functions
211 //
212 double Magnitude(QPointF p)
213 {
214         return sqrt((p.x() * p.x()) + (p.y() * p.y()));
215 }
216
217 QPointF UnitVector(QPointF p)
218 {
219         double magnitude = Magnitude(p);
220
221         if (magnitude == 0)
222                 return QPointF(0, 0);
223
224         return QPointF(p.x() / magnitude, p.y() / magnitude);
225 }
226
227 double Angle(QPointF p)
228 {
229         double angle = atan2(p.y(), p.x());
230
231         if (angle < 0)
232                 angle += TAU;
233
234         return angle;
235 }
236
237 double Angle(QPoint p)
238 {
239         double angle = atan2((double)p.y(), (double)p.x());
240
241         if (angle < 0)
242                 angle += TAU;
243
244         return angle;
245 }
246
247 double Dot(QPointF a, QPointF b)
248 {
249         return (a.x() * b.x()) + (a.y() * b.y());
250 }
251
252 double Determinant(QPointF a, QPointF b)
253 {
254         return (a.x() * b.y()) - (b.x() * a.y());
255 }
256
257 // Returns the parameter of a point in space to this vector. If the parameter
258 // is between 0 and 1, the normal of the vector to the point is on the vector.
259 double ParameterOfLineAndPoint(QPointF tail, QPointF head, QPointF point)
260 {
261         // Geometric interpretation:
262         // The parameterized point on the vector lineSegment is where the normal of
263         // the lineSegment to the point intersects lineSegment. If the pp < 0, then
264         // the perpendicular lies beyond the 1st endpoint. If pp > 1, then the
265         // perpendicular lies beyond the 2nd endpoint.
266
267         QPointF lineSegment = head - tail;
268         double magnitude = Magnitude(lineSegment);
269         QPointF pointSegment = point - tail;
270         double t = Dot(lineSegment, pointSegment) / (magnitude * magnitude);
271
272         return t;
273 }