From: Shamus Hammons Date: Tue, 3 Sep 2013 22:22:38 +0000 (-0500) Subject: Added rotation tool. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=architektonas;a=commitdiff_plain;h=921bf050ffe5fc81a9ab377e634180e659ee5d5d Added rotation tool. --- diff --git a/architektonas.pro b/architektonas.pro index 138d129..edea5ee 100644 --- a/architektonas.pro +++ b/architektonas.pro @@ -75,6 +75,7 @@ HEADERS = \ src/mathconstants.h \ src/object.h \ src/painter.h \ + src/rotateaction.h \ src/settingsdialog.h \ src/text.h \ src/vector.h @@ -108,6 +109,7 @@ SOURCES = \ src/mirroraction.cpp \ src/object.cpp \ src/painter.cpp \ + src/rotateaction.cpp \ src/settingsdialog.cpp \ src/text.cpp \ src/vector.cpp diff --git a/src/applicationwindow.cpp b/src/applicationwindow.cpp index 83dbd54..71e8a08 100644 --- a/src/applicationwindow.cpp +++ b/src/applicationwindow.cpp @@ -40,6 +40,7 @@ #include "layerwidget.h" #include "mirroraction.h" #include "painter.h" +#include "rotateaction.h" #include "settingsdialog.h" @@ -401,7 +402,6 @@ void ApplicationWindow::SetInternalToolStates(void) { Object::SetDeleteActive(deleteAct->isChecked()); Object::SetDimensionActive(addDimensionAct->isChecked()); - drawing->SetRotateToolActive(rotateAct->isChecked()); // We can be sure that if we've come here, then either an active tool is // being deactivated, or a new tool is being created. In either case, the @@ -413,23 +413,17 @@ void ApplicationWindow::SetInternalToolStates(void) Object::ignoreClicks = false; } -#if 0 - drawing->SetAddLineToolActive(addLineAct->isChecked()); - drawing->SetAddCircleToolActive(addCircleAct->isChecked()); - drawing->SetAddArcToolActive(addArcAct->isChecked()); - drawing->SetAddDimensionToolActive(addDimensionAct->isChecked()); -#else drawing->SetToolActive(addLineAct->isChecked() ? new DrawLineAction() : NULL); drawing->SetToolActive(addCircleAct->isChecked() ? new DrawCircleAction() : NULL); drawing->SetToolActive(addArcAct->isChecked() ? new DrawArcAction() : NULL); drawing->SetToolActive(addDimensionAct->isChecked() ? new DrawDimensionAction() : NULL); drawing->SetToolActive(mirrorAct->isChecked() ? new MirrorAction() : NULL); -#endif + drawing->SetToolActive(rotateAct->isChecked() ? new RotateAction() : NULL); if (drawing->toolAction) Object::ignoreClicks = true; - update(); + drawing->update(); } diff --git a/src/arc.cpp b/src/arc.cpp index f7cde52..e4a6b6f 100644 --- a/src/arc.cpp +++ b/src/arc.cpp @@ -456,6 +456,18 @@ same reference number. } +/*virtual*/ void Arc::Rotate(Point point, double angle) +{ + Point c1 = Geometry::RotatePointAroundPoint(position, point, angle); + Point ap1(cos(startAngle), sin(startAngle)); + Point angleStartPoint = (ap1 * radius) + position; + Point c2 = Geometry::RotatePointAroundPoint(angleStartPoint, point, angle); + + position = c1; + startAngle = Vector(c2, c1).Angle(); +} + + /*virtual*/ void Arc::Mirror(Point p1, Point p2) { Point c1 = Geometry::MirrorPointAroundLine(position, p1, p2); diff --git a/src/arc.h b/src/arc.h index da0a6ea..bb70776 100644 --- a/src/arc.h +++ b/src/arc.h @@ -18,6 +18,7 @@ class Arc: public Object virtual void Enumerate(FILE *); virtual Object * Copy(void); virtual QRectF Extents(void); + virtual void Rotate(Point, double); virtual void Mirror(Point, Point); virtual void Save(void); virtual void Restore(void); diff --git a/src/circle.cpp b/src/circle.cpp index b722f4d..d8a2e5d 100644 --- a/src/circle.cpp +++ b/src/circle.cpp @@ -243,6 +243,13 @@ same reference number. } +/*virtual*/ void Circle::Rotate(Point point, double angle) +{ + Point c1 = Geometry::RotatePointAroundPoint(position, point, angle); + position = c1; +} + + /*virtual*/ void Circle::Mirror(Point p1, Point p2) { Point c1 = Geometry::MirrorPointAroundLine(position, p1, p2); diff --git a/src/circle.h b/src/circle.h index 6fd22cd..527ea0f 100644 --- a/src/circle.h +++ b/src/circle.h @@ -18,6 +18,7 @@ class Circle: public Object virtual void Enumerate(FILE *); virtual Object * Copy(void); virtual QRectF Extents(void); + virtual void Rotate(Point, double); virtual void Mirror(Point, Point); virtual void Save(void); virtual void Restore(void); diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 3020368..89c63ed 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -19,6 +19,7 @@ // // STILL TO BE DONE: // +// - Lots of stuff // // Uncomment this for debugging... @@ -47,8 +48,8 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent), gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE), scale(1.0), offsetX(-10), offsetY(-10), document(Vector(0, 0)), - /*gridSpacing(12.0),*/ gridPixels(0), collided(false), rotateTool(false), - rx(150.0), ry(150.0), + /*gridSpacing(12.0),*/ gridPixels(0), collided(false), //rotateTool(false), +// rx(150.0), ry(150.0), // scrollDrag(false), addLineTool(false), addCircleTool(false), // addDimensionTool(false), toolAction(NULL) @@ -130,13 +131,6 @@ we do! :-) } -void DrawingView::SetRotateToolActive(bool state/*= true*/) -{ - rotateTool = state; - update(); -} - - void DrawingView::SetToolActive(Action * action) { if (action != NULL) @@ -291,28 +285,6 @@ QPoint DrawingView::GetAdjustedClientPosition(int x, int y) } -#if 0 -// -// This looks strange, but it's really quite simple: We want a point that's -// more than half-way to the next grid point to snap there while conversely we -// want a point that's less than half-way to to the next grid point then snap -// to the one before it. So we add half of the grid spacing to the point, then -// divide by it so that we can remove the fractional part, then multiply it -// back to get back to the correct answer. -// -Vector DrawingView::SnapPointToGrid(Vector point) -{ - point += gridSpacing / 2.0; // *This* adds to Z!!! - point /= gridSpacing; - point.x = floor(point.x);//need to fix this for negative numbers... - point.y = floor(point.y); - point.z = 0; // Make *sure* Z doesn't go anywhere!!! - point *= gridSpacing; - return point; -} -#endif - - void DrawingView::paintEvent(QPaintEvent * /*event*/) { QPainter qtPainter(this); @@ -321,35 +293,18 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) if (useAntialiasing) qtPainter.setRenderHint(QPainter::Antialiasing); -// Painter::screenSize = Vector(size().width(), size().height()); Object::SetViewportHeight(size().height()); // Draw coordinate axes - painter.SetPen(QPen(Qt::blue, 1.0, Qt::DotLine)); painter.DrawLine(0, -16384, 0, 16384); painter.DrawLine(-16384, 0, 16384, 0); - // Draw supplemental (tool related) points -// NOTE that this can be done as an action! -// In that case, we would need access to the document... -// [We can do that by making the document a class object...] - if (rotateTool) - { - painter.SetPen(QPen(QColor(0, 200, 0), 2.0, Qt::SolidLine)); - painter.DrawLine(rx - 10, ry, rx + 10, ry); - painter.DrawLine(rx, ry - 10, rx, ry + 10); - } - -// Maybe we can make the grid into a background brush instead, and let Qt deal -// with it??? YES!! - // The top level document takes care of rendering for us... document.Draw(&painter); if (toolAction) { -// painter.SetPen(QPen(Qt::green, 1.0, Qt::DashLine)); painter.SetPen(QPen(QColor(200, 100, 0, 255), 1.0, Qt::DashLine)); painter.DrawCrosshair(oldPoint); toolAction->Draw(&painter); @@ -357,9 +312,7 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) if (Object::selectionInProgress) { -// painter.SetPen(QPen(Qt::green, 1.0, Qt::SolidLine)); painter.SetPen(QPen(QColor(255, 127, 0, 255))); -// painter.SetBrush(QBrush(Qt::NoBrush)); painter.SetBrush(QBrush(QColor(255, 127, 0, 100))); painter.DrawRect(Object::selection); } diff --git a/src/drawingview.h b/src/drawingview.h index 55384fa..bd3e07e 100644 --- a/src/drawingview.h +++ b/src/drawingview.h @@ -14,7 +14,7 @@ class DrawingView: public QWidget DrawingView(QWidget * parent = NULL); public: - void SetRotateToolActive(bool state = true); +// void SetRotateToolActive(bool state = true); void SetToolActive(Action * action); void SetGridSize(uint32_t); void UpdateGridBackground(void); @@ -50,8 +50,8 @@ class DrawingView: public QWidget bool collided; //Should this go into Object's class variables??? //maybe, maybe not... :-P - bool rotateTool; - double rx, ry; +// bool rotateTool; +// double rx, ry; bool scrollDrag; Vector oldPoint; // bool addLineTool; diff --git a/src/geometry.cpp b/src/geometry.cpp index fdceb8e..5f9a30b 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -14,7 +14,7 @@ // #include "geometry.h" - +#include Point Geometry::IntersectionOfLineAndLine(Point p1, Point p2, Point p3, Point p4) { @@ -76,3 +76,13 @@ Point Geometry::MirrorPointAroundLine(Point point, Point p1, Point p2) return mirroredPoint; } + +Point Geometry::RotatePointAroundPoint(Point point, Point rotationPoint, double angle) +{ + Vector v = Vector(point, rotationPoint); + double px = (v.x * cos(angle)) - (v.y * sin(angle)); + double py = (v.x * sin(angle)) + (v.y * cos(angle)); + + return Vector(rotationPoint.x + px, rotationPoint.y + py, 0); +} + diff --git a/src/geometry.h b/src/geometry.h index d2ec82b..6ff4564 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -10,6 +10,7 @@ class Geometry static Point IntersectionOfLineAndLine(Point, Point, Point, Point); static double ParameterOfLineAndPoint(Point, Point, Point); static Point MirrorPointAroundLine(Point, Point, Point); + static Point RotatePointAroundPoint(Point, Point, double); }; #endif // __GEOMETRY_H__ diff --git a/src/line.cpp b/src/line.cpp index b7abc9a..90b5dc2 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -123,6 +123,11 @@ Line::~Line() /*virtual*/ bool Line::Collided(Vector point) { +/* +what we can do here is set ignoreClicks to true to keep other objects that are +selected from deselecting themselves. Will that fuck up something else? Not sure +yet... :-/ +*/ // Someone told us to fuck off, so we'll fuck off. :-) if (ignoreClicks) return false; @@ -571,12 +576,16 @@ same reference number. } -/*virtual*/ void Line::Rotate(Vector point, double angle) +/*virtual*/ void Line::Rotate(Point point, double angle) { + Point l1 = Geometry::RotatePointAroundPoint(position, point, angle); + Point l2 = Geometry::RotatePointAroundPoint(endpoint, point, angle); + position = l1; + endpoint = l2; } -/*virtual*/ void Line::Scale(Vector point, double amount) +/*virtual*/ void Line::Scale(Point point, double amount) { } diff --git a/src/line.h b/src/line.h index 5d84b39..4e5d7b5 100644 --- a/src/line.h +++ b/src/line.h @@ -23,7 +23,7 @@ class Line: public Object virtual Vector GetPointAtParameter(double parameter); virtual QRectF Extents(void); virtual void Translate(Vector); - virtual void Rotate(Vector, double); + virtual void Rotate(Point, double); virtual void Scale(Vector, double); virtual void Mirror(Point, Point); virtual void Save(void); diff --git a/src/object.cpp b/src/object.cpp index a3ff1ac..ca065dc 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -224,12 +224,12 @@ printf("Object: Destroyed!\n"); } -/*virtual*/ void Object::Rotate(Vector, double) +/*virtual*/ void Object::Rotate(Point, double) { } -/*virtual*/ void Object::Scale(Vector, double) +/*virtual*/ void Object::Scale(Point, double) { } diff --git a/src/object.h b/src/object.h index d34e79a..ec775d1 100644 --- a/src/object.h +++ b/src/object.h @@ -42,8 +42,8 @@ class Object virtual QRectF Extents(void); // virtual ObjectType Type(void);// = 0; // Pure virtual, must be implemented virtual void Translate(Vector); - virtual void Rotate(Vector, double); - virtual void Scale(Vector, double); + virtual void Rotate(Point, double); + virtual void Scale(Point, double); virtual void Mirror(Point, Point); virtual void Save(void); virtual void Restore(void); diff --git a/src/rotateaction.cpp b/src/rotateaction.cpp new file mode 100644 index 0000000..661e617 --- /dev/null +++ b/src/rotateaction.cpp @@ -0,0 +1,167 @@ +// rotateaction.cpp: Action class for rotating selected objects +// +// 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 09/03/2011 Created this file +// + +#include "rotateaction.h" +#include "applicationwindow.h" +#include "container.h" +#include "drawingview.h" +#include "line.h" +#include "mathconstants.h" +#include "painter.h" +//#include "vector.h" + + +//#define FIRST_POINT 0 +//#define NEXT_POINT 1 +enum { FIRST_POINT, NEXT_POINT }; + + +RotateAction::RotateAction(): state(FIRST_POINT), line(NULL), + shiftWasPressedOnNextPoint(false), spin(new Container(Vector())) +{ +// ApplicationWindow::drawing->document.CopySelectedContentsTo(selected); + ApplicationWindow::drawing->document.CopySelectedContentsTo(spin); + +// for(std::vector::iterator i=spin->objects.begin(); i!=spin->objects.end(); i++) +// (*i)->Save(); + spin->Save(); +} + + +RotateAction::~RotateAction() +{ +} + + +/*virtual*/ void RotateAction::Draw(Painter * painter) +{ + painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine)); + + // I think stuff like crosshairs should be done in the DrawingView, tho + // (and it's done there now...) + if (state == FIRST_POINT) + { + painter->DrawHandle(p1); + } + else + { +// Vector reflectedP2 = -(p2 - p1); +// Point newP2 = p1 + reflectedP2; + painter->DrawLine(p1, 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); +// QString text = tr("Length: %1 in."); +// text = text.arg(Vector::Magnitude(p1, p2)); + painter->DrawInformativeText(text); + + // Draw the rotated objects only if there's been a line to spin around + if (p1 != p2) + spin->Draw(painter); + } +} + + +/*virtual*/ void RotateAction::MouseDown(Vector point) +{ + // Clear our override... + shiftWasPressedOnNextPoint = false; + + if (state == FIRST_POINT) + p1 = point; + else + p2 = point; +} + + +/*virtual*/ void RotateAction::MouseMoved(Vector point) +{ + if (state == FIRST_POINT) + p1 = point; + else + { + p2 = point; + double angle = Vector(p2, p1).Angle(); + + for(std::vector::iterator i=spin->objects.begin(); i!=spin->objects.end(); i++) + { + (*i)->Restore(); + (*i)->Rotate(p1, angle); + } + } +} + + +/*virtual*/ void RotateAction::MouseReleased(void) +{ + if (state == FIRST_POINT) + { + p2 = p1; + state = NEXT_POINT; + } + else if (state == NEXT_POINT) + { + state = FIRST_POINT; + + std::vector & objs = ApplicationWindow::drawing->document.objects; + double angle = Vector(p2, p1).Angle(); + + for(std::vector::iterator i=objs.begin(); i!=objs.end(); i++) + { + if ((*i)->state == OSSelected) + (*i)->Rotate(p1, angle); + } + + spin->Clear(); + ApplicationWindow::drawing->document.CopySelectedContentsTo(spin); + spin->Save(); + } +} + + +/*virtual*/ bool RotateAction::KeyDown(int key) +{ + if ((key == Qt::Key_Shift) && (state == NEXT_POINT)) + { + shiftWasPressedOnNextPoint = true; + p1Save = p1; + p1 = p2; + state = FIRST_POINT; + return true; + } + + return false; +} + + +/*virtual*/ bool RotateAction::KeyReleased(int key) +{ + if ((key == Qt::Key_Shift) && shiftWasPressedOnNextPoint) + { + shiftWasPressedOnNextPoint = false; + p2 = p1; + p1 = p1Save; + state = NEXT_POINT; + return true; + } + + return false; +} + diff --git a/src/rotateaction.h b/src/rotateaction.h new file mode 100644 index 0000000..91a9bdd --- /dev/null +++ b/src/rotateaction.h @@ -0,0 +1,32 @@ +#ifndef __ROTATEACTION_H__ +#define __ROTATEACTION_H__ + +#include "action.h" + +class Container; +class Line; + +class RotateAction: public Action +{ + public: + RotateAction(); + ~RotateAction(); + + virtual void Draw(Painter *); + virtual void MouseDown(Vector); + virtual void MouseMoved(Vector); + virtual void MouseReleased(void); + virtual bool KeyDown(int); + virtual bool KeyReleased(int); + + private: + int state; + Line * line; + Point p1, p2, p1Save; + bool shiftWasPressedOnNextPoint; +// Container * selected; + Container * spin; +}; + +#endif // __ROTATEACTION_H__ +