case OTText:
{
Text * t = (Text *)obj;
- painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness);
+
+ if (t->measured == false)
+ {
+ t->extents = painter->MeasureTextObject(t->s.c_str(), scaledThickness);
+ t->measured = true;
+ }
+
+ painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness, t->angle[0]);
break;
}
case OTSpline:
rect = Rect(obj->p[0], obj->p[1]);
break;
}
+
case OTCircle:
{
rect = Rect(obj->p[0], obj->p[0]);
rect.Expand(obj->radius[0]);
break;
}
+
case OTArc:
{
Arc * a = (Arc *)obj;
rect *= a->radius[0];
rect.Translate(a->p[0]);
+ break;
+ }
+ case OTText:
+ {
+ Text * t = (Text *)obj;
+ rect = Rect(t->p[0], Point(t->p[0].x + t->extents.Width(), t->p[0].y - t->extents.Height()));
break;
}
+
case OTContainer:
{
Container * c = (Container *)obj;
for(; i!=c->objects.end(); i++)
rect |= GetObjectExtents((Object *)*i);
}
+
default:
break;
}
break;
}
+
case OTCircle:
{
Circle * c = (Circle *)obj;
break;
}
+
case OTArc:
{
Arc * a = (Arc *)obj;
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))
+ t->selected = true;
+
+ break;
+ }
+
default:
break;
}
break;
}
+
case OTCircle:
{
bool oldHP = obj->hitPoint[0], oldHO = obj->hitObject;
double length = Vector::Magnitude(obj->p[0], point);
if ((length * Global::zoom) < 8.0)
+ {
obj->hitPoint[0] = true;
+ hoverPoint = obj->p[0];
+ hoverPointValid = true;
+ }
else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0)
obj->hitObject = true;
break;
}
+
case OTArc:
{
bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHO = obj->hitObject;
double length3 = Vector::Magnitude(point, handle2);
if ((length * Global::zoom) < 8.0)
+ {
obj->hitPoint[0] = true;
+ hoverPoint = obj->p[0];
+ hoverPointValid = true;
+ }
else if ((length2 * Global::zoom) < 8.0)
{
obj->hitPoint[1] = 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;
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 OTText:
+ {
+ Text * t = (Text *)obj;
+ bool oldHO = obj->hitObject;
+ obj->hitObject = false;
+
+ Rect r(obj->p[0], Point(obj->p[0].x + t->extents.Width(), obj->p[0].y - t->extents.Height()));
+//printf("Text: p=<%lf, %lf>, w/h=%lf, %lf [lrtb=%lf, %lf, %lf, %lf]\n", obj->p[0].x, obj->p[0].y, t->extents.Width(), t->extents.Height(), t->extents.l, t->extents.r, t->extents.t, t->extents.b);
+
+ if (r.Contains(point))
+ obj->hitObject = true;
+
+ obj->hovered = (obj->hitObject ? true : false);
+
+ if (oldHO != obj->hitObject)
+ needUpdate = true;
break;
}
+
case OTContainer:
{
// Containers must be recursively tested...
break;
}
+
default:
break;
}
break;
+ case OTText:
+ if (obj->hitObject)
+ obj->p[0] += delta;
+
+ break;
+
case OTContainer:
// This is shitty, but works for now until I can code up something
// nicer :-)
const char objName[OTCount][16] = {
"None", "Line", "Circle", "Ellipse", "Arc", "Polygon", "Dimension", "Spline", "Text", "Container"
};
+ const char dimName[DTCount][32] = {
+ "Linear", "Vertical", "Horizontal", "Radial", "Diametric",
+ "Circumferential", "Angular", "Leader"
+ };
// Sanity check
if (obj == NULL)
s += QString("<%1, %2> to <%3, %4><br>Length: %5<br>Angle: %6°<br>").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->p[1].x).arg(obj->p[1].y).arg(line.Magnitude()).arg(line.Angle() * RADIANS_TO_DEGREES);
break;
}
+
case OTCircle:
s += QString("Center: <%1, %2><br>Radius: %3<br>").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->radius[0]);
break;
+
case OTEllipse:
break;
+
case OTArc:
s += QString("Center: <%1, %2><br>Radius: %3<br>Start: %4°<br>End: %5°<br>").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->radius[0]).arg(obj->angle[0] * RADIANS_TO_DEGREES).arg(obj->angle[1] * RADIANS_TO_DEGREES);
break;
break;
+
case OTPolygon:
break;
+
case OTDimension:
break;
+
case OTSpline:
break;
+
case OTText:
+ {
+ Text * t = (Text *)obj;
+ s += QString("<%1, %2><br>Width/Height: %3/%4<br>Angle: %5°<br>").arg(t->p[0].x).arg(t->p[0].y).arg(t->extents.Width()).arg(t->extents.Height()).arg(obj->angle[0] * RADIANS_TO_DEGREES);
break;
+ }
+
case OTContainer:
break;
+
default:
break;
}
}
+//
+// Return the non-rotated rectangle containing the extents of the text in
+// Cartesian coordiates (starting from <0, 0>, the lower left hand side)
+//
+Rect Painter::MeasureTextObject(QString text, double size)
+{
+ if (!painter)
+ return Rect();
+
+ painter->setFont(QFont("Arial", Global::zoom * size));
+ int textWidth = QFontMetrics(painter->font()).width(text);
+ int textHeight = QFontMetrics(painter->font()).height();
+ Point measured((double)textWidth / Global::zoom, (double)textHeight / Global::zoom);// = QtToCartesianCoords(Point(textWidth, textHeight));
+//printf("QFontMetrics w/h=%i/%i, measured=%lf/%lf\n", textWidth, textHeight, measured.x, measured.y);
+
+ return Rect(Point(0, 0), measured);
+}
+
+
void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
{
if (!painter)
if (!painter)
return;
-// QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
-
Vector v1 = CartesianToQtCoords(Vector(rect.l, rect.t));
Vector v2 = CartesianToQtCoords(Vector(rect.r, rect.b));
-// QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
-// screenRect.adjust(-8, 8, 8, -8); // Left/top, right/bottom
-// painter->drawRect(screenRect);
v1 += Vector(-8.0, -8.0);
v2 += Vector(+8.0, +8.0);
painter->setPen(QPen(Qt::red, 2.0, Qt::DashLine));
void SetFont(QFont);
void DrawAngledText(Vector, double, QString, double);
void DrawTextObject(Vector, QString, double, double angle = 0);
+ Rect MeasureTextObject(QString text, double size);
void DrawArc(Vector, double, double, double);
void DrawEllipse(Vector, double, double);
void DrawHandle(Vector);
b -= amt;
}
+
+double Rect::Width(void)
+{
+ return r - l;
+}
+
+
+double Rect::Height(void)
+{
+ return t - b;
+}
+
+
+bool Rect::Contains(Point p)
+{
+ return ((p.x >= l) && (p.x <= r) && (p.y >= b) && (p.y <= t) ? true : false);
+}
+
+
+Point Rect::TopLeft(void)
+{
+ return Point(t, l);
+}
+
+
+Point Rect::BottomRight(void)
+{
+ return Point(b, r);
+}
+
void Normalize(void);
void Translate(Point p);
void Expand(double amt);
+ double Width(void);
+ double Height(void);
+ bool Contains(Point p);
+ Point TopLeft(void);
+ Point BottomRight(void);
};
#endif // __RECT_H__
#include <vector>
#include <string>
#include "global.h"
+#include "rect.h"
#include "vector.h"
enum ObjectType { OTNone = 0, OTLine, OTCircle, OTEllipse, OTArc, OTPolygon, OTDimension, OTSpline, OTText, OTContainer, OTCount };
-enum DimensionType { DTLinear, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric, DTCircumferential, DTAngular, DTLeader };
+enum DimensionType { DTLinear = 0, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric, DTCircumferential, DTAngular, DTLeader, DTCount };
enum ToolType { TTNone, TTLine, TTCircle, TTEllipse, TTArc, TTDimension, TTText, TTPolygon, TTSpline, TTRotate, TTMirror, TTTrim, TTTriangulate, TTDelete };
double angle[2]; \
double radius[2];
+struct Object {
+ OBJECT_COMMON;
+};
+
struct Line {
OBJECT_COMMON;
struct Text {
OBJECT_COMMON;
+ Rect extents;
+ bool measured;
std::string s;
Text(): type(OTText), id(Global::objectID++) {}
Text(Vector pt1, char * str, float th = 10.0, uint32_t c = 0):
type(OTText), id(Global::objectID++), layer(0), color(c), thickness(th),
- style(LSSolid), selected(false), hovered(false), hitObject(false), s(str) { p[0] = pt1; }
+ style(LSSolid), selected(false), hovered(false), hitObject(false),
+ measured(false), s(str) { p[0] = pt1; angle[0] = 0; }
};
struct Polygon {
}*/
};
-struct Object {
- OBJECT_COMMON;
-};
-
#endif // __STRUCTS_H__