X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=src%2Fdrawingview.cpp;h=39196a753646a9eb7929e8d699b9e21f89c8fce3;hb=3c890e51a9763ffcee49e15753453a7da248272b;hp=4ae021c6da555d0091cda947e9296638efb3e9c4;hpb=fce575a51ba1f26418869c20e63b9f388e118ab6;p=architektonas diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 4ae021c..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; @@ -193,7 +195,6 @@ void DrawingView::DrawSubGrid(Painter * painter, uint32_t color, double step, Ve // void DrawingView::DeleteCurrentLayer(int layer) { -//printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer); VPVectorIter i = document.objects.begin(); while (i != document.objects.end()) @@ -230,7 +231,6 @@ void DrawingView::HandleLayerToggle(void) // void DrawingView::HandleLayerSwap(int layer1, int layer2) { -//printf("DrawingView: Swapping layers %i and %i.\n", layer1, layer2); HandleLayerSwap(layer1, layer2, document.objects); } @@ -253,42 +253,6 @@ void DrawingView::HandleLayerSwap(int layer1, int layer2, VPVector & v) } } -void DrawingView::HandlePenWidth(float width) -{ - for(VPVectorIter i=select.begin(); i!=select.end(); i++) - { - Object * obj = (Object *)(*i); - obj->thickness = width; - } - - supressSelected = true; - update(); -} - -void DrawingView::HandlePenStyle(int style) -{ - for(VPVectorIter i=select.begin(); i!=select.end(); i++) - { - Object * obj = (Object *)(*i); - obj->style = style; - } - - supressSelected = true; - update(); -} - -void DrawingView::HandlePenColor(uint32_t color) -{ - for(VPVectorIter i=select.begin(); i!=select.end(); i++) - { - Object * obj = (Object *)(*i); - obj->color = color; - } - - supressSelected = true; - update(); -} - void DrawingView::HandlePenStamp(QAction * action) { PenWidget * pw = (PenWidget *)action->parentWidget(); @@ -340,7 +304,6 @@ QPoint DrawingView::GetAdjustedClientPosition(int x, int y) void DrawingView::focusOutEvent(QFocusEvent * /*event*/) { -// printf("DrawingView::focusOutEvent()...\n"); // Make sure all modkeys being held are marked as released when the app // loses focus (N.B.: This only works because the app sets the focus policy // of this object to something other than Qt::NoFocus) @@ -355,9 +318,6 @@ void DrawingView::focusInEvent(QFocusEvent * /*event*/) setCursor(curMarker); else if (Global::penDropper) setCursor(curDropper); -//FocusOut already set this... -// else -// setCursor(Qt::ArrowCursor); } void DrawingView::paintEvent(QPaintEvent * /*event*/) @@ -399,8 +359,8 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) // Do selection rectangle rendering, if any if (Global::selectionInProgress) { - painter.SetPen(QPen(QColor(255, 127, 0, 255))); - painter.SetBrush(QBrush(QColor(255, 127, 0, 100))); + painter.SetPen(QPen(QColor(0xFF, 0x7F, 0x00, 0xFF))); + painter.SetBrush(QBrush(QColor(0xFF, 0x7F, 0x00, 0x64))); painter.DrawRect(Global::selection); } @@ -495,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; @@ -598,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(). @@ -685,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: { @@ -723,16 +702,45 @@ Where is the text offset? It looks like it's drawing in the center, but obvious } // -// This toggles the selection being hovered (typically, only 1 object) +// This toggles the selection being hovered (typically, only 1 object). We +// toggle because the CTRL key might be held, in which case, we want to +// deselect a selected object. // -void DrawingView::AddHoveredToSelection(void) +void DrawingView::HandleSelectionClick(VPVector & v) { - for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++) + if (ctrlDown) + { + for(VPVectorIter i=v.begin(); i!=v.end(); i++) + { + Object * obj = (Object *)(*i); + + if (obj->hovered) + obj->selected = !obj->selected; + } + + return; + } + + for(VPVectorIter i=v.begin(); i!=v.end(); i++) + ((Object *)(*i))->selected = false; + + // Check if the hover changed, and if so, reset the selection stack + if (oldHover.size() != v.size()) { - if (((Object *)(*i))->hovered) -// ((Object *)(*i))->selected = true; - ((Object *)(*i))->selected = !((Object *)(*i))->selected; + oldHover = v; + currentSelect = 0; } + else + { + // Select next object in the stack under the cursor + currentSelect++; + + if (currentSelect >= v.size()) + currentSelect = 0; + } + + dragged = (Object *)v[currentSelect]; + dragged->selected = true; } VPVector DrawingView::GetSelection(void) @@ -822,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]); @@ -843,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]); @@ -863,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]); @@ -907,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) @@ -928,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) @@ -954,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]); @@ -976,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... @@ -987,9 +1002,43 @@ 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); + painter->SetBrush(QBrush(Qt::NoBrush)); + + double length = Vector::Magnitude(toolObj[0]->p[0], toolPoint[0]); + bool inside = (length >= toolObj[0]->radius[0] ? false : true); + + for(int i=1; i<=Global::parallelNum; i++) + { + if (toolObj[0]->type == OTLine) + { + painter->DrawLine(toolObj[0]->p[0] + (toolPoint[0] * Global::parallelDist * (double)i), toolObj[0]->p[1] + (toolPoint[0] * Global::parallelDist * (double)i)); + } + else if ((toolObj[0]->type == OTCircle) || (toolObj[0]->type == OTArc)) + { + double radius = toolObj[0]->radius[0] + ((double)i * Global::parallelDist * (inside ? -1.0 : 1.0)); + + if (radius > 0) + { + if (toolObj[0]->type == OTCircle) + painter->DrawEllipse(toolObj[0]->p[0], radius, radius); + else + painter->DrawArc(toolObj[0]->p[0], radius, toolObj[0]->angle[0], toolObj[0]->angle[1]); + } + } + } + } + + break; + + default: + break; } } @@ -1770,14 +1819,85 @@ void DrawingView::TrimHandler(int mode, Point p) } } -void DrawingView::ParallelHandler(int mode, Point /*p*/) +void DrawingView::ParallelHandler(int mode, Point p) { switch (mode) { case ToolMouseDown: + if (numHovered == 1) + { + // New selection made... + VPVector hover = GetHovered(); + toolObj[0] = (Object *)hover[0]; + Global::toolState = TSNone; + } + else if ((numHovered == 0) && (toolObj[0] != NULL)) + { + double length = Vector::Magnitude(toolObj[0]->p[0], toolPoint[0]); + bool inside = (length >= toolObj[0]->radius[0] ? false : true); + + // Stamp out new parallel object(s)... + for(int i=1; i<=Global::parallelNum; i++) + { + if (toolObj[0]->type == OTLine) + { + Line * l = new Line(toolObj[0]->p[0] + (toolPoint[0] * Global::parallelDist * (double)i), toolObj[0]->p[1] + (toolPoint[0] * Global::parallelDist * (double)i), Global::penWidth, Global::penColor, Global::penStyle); + // Should probably have a user selection for this whether it goes into the selected objects layer or the global layer... + l->layer = toolObj[0]->layer; + document.objects.push_back(l); + } + else if (toolObj[0]->type == OTCircle) + { + double radius = toolObj[0]->radius[0] + ((double)i * Global::parallelDist * (inside ? -1.0 : 1.0)); + + if (radius > 0) + { + Circle * c = new Circle(toolObj[0]->p[0], radius, Global::penWidth, Global::penColor, Global::penStyle); + c->layer = toolObj[0]->layer; + document.objects.push_back(c); + } + } + else if (toolObj[0]->type == OTArc) + { + double radius = toolObj[0]->radius[0] + ((double)i * Global::parallelDist * (inside ? -1.0 : 1.0)); + + if (radius > 0) + { + Arc * a = new Arc(toolObj[0]->p[0], radius, toolObj[0]->angle[0], toolObj[0]->angle[1], Global::penWidth, Global::penColor, Global::penStyle); + a->layer = toolObj[0]->layer; + document.objects.push_back(a); + } + } + } + + // Then reset the state + toolObj[0]->selected = false; + toolObj[0] = NULL; + Global::toolState = TSNone; + } + break; case ToolMouseMove: + if ((numHovered == 0) && toolObj[0] != NULL) + Global::toolState = TSPoint1; + else + Global::toolState = TSNone; + + if (Global::toolState == TSPoint1) + { + // Figure out which side of the object we're on, and draw the preview on that side... + if (toolObj[0]->type == OTLine) + { + Vector normal = Geometry::GetNormalOfPointAndLine(p, (Line *)toolObj[0]); + toolPoint[0] = normal; + } + else if ((toolObj[0]->type == OTCircle) || (toolObj[0]->type == OTArc)) + { + toolPoint[0] = p; + } + } + break; case ToolMouseUp: @@ -1798,7 +1918,6 @@ void DrawingView::mousePressEvent(QMouseEvent * event) { if (event->button() == Qt::LeftButton) { -//printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered); Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); // Handle tool processing, if any @@ -1819,17 +1938,11 @@ void DrawingView::mousePressEvent(QMouseEvent * event) if (!ctrlDown) ClearSelected(document.objects); - // If any objects are being hovered on click, add them to the selection - // & return + // If any objects are being hovered on click, deal with 'em if (numHovered > 0) { - AddHoveredToSelection(); - update(); // needed?? -// GetHovered(hover); // prolly needed VPVector hover2 = GetHovered(); dragged = (Object *)hover2[0]; - draggingObject = true; -//printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]); // Alert the pen widget if (Global::penDropper) @@ -1838,26 +1951,27 @@ void DrawingView::mousePressEvent(QMouseEvent * event) Global::penWidth = dragged->thickness; Global::penStyle = dragged->style; emit ObjectSelected(dragged); - ClearSelected(document.objects); return; } - - if (Global::penStamp) + else if (Global::penStamp) { dragged->color = Global::penColor; dragged->thickness = Global::penWidth; dragged->style = Global::penStyle; return; } - - // See if anything is using just a straight click on a handle - if (HandleObjectClicked()) + // See if anything is using just a straight click on a custom + // object handle (like Dimension objects) + else if (HandleObjectClicked()) { - draggingObject = false; update(); return; } + draggingObject = true; + HandleSelectionClick(hover2); + update(); // needed?? + // Needed for grab & moving objects // We do it *after*... why? (doesn't seem to confer any advantage...) if (hoveringIntersection) @@ -1871,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) @@ -1888,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) @@ -1911,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; @@ -2324,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; @@ -2351,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]); @@ -2390,6 +2539,8 @@ void DrawingView::CheckObjectBounds(void) { Object * obj = (Object *)(*i); obj->selected = false; + Rect selection = Global::selection; + selection.Normalize(); switch (obj->type) { @@ -2398,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; @@ -2407,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; @@ -2420,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; @@ -2496,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; @@ -2541,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: @@ -2879,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) @@ -2916,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; @@ -2942,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]) { @@ -2963,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; } @@ -2973,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) { @@ -2985,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;