#include "painter.h"
#include "penwidget.h"
#include "structs.h"
+#include "units.h"
#include "utils.h"
#define BACKGROUND_MAX_SIZE 512
gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE),
scale(1.0), offsetX(-10), offsetY(-10), supressSelected(false),
document(true),
- gridPixels(0), collided(false), scrollDrag(false), hoverPointValid(false),
- hoveringIntersection(false), dragged(NULL), draggingObject(false),
+ gridPixels(0), collided(false), scrollDrag(false),
+ hoverPointValid(false), hoveringIntersection(false),
+ dragged(NULL), draggingObject(false),
angleSnap(false), dirty(false)
{
//wtf? doesn't work except in c++11??? document = { 0 };
painter->SetBrush(0xF0F0F0);
painter->SetPen(0xF0F0F0, 1, 1);
- painter->DrawRect(QRectF(QPointF(ul.x, ul.y), QPointF(br.x, br.y)));
+ painter->DrawRect(Rect(ul, br));
double spacing = Global::gridSpacing;
break;
+ case OTPolyline:
+ {
+ painter->SetBrush(QBrush(Qt::NoBrush));
+ Polyline * pl = (Polyline *)obj;
+ Point lastp;
+ double lastbump;
+
+ for(VPVectorIter i=pl->points.begin(); i!=pl->points.end(); i++)
+ {
+ if (i != pl->points.begin())
+ {
+ Point p = ((Object *)(*i))->p[0];
+ double bump = ((Object *)(*i))->length;
+
+ if (lastbump == 0)
+ painter->DrawLine(lastp, p);
+ else
+ {
+ Arc a = Geometry::Unpack(lastp, p, lastbump);
+ painter->DrawArc(a.p[0], a.radius[0], a.angle[0], a.angle[1]);
+ }
+
+ lastp = p;
+ lastbump = bump;
+ }
+ else
+ {
+ lastp = ((Object *)(*i))->p[0];
+ lastbump = ((Object *)(*i))->length;
+ }
+ }
+
+ break;
+ }
+
case OTDimension:
{
Dimension * d = (Dimension *)obj;
painter->SetFont(QFont("Arial", 8.0 * Global::zoom * scaledThickness));
Point ctr = p2 + (Vector(p2, p1) / 2.0);
- QString dimText;
-
- if (length < 12.0)
- dimText = QString("%1\"").arg(length);
- else
- {
- double feet = (double)((int)length / 12);
- double inches = length - (feet * 12.0);
-
- if (inches == 0)
- dimText = QString("%1'").arg(feet);
- else
- dimText = QString("%1' %2\"").arg(feet).arg(inches);
- }
+ QString dimText = GetDimensionText(&document, length);
/*
Where is the text offset? It looks like it's drawing in the center, but obviously it isn't. It isn't here, it's in Painter::DrawAngledText().
break;
}
+#if 0
case OTPolygon:
{
break;
}
-
- case OTPolyline:
- {
- break;
- }
+#endif
case OTContainer:
{
void DrawingView::ToolDraw(Painter * painter)
{
- if (Global::tool == TTLine)
+ switch (Global::tool)
{
+ case TTLine:
if (Global::toolState == TSNone)
{
painter->DrawHandle(toolPoint[0]);
QString text = tr("Length: %1 in.\n") + QChar(0x2221) + tr(": %2");
informativeText = text.arg(absLength).arg(absAngle);
}
- }
- else if (Global::tool == TTCircle)
- {
+
+ break;
+
+ case TTCircle:
if (Global::toolState == TSNone)
{
painter->DrawHandle(toolPoint[0]);
QString text = tr("Radius: %1 in.");
informativeText = text.arg(length);
}
- }
- else if (Global::tool == TTArc)
- {
+
+ break;
+
+ case TTArc:
if (Global::toolState == TSNone)
{
painter->DrawHandle(toolPoint[0]);
QString text = tr("Arc span: %1") + QChar(0x00B0);
informativeText = text.arg(RADIANS_TO_DEGREES * span);
}
- }
- else if (Global::tool == TTRotate)
- {
+
+ break;
+
+ case TTRotate:
if ((Global::toolState == TSNone) || (Global::toolState == TSPoint1))
painter->DrawHandle(toolPoint[0]);
else if ((Global::toolState == TSPoint2) && shiftDown)
if (ctrlDown)
informativeText += " (Copy)";
}
- }
- else if (Global::tool == TTMirror)
- {
+
+ break;
+
+ case TTMirror:
if ((Global::toolState == TSNone) || (Global::toolState == TSPoint1))
painter->DrawHandle(toolPoint[0]);
else if ((Global::toolState == TSPoint2) && shiftDown)
if (ctrlDown)
informativeText += " (Copy)";
}
- }
- else if (Global::tool == TTDimension)
- {
+
+ break;
+
+ case TTDimension:
if (Global::toolState == TSNone)
{
painter->DrawHandle(toolPoint[0]);
QString text = tr("Length: %1 in.\n") + QChar(0x2221) + tr(": %2");
informativeText = text.arg(absLength).arg(absAngle);
}
- }
- else if (Global::tool == TTTrim)
- {
+
+ break;
+
+ case TTTrim:
if (toolObj[0] != NULL)
{
// We're assuming ATM it's just a line...
// QString text = tr("Arc span: %1") + QChar(0x00B0);
// informativeText = text.arg(RADIANS_TO_DEGREES * span);
}
- }
- else if (Global::tool == TTParallel)
- {
+
+ break;
+
+ case TTParallel:
if (Global::toolState == TSPoint1)
{
painter->SetPen(0xFF00FF, 2.0, LSSolid);
}
}
}
+
+ break;
+
+ default:
+ break;
}
}
// Didn't hit any object and not using a tool, so do a selection
// rectangle
Global::selectionInProgress = true;
- Global::selection.setTopLeft(QPointF(point.x, point.y));
- Global::selection.setBottomRight(QPointF(point.x, point.y));
+ Global::selection.l = Global::selection.r = point.x;
+ Global::selection.t = Global::selection.b = point.y;
select = GetSelection();
}
else if (event->button() == Qt::MiddleButton)
}
Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
- Global::selection.setBottomRight(QPointF(point.x, point.y));
+ Global::selection.r = point.x;
+ Global::selection.b = point.y;
// Only needs to be done here, as mouse down is always preceded by movement
Global::snapPointIsValid = false;
hoveringIntersection = false;
double start = a->angle[0];
double end = start + a->angle[1];
+
+ // Swap 'em if the span is negative...
+ if (a->angle[1] < 0)
+ {
+ end = a->angle[0];
+ start = end + a->angle[1];
+ }
+
rect = Rect(Point(cos(start), sin(start)), Point(cos(end), sin(end)));
// If the end of the arc is before the beginning, add 360 degrees to it
if (end < start)
end += TAU;
+/*
+Find which quadrant the start angle is in (consider the beginning of the 90° angle to be in the quadrant, the end to be in the next quadrant). Then, divide the span into 90° segments. The integer portion is the definite axis crossings; the remainder needs more scrutiny. There will be an additional axis crossing if the the sum of the start angle and the remainder is > 90°.
+*/
+#if 1
+ int quadStart = (int)(a->angle[0] / QTR_TAU);
+ double qsRemain = a->angle[0] - ((double)quadStart * QTR_TAU);
+ int numAxes = (int)((a->angle[1] + qsRemain) / QTR_TAU);
+
+ double axis[4] = { 0, 0, 0, 0 };
+ axis[0] = rect.t, axis[1] = rect.l, axis[2] = rect.b, axis[3] = rect.r;
+ double box[4] = { 1.0, -1.0, -1.0, 1.0 };
+
+ for(int i=0; i<numAxes; i++)
+ axis[(quadStart + i) % 4] = box[(quadStart + i) % 4];
+
+ // The rect is constructed the same way we traverse the axes: TLBR
+ Rect r2(axis[0], axis[1], axis[2], axis[3]);
+
+ rect |= r2;
+#else
// Adjust the bounds depending on which axes are crossed
if ((start < QTR_TAU) && (end > QTR_TAU))
rect.t = 1.0;
if ((start < (TAU + THREE_QTR_TAU)) && (end > (TAU + THREE_QTR_TAU)))
rect.b = -1.0;
+#endif
rect *= a->radius[0];
rect.Translate(a->p[0]);
{
Object * obj = (Object *)(*i);
obj->selected = false;
+ Rect selection = Global::selection;
+ selection.Normalize();
switch (obj->type)
{
{
Line * l = (Line *)obj;
- if (Global::selection.contains(l->p[0].x, l->p[0].y) && Global::selection.contains(l->p[1].x, l->p[1].y))
+ if (selection.Contains(l->p[0]) && selection.Contains(l->p[1]))
l->selected = true;
break;
case OTCircle:
{
Circle * c = (Circle *)obj;
+ Vector radVec(c->radius[0], c->radius[0]);
- if (Global::selection.contains(c->p[0].x - c->radius[0], c->p[0].y - c->radius[0]) && Global::selection.contains(c->p[0].x + c->radius[0], c->p[0].y + c->radius[0]))
+ if (selection.Contains(c->p[0] - radVec) && selection.Contains(c->p[0] + radVec))
c->selected = true;
break;
double start = a->angle[0];
double end = start + a->angle[1];
- QPointF p1(cos(start), sin(start));
- QPointF p2(cos(end), sin(end));
- QRectF bounds(p1, p2);
-#if 1
- // Swap X/Y coordinates if they're backwards...
- if (bounds.left() > bounds.right())
+ // Swap 'em if the span is negative...
+ if (a->angle[1] < 0)
{
- double temp = bounds.left();
- bounds.setLeft(bounds.right());
- bounds.setRight(temp);
+ end = a->angle[0];
+ start = end + a->angle[1];
}
- if (bounds.bottom() > bounds.top())
- {
- double temp = bounds.bottom();
- bounds.setBottom(bounds.top());
- bounds.setTop(temp);
- }
-#else
- // Doesn't work as advertised! For shame!
- bounds = bounds.normalized();
-#endif
-
// If the end of the arc is before the beginning, add 360 degrees
// to it
if (end < start)
end += TAU;
+#if 1
+ int quadStart = (int)(a->angle[0] / QTR_TAU);
+ double qsRemain = a->angle[0] - ((double)quadStart * QTR_TAU);
+ int numAxes = (int)((a->angle[1] + qsRemain) / QTR_TAU);
+
+ Rect bounds(sin(start), cos(start), sin(end), cos(end));
+ const double box[4] = { 1.0, -1.0, -1.0, 1.0 };
+
+ for(int i=0; i<numAxes; i++)
+ bounds[(quadStart + i) % 4] = box[(quadStart + i) % 4];
+#else
// Adjust the bounds depending on which axes are crossed
if ((start < QTR_TAU) && (end > QTR_TAU))
- bounds.setTop(1.0);
+ bounds.t = 1.0;
if ((start < HALF_TAU) && (end > HALF_TAU))
- bounds.setLeft(-1.0);
+ bounds.l = -1.0;
if ((start < THREE_QTR_TAU) && (end > THREE_QTR_TAU))
- bounds.setBottom(-1.0);
+ bounds.b = -1.0;
if ((start < TAU) && (end > TAU))
- bounds.setRight(1.0);
+ bounds.r = 1.0;
if ((start < (TAU + QTR_TAU)) && (end > (TAU + QTR_TAU)))
- bounds.setTop(1.0);
+ bounds.t = 1.0;
if ((start < (TAU + HALF_TAU)) && (end > (TAU + HALF_TAU)))
- bounds.setLeft(-1.0);
+ bounds.l = -1.0;
if ((start < (TAU + THREE_QTR_TAU)) && (end > (TAU + THREE_QTR_TAU)))
- bounds.setBottom(-1.0);
+ bounds.b = -1.0;
+#endif
- bounds.setTopLeft(QPointF(bounds.left() * a->radius[0], bounds.top() * a->radius[0]));
- bounds.setBottomRight(QPointF(bounds.right() * a->radius[0], bounds.bottom() * a->radius[0]));
- bounds.translate(a->p[0].x, a->p[0].y);
+ bounds *= a->radius[0];
+ bounds.Translate(a->p[0]);
- if (Global::selection.contains(bounds))
+ if (selection.Contains(bounds))
a->selected = true;
break;
}
+ case OTPolyline:
+ {
+ Polyline * pl = (Polyline *)obj;
+ Rect r(((Object *)(pl->points[0]))->p[0]);
+
+ for(int i=0; i<(pl->points.size()-1); i++)
+ {
+ r += ((Object *)(pl->points[i]))->p[0];
+ r += ((Object *)(pl->points[i + 1]))->p[0];
+ }
+
+ if (selection.Contains(r))
+ pl->selected = true;
+
+ break;
+ }
+
case OTText:
{
Text * t = (Text *)obj;
Rect r(obj->p[0], Point(t->p[0].x + t->extents.Width(), t->p[0].y - t->extents.Height()));
- if (Global::selection.contains(r.l, r.t) && Global::selection.contains(r.r, r.b))
+ if (selection.Contains(r))
t->selected = true;
break;
{
Container * c = (Container *)obj;
- if (Global::selection.contains(c->p[0].x, c->p[0].y) && Global::selection.contains(c->p[1].x, c->p[1].y))
+ if (selection.Contains(c->p[0]) && selection.Contains(c->p[1]))
c->selected = true;
break;
{
bool needUpdate = false;
+ // Make sure we don't hit test stuff on an invisible layer...
+ if (Global::layerHidden[obj->layer] == true)
+ return false;
+
switch (obj->type)
{
case OTLine:
obj->radius[0] = Vector::Magnitude(obj->p[0], point);
QString text = QObject::tr("Radius: %1\nScale: %2%");
- informativeText = text.arg(obj->radius[0], 0, 'd', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'd', 0);
+ informativeText = text.arg(obj->radius[0], 0, 'f', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'f', 0);
}
break;
obj->angle[1] += TAU;
QString text = QObject::tr("Span: %1") + QChar(0x00B0) + QObject::tr("\n%2") + QChar(0x00B0) + QObject::tr(" - %3") + QChar(0x00B0);
- informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'd', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 2);
+ informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'f', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'f', 2);
return;
}
double angle = Vector::Angle(obj->p[0], point);
obj->angle[0] = angle;
QString text = QObject::tr("Start angle: %1") + QChar(0x00B0);
- informativeText = text.arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 4);
+ informativeText = text.arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 4);
}
else if (obj->hitPoint[2])
{
obj->angle[1] += TAU;
QString text = QObject::tr("Span: %1") + QChar(0x00B0) + QObject::tr("\n%2") + QChar(0x00B0) + QObject::tr(" - %3") + QChar(0x00B0);
- informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'd', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 2);
+ informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'f', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'f', 2);
return;
}
if (obj->angle[0] < 0)
obj->angle[0] += TAU;
+ double endAngle = obj->angle[0] + obj->angle[1];
+
+ if (endAngle > TAU)
+ endAngle -= TAU;
+
QString text = QObject::tr("End angle: %1") + QChar(0x00B0);
- informativeText = text.arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 4);
+ informativeText = text.arg(endAngle * RADIANS_TO_DEGREES, 0, 'f', 4);
}
else if (obj->hitObject)
{
obj->radius[0] = Vector::Magnitude(obj->p[0], point);
QString text = QObject::tr("Radius: %1");
- informativeText = text.arg(obj->radius[0], 0, 'd', 4);
+ informativeText = text.arg(obj->radius[0], 0, 'f', 4);
}
break;