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;
break;
}
+#if 0
case OTPolygon:
{
break;
}
-
- case OTPolyline:
- {
- break;
- }
+#endif
case OTContainer:
{
// 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())
- {
- 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<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;
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;