X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=inline;f=src%2Fdrawingview.cpp;h=39196a753646a9eb7929e8d699b9e21f89c8fce3;hb=3c890e51a9763ffcee49e15753453a7da248272b;hp=8ad55628ced17fd993c289c2c58e524a490ea8b4;hpb=b8bab716d9302fbb04d97679ee499eac781f1b22;p=architektonas diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 8ad5562..39196a7 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -41,6 +41,7 @@ #include "painter.h" #include "penwidget.h" #include "structs.h" +#include "units.h" #include "utils.h" #define BACKGROUND_MAX_SIZE 512 @@ -52,8 +53,9 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent), 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 }; @@ -131,7 +133,7 @@ void DrawingView::DrawBackground(Painter * painter) 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; @@ -453,6 +455,41 @@ void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool 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; @@ -556,20 +593,7 @@ void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool 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(). @@ -643,15 +667,12 @@ Where is the text offset? It looks like it's drawing in the center, but obvious break; } +#if 0 case OTPolygon: { break; } - - case OTPolyline: - { - break; - } +#endif case OTContainer: { @@ -809,8 +830,9 @@ void DrawingView::ToolHandler(int mode, Point p) void DrawingView::ToolDraw(Painter * painter) { - if (Global::tool == TTLine) + switch (Global::tool) { + case TTLine: if (Global::toolState == TSNone) { painter->DrawHandle(toolPoint[0]); @@ -830,9 +852,10 @@ void DrawingView::ToolDraw(Painter * painter) 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]); @@ -850,9 +873,10 @@ void DrawingView::ToolDraw(Painter * painter) 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]); @@ -894,9 +918,10 @@ void DrawingView::ToolDraw(Painter * painter) 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) @@ -915,9 +940,10 @@ void DrawingView::ToolDraw(Painter * painter) 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) @@ -941,9 +967,10 @@ void DrawingView::ToolDraw(Painter * painter) if (ctrlDown) informativeText += " (Copy)"; } - } - else if (Global::tool == TTDimension) - { + + break; + + case TTDimension: if (Global::toolState == TSNone) { painter->DrawHandle(toolPoint[0]); @@ -963,9 +990,10 @@ void DrawingView::ToolDraw(Painter * painter) 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... @@ -974,9 +1002,10 @@ void DrawingView::ToolDraw(Painter * painter) // 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); @@ -1005,6 +1034,11 @@ void DrawingView::ToolDraw(Painter * painter) } } } + + break; + + default: + break; } } @@ -1951,9 +1985,14 @@ void DrawingView::mousePressEvent(QMouseEvent * event) if (Global::fixedLength) { if (dragged->type == OTLine) - { - dragged->length = Vector::Magnitude(dragged->p[0], dragged->p[1]); - } + dragged->length = ((Line *)dragged)->Length(); + } + + // Needed for fixed angle handling + if (Global::fixedAngle) + { + if (dragged->type == OTLine) + dragged->p[2] = ((Line *)dragged)->Unit(); } if (dragged->type == OTCircle) @@ -1968,8 +2007,8 @@ void DrawingView::mousePressEvent(QMouseEvent * event) // 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) @@ -1991,7 +2030,8 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event) } 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; @@ -2404,12 +2444,40 @@ Rect DrawingView::GetObjectExtents(Object * obj) 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 QTR_TAU)) rect.t = 1.0; @@ -2431,6 +2499,7 @@ Rect DrawingView::GetObjectExtents(Object * obj) 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]); @@ -2470,6 +2539,8 @@ void DrawingView::CheckObjectBounds(void) { Object * obj = (Object *)(*i); obj->selected = false; + Rect selection = Global::selection; + selection.Normalize(); switch (obj->type) { @@ -2478,7 +2549,7 @@ void DrawingView::CheckObjectBounds(void) { 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; @@ -2487,8 +2558,9 @@ void DrawingView::CheckObjectBounds(void) 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; @@ -2500,73 +2572,85 @@ void DrawingView::CheckObjectBounds(void) 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()) - { - double temp = bounds.left(); - bounds.setLeft(bounds.right()); - bounds.setRight(temp); - } - - if (bounds.bottom() > bounds.top()) + // Swap 'em if the span is negative... + if (a->angle[1] < 0) { - double temp = bounds.bottom(); - bounds.setBottom(bounds.top()); - bounds.setTop(temp); + end = a->angle[0]; + start = end + a->angle[1]; } -#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 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; @@ -2576,7 +2660,7 @@ void DrawingView::CheckObjectBounds(void) { 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; @@ -2621,6 +2705,10 @@ bool DrawingView::HitTest(Object * obj, Point point) { 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: @@ -2959,24 +3047,40 @@ void DrawingView::HandleObjectMovement(Point point) case OTLine: if (obj->hitPoint[0]) { +/* +N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not* going to work out in any meaningful way, and we should probably make the GUI force these to be mutually exclusive. Besides, this combined effect already works by dragging the line segment by clicking on it. :-P +*/ if (Global::fixedLength) { - Vector line = point - obj->p[1]; - Vector unit = line.Unit(); + Vector unit = Vector::Unit(obj->p[1], point); point = obj->p[1] + (unit * obj->length); } + if (Global::fixedAngle) + { + // Calculate the component of the current vector along the + // fixed angle: A_compB = (A • Bu) * Bu (p[2] has the unit + // vector "Bu".) + double magnitudeAlongB = Vector::Dot(Vector(point - obj->p[1]), obj->p[2]); + point = obj->p[1] + (obj->p[2] * magnitudeAlongB); + } + obj->p[0] = point; } else if (obj->hitPoint[1]) { if (Global::fixedLength) { - Vector line = point - obj->p[0]; - Vector unit = line.Unit(); + Vector unit = Vector::Unit(obj->p[0], point); point = obj->p[0] + (unit * obj->length); } + if (Global::fixedAngle) + { + double magnitudeAlongB = Vector::Dot(Vector(point - obj->p[0]), obj->p[2]); + point = obj->p[0] + (obj->p[2] * magnitudeAlongB); + } + obj->p[1] = point; } else if (obj->hitObject) @@ -2996,7 +3100,7 @@ void DrawingView::HandleObjectMovement(Point point) 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; @@ -3022,14 +3126,14 @@ void DrawingView::HandleObjectMovement(Point point) 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]) { @@ -3043,7 +3147,7 @@ void DrawingView::HandleObjectMovement(Point point) 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; } @@ -3053,8 +3157,13 @@ void DrawingView::HandleObjectMovement(Point point) 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) { @@ -3065,7 +3174,7 @@ void DrawingView::HandleObjectMovement(Point point) 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;