remove it and it only, or to cut the entity at other entities crossing)
- Make Architektonas an MDI application
- Parallel tool (be able to make copy of object that's parallel to original)
- - Pen marker doesn't set attributes on the highlighted part of the group.
+ - Add command line tool
+ - Be able to show dimensions in pure inches as well as feet & inches
Stuff That's Done
----------------
Grouping items on different layers currently makes the items *not* on the current layer disappear. Not sure how this should be handled... Maybe we should honor the top level Container's attributes, and not the attributes of the contained objects?
+
+
+Bugs
+----
+
+ - Add new dimension doesn't honor the scale parameter set by user
+ - Dimension object prevents system from finding intersections when near or on
+ object intersection
+ - Pen marker doesn't set attributes on the highlighted part of the group.
+ - Can't move objects to other layers
+ - Dimension lines extents aren't properly taken into account when printing
src/baseunittab.h \
src/blockitemwidget.h \
src/blockwidget.h \
+ src/consolewidget.h \
src/drawingview.h \
src/fileio.h \
src/generaltab.h \
src/main.h \
src/mathconstants.h \
src/objectwidget.h \
- src/penwidget.h \
src/painter.h \
+ src/penwidget.h \
+ src/promptlineedit.h \
src/rect.h \
src/settingsdialog.h \
src/structs.h \
src/baseunittab.cpp \
src/blockitemwidget.cpp \
src/blockwidget.cpp \
+ src/consolewidget.cpp \
src/drawingview.cpp \
src/fileio.cpp \
src/generaltab.cpp \
src/layeritemwidget.cpp \
src/main.cpp \
src/objectwidget.cpp \
- src/penwidget.cpp \
src/painter.cpp \
+ src/penwidget.cpp \
+ src/promptlineedit.cpp \
src/rect.cpp \
src/settingsdialog.cpp \
src/utils.cpp \
<file>cursor-marker.png</file>
<file>cursor-dropper.png</file>
<file>print-preview.png</file>
+ <file>parallel-tool.png</file>
</qresource>
</RCC>
#include <QPrintPreviewDialog>
#include "about.h"
#include "blockwidget.h"
+#include "consolewidget.h"
#include "drawingview.h"
#include "fileio.h"
#include "generaltab.h"
ObjectWidget * ow = new ObjectWidget;
dock3->setWidget(ow);
addDockWidget(Qt::RightDockWidgetArea, dock3);
+ QDockWidget * dock4 = new QDockWidget(tr("Command"), this);
+ ConsoleWidget * cw = new ConsoleWidget;
+ dock4->setWidget(cw);
+ addDockWidget(Qt::BottomDockWidgetArea, dock4);
+
// Needed for saveState()
dock1->setObjectName("Layers");
dock2->setObjectName("Blocks");
dock3->setObjectName("Object");
+ dock4->setObjectName("Commands");
// Create status bar
zoomIndicator = new QLabel("Zoom: 100% Grid: 12.0\" BU: Inch");
void ApplicationWindow::contextMenuEvent(QContextMenuEvent * event)
{
+ // Proof of concept, still need to code up the real thing
QMenu menu(this);
menu.addAction(mirrorAct);
menu.addAction(rotateAct);
SetInternalToolStates();
}
+void ApplicationWindow::ParallelTool(void)
+{
+ ClearUIToolStatesExcept(parallelAct);
+ SetInternalToolStates();
+}
+
void ApplicationWindow::TriangulateTool(void)
{
ClearUIToolStatesExcept(triangulateAct);
Global::tool = TTRotate;
else if (trimAct->isChecked())
Global::tool = TTTrim;
+ else if (parallelAct->isChecked())
+ Global::tool = TTParallel;
else if (triangulateAct->isChecked())
Global::tool = TTTriangulate;
else
trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
+ parallelAct = CreateAction(tr("&Parallel"), tr("Parallel"), tr("Create copies of objects parallel to the original."), QIcon(":/res/parallel-tool.png"), QKeySequence("p,a"), true);
+ connect(parallelAct, SIGNAL(triggered()), this, SLOT(ParallelTool()));
+
triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
menu->addAction(rotateAct);
menu->addAction(mirrorAct);
menu->addAction(trimAct);
+ menu->addAction(parallelAct);
menu->addAction(triangulateAct);
menu->addAction(connectAct);
menu->addAction(disconnectAct);
toolbar->addAction(rotateAct);
toolbar->addAction(mirrorAct);
toolbar->addAction(trimAct);
+ toolbar->addAction(parallelAct);
toolbar->addAction(triangulateAct);
toolbar->addAction(editCutAct);
toolbar->addAction(editCopyAct);
void RotateTool(void);
void MirrorTool(void);
void TrimTool(void);
+ void ParallelTool(void);
void TriangulateTool(void);
void AddLineTool(void);
void AddCircleTool(void);
QAction * disconnectAct;
QAction * mirrorAct;
QAction * trimAct;
+ QAction * parallelAct;
QAction * triangulateAct;
QAction * editCutAct;
QAction * editCopyAct;
};
#endif // __APPLICATIONWINDOW_H__
-
--- /dev/null
+//
+// consolewidget.cpp: Command line widget
+//
+// Part of the Architektonas Project
+// (C) 2021 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 11/20/2021 Created this file
+//
+
+#include "consolewidget.h"
+
+ConsoleWidget::ConsoleWidget(QWidget * parent/*= NULL*/): QWidget(parent)
+{
+ cmdline = new PromptLineEdit(this);
+ cmdline->setFrame(false);
+
+ screen = new QTextEdit;
+ screen->setAlignment(Qt::AlignBottom | Qt::AlignLeft);
+ screen->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ screen->setReadOnly(true);
+
+ QVBoxLayout * mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(screen);
+ mainLayout->addWidget(cmdline);
+
+ setLayout(mainLayout);
+
+ connect(cmdline, SIGNAL(returnPressed()), this, SLOT(Execute()));
+
+ QScrollBar * scrollbar = screen->verticalScrollBar();
+ connect(scrollbar, SIGNAL(rangeChanged(int, int)), this, SLOT(MoveScrollBarToBottom(int, int)));
+}
+
+ConsoleWidget::~ConsoleWidget()
+{
+}
+
+void ConsoleWidget::Execute(void)
+{
+ screen->append(cmdline->text());
+ screen->append("<font color=red>Error: don't know how to '" + cmdline->text() + "'</font>");
+ cmdline->clear();
+}
+
+void ConsoleWidget::MoveScrollBarToBottom(int min, int max)
+{
+ Q_UNUSED(min);
+ screen->verticalScrollBar()->setValue(max);
+}
+
+void ConsoleWidget::paintEvent(QPaintEvent * /*event*/)
+{
+}
--- /dev/null
+#ifndef __CONSOLEWIDGET_H__
+#define __CONSOLEWIDGET_H__
+
+#include <QtWidgets>
+#include "promptlineedit.h"
+
+class ConsoleWidget: public QWidget
+{
+ Q_OBJECT
+
+ public:
+ ConsoleWidget(QWidget * parent = NULL);
+ ~ConsoleWidget();
+
+ public slots:
+ void Execute(void);
+ void MoveScrollBarToBottom(int min, int max);
+
+ protected:
+ void paintEvent(QPaintEvent * event);
+
+ public:
+ PromptLineEdit * cmdline;
+ QTextEdit * screen;
+};
+
+#endif // __CONSOLEWIDGET_H__
break;
}
+ case OTPolyline:
+ {
+ break;
+ }
+
case OTContainer:
{
// Containers require recursive rendering...
return v;
}
-VPVector DrawingView::GetHovered(void)
+//
+// When testing for hovered intersections, we need to be able to exclude some
+// objects which have funky characteristics or handles; so we allow for that
+// here.
+//
+VPVector DrawingView::GetHovered(bool exclude/*= false*/)
{
VPVector v;
for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
- if (((Object *)(*i))->hovered)
+ Object * obj = (Object *)(*i);
+
+ if (obj->hovered)
+ {
+ if (exclude
+ && ((obj->type == OTDimension)
+ || ((obj->type == OTCircle) && (obj->hitPoint[0] == true))
+ || ((obj->type == OTArc) && (obj->hitPoint[0] == true))
+ || (draggingObject && (obj == dragged))))
+ continue;
+
v.push_back(*i);
+ }
}
return v;
switch (mode)
{
case ToolMouseDown:
+/* toolObj[0] = NULL;
+
+ // Check to see if we can do a circle tangent snap
+ if (numHovered == 1)
+ {
+ VPVector hover = GetHovered();
+ Object * obj = (Object *)hover[0];
+
+ // Save for later if the object clicked was a circle (need to check that it wasn't the center clicked on, because that will fuck up connecting centers of circles with lines... and now we do! :-)
+ if ((obj->type == OTCircle) && (obj->hitPoint[0] == false))
+ toolObj[0] = obj;
+ }*/
+
if (Global::toolState == TSNone)
toolPoint[0] = p;
else
if (Global::toolState == TSNone)
toolPoint[0] = p;
else
+ {
toolPoint[1] = p;
+/* bool isCircle = false;
+
+ if (numHovered == 1)
+ {
+ VPVector hover = GetHovered();
+ Object * obj = (Object *)hover[0];
+
+ if ((obj->type == OTCircle) && (obj->hitPoint[0] == false))
+ {
+ isCircle = true;
+ toolObj[1] = obj;
+ }
+ }
+
+ // Adjust initial point if it's on a circle (tangent point)
+ if (toolObj[0] != NULL)
+ {
+ if (isCircle)
+ {
+ Geometry::FindTangents(toolObj[0], toolObj[1]);
+
+ if (Global::numIntersectPoints > 0)
+ {
+ toolPoint[0] = Global::intersectPoint[0];
+ toolPoint[1] = Global::intersectPoint[1];
+ }
+ }
+ else
+ {
+ Geometry::FindTangents(toolObj[0], p);
+
+ if (Global::numIntersectPoints > 0)
+ toolPoint[0] = Global::intersectPoint[0];
+ }
+ }
+ else
+ {
+ if (isCircle)
+ {
+ Geometry::FindTangents(toolObj[1], toolPoint[0]);
+
+ if (Global::numIntersectPoints > 0)
+ toolPoint[1] = Global::intersectPoint[0];
+ }
+ }*/
+ }
break;
void DrawingView::TrimHandler(int mode, Point p)
{
/*
-n.b.: this code is lifted straight out of the old oo code. needs to be updated.
+N.B.: this code is lifted straight out of the old oo code. needs to be updated.
+ Also: trim tool should ignore snap.
*/
switch (mode)
{
// Do object hit testing...
bool needUpdate = HitTestObjects(point);
- VPVector hover2 = GetHovered();
+ VPVector hover2 = GetHovered(true); // Exclude dimension objects and circle centers (probably need to add arc centers too) from hover (also dragged objects...)
#if 0
{
if (needUpdate)
#endif
// Check for multi-hover...
- if (numHovered > 1)
+ if (hover2.size() > 1)
{
-//need to check for case where hover is over 2 circles and a 3rd's center...
+//need to check for case where hover is over 2 circles and a 3rd's center (no longer a problem, I think)...
Object * obj1 = (Object *)hover2[0], * obj2 = (Object *)hover2[1];
Geometry::Intersects(obj1, obj2);
intersectionPoint = v1;
}
}
- else if (numHovered == 1)
+ else if (hover2.size() == 1)
{
Object * obj = (Object *)hover2[0];
{
/*
Not sure that this is the best way to handle this, but it works(TM)...
-Except when lines are overlapping, then it doesn't work... !!! FIX !!!
*/
Point midpoint = Geometry::Midpoint((Line *)obj);
Vector v1 = Vector::Magnitude(midpoint, point);
needUpdate = true;
}
}
+ else if (obj->type == OTCircle)
+ {
+ if ((draggingObject && (dragged->type == OTLine)) && (dragged->hitPoint[0] || dragged->hitPoint[1]))
+ {
+ Point p = (dragged->hitPoint[0] ? dragged->p[1] : dragged->p[0]);
+ Geometry::FindTangents(obj, p);
+
+ if (Global::numIntersectPoints > 0)
+ {
+ hoveringIntersection = true;
+ intersectionPoint = Geometry::NearestTo(point, Global::intersectPoint[0], Global::intersectPoint[1]);
+ }
+ }
+ else if ((Global::tool == TTLine) && (Global::toolState == TSPoint2))
+ {
+ Geometry::FindTangents(obj, toolPoint[0]);
+
+ if (Global::numIntersectPoints > 0)
+ {
+ hoveringIntersection = true;
+ intersectionPoint = Geometry::NearestTo(point, Global::intersectPoint[0], Global::intersectPoint[1]);
+ }
+ }
+ }
}
// Handle object movement (left button down & over an object)
switch (obj->type)
{
case OTLine:
- case OTDimension:
+ case OTDimension: // N.B.: We don't check this properly...
{
Line * l = (Line *)obj;
void RenderObjects(Painter *, VPVector &, int, bool ignoreLayer = false);
void AddHoveredToSelection(void);
VPVector GetSelection(void);
- VPVector GetHovered(void);
+ VPVector GetHovered(bool exclude = false);
void ToolHandler(int, Point);
void ToolDraw(Painter *);
void LineHandler(int, Point);
};
#endif // __DRAWINGVIEW_H__
-
+//
// geometry.cpp: Algebraic geometry helper functions
//
// Part of the Architektonas Project
#include "global.h"
#include "mathconstants.h"
-
// 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.
// Note: lp1 is the tail, lp2 is the head of the line (vector).
double magnitude = lineSegment.Magnitude();
Vector pointSegment = point - tail;
double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude);
+
return t;
}
-
double Geometry::DistanceToLineFromPoint(Point tail, Point head, Point point)
{
// Interpretation: given a line in the form x = a + tu, where u is the
return dist.Magnitude() * (angle < HALF_TAU ? +1.0 : -1.0);
}
-
Point Geometry::MirrorPointAroundLine(Point point, Point tail, Point head)
{
// Get the vector of the intersection of the line and the normal on the
return mirroredPoint;
}
-
//
// point: The point we're rotating
// rotationPoint: The point we're rotating around
return Vector(rotationPoint.x + px, rotationPoint.y + py, 0);
}
-
double Geometry::Determinant(Point p1, Point p2)
{
return (p1.x * p2.y) - (p2.x * p1.y);
}
-
void Geometry::Intersects(Object * obj1, Object * obj2)
{
Global::numIntersectPoints = Global::numIntersectParams = 0;
CheckLineToCircleIntersection(obj2, obj1);
}
-
/*
Intersecting line segments:
An easier way:
Global::numIntersectParams = 1;
}
-
void Geometry::CheckCircleToCircleIntersection(Object * c1, Object * c2)
{
// Set up global vars
Global::numIntersectPoints = 2;
}
-
//
// N.B.: l is the line, c is the circle
//
}
}
-
// should we just do common trig solves, like AAS, ASA, SAS, SSA?
// Law of Cosines:
// c² = a² + b² - 2ab * cos(C)
*a3 = angle3;
}
-
Point Geometry::GetPointForParameter(Object * obj, double t)
{
if (obj->type == OTLine)
return Point(0, 0);
}
-
Point Geometry::Midpoint(Line * line)
{
return Point((line->p[0].x + line->p[1].x) / 2.0,
(line->p[0].y + line->p[1].y) / 2.0);
}
-
/*
How to find the tangent of a point off a circle:
- • Calculate the midpoint on the point and the center of the circle
- • Get the length of the line segment from the and the center divided by two
+ • Calculate the midpoint of the point and the center of the circle
+ • Get the length of the line segment from point and the center divided by two
• Use that length to construct a circle with the point at the center and the
radius equal to that length
• The intersection of the two circles are the tangent points
+Another way:
+
+ • Find angle between radius and line between point and center
+ • Angle +/- from line (point to center) are the tangent points
+
+*/
+void Geometry::FindTangents(Object * c, Point p)
+{
+ // Set up global vars
+ Global::numIntersectPoints = Global::numIntersectParams = 0;
+
+ // Get the distance between the point and the center of the circle, the
+ // length, and the angle.
+ Vector centerLine(c->p[0], p);
+ double d = centerLine.Magnitude();
+ double clAngle = centerLine.Angle();
+
+ // If the point is on or inside the circle, there are no tangents.
+ if (d <= c->radius[0])
+ return;
+
+ // Use 'cos(a) = adjacent / hypotenuse' to get the tangent angle
+ double a = acos(c->radius[0] / d);
+
+ // Finally, find the points of intersection by using +/- the angle found
+ // from the centerline's angle
+ Global::intersectPoint[0].x = c->p[0].x + (cos(clAngle + a) * c->radius[0]);
+ Global::intersectPoint[0].y = c->p[0].y + (sin(clAngle + a) * c->radius[0]);
+ Global::intersectPoint[1].x = c->p[0].x + (cos(clAngle - a) * c->radius[0]);
+ Global::intersectPoint[1].y = c->p[0].y + (sin(clAngle - a) * c->radius[0]);
+ Global::numIntersectPoints = 2;
+}
+
+/*
+The extangents can be found by collapsing the circle of smaller radius to a point, and diminishing the larger circle by the radius of the smaller, then treating it like the point-circle case (you have to translate the tangent back out by the length of the radius of the smaller circle once found).
+
+Not sure what the analogous method for finding the intangents are... :-/
+Looks like the intangent can be found by augmenting the larger circle by the smaller radius, and doing the center of the smaller as the point-circle case again, only translating the line back by the radius of the smaller.
*/
+void Geometry::FindTangents(Object * c1, Object * c2)
+{
+ // Set up global vars
+ Global::numIntersectPoints = Global::numIntersectParams = 0;
+
+ // Find the larger and smaller of the two:
+ Object * cLg = c1, * cSm = c2;
+
+ if (c2->radius[0] > c1->radius[0])
+ cLg = c2, cSm = c1;
+
+ // Get the distance between the point and the center of the circle, the
+ // length, and the angle.
+ Vector centerLine(cLg->p[0], cSm->p[0]);
+ double d = centerLine.Magnitude();
+ double clAngle = centerLine.Angle();
+
+ // If one circle is completely inside the other, there are no tangents.
+ if ((d + cSm->radius[0]) <= cLg->radius[0])
+ return;
+ // Subtract the radius of the smaller from the larger, and use the point-circle method to find the extangent:
+ double a = acos((cLg->radius[0] - cSm->radius[0]) / d);
+
+ // Finally, find the points of intersection by using +/- the angle found
+ // from the centerline's angle
+ Global::intersectPoint[0].x = cLg->p[0].x + (cos(clAngle + a) * cLg->radius[0]);
+ Global::intersectPoint[0].y = cLg->p[0].y + (sin(clAngle + a) * cLg->radius[0]);
+ Global::intersectPoint[1].x = cSm->p[0].x + (cos(clAngle + a) * cSm->radius[0]);
+ Global::intersectPoint[1].y = cSm->p[0].y + (sin(clAngle + a) * cSm->radius[0]);
+
+ Global::intersectPoint[2].x = cLg->p[0].x + (cos(clAngle - a) * cLg->radius[0]);
+ Global::intersectPoint[2].y = cLg->p[0].y + (sin(clAngle - a) * cLg->radius[0]);
+ Global::intersectPoint[3].x = cSm->p[0].x + (cos(clAngle - a) * cSm->radius[0]);
+ Global::intersectPoint[3].y = cSm->p[0].y + (sin(clAngle - a) * cSm->radius[0]);
+ Global::numIntersectPoints = 4;
+
+ // If the circles overlap, there are no intangents.
+ if (d <= (cLg->radius[0] + cSm->radius[0]))
+ return;
+
+ // Add the radius of the smaller from the larger, and use the point-circle method to find the intangent:
+ a = acos((cLg->radius[0] + cSm->radius[0]) / d);
+
+ // Finally, find the points of intersection by using +/- the angle found
+ // from the centerline's angle
+ Global::intersectPoint[4].x = cLg->p[0].x + (cos(clAngle + a) * cLg->radius[0]);
+ Global::intersectPoint[4].y = cLg->p[0].y + (sin(clAngle + a) * cLg->radius[0]);
+ Global::intersectPoint[5].x = cSm->p[0].x + (cos(clAngle - a) * cSm->radius[0]);
+ Global::intersectPoint[5].y = cSm->p[0].y + (sin(clAngle - a) * cSm->radius[0]);
+
+ Global::intersectPoint[6].x = cLg->p[0].x + (cos(clAngle - a) * cLg->radius[0]);
+ Global::intersectPoint[6].y = cLg->p[0].y + (sin(clAngle - a) * cLg->radius[0]);
+ Global::intersectPoint[7].x = cSm->p[0].x + (cos(clAngle + a) * cSm->radius[0]);
+ Global::intersectPoint[7].y = cSm->p[0].y + (sin(clAngle + a) * cSm->radius[0]);
+ Global::numIntersectPoints = 8;
+}
+
+//
+// Parameter 1: point in question
+// Parameter 2, 3: points we are comparing to
+//
+Point Geometry::NearestTo(Point point, Point p1, Point p2)
+{
+ double l1 = Vector::Magnitude(point, p1);
+ double l2 = Vector::Magnitude(point, p2);
+
+ return (l1 < l2 ? p1 : p2);
+}
static void FindAnglesForSides(double s1, double s2, double s3, double * a1, double * a2, double * a3);
static Point GetPointForParameter(Object *, double);
static Point Midpoint(Line *);
+ static void FindTangents(Object *, Point);
+ static void FindTangents(Object *, Object *);
+ static Point NearestTo(Point, Point, Point);
};
#endif // __GEOMETRY_H__
-
--- /dev/null
+//
+// promptlineedit.cpp: QLineEdit widget with uneditable (by user) prompt
+//
+// Part of the Architektonas Project
+// (C) 2021 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 11/27/2021 Created this file
+//
+
+#include "promptlineedit.h"
+
+PromptLineEdit::PromptLineEdit(QWidget * parent/*= NULL*/): QLineEdit(parent)
+{
+ connect(this, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(HandleCursorMoved(int, int)));
+ connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(HandleTextChanged(const QString &)));
+ connect(this, SIGNAL(selectionChanged(void)), this, SLOT(HandleSelectionChanged(void)));
+
+ SetPrompt("ATNS");
+}
+
+PromptLineEdit::~PromptLineEdit()
+{
+}
+
+void PromptLineEdit::HandleCursorMoved(int /*old*/, int neu)
+{
+ if (neu < prompt.length())
+ setCursorPosition(prompt.length());
+}
+
+void PromptLineEdit::HandleTextChanged(const QString & s)
+{
+ if (s.length() == 0)
+ setText(prompt);
+}
+
+void PromptLineEdit::HandleSelectionChanged(void)
+{
+ int selStart = selectionStart();
+ int selEnd = selectionEnd();
+ int promptLen = prompt.length();
+
+ if (selStart == -1)
+ return;
+
+ if (selStart < promptLen)
+ setSelection(selEnd, -(selEnd - promptLen));
+}
+
+void PromptLineEdit::keyPressEvent(QKeyEvent * event)
+{
+ if (event->key() == Qt::Key_Backspace)
+ {
+ if (cursorPosition() <= prompt.length())
+ {
+ event->accept();
+ return;
+ }
+ }
+
+ QLineEdit::keyPressEvent(event);
+}
+
+QString PromptLineEdit::text(void) const
+{
+ QString s = QLineEdit::text();
+
+ return s.right(s.length() - prompt.length());
+}
+
+void PromptLineEdit::SetPrompt(QString s)
+{
+ prompt = s + ": ";
+ setText(prompt);
+}
--- /dev/null
+#ifndef __PROMPTLINEEDIT_H__
+#define __PROMPTLINEEDIT_H__
+
+#include <QtWidgets>
+
+class PromptLineEdit: public QLineEdit
+{
+ Q_OBJECT
+
+ public:
+ PromptLineEdit(QWidget * parent = NULL);
+ ~PromptLineEdit();
+
+ public slots:
+ void HandleCursorMoved(int, int);
+ void HandleTextChanged(const QString &);
+ void HandleSelectionChanged(void);
+
+ protected:
+ void keyPressEvent(QKeyEvent *);
+
+ public:
+ QString text(void) const;
+ void SetPrompt(QString);
+
+ private:
+ QString prompt;
+};
+
+#endif // __PROMPTLINEEDIT_H__
#include "rect.h"
#include "vector.h"
-enum ObjectType { OTNone = 0, OTLine, OTCircle, OTEllipse, OTArc, OTPolygon, OTDimension, OTSpline, OTText, OTContainer, OTCount };
+enum ObjectType { OTNone = 0, OTLine, OTCircle, OTEllipse, OTArc, OTPolygon, OTDimension, OTSpline, OTText, OTContainer, OTPolyline, OTCount };
enum DimensionType { DTLinear = 0, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric, DTCircumferential, DTAngular, DTLeader, DTCount };
bool hitPoint[5]; \
bool hitObject; \
Point p[5]; \
- double angle[2]; \
+ double angle[3]; \
double radius[2]; \
double length;
struct Polygon {
OBJECT_COMMON;
+ int sides;
Polygon(): type(OTPolygon), id(Global::objectID++) {}
};
+struct Polyline {
+ OBJECT_COMMON;
+ VPVector objects;
+ bool closed;
+ Object * clicked;
+
+ Polyline(): type(OTPolyline), id(Global::objectID++), selected(false), hovered(false), hitObject(false), clicked(NULL) {}
+ void Add(void * obj) { objects.push_back(obj); }
+ void Add(VPVector objs) { objects.insert(objects.end(), objs.begin(), objs.end()); }
+};
+
struct Spline {
OBJECT_COMMON;
};
#endif // __STRUCTS_H__
-
{
}
-
Vector::Vector(Vector tail, Vector head): x(head.x - tail.x), y(head.y - tail.y), z(head.z - tail.z)
{
}
+Vector::Vector(const Vector &v): x(v.x), y(v.y), z(v.z)
+{
+}
// Create vector from angle + length (2D; z is set to zero)
void Vector::SetAngleAndLength(double angle, double length)
z = 0;
}
-
Vector Vector::operator=(Vector const v)
{
x = v.x, y = v.y, z = v.z;
return *this;
}
-
Vector Vector::operator+(Vector const v)
{
return Vector(x + v.x, y + v.y, z + v.z);
}
-
Vector Vector::operator-(Vector const v)
{
return Vector(x - v.x, y - v.y, z - v.z);
}
-
// Unary negation
Vector Vector::operator-(void)
return Vector(-x, -y, -z);
}
-
// Vector x constant
Vector Vector::operator*(double const v)
return Vector(x * v, y * v, z * v);
}
-
// Vector x constant
Vector Vector::operator*(float const v)
return Vector(x * v, y * v, z * v);
}
-
// Vector / constant
Vector Vector::operator/(double const v)
return Vector(x / v, y / v, z / v);
}
-
// Vector / constant
Vector Vector::operator/(float const v)
return Vector(x / v, y / v, z / v);
}
-
// Vector (cross) product
Vector Vector::operator*(Vector const v)
return Vector((y * v.z) - (z * v.y), (z * v.x) - (x * v.z), (x * v.y) - (y * v.x));
}
-
// Dot product
double Vector::Dot(Vector const v)
return (x * v.x) + (y * v.y) + (z * v.z);
}
-
// Vector x constant, self assigned
Vector& Vector::operator*=(double const v)
return *this;
}
-
// Vector / constant, self assigned
Vector& Vector::operator/=(double const v)
return *this;
}
-
// Vector + constant, self assigned
Vector& Vector::operator+=(double const v)
return *this;
}
-
// Vector - vector, self assigned
Vector& Vector::operator-=(Vector const v)
return *this;
}
-
// Vector - constant, self assigned
Vector& Vector::operator-=(double const v)
return *this;
}
-
// Check for equality
bool Vector::operator==(Vector const v)
{
return (x == v.x && y == v.y && z == v.z ? true : false);
}
-
// Check for inequality
bool Vector::operator!=(Vector const v)
{
return (x != v.x || y != v.y || z != v.z ? true : false);
}
-
Vector Vector::Unit(void)
{
double mag = Magnitude();
return Vector(x / mag, y / mag, z / mag);
}
-
double Vector::Magnitude(void)
{
return sqrt((x * x) + (y * y) + (z * z));
}
-
double Vector::Angle(void)
{
// acos returns a value between zero and TAU/2, which means we don't know
return correctedAngle;
}
-
bool Vector::isZero(double epsilon/*= 1e-6*/)
{
return (fabs(x) < epsilon && fabs(y) < epsilon && fabs(z) < epsilon ? true : false);
}
-
// Class methods
/*static*/ double Vector::Dot(Vector v1, Vector v2)
return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}
-
/*static*/ double Vector::Magnitude(Vector v1, Vector v2)
{
double xx = v1.x - v2.x;
double yy = v1.y - v2.y;
double zz = v1.z - v2.z;
+
return sqrt((xx * xx) + (yy * yy) + (zz * zz));
}
-
//
// Convenience function
//
return Vector(p1, p2).Angle();
}
-
// 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.
// Note: v1 is the tail, v2 is the head of the line (vector).
double magnitude = lineSegment.Magnitude();
Vector pointSegment = p - tail;
double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude);
+
return t;
}
-
// Return the 2D normal to the linesegment formed by the passed in points.
// The normal thus calculated should rotate anti-clockwise.
/*static*/ Vector Vector::Normal(Vector tail, Vector head)
{
Vector v = (head - tail).Unit();
+
return Vector(-v.y, v.x);
}
-
/*static*/ double Vector::AngleBetween(Vector a, Vector b)
{
// This is done using the following formula:
return acos(a.Dot(b) / (a.Magnitude() * b.Magnitude()));
}
-
{
public:
Vector(double xx = 0, double yy = 0, double zz = 0);
- Vector(Vector tail, Vector head); // Create vector from two points
+ Vector(Vector tail, Vector head); // Create vector from two points
+ Vector(const Vector &v);
void SetAngleAndLength(double angle, double length);
Vector operator=(Vector const v);
Vector operator+(Vector const v);
Vector& operator-=(Vector const v); // Vector minus Vector self-assignment
Vector& operator-=(double const v); // Vector minus constant self-assignment
- bool operator==(Vector const v); // Check for equality
- bool operator!=(Vector const v); // Check for inequality
+ bool operator==(Vector const v); // Check for equality
+ bool operator!=(Vector const v); // Check for inequality
Vector Unit(void);
double Magnitude(void);