gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE),
scale(1.0), offsetX(-10), offsetY(-10), document(true),
gridPixels(0), collided(false), hoveringIntersection(false),
- dragged(NULL), draggingObject(false)
+ dragged(NULL), draggingObject(false), angleSnap(false)
{
//wtf? doesn't work except in c++11??? document = { 0 };
setBackgroundRole(QPalette::Base);
Vector v(d->p[0], d->p[1]);
double angle = v.Angle();
Vector unit = v.Unit();
- Vector linePt1 = d->p[0], linePt2 = d->p[1];
+ d->lp[0] = d->p[0], d->lp[1] = d->p[1];
Vector ortho;
double x1, y1, length;
angle = QTR_TAU;
}
- linePt1.x = linePt2.x = x1;
+ d->lp[0].x = d->lp[1].x = x1;
length = fabs(d->p[0].y - d->p[1].y);
}
else if (d->subtype == DTLinearHorz)
angle = HALF_TAU;
}
- linePt1.y = linePt2.y = y1;
+ d->lp[0].y = d->lp[1].y = y1;
length = fabs(d->p[0].x - d->p[1].x);
}
else if (d->subtype == DTLinear)
{
- angle = Vector(linePt1, linePt2).Angle();
- ortho = Vector::Normal(linePt1, linePt2);
+ angle = Vector(d->lp[0], d->lp[1]).Angle();
+ ortho = Vector::Normal(d->lp[0], d->lp[1]);
length = v.Magnitude();
}
- unit = Vector(linePt1, linePt2).Unit();
+ unit = Vector(d->lp[0], d->lp[1]).Unit();
- Point p1 = linePt1 + (ortho * 10.0 * scaledThickness);
- Point p2 = linePt2 + (ortho * 10.0 * scaledThickness);
- Point p3 = linePt1 + (ortho * 16.0 * scaledThickness);
- Point p4 = linePt2 + (ortho * 16.0 * scaledThickness);
+ Point p1 = d->lp[0] + (ortho * 10.0 * scaledThickness);
+ Point p2 = d->lp[1] + (ortho * 10.0 * scaledThickness);
+ Point p3 = d->lp[0] + (ortho * 16.0 * scaledThickness);
+ Point p4 = d->lp[1] + (ortho * 16.0 * scaledThickness);
Point p5 = d->p[0] + (ortho * 4.0 * scaledThickness);
Point p6 = d->p[1] + (ortho * 4.0 * scaledThickness);
// Calculate whether or not the arrowheads are too crowded to put
// inside the extension lines. 9.0 is the length of the arrowhead.
- double t = Geometry::ParameterOfLineAndPoint(linePt1, linePt2, linePt2 - (unit * 9.0 * scaledThickness));
+ double t = Geometry::ParameterOfLineAndPoint(d->lp[0], d->lp[1], d->lp[1] - (unit * 9.0 * scaledThickness));
// On the screen, it's acting like this is actually 58%...
// This is correct, we want it to happen at > 50%
painter->DrawAngledText(ctr, angle, dimText, scaledThickness);
+ if (d->hitObject)
+ {
+ Point hp1 = (p1 + p2) / 2.0;
+ Point hp2 = (p1 + hp1) / 2.0;
+ Point hp3 = (hp1 + p2) / 2.0;
+
+ if (d->hitPoint[2])
+ {
+ painter->SetPen(QPen(Qt::magenta, 1.0, Qt::SolidLine));
+ painter->SetBrush(QBrush(QColor(Qt::magenta)));
+ painter->DrawArrowHandle(hp1, ortho.Angle() + HALF_TAU);
+ painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DotLine));
+ }
+
+ painter->DrawHandle(hp1);
+ painter->SetPen(QPen(Qt::blue, 1.0 * Global::zoom * scaledThickness, Qt::SolidLine));
+
+ if (d->hitPoint[3])
+ {
+ painter->SetPen(QPen(Qt::magenta, 1.0, Qt::SolidLine));
+ painter->SetBrush(QBrush(QColor(Qt::magenta)));
+ painter->DrawArrowToLineHandle(hp2, (d->subtype == DTLinearVert ? v.Angle() - QTR_TAU : (v.Angle() < HALF_TAU ? HALF_TAU : 0)));
+ painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DotLine));
+ }
+
+ painter->DrawHandle(hp2);
+ painter->SetPen(QPen(Qt::blue, 1.0 * Global::zoom * scaledThickness, Qt::SolidLine));
+
+ if (d->hitPoint[4])
+ {
+ painter->SetPen(QPen(Qt::magenta, 1.0, Qt::SolidLine));
+ painter->SetBrush(QBrush(QColor(Qt::magenta)));
+ painter->DrawArrowToLineHandle(hp3, (d->subtype == DTLinearHorz ? v.Angle() - QTR_TAU : (v.Angle() > HALF_TAU && v.Angle() < THREE_QTR_TAU ? THREE_QTR_TAU : QTR_TAU)));
+ painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DotLine));
+ }
+
+ painter->DrawHandle(hp3);
+ }
+
+ if (obj->hitPoint[0])
+ painter->DrawHandle(obj->p[0]);
+
+ if (obj->hitPoint[1])
+ painter->DrawHandle(obj->p[1]);
+
break;
}
case OTText:
void DrawingView::ToolHandler(int mode, Point p)
{
+ // Drop angle snap until it's needed
+ angleSnap = false;
+
if (Global::tool == TTLine)
LineHandler(mode, p);
else if (Global::tool == TTCircle)
else if (Global::toolState == TSPoint2)
toolPoint[1] = p;
else if (Global::toolState == TSPoint3)
+ {
toolPoint[2] = p;
+ angleSnap = true;
+ }
else
+ {
toolPoint[3] = p;
+ angleSnap = true;
+ }
break;
case ToolMouseUp:
{
if (shiftDown)
{
- // Key override is telling us to start circle at new center, not
+ // Key override is telling us to start arc at new center, not
// continue the current one.
toolPoint[0] = toolPoint[1];
return;
if (shiftDown)
return;
+ angleSnap = true;
double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
std::vector<void *>::iterator j = select.begin();
std::vector<Object>::iterator i = toolScratch.begin();
if (shiftDown)
return;
+ angleSnap = true;
double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
std::vector<void *>::iterator j = select.begin();
std::vector<Object>::iterator i = toolScratch.begin();
dragged = (Object *)hover[0];
draggingObject = true;
+ // See if anything is using just a straight click on a handle
+ if (HandleObjectClicked())
+ {
+ draggingObject = false;
+ update();
+ return;
+ }
+
// Needed for grab & moving objects
// We do it *after*... why? (doesn't seem to confer any advantage...)
if (hoveringIntersection)
else if (hoverPointValid)
point = hoverPoint;
else if (Global::snapToGrid)
- point = SnapPointToGrid(point);
+ {
+ if (angleSnap)
+ point = SnapPointToAngle(point);
+ else
+ point = SnapPointToGrid(point);
+ }
ToolHandler(ToolMouseMove, point);
}
}
+Point DrawingView::SnapPointToAngle(Point point)
+{
+ // Snap to a single digit angle (using toolpoint #1 as the center)
+ double angle = Vector::Angle(toolPoint[0], point);
+ double length = Vector::Magnitude(toolPoint[0], point);
+
+ // Convert from radians to degrees
+ double degAngle = angle * RADIANS_TO_DEGREES;
+ double snapAngle = (double)((int)(degAngle + 0.5));
+
+ Vector v;
+ v.SetAngleAndLength(snapAngle * DEGREES_TO_RADIANS, length);
+ point = toolPoint[0] + v;
+
+ return point;
+}
+
+
Rect DrawingView::GetObjectExtents(Object * obj)
{
// Default to empty rect, if object checks below fail for some reason
if ((length * Global::zoom) < 8.0)
obj->hitPoint[0] = true;
else if ((length2 * Global::zoom) < 8.0)
+ {
obj->hitPoint[1] = true;
+ hoverPoint = handle1;
+ hoverPointValid = true;
+ }
else if ((length3 * Global::zoom) < 8.0)
+ {
obj->hitPoint[2] = true;
+ hoverPoint = handle2;
+ hoverPointValid = true;
+ }
else if (((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) && (span < obj->angle[1]))
obj->hitObject = true;
break;
}
+ case OTDimension:
+ {
+ bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHP3 = obj->hitPoint[3], oldHP4 = obj->hitPoint[4], oldHO = obj->hitObject;
+ obj->hitPoint[0] = obj->hitPoint[1] = obj->hitPoint[2] = obj->hitPoint[3] = obj->hitPoint[4] = obj->hitObject = false;
+
+ Dimension * d = (Dimension *)obj;
+
+ Vector orthogonal = Vector::Normal(d->lp[0], d->lp[1]);
+ // Get our line parallel to our points
+ float scaledThickness = Global::scale * obj->thickness;
+ Point p1 = d->lp[0] + (orthogonal * 10.0 * scaledThickness);
+ Point p2 = d->lp[1] + (orthogonal * 10.0 * scaledThickness);
+ Point p3(p1, point);
+
+ Vector v1(d->p[0], point);
+ Vector v2(d->p[1], point);
+ Vector lineSegment(p1, p2);
+ double t = Geometry::ParameterOfLineAndPoint(p1, p2, point);
+ double distance;
+ Point midpoint = (p1 + p2) / 2.0;
+ Point hFSPoint = Point(midpoint, point);
+ Point hCS1Point = Point((p1 + midpoint) / 2.0, point);
+ Point hCS2Point = Point((midpoint + p2) / 2.0, point);
+
+ if (t < 0.0)
+ distance = v1.Magnitude();
+ else if (t > 1.0)
+ distance = v2.Magnitude();
+ else
+ // distance = ?Det?(ls, v1) / |ls|
+ distance = fabs((lineSegment.x * p3.y - p3.x * lineSegment.y)
+ / lineSegment.Magnitude());
+
+ if ((v1.Magnitude() * Global::zoom) < 8.0)
+ obj->hitPoint[0] = true;
+ else if ((v2.Magnitude() * Global::zoom) < 8.0)
+ obj->hitPoint[1] = true;
+ else if ((distance * Global::zoom) < 5.0)
+ obj->hitObject = true;
+
+ if ((hFSPoint.Magnitude() * Global::zoom) < 8.0)
+ obj->hitPoint[2] = true;
+ else if ((hCS1Point.Magnitude() * Global::zoom) < 8.0)
+ obj->hitPoint[3] = true;
+ else if ((hCS2Point.Magnitude() * Global::zoom) < 8.0)
+ obj->hitPoint[4] = true;
+
+// return (hitPoint1 || hitPoint2 || hitLine || hitFlipSwitch || hitChangeSwitch1 || hitChangeSwitch2 ? true : false);
+ obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitPoint[3] || obj->hitPoint[4] || obj->hitObject ? true : false);
+
+ if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHP3 != obj->hitPoint[3]) || (oldHP4 != obj->hitPoint[4]) || (oldHO != obj->hitObject))
+ needUpdate = true;
+
+
+ break;
+ }
case OTContainer:
{
// Containers must be recursively tested...
}
+bool DrawingView::HandleObjectClicked(void)
+{
+ if (dragged->type == OTDimension)
+ {
+ Dimension * d = (Dimension *)dragged;
+
+ if (d->hitPoint[2])
+ {
+ // Hit the "flip sides" switch, so flip 'em
+ Point temp = d->p[0];
+ d->p[0] = d->p[1];
+ d->p[1] = temp;
+ return true;
+ }
+ else if (d->hitPoint[3])
+ {
+ // There are three cases here: aligned, horizontal, & vertical.
+ // Aligned and horizontal do the same thing, vertical goes back to
+ // linear.
+ if (d->subtype == DTLinearVert)
+ d->subtype = DTLinear;
+ else
+ d->subtype = DTLinearVert;
+
+ return true;
+ }
+ else if (d->hitPoint[4])
+ {
+ // There are three cases here: aligned, horizontal, & vertical.
+ // Aligned and vertical do the same thing, horizontal goes back to
+ // linear.
+ if (d->subtype == DTLinearHorz)
+ d->subtype = DTLinear;
+ else
+ d->subtype = DTLinearHorz;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
void DrawingView::HandleObjectMovement(Point point)
{
Point delta = point - oldPoint;
}
break;
+
case OTCircle:
if (obj->hitPoint[0])
obj->p[0] = point;
}
break;
+
case OTArc:
if (obj->hitPoint[0])
obj->p[0] = point;
}
break;
+
+ case OTDimension:
+ if (obj->hitPoint[0])
+ obj->p[0] = point;
+ else if (obj->hitPoint[1])
+ obj->p[1] = point;
+ else if (obj->hitObject)
+ {
+ obj->p[0] += delta;
+ obj->p[1] += delta;
+ }
+
+ break;
+
case OTContainer:
// This is shitty, but works for now until I can code up something
// nicer :-)