From 4b37ccbdf263a4798e53a62e33d869a728ace283 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Sat, 31 Aug 2013 16:35:06 -0500 Subject: [PATCH] Added Geometry class for common geometric tools used everywhere. --- architektonas.pro | 2 + src/applicationwindow.cpp | 4 ++ src/geometry.cpp | 78 +++++++++++++++++++++++++++++++++++ src/geometry.h | 16 ++++++++ src/line.cpp | 85 ++++++++++++++++++++++----------------- src/mirroraction.cpp | 19 ++++++++- src/mirroraction.h | 2 + src/vector.cpp | 6 +-- 8 files changed, 170 insertions(+), 42 deletions(-) create mode 100644 src/geometry.cpp create mode 100644 src/geometry.h diff --git a/architektonas.pro b/architektonas.pro index 54e428e..138d129 100644 --- a/architektonas.pro +++ b/architektonas.pro @@ -66,6 +66,7 @@ HEADERS = \ src/ellipse.h \ src/fileio.h \ src/generaltab.h \ + src/geometry.h \ src/layerwidget.h \ src/layeritemwidget.h \ src/line.h \ @@ -99,6 +100,7 @@ SOURCES = \ src/ellipse.cpp \ src/fileio.cpp \ src/generaltab.cpp \ + src/geometry.cpp \ src/layerwidget.cpp \ src/layeritemwidget.cpp \ src/line.cpp \ diff --git a/src/applicationwindow.cpp b/src/applicationwindow.cpp index 445e546..83dbd54 100644 --- a/src/applicationwindow.cpp +++ b/src/applicationwindow.cpp @@ -410,6 +410,7 @@ void ApplicationWindow::SetInternalToolStates(void) { delete drawing->toolAction; drawing->toolAction = NULL; + Object::ignoreClicks = false; } #if 0 @@ -425,6 +426,9 @@ void ApplicationWindow::SetInternalToolStates(void) drawing->SetToolActive(mirrorAct->isChecked() ? new MirrorAction() : NULL); #endif + if (drawing->toolAction) + Object::ignoreClicks = true; + update(); } diff --git a/src/geometry.cpp b/src/geometry.cpp new file mode 100644 index 0000000..fdceb8e --- /dev/null +++ b/src/geometry.cpp @@ -0,0 +1,78 @@ +// geometry.cpp: Algebraic geometry helper functions +// +// Part of the Architektonas Project +// (C) 2011 Underground Software +// See the README and GPLv3 files for licensing and warranty information +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 08/31/2011 Created this file +// +// NOTE: All methods in this class are static. +// + +#include "geometry.h" + + +Point Geometry::IntersectionOfLineAndLine(Point p1, Point p2, Point p3, Point p4) +{ + // Find the intersection of the lines by formula: + // px = (x1y2 - y1x2)(x3 - x4) - (x1 - x2)(x3y4 - y3x4) + // py = (x1y2 - y1x2)(y3 - y4) - (y1 - y2)(x3y4 - y3x4) + // d = (x1 - x2)(y3 - y4) - (y1 - y2)(x3 - x4) = 0 if lines are parallel + // Intersection is (px / d, py / d) + + double d = ((p1.x - p2.x) * (p3.y - p4.y)) - ((p1.y - p2.y) * (p3.x - p4.x)); + + // Check for parallel lines, and return sentinel if so + if (d == 0) + return Point(0, 0, -1); + + double px = (((p1.x * p2.y) - (p1.y * p2.x)) * (p3.x - p4.x)) + - ((p1.x - p2.x) * ((p3.x * p4.y) - (p3.y * p4.x))); + double py = (((p1.x * p2.y) - (p1.y * p2.x)) * (p3.y - p4.y)) + - ((p1.y - p2.y) * ((p3.x * p4.y) - (p3.y * p4.x))); + + return Point(px / d, py / d, 0); +} + + +// Returns the parameter of a point in space to this vector. If the parameter +// is between 0 and 1, the normal of the vector to the point is on the vector. +double Geometry::ParameterOfLineAndPoint(Point lp1, Point lp2, Point point) +{ + // Geometric interpretation: + // The parameterized point on the vector lineSegment is where the normal of + // the lineSegment to the point intersects lineSegment. If the pp < 0, then + // the perpendicular lies beyond the 1st endpoint. If pp > 1, then the + // perpendicular lies beyond the 2nd endpoint. + + Vector lineSegment = lp1 - lp2; + double magnitude = lineSegment.Magnitude(); + Vector pointSegment = point - lp2; + double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude); + return t; +} + + +Point Geometry::MirrorPointAroundLine(Point point, Point p1, Point p2) +{ + // Get the vector of the intersection of the line and the normal on the + // line to the point in question. + double t = ParameterOfLineAndPoint(p1, p2, point); + Vector v = Vector(p1, p2) * t; + + // Get the point normal to point to the line passed in (p2 is the tail) + Point normalOnLine = p2 + v; + + // Make our mirrored vector (head - tail) + Vector mirror = -(point - normalOnLine); + + // Find the mirrored point + Point mirroredPoint = normalOnLine + mirror; + + return mirroredPoint; +} + diff --git a/src/geometry.h b/src/geometry.h new file mode 100644 index 0000000..d2ec82b --- /dev/null +++ b/src/geometry.h @@ -0,0 +1,16 @@ +#ifndef __GEOMETRY_H__ +#define __GEOMETRY_H__ + +#include "vector.h" + +class Geometry +{ + public: + // All methods are class methods for this class + static Point IntersectionOfLineAndLine(Point, Point, Point, Point); + static double ParameterOfLineAndPoint(Point, Point, Point); + static Point MirrorPointAroundLine(Point, Point, Point); +}; + +#endif // __GEOMETRY_H__ + diff --git a/src/line.cpp b/src/line.cpp index 8425e62..956b9bd 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -21,6 +21,7 @@ #include #include "container.h" #include "dimension.h" +#include "geometry.h" #include "mathconstants.h" #include "painter.h" @@ -122,6 +123,10 @@ Line::~Line() /*virtual*/ bool Line::Collided(Vector point) { + // Someone told us to fuck off, so we'll fuck off. :-) + if (ignoreClicks) + return false; + // We can assume this, since this is a mouse down event here. objectWasDragged = false; HitTest(point); @@ -445,7 +450,8 @@ the horizontal line or vertical line that intersects from the current mouse posi Vector lineSegment = endpoint - position; Vector v1 = point - position; Vector v2 = point - endpoint; - double t = Vector::Parameter(position, endpoint, point); +// double t = Vector::Parameter(position, endpoint, point); + double t = Geometry::ParameterOfLineAndPoint(position, endpoint, point); double distance; // Geometric interpretation: @@ -577,52 +583,55 @@ same reference number. /*virtual*/ Object * Line::Mirror(Vector p1, Vector p2) { -#if 0 - return NULL; +#if 1 + Point l1 = Geometry::MirrorPointAroundLine(position, p1, p2); + Point l2 = Geometry::MirrorPointAroundLine(endpoint, p1, p2); + return new Line(l1, l2); +#else + Vector normal = Vector::Normal(p1, p2); + Vector p4 = position + normal; -double Vector::Parameter(Vector v1, Vector v2, Vector p) -{ - // Geometric interpretation: - // The parameterized point on the vector lineSegment is where the normal of - // the lineSegment to the point intersects lineSegment. If the pp < 0, then - // the perpendicular lies beyond the 1st endpoint. If pp > 1, then the - // perpendicular lies beyond the 2nd endpoint. - - Vector lineSegment = v2 - v1; - double magnitude = lineSegment.Magnitude(); - Vector pointSegment = p - v1; - double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude); - return t; -} + // Find the intersection of the line and position + normal to the line + double px = (((p1.x * p2.y) - (p1.y * p2.x)) * (position.x - p4.x)) + - ((p1.x - p2.x) * ((position.x * p4.y) - (position.y * p4.x))); + double py = (((p1.x * p2.y) - (p1.y * p2.x)) * (position.y - p4.y)) + - ((p1.y - p2.y) * ((position.x * p4.y) - (position.y * p4.x))); + double d = ((p1.x - p2.x) * (position.y - p4.y)) + - ((p1.y - p2.y) * (position.x - p4.x)); + // px = (x1y2 - y1x2)(x3 - x4) - (x1 - x2)(x3y4 - y3x4) + // py = (x1y2 - y1x2)(y3 - y4) - (y1 - y2)(x3y4 - y3x4) + // d = (x1 - x2)(y3 - y4) - (y1 - y2)(x3 - x4) = 0 if lines are parallel + // Intersection is (px / d, py / d) -// Return the normal to the linesegment formed by the passed in points. -// (Not sure which is head or tail, or which hand the normal lies) -/*static*/ Vector Vector::Normal(Vector v1, Vector v2) -#endif + Vector v1(px / d, py / d); - double t1 = Vector::Parameter(p1, p2, position); - double t2 = Vector::Parameter(p1, p2, endpoint); +// Vector normal = Vector::Normal(p1, p2); + p4 = endpoint + normal; - Vector unit = Vector(p1, p2).Unit(); - Vector v1 = unit * t1; - Vector v2 = unit * t2; + // Find the intersection of the line and endpoint + normal to the line + px = (((p1.x * p2.y) - (p1.y * p2.x)) * (endpoint.x - p4.x)) + - ((p1.x - p2.x) * ((endpoint.x * p4.y) - (endpoint.y * p4.x))); + py = (((p1.x * p2.y) - (p1.y * p2.x)) * (endpoint.y - p4.y)) + - ((p1.y - p2.y) * ((endpoint.x * p4.y) - (endpoint.y * p4.x))); + d = ((p1.x - p2.x) * (endpoint.y - p4.y)) + - ((p1.y - p2.y) * (endpoint.x - p4.x)); -// Vector normal = Vector::Normal(p1, p2); - // Get the points normal to position & endpoint to the line passed in - // (these are tails) - Vector v3 = p1 + v1; - Vector v4 = p1 + v2; + Vector v2(px / d, py / d); - // Make our mirrored vectors - Vector v5 = -(position - v3); - Vector v6 = -(endpoint - v4); +#if 0 + Vector v3 = position - v1; + Vector v4 = endpoint - v2; - // Find the points - Vector v7 = v3 + v5; - Vector v8 = v4 + v6; + Vector v5 = v1 + -v3; + Vector v6 = v2 + -v4; +#else + Vector v5 = v1 + v1 - position; + Vector v6 = v2 + v2 - endpoint; +#endif - return new Line(v7, v8); + return new Line(v5, v6); +#endif } diff --git a/src/mirroraction.cpp b/src/mirroraction.cpp index 998a0e1..720692e 100644 --- a/src/mirroraction.cpp +++ b/src/mirroraction.cpp @@ -13,6 +13,8 @@ #include "mirroraction.h" #include "applicationwindow.h" +#include "container.h" +#include "drawingview.h" #include "line.h" #include "mathconstants.h" #include "painter.h" @@ -25,7 +27,7 @@ enum { FIRST_POINT, NEXT_POINT }; MirrorAction::MirrorAction(): state(FIRST_POINT), line(NULL), - shiftWasPressedOnNextPoint(false) + shiftWasPressedOnNextPoint(false), mirror(new Container(Vector())) { } @@ -58,6 +60,8 @@ MirrorAction::~MirrorAction() // QString text = tr("Length: %1 in."); // text = text.arg(Vector::Magnitude(p1, p2)); painter->DrawInformativeText(text); + + mirror->Draw(painter); } } @@ -81,6 +85,19 @@ MirrorAction::~MirrorAction() else { p2 = point; + + mirror->Clear(); + int itemsSelected = ApplicationWindow::drawing->document.ItemsSelected(); + + if (itemsSelected == 0) + return; + + for(int i=0; idocument.SelectedItem(i); + Object * mirrored = object->Mirror(p1, p2); + mirror->Add(mirrored); + } } } diff --git a/src/mirroraction.h b/src/mirroraction.h index 0ff0a79..2198a88 100644 --- a/src/mirroraction.h +++ b/src/mirroraction.h @@ -3,6 +3,7 @@ #include "action.h" +class Container; class Line; class MirrorAction: public Action @@ -23,6 +24,7 @@ class MirrorAction: public Action Line * line; Vector p1, p2, p1Save; bool shiftWasPressedOnNextPoint; + Container * mirror; }; #endif // __MIRRORACTION_H__ diff --git a/src/vector.cpp b/src/vector.cpp index 23bd783..ac5a205 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -244,9 +244,9 @@ double Vector::Parameter(Vector v1, Vector v2, Vector p) // the perpendicular lies beyond the 1st endpoint. If pp > 1, then the // perpendicular lies beyond the 2nd endpoint. - Vector lineSegment = v2 - v1; + Vector lineSegment = v1 - v2; double magnitude = lineSegment.Magnitude(); - Vector pointSegment = p - v1; + Vector pointSegment = p - v2; double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude); return t; } @@ -256,7 +256,7 @@ double Vector::Parameter(Vector v1, Vector v2, Vector p) // (Not sure which is head or tail, or which hand the normal lies) /*static*/ Vector Vector::Normal(Vector v1, Vector v2) { - Vector v = (v2 - v1).Unit(); + Vector v = (v1 - v2).Unit(); return Vector(-v.y, v.x); } -- 2.37.2