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