]> Shamusworld >> Repos - architektonas/blob - src/triangulateaction.cpp
1f6a94938a1fefc04cd94d40f30f773a47dadd93
[architektonas] / src / triangulateaction.cpp
1 // triangulateaction.cpp: Action class for creating triangles from lines
2 //
3 // Part of the Architektonas Project
4 // (C) 2014 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  05/07/2014  Created this file
12 //
13
14 #include "triangulateaction.h"
15 #include "applicationwindow.h"
16 #include "circle.h"
17 #include "container.h"
18 #include "drawingview.h"
19 #include "geometry.h"
20 #include "line.h"
21 #include "mathconstants.h"
22 #include "painter.h"
23
24
25 enum { FIRST_LINE, SECOND_LINE, THIRD_LINE };
26
27
28 TriangulateAction::TriangulateAction(): state(FIRST_LINE),// t(0), u(1.0),
29         line1(NULL), line2(NULL), line3(NULL),
30         doc(&(ApplicationWindow::drawing->document))
31 //, line(NULL),
32 //      shiftWasPressedOnNextPoint(false), ctrlWasPressed(false),
33 //      mirror(new Container(Vector()))
34 {
35 //      ApplicationWindow::drawing->document.CopySelectedContentsTo(mirror);
36 //      mirror->Save();
37 }
38
39
40 TriangulateAction::~TriangulateAction()
41 {
42 }
43
44
45 /*virtual*/ void TriangulateAction::Draw(Painter * painter)
46 {
47         Object * obj = doc->lastObjectHovered;
48
49         if (obj == NULL)
50                 return;
51
52         // This assumes a Line, but it might not be!
53         painter->SetPen(QPen(Qt::blue, 2.0, Qt::DotLine));
54 //      Vector v(((Line *)obj)->position, ((Line *)obj)->endpoint);
55         Point p1 = ((Line *)obj)->position;
56         Point p2 = ((Line *)obj)->endpoint;
57         painter->DrawLine(p1, p2);
58 #if 0
59         if (state == FIRST_POINT)
60         {
61                 painter->DrawHandle(p1);
62         }
63         else
64         {
65                 Vector reflectedP2 = -(p2 - p1);
66                 Point newP2 = p1 + reflectedP2;
67                 painter->DrawLine(newP2, p2);
68                 painter->DrawHandle(p1);
69
70                 double absAngle = (Vector(p2 - p1).Angle()) * RADIANS_TO_DEGREES;
71
72                 // Keep the angle between 0 and 180 degrees
73                 if (absAngle > 180.0)
74                         absAngle -= 180.0;
75
76                 QString text = QChar(0x2221) + QObject::tr(": %1");
77                 text = text.arg(absAngle);
78
79                 if (ctrlWasPressed)
80                         text += " (Copy)";
81
82                 painter->DrawInformativeText(text);
83
84                 // Draw the mirror only if there's been a line to mirror around
85                 if (p1 != p2)
86                         mirror->Draw(painter);
87         }
88 #endif
89 }
90
91
92 /*virtual*/ void TriangulateAction::MouseDown(Vector /*point*/)
93 {
94 #if 0
95 // this is not accurate enough. need to use the actual intersection point, not
96 // just the parameter(s).
97         Object * toTrim = doc->lastObjectHovered;
98
99         if (toTrim == NULL)
100                 return;
101
102 //it would be nice to do it like this, but if we bisect the object, we have to
103 //create an extra one...
104 //      toTrim->Trim(t, u);
105
106         Vector v(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint);
107
108         // Check to see which case we have...
109         // We're trimming point #1...
110         if (t == 0)
111         {
112                 ((Line *)toTrim)->position = ((Line *)toTrim)->position + (v * u);
113 //              u = 1.0;
114         }
115         else if (u == 1.0)
116         {
117                 ((Line *)toTrim)->endpoint = ((Line *)toTrim)->position + (v * t);
118 //              t = 0;
119         }
120         else
121         {
122                 Point p1 = ((Line *)toTrim)->position + (v * t);
123                 Point p2 = ((Line *)toTrim)->position + (v * u);
124                 Point p3 = ((Line *)toTrim)->endpoint;
125                 ((Line *)toTrim)->endpoint = p1;
126                 Line * line = new Line(p2, p3);
127                 emit ObjectReady(line);
128 //              t = 0, u = 1.0;
129         }
130
131         doc->lastObjectHovered = NULL;
132 #endif
133 }
134
135
136 /*virtual*/ void TriangulateAction::MouseMoved(Vector point)
137 {
138 #if 0
139         if (state == FIRST_POINT)
140                 p1 = point;
141 //      else
142 //      {
143 //              p2 = point;
144 //              mirror->Restore();
145 //              mirror->Mirror(p1, p2);
146 //      }
147 #endif
148
149 #if 0
150 //      Container & doc = ApplicationWindow::drawing->document;
151 //      int items = doc.ItemsSelected();
152         Object * toTrim = doc->lastObjectHovered;
153 //      double closestPt1 = 0, closestPt2 = 1.0;
154         t = 0, u = 1.0;
155
156         if (toTrim == NULL)
157                 return;
158
159         if (toTrim->type != OTLine)
160                 return;
161
162         double pointHoveredT = Geometry::ParameterOfLineAndPoint(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint, point);
163
164         std::vector<Object *>::iterator i;
165
166         for(i=doc->objects.begin(); i!=doc->objects.end(); i++)
167         {
168                 // Can't trim against yourself... :-P
169                 if (*i == toTrim)
170                         continue;
171
172                 Object * trimAgainst = *i;
173                 double t1;//, u1;
174
175                 if ((toTrim->type != OTLine) || (trimAgainst->type != OTLine))
176                         continue;
177
178                 int intersects = Geometry::Intersects((Line *)toTrim, (Line *)trimAgainst, &t1);//, &u1);
179
180                 if (intersects)
181                 {
182                         // Now what? We don't know which side to trim!
183                         // ... now we do, we know which side of the Line we're on!
184                         if ((t1 > t) && (t1 < pointHoveredT))
185                                 t = t1;
186
187                         if ((t1 < u) && (t1 > pointHoveredT))
188                                 u = t1;
189                 }
190         }
191 #endif
192 }
193
194
195 /*virtual*/ void TriangulateAction::MouseReleased(void)
196 {
197 #if 0
198         if (state == FIRST_POINT)
199         {
200                 p2 = p1;
201                 state = NEXT_POINT;
202         }
203         else if (state == NEXT_POINT)
204         {
205                 if (!ctrlWasPressed)
206                 {
207                         state = FIRST_POINT;
208                         ApplicationWindow::drawing->document.MirrorSelected(p1, p2);
209
210                         mirror->Clear();
211                         ApplicationWindow::drawing->document.CopySelectedContentsTo(mirror);
212                         mirror->Save();
213                 }
214                 else
215                 {
216                         mirror->CopyContentsTo(&(ApplicationWindow::drawing->document));
217                 }
218         }
219 #endif
220         Object * obj = doc->lastObjectHovered;
221
222         if (obj == NULL)
223                 return;
224
225         if (obj->type != OTLine)
226                 return;
227
228         if (state == FIRST_LINE)
229         {
230                 line1 = (Line *)obj;
231                 line1->state = OSSelected;
232                 state = SECOND_LINE;
233         }
234         else if (state == SECOND_LINE)
235         {
236                 line2 = (Line *)obj;
237                 line2->state = OSSelected;
238                 state = THIRD_LINE;
239         }
240         else if (state == THIRD_LINE)
241         {
242                 line3 = (Line *)obj;
243                 state = FIRST_LINE;
244                 Triangulate();
245         }
246 }
247
248
249 /*virtual*/ void TriangulateAction::KeyDown(int /*key*/)
250 {
251 #if 0
252         if ((key == Qt::Key_Shift) && (state == NEXT_POINT))
253         {
254                 shiftWasPressedOnNextPoint = true;
255                 p1Save = p1;
256                 p1 = p2;
257                 state = FIRST_POINT;
258                 emit NeedRefresh();
259         }
260         else if (key == Qt::Key_Control)
261         {
262                 ctrlWasPressed = true;
263                 emit NeedRefresh();
264         }
265 #endif
266 #if 0
267         if ((t == 0) && (u == 1.0))
268                 return;
269
270         t = 0, u = 1.0;
271 #endif
272 }
273
274
275 /*virtual*/ void TriangulateAction::KeyReleased(int /*key*/)
276 {
277 #if 0
278         if ((key == Qt::Key_Shift) && shiftWasPressedOnNextPoint)
279         {
280                 shiftWasPressedOnNextPoint = false;
281                 p2 = p1;
282                 p1 = p1Save;
283                 state = NEXT_POINT;
284                 emit NeedRefresh();
285         }
286         else if (key == Qt::Key_Control)
287         {
288                 ctrlWasPressed = false;
289                 emit NeedRefresh();
290         }
291 #endif
292 }
293
294
295 void TriangulateAction::Triangulate(void)
296 {
297 // N.B.: Should connect the line segments together, once made into a triangle...
298         double length2 = Vector(line2->position, line2->endpoint).Magnitude();
299         double length3 = Vector(line3->position, line3->endpoint).Magnitude();
300 #if 0
301         double angle1, angle2, angle3;
302         double length1 = Vector(line1->position, line1->endpoint).Magnitude();
303         Geometry::FindAnglesForSides(length1, length2, length3, &angle1, &angle2, &angle3);
304 printf("Triangulate: l1=%lf, l2=%lf, l3=%lf, a1=%lf, a2=%lf, a3=%lf\n", length1, length2, length3, angle1, angle2, angle3);
305
306         // We use line1 as the base. Move the other lines to it.
307         double line1Angle = Vector(line1->position, line1->endpoint).Angle();
308         double newLine2Angle = line1Angle + angle3;
309         Vector v;
310         v.SetAngleAndLength(newLine2Angle, length2);
311 printf("             line1Angle=%lf, newLine2Angle=%lf\n", line1Angle, newLine2Angle);
312
313         line2->position = line1->endpoint;
314         line2->endpoint = line1->endpoint - v;
315
316 //      double line2Angle = Vector(line2->position, line2->endpoint).Angle();
317 //      double newLine3Angle = line2Angle + angle1;
318 //      Vector v2;
319 //      v2.SetAngleAndLength(newLine3Angle, length3);
320 #else
321         Circle c1(line1->position, length2), c2(line1->endpoint, length3);
322         Point p1, p2;
323         int n = Geometry::Intersects(&c1, &c2, 0, 0, 0, 0, &p1, &p2);
324 //printf("Circle-circle intersections: n=%i, <%lf, %lf, %lf>, <%lf, %lf, %lf>\n", n, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
325 #endif
326         line2->position = line1->endpoint;
327         line2->endpoint = p1;
328
329         line3->position = line2->endpoint;
330         line3->endpoint = line1->position;
331
332         line1->state = OSInactive;
333         line2->state = OSInactive;
334 }
335