+// triangulateaction.cpp: Action class for creating triangles from lines
+//
+// Part of the Architektonas Project
+// (C) 2014 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 05/07/2014 Created this file
+//
+
+#include "triangulateaction.h"
+#include "applicationwindow.h"
+#include "circle.h"
+#include "container.h"
+#include "drawingview.h"
+#include "geometry.h"
+#include "line.h"
+#include "mathconstants.h"
+#include "painter.h"
+
+
+enum { FIRST_LINE, SECOND_LINE, THIRD_LINE };
+
+
+TriangulateAction::TriangulateAction(): state(FIRST_LINE),// t(0), u(1.0),
+ line1(NULL), line2(NULL), line3(NULL),
+ doc(&(ApplicationWindow::drawing->document))
+//, line(NULL),
+// shiftWasPressedOnNextPoint(false), ctrlWasPressed(false),
+// mirror(new Container(Vector()))
+{
+// ApplicationWindow::drawing->document.CopySelectedContentsTo(mirror);
+// mirror->Save();
+}
+
+
+TriangulateAction::~TriangulateAction()
+{
+}
+
+
+/*virtual*/ void TriangulateAction::Draw(Painter * painter)
+{
+ Object * obj = doc->lastObjectHovered;
+
+ if (obj == NULL)
+ return;
+
+ // This assumes a Line, but it might not be!
+ painter->SetPen(QPen(Qt::blue, 2.0, Qt::DotLine));
+// Vector v(((Line *)obj)->position, ((Line *)obj)->endpoint);
+ Point p1 = ((Line *)obj)->position;
+ Point p2 = ((Line *)obj)->endpoint;
+ painter->DrawLine(p1, p2);
+#if 0
+ if (state == FIRST_POINT)
+ {
+ painter->DrawHandle(p1);
+ }
+ else
+ {
+ Vector reflectedP2 = -(p2 - p1);
+ Point newP2 = p1 + reflectedP2;
+ painter->DrawLine(newP2, p2);
+ painter->DrawHandle(p1);
+
+ double absAngle = (Vector(p2 - p1).Angle()) * RADIANS_TO_DEGREES;
+
+ // Keep the angle between 0 and 180 degrees
+ if (absAngle > 180.0)
+ absAngle -= 180.0;
+
+ QString text = QChar(0x2221) + QObject::tr(": %1");
+ text = text.arg(absAngle);
+
+ if (ctrlWasPressed)
+ text += " (Copy)";
+
+ painter->DrawInformativeText(text);
+
+ // Draw the mirror only if there's been a line to mirror around
+ if (p1 != p2)
+ mirror->Draw(painter);
+ }
+#endif
+}
+
+
+/*virtual*/ void TriangulateAction::MouseDown(Vector /*point*/)
+{
+#if 0
+// this is not accurate enough. need to use the actual intersection point, not
+// just the parameter(s).
+ Object * toTrim = doc->lastObjectHovered;
+
+ if (toTrim == NULL)
+ return;
+
+//it would be nice to do it like this, but if we bisect the object, we have to
+//create an extra one...
+// toTrim->Trim(t, u);
+
+ Vector v(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint);
+
+ // Check to see which case we have...
+ // We're trimming point #1...
+ if (t == 0)
+ {
+ ((Line *)toTrim)->position = ((Line *)toTrim)->position + (v * u);
+// u = 1.0;
+ }
+ else if (u == 1.0)
+ {
+ ((Line *)toTrim)->endpoint = ((Line *)toTrim)->position + (v * t);
+// t = 0;
+ }
+ else
+ {
+ Point p1 = ((Line *)toTrim)->position + (v * t);
+ Point p2 = ((Line *)toTrim)->position + (v * u);
+ Point p3 = ((Line *)toTrim)->endpoint;
+ ((Line *)toTrim)->endpoint = p1;
+ Line * line = new Line(p2, p3);
+ emit ObjectReady(line);
+// t = 0, u = 1.0;
+ }
+
+ doc->lastObjectHovered = NULL;
+#endif
+}
+
+
+/*virtual*/ void TriangulateAction::MouseMoved(Vector point)
+{
+#if 0
+ if (state == FIRST_POINT)
+ p1 = point;
+// else
+// {
+// p2 = point;
+// mirror->Restore();
+// mirror->Mirror(p1, p2);
+// }
+#endif
+
+#if 0
+// Container & doc = ApplicationWindow::drawing->document;
+// int items = doc.ItemsSelected();
+ Object * toTrim = doc->lastObjectHovered;
+// double closestPt1 = 0, closestPt2 = 1.0;
+ t = 0, u = 1.0;
+
+ if (toTrim == NULL)
+ return;
+
+ if (toTrim->type != OTLine)
+ return;
+
+ double pointHoveredT = Geometry::ParameterOfLineAndPoint(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint, point);
+
+ std::vector<Object *>::iterator i;
+
+ for(i=doc->objects.begin(); i!=doc->objects.end(); i++)
+ {
+ // Can't trim against yourself... :-P
+ if (*i == toTrim)
+ continue;
+
+ Object * trimAgainst = *i;
+ double t1;//, u1;
+
+ if ((toTrim->type != OTLine) || (trimAgainst->type != OTLine))
+ continue;
+
+ int intersects = Geometry::Intersects((Line *)toTrim, (Line *)trimAgainst, &t1);//, &u1);
+
+ if (intersects)
+ {
+ // Now what? We don't know which side to trim!
+ // ... now we do, we know which side of the Line we're on!
+ if ((t1 > t) && (t1 < pointHoveredT))
+ t = t1;
+
+ if ((t1 < u) && (t1 > pointHoveredT))
+ u = t1;
+ }
+ }
+#endif
+}
+
+
+/*virtual*/ void TriangulateAction::MouseReleased(void)
+{
+#if 0
+ if (state == FIRST_POINT)
+ {
+ p2 = p1;
+ state = NEXT_POINT;
+ }
+ else if (state == NEXT_POINT)
+ {
+ if (!ctrlWasPressed)
+ {
+ state = FIRST_POINT;
+ ApplicationWindow::drawing->document.MirrorSelected(p1, p2);
+
+ mirror->Clear();
+ ApplicationWindow::drawing->document.CopySelectedContentsTo(mirror);
+ mirror->Save();
+ }
+ else
+ {
+ mirror->CopyContentsTo(&(ApplicationWindow::drawing->document));
+ }
+ }
+#endif
+ Object * obj = doc->lastObjectHovered;
+
+ if (obj == NULL)
+ return;
+
+ if (obj->type != OTLine)
+ return;
+
+ if (state == FIRST_LINE)
+ {
+ line1 = (Line *)obj;
+ line1->state = OSSelected;
+ state = SECOND_LINE;
+ }
+ else if (state == SECOND_LINE)
+ {
+ line2 = (Line *)obj;
+ line2->state = OSSelected;
+ state = THIRD_LINE;
+ }
+ else if (state == THIRD_LINE)
+ {
+ line3 = (Line *)obj;
+ state = FIRST_LINE;
+ Triangulate();
+ }
+}
+
+
+/*virtual*/ void TriangulateAction::KeyDown(int /*key*/)
+{
+#if 0
+ if ((key == Qt::Key_Shift) && (state == NEXT_POINT))
+ {
+ shiftWasPressedOnNextPoint = true;
+ p1Save = p1;
+ p1 = p2;
+ state = FIRST_POINT;
+ emit NeedRefresh();
+ }
+ else if (key == Qt::Key_Control)
+ {
+ ctrlWasPressed = true;
+ emit NeedRefresh();
+ }
+#endif
+#if 0
+ if ((t == 0) && (u == 1.0))
+ return;
+
+ t = 0, u = 1.0;
+#endif
+}
+
+
+/*virtual*/ void TriangulateAction::KeyReleased(int /*key*/)
+{
+#if 0
+ if ((key == Qt::Key_Shift) && shiftWasPressedOnNextPoint)
+ {
+ shiftWasPressedOnNextPoint = false;
+ p2 = p1;
+ p1 = p1Save;
+ state = NEXT_POINT;
+ emit NeedRefresh();
+ }
+ else if (key == Qt::Key_Control)
+ {
+ ctrlWasPressed = false;
+ emit NeedRefresh();
+ }
+#endif
+}
+
+
+void TriangulateAction::Triangulate(void)
+{
+// N.B.: Should connect the line segments together, once made into a triangle...
+ double length2 = Vector(line2->position, line2->endpoint).Magnitude();
+ double length3 = Vector(line3->position, line3->endpoint).Magnitude();
+#if 0
+ double angle1, angle2, angle3;
+ double length1 = Vector(line1->position, line1->endpoint).Magnitude();
+ Geometry::FindAnglesForSides(length1, length2, length3, &angle1, &angle2, &angle3);
+printf("Triangulate: l1=%lf, l2=%lf, l3=%lf, a1=%lf, a2=%lf, a3=%lf\n", length1, length2, length3, angle1, angle2, angle3);
+
+ // We use line1 as the base. Move the other lines to it.
+ double line1Angle = Vector(line1->position, line1->endpoint).Angle();
+ double newLine2Angle = line1Angle + angle3;
+ Vector v;
+ v.SetAngleAndLength(newLine2Angle, length2);
+printf(" line1Angle=%lf, newLine2Angle=%lf\n", line1Angle, newLine2Angle);
+
+ line2->position = line1->endpoint;
+ line2->endpoint = line1->endpoint - v;
+
+// double line2Angle = Vector(line2->position, line2->endpoint).Angle();
+// double newLine3Angle = line2Angle + angle1;
+// Vector v2;
+// v2.SetAngleAndLength(newLine3Angle, length3);
+#else
+ Circle c1(line1->position, length2), c2(line1->endpoint, length3);
+ Point p1, p2;
+ int n = Geometry::Intersects(&c1, &c2, 0, 0, 0, 0, &p1, &p2);
+//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);
+#endif
+ line2->position = line1->endpoint;
+ line2->endpoint = p1;
+
+ line3->position = line2->endpoint;
+ line3->endpoint = line1->position;
+
+ line1->state = OSInactive;
+ line2->state = OSInactive;
+}
+