1 // triangulateaction.cpp: Action class for creating triangles from lines
3 // Part of the Architektonas Project
4 // (C) 2014 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 05/07/2014 Created this file
14 #include "triangulateaction.h"
15 #include "applicationwindow.h"
17 #include "container.h"
18 #include "drawingview.h"
21 #include "mathconstants.h"
25 enum { FIRST_LINE, SECOND_LINE, THIRD_LINE };
28 TriangulateAction::TriangulateAction(): state(FIRST_LINE),// t(0), u(1.0),
29 line1(NULL), line2(NULL), line3(NULL),
30 doc(&(ApplicationWindow::drawing->document))
32 // shiftWasPressedOnNextPoint(false), ctrlWasPressed(false),
33 // mirror(new Container(Vector()))
35 // ApplicationWindow::drawing->document.CopySelectedContentsTo(mirror);
40 TriangulateAction::~TriangulateAction()
45 /*virtual*/ void TriangulateAction::Draw(Painter * painter)
47 Object * obj = doc->lastObjectHovered;
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);
59 if (state == FIRST_POINT)
61 painter->DrawHandle(p1);
65 Vector reflectedP2 = -(p2 - p1);
66 Point newP2 = p1 + reflectedP2;
67 painter->DrawLine(newP2, p2);
68 painter->DrawHandle(p1);
70 double absAngle = (Vector(p2 - p1).Angle()) * RADIANS_TO_DEGREES;
72 // Keep the angle between 0 and 180 degrees
76 QString text = QChar(0x2221) + QObject::tr(": %1");
77 text = text.arg(absAngle);
82 painter->DrawInformativeText(text);
84 // Draw the mirror only if there's been a line to mirror around
86 mirror->Draw(painter);
92 /*virtual*/ void TriangulateAction::MouseDown(Vector /*point*/)
95 // this is not accurate enough. need to use the actual intersection point, not
96 // just the parameter(s).
97 Object * toTrim = doc->lastObjectHovered;
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);
106 Vector v(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint);
108 // Check to see which case we have...
109 // We're trimming point #1...
112 ((Line *)toTrim)->position = ((Line *)toTrim)->position + (v * u);
117 ((Line *)toTrim)->endpoint = ((Line *)toTrim)->position + (v * t);
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);
131 doc->lastObjectHovered = NULL;
136 /*virtual*/ void TriangulateAction::MouseMoved(Vector point)
139 if (state == FIRST_POINT)
144 // mirror->Restore();
145 // mirror->Mirror(p1, p2);
150 // Container & doc = ApplicationWindow::drawing->document;
151 // int items = doc.ItemsSelected();
152 Object * toTrim = doc->lastObjectHovered;
153 // double closestPt1 = 0, closestPt2 = 1.0;
159 if (toTrim->type != OTLine)
162 double pointHoveredT = Geometry::ParameterOfLineAndPoint(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint, point);
164 std::vector<Object *>::iterator i;
166 for(i=doc->objects.begin(); i!=doc->objects.end(); i++)
168 // Can't trim against yourself... :-P
172 Object * trimAgainst = *i;
175 if ((toTrim->type != OTLine) || (trimAgainst->type != OTLine))
178 int intersects = Geometry::Intersects((Line *)toTrim, (Line *)trimAgainst, &t1);//, &u1);
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))
187 if ((t1 < u) && (t1 > pointHoveredT))
195 /*virtual*/ void TriangulateAction::MouseReleased(void)
198 if (state == FIRST_POINT)
203 else if (state == NEXT_POINT)
208 ApplicationWindow::drawing->document.MirrorSelected(p1, p2);
211 ApplicationWindow::drawing->document.CopySelectedContentsTo(mirror);
216 mirror->CopyContentsTo(&(ApplicationWindow::drawing->document));
220 Object * obj = doc->lastObjectHovered;
225 if (obj->type != OTLine)
228 if (state == FIRST_LINE)
231 line1->state = OSSelected;
234 else if (state == SECOND_LINE)
237 line2->state = OSSelected;
240 else if (state == THIRD_LINE)
249 /*virtual*/ void TriangulateAction::KeyDown(int /*key*/)
252 if ((key == Qt::Key_Shift) && (state == NEXT_POINT))
254 shiftWasPressedOnNextPoint = true;
260 else if (key == Qt::Key_Control)
262 ctrlWasPressed = true;
267 if ((t == 0) && (u == 1.0))
275 /*virtual*/ void TriangulateAction::KeyReleased(int /*key*/)
278 if ((key == Qt::Key_Shift) && shiftWasPressedOnNextPoint)
280 shiftWasPressedOnNextPoint = false;
286 else if (key == Qt::Key_Control)
288 ctrlWasPressed = false;
295 void TriangulateAction::Triangulate(void)
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();
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);
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;
310 v.SetAngleAndLength(newLine2Angle, length2);
311 printf(" line1Angle=%lf, newLine2Angle=%lf\n", line1Angle, newLine2Angle);
313 line2->position = line1->endpoint;
314 line2->endpoint = line1->endpoint - v;
316 // double line2Angle = Vector(line2->position, line2->endpoint).Angle();
317 // double newLine3Angle = line2Angle + angle1;
319 // v2.SetAngleAndLength(newLine3Angle, length3);
321 Circle c1(line1->position, length2), c2(line1->endpoint, length3);
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);
326 line2->position = line1->endpoint;
327 line2->endpoint = p1;
329 line3->position = line2->endpoint;
330 line3->endpoint = line1->position;
332 line1->state = OSInactive;
333 line2->state = OSInactive;