forked from qt-creator/qt-creator
modeleditor: Intersect relations with shape of item
Change-Id: I40d898715772f74ffa225ac27b91ee7ad4d8fedc Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -42,6 +42,10 @@
|
||||
// ArcTo { x: <center_x>; y: <center_y>; radiusX: <radius_x>; radiusY: <radius_y>; start: <start_angle>; span: <span_angle> }
|
||||
// Close
|
||||
// }
|
||||
// Outline {
|
||||
// // same as in Shape to define the geometrical ouline of the icon
|
||||
// // if the outline is not defined it defaults to the shape
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
@@ -165,6 +169,10 @@ Icon {
|
||||
Line { x0: 0.0; y0: 0.0; x1: 0.0; y1: 20.0 }
|
||||
Line { x0: 0.0; y0: 10.0; x1: 4.0; y1: 10.0 }
|
||||
}
|
||||
Outline {
|
||||
Circle { x: 14.0; y: 10.0; radius: 10.0 }
|
||||
Rect { x: 0; y: 0; width: 14; height: 20 }
|
||||
}
|
||||
}
|
||||
|
||||
Icon {
|
||||
@@ -178,6 +186,9 @@ Icon {
|
||||
Line { x0: 10.0; y0: 0.0; x1: 14.0; y1: -2.0 }
|
||||
Line { x0: 10.0; y0: 0.0; x1: 14.0; y1: 4.0 }
|
||||
}
|
||||
Outline {
|
||||
Circle { x: 10.0; y: 10.0; radius: 10.0 }
|
||||
}
|
||||
}
|
||||
|
||||
Icon {
|
||||
@@ -190,6 +201,10 @@ Icon {
|
||||
Circle { x: 10.0; y: 10.0; radius: 10.0 }
|
||||
Line { x0: 0.0; y0: 20.0; x1: 20.0; y1: 20.0 }
|
||||
}
|
||||
Outline {
|
||||
Circle { x: 10.0; y: 10.0; radius: 10.0 }
|
||||
Rect { x: 0; y: 10; width: 20; height: 10 }
|
||||
}
|
||||
}
|
||||
|
||||
Association {
|
||||
@@ -313,6 +328,10 @@ Icon {
|
||||
Line { x0: 10; y0: 25; x1: 3; y1: 40 }
|
||||
Line { x0: 10; y0: 25; x1: 17; y1: 40 }
|
||||
}
|
||||
Outline {
|
||||
Circle { x: 10; y: 5; radius: 5 }
|
||||
Rect { x: 3; y: 5; width: 14; height: 35 }
|
||||
}
|
||||
}
|
||||
|
||||
Relation {
|
||||
@@ -522,6 +541,9 @@ Icon {
|
||||
Line { x0: 0; y0: 0; x1: 10; y1: 10 }
|
||||
Line { x0: 0; y0: 10; x1: 10; y1: 0 }
|
||||
}
|
||||
Outline {
|
||||
Circle { x: 5; y: 5; radius: 2 }
|
||||
}
|
||||
}
|
||||
|
||||
Icon {
|
||||
|
@@ -55,6 +55,7 @@ static const int KEYWORD_DISPLAY = 11;
|
||||
static const int KEYWORD_TEXTALIGN = 12;
|
||||
static const int KEYWORD_BASECOLOR = 13;
|
||||
static const int KEYWORD_SHAPE = 14;
|
||||
static const int KEYWORD_OUTLINE = 15;
|
||||
|
||||
// Shape items
|
||||
static const int KEYWORD_CIRCLE = 30;
|
||||
@@ -245,6 +246,7 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
|
||||
<< qMakePair(QString("textalignment"), KEYWORD_TEXTALIGN)
|
||||
<< qMakePair(QString("basecolor"), KEYWORD_BASECOLOR)
|
||||
<< qMakePair(QString("shape"), KEYWORD_SHAPE)
|
||||
<< qMakePair(QString("outline"), KEYWORD_OUTLINE)
|
||||
<< qMakePair(QString("circle"), KEYWORD_CIRCLE)
|
||||
<< qMakePair(QString("ellipse"), KEYWORD_ELLIPSE)
|
||||
<< qMakePair(QString("line"), KEYWORD_LINE)
|
||||
@@ -436,6 +438,9 @@ void StereotypeDefinitionParser::parseIcon()
|
||||
case KEYWORD_SHAPE:
|
||||
stereotypeIcon.setIconShape(parseIconShape());
|
||||
break;
|
||||
case KEYWORD_OUTLINE:
|
||||
stereotypeIcon.setOutlineShape(parseIconShape());
|
||||
break;
|
||||
case KEYWORD_NAME:
|
||||
stereotypeIcon.setName(parseStringProperty());
|
||||
stereotypeIcon.setHasName(true);
|
||||
|
@@ -287,8 +287,13 @@ void ClassItem::update()
|
||||
|
||||
bool ClassItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||
{
|
||||
if (m_customIcon) {
|
||||
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||
for (int i = 0; i < polygons.size(); ++i)
|
||||
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||
}
|
||||
QPolygonF polygon;
|
||||
// TODO if m_customIcon then use that shape + label's shape as intersection path
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
|
@@ -160,13 +160,14 @@ void ComponentItem::update()
|
||||
|
||||
bool ComponentItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||
{
|
||||
QPolygonF polygon;
|
||||
if (m_customIcon) {
|
||||
// TODO use customIcon path as shape
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
} else if (hasPlainShape()) {
|
||||
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||
for (int i = 0; i < polygons.size(); ++i)
|
||||
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||
}
|
||||
QPolygonF polygon;
|
||||
if (hasPlainShape()) {
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
|
@@ -122,17 +122,17 @@ void DiagramItem::update()
|
||||
|
||||
bool DiagramItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||
{
|
||||
QPolygonF polygon;
|
||||
if (m_customIcon) {
|
||||
// TODO use customIcon path as shape
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
} else {
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||
for (int i = 0; i < polygons.size(); ++i)
|
||||
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||
}
|
||||
QPolygonF polygon;
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
// TODO use real outline
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
|
||||
}
|
||||
|
||||
|
@@ -130,17 +130,16 @@ void ItemItem::update()
|
||||
|
||||
bool ItemItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||
{
|
||||
QPolygonF polygon;
|
||||
if (m_customIcon) {
|
||||
// TODO use customIcon path as shape
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
} else {
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||
for (int i = 0; i < polygons.size(); ++i)
|
||||
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||
}
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
QPolygonF polygon;
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
|
||||
}
|
||||
|
||||
|
@@ -141,21 +141,20 @@ void PackageItem::update()
|
||||
|
||||
bool PackageItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||
{
|
||||
QPolygonF polygon;
|
||||
if (m_customIcon) {
|
||||
// TODO use customIcon path as shape
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
} else {
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
ShapeGeometry shape = calcMinimumGeometry();
|
||||
polygon << rect.topLeft() << (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), 0.0))
|
||||
<< (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), shape.m_minimumTabSize.height()))
|
||||
<< rect.topRight() + QPointF(0.0, shape.m_minimumTabSize.height())
|
||||
<< rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||
for (int i = 0; i < polygons.size(); ++i)
|
||||
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||
}
|
||||
QPolygonF polygon;
|
||||
QRectF rect = object()->rect();
|
||||
rect.translate(object()->pos());
|
||||
ShapeGeometry shape = calcMinimumGeometry();
|
||||
polygon << rect.topLeft() << (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), 0.0))
|
||||
<< (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), shape.m_minimumTabSize.height()))
|
||||
<< rect.topRight() + QPointF(0.0, shape.m_minimumTabSize.height())
|
||||
<< rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
|
||||
}
|
||||
|
||||
|
@@ -33,6 +33,8 @@
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
//#define DEBUG_OUTLINE
|
||||
|
||||
namespace qmt {
|
||||
|
||||
CustomIconItem::CustomIconItem(DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent)
|
||||
@@ -102,9 +104,30 @@ void CustomIconItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *op
|
||||
painter->save();
|
||||
painter->setBrush(m_brush);
|
||||
painter->setPen(m_pen);
|
||||
#ifdef DEBUG_OUTLINE
|
||||
ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
|
||||
IconShape shape = m_stereotypeIcon.outlineShape();
|
||||
if (shape.isEmpty())
|
||||
shape = m_stereotypeIcon.iconShape();
|
||||
shape.visitShapes(&visitor);
|
||||
painter->drawPath(visitor.path());
|
||||
ShapePaintVisitor visitor1(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
|
||||
m_stereotypeIcon.iconShape().visitShapes(&visitor1);
|
||||
#else
|
||||
ShapePaintVisitor visitor(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
|
||||
m_stereotypeIcon.iconShape().visitShapes(&visitor);
|
||||
#endif
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QList<QPolygonF> CustomIconItem::outline() const
|
||||
{
|
||||
ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
|
||||
IconShape shape = m_stereotypeIcon.outlineShape();
|
||||
if (shape.isEmpty())
|
||||
shape = m_stereotypeIcon.iconShape();
|
||||
shape.visitShapes(&visitor);
|
||||
return visitor.toPolygons();
|
||||
}
|
||||
|
||||
} // namespace qmt
|
||||
|
@@ -55,6 +55,8 @@ public:
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
QList<QPolygonF> outline() const;
|
||||
|
||||
private:
|
||||
DiagramSceneModel *m_diagramSceneModel = nullptr;
|
||||
QString m_stereotypeIconId;
|
||||
|
@@ -88,6 +88,49 @@ bool GeometryUtilities::intersect(const QPolygonF &polygon, const QLineF &line,
|
||||
return found;
|
||||
}
|
||||
|
||||
bool GeometryUtilities::intersect(const QList<QPolygonF> &polygons, const QLineF &line,
|
||||
int *intersectionPolygon, QPointF *intersectionPoint,
|
||||
QLineF *intersectionLine, int nearestPoint)
|
||||
{
|
||||
bool found = false;
|
||||
qreal mindist = 0;
|
||||
int ipolygon = -1;
|
||||
QPointF ipoint;
|
||||
QLineF iline;
|
||||
for (int p = 0; p < polygons.size(); ++p) {
|
||||
const QPolygonF polygon = polygons.at(p);
|
||||
for (int i = 0; i <= polygon.size() - 2; ++i) {
|
||||
const QLineF polygonLine(polygon.at(i), polygon.at(i + 1));
|
||||
QPointF point;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
QLineF::IntersectType intersectionType = polygonLine.intersect(line, &point);
|
||||
#else
|
||||
QLineF::IntersectType intersectionType = polygonLine.intersects(line, &point);
|
||||
#endif
|
||||
if (intersectionType == QLineF::BoundedIntersection) {
|
||||
qreal dist = QLineF(point, nearestPoint <= 0 ? line.p1() : line.p2()).length();
|
||||
if (!found || dist < mindist) {
|
||||
mindist = dist;
|
||||
ipolygon = p;
|
||||
ipoint = point;
|
||||
iline = polygonLine;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (intersectionPolygon)
|
||||
*intersectionPolygon = ipolygon;
|
||||
if (intersectionPoint)
|
||||
*intersectionPoint = ipoint;
|
||||
if (intersectionLine)
|
||||
*intersectionLine = iline;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class Candidate
|
||||
|
@@ -54,6 +54,9 @@ public:
|
||||
static bool intersect(const QPolygonF &polygon, const QLineF &line,
|
||||
QPointF *intersectionPoint = nullptr, QLineF *intersectionLine = nullptr,
|
||||
int nearestPoint = 1);
|
||||
static bool intersect(const QList<QPolygonF> &polygons, const QLineF &line,
|
||||
int *intersectionPolygon, QPointF *intersectionPoint = nullptr, QLineF *intersectionLine = nullptr,
|
||||
int nearestPoint = 1);
|
||||
static bool placeRectAtLine(const QRectF &rect, const QLineF &line, double lineOffset,
|
||||
double distance, const QLineF &intersectionLine, QPointF *placement,
|
||||
Side *horizontalAlignedSide);
|
||||
|
@@ -107,6 +107,11 @@ IconShape &IconShape::operator=(const IconShape &rhs)
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IconShape::isEmpty() const
|
||||
{
|
||||
return d->m_shapes.isEmpty();
|
||||
}
|
||||
|
||||
void IconShape::addLine(const ShapePointF &pos1, const ShapePointF &pos2)
|
||||
{
|
||||
d->m_shapes.append(new LineShape(pos1, pos2));
|
||||
|
@@ -46,6 +46,7 @@ public:
|
||||
|
||||
IconShape &operator=(const IconShape &rhs);
|
||||
|
||||
bool isEmpty() const;
|
||||
QSizeF size() const;
|
||||
void setSize(const QSizeF &size);
|
||||
|
||||
|
@@ -261,4 +261,152 @@ void ShapeSizeVisitor::visitPath(const PathShape *shapePath)
|
||||
m_boundingRect |= path.boundingRect();
|
||||
}
|
||||
|
||||
ShapePolygonVisitor::ShapePolygonVisitor(const QPointF &scaledOrigin, const QSizeF &originalSize,
|
||||
const QSizeF &baseSize, const QSizeF &size)
|
||||
: m_scaledOrigin(scaledOrigin),
|
||||
m_originalSize(originalSize),
|
||||
m_baseSize(baseSize),
|
||||
m_size(size)
|
||||
{
|
||||
m_path.setFillRule(Qt::WindingFill);
|
||||
}
|
||||
|
||||
QList<QPolygonF> ShapePolygonVisitor::toPolygons() const
|
||||
{
|
||||
return m_path.toSubpathPolygons();
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitLine(const LineShape *shapeLine)
|
||||
{
|
||||
QPointF p1 = shapeLine->pos1().mapScaledTo(m_scaledOrigin, m_originalSize, m_baseSize, m_size);
|
||||
QPointF p2 = shapeLine->pos2().mapScaledTo(m_scaledOrigin, m_originalSize, m_baseSize, m_size);
|
||||
m_path.moveTo(p1);
|
||||
m_path.lineTo(p2);
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitRect(const RectShape *shapeRect)
|
||||
{
|
||||
m_path.addRect(QRectF(shapeRect->pos().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size),
|
||||
shapeRect->size().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size)));
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitRoundedRect(const RoundedRectShape *shapeRoundedRect)
|
||||
{
|
||||
qreal radiusX = shapeRoundedRect->radius().mapScaledTo(0, m_originalSize.width(),
|
||||
m_baseSize.width(), m_size.width());
|
||||
qreal radiusY = shapeRoundedRect->radius().mapScaledTo(0, m_originalSize.height(),
|
||||
m_baseSize.height(), m_size.height());
|
||||
m_path.addRoundedRect(QRectF(shapeRoundedRect->pos().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size),
|
||||
shapeRoundedRect->size().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size)),
|
||||
radiusX, radiusY);
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitCircle(const CircleShape *shapeCircle)
|
||||
{
|
||||
m_path.addEllipse(shapeCircle->center().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size),
|
||||
shapeCircle->radius().mapScaledTo(m_scaledOrigin.x(), m_originalSize.width(),
|
||||
m_baseSize.width(), m_size.width()),
|
||||
shapeCircle->radius().mapScaledTo(m_scaledOrigin.y(), m_originalSize.height(),
|
||||
m_baseSize.height(), m_size.height()));
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitEllipse(const EllipseShape *shapeEllipse)
|
||||
{
|
||||
QSizeF radius = shapeEllipse->radius().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
m_path.addEllipse(shapeEllipse->center().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size),
|
||||
radius.width(), radius.height());
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitDiamond(const DiamondShape *shapeDiamond)
|
||||
{
|
||||
QPainterPath path;
|
||||
QPointF center = shapeDiamond->center().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
QSizeF size = shapeDiamond->size().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
path.moveTo(center + QPointF(0.0, size.height() / 2.0));
|
||||
path.lineTo(center + QPointF(-size.width() / 2.0, 0.0));
|
||||
path.lineTo(center + QPointF(0.0, -size.height() / 2.0));
|
||||
path.lineTo(center + QPointF(size.width() / 2.0, 0.0));
|
||||
path.closeSubpath();
|
||||
m_path.addPath(path);
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitTriangle(const TriangleShape *shapeTriangle)
|
||||
{
|
||||
QPainterPath path;
|
||||
QPointF center = shapeTriangle->center().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
QSizeF size = shapeTriangle->size().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
path.moveTo(center + QPointF(size.width() / 2.0, size.height() / 2.0));
|
||||
path.lineTo(center + QPointF(-size.width() / 2.0, size.height() / 2.0));
|
||||
path.lineTo(center + QPointF(0.0, -size.height() / 2.0));
|
||||
path.closeSubpath();
|
||||
m_path.addPath(path);
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitArc(const ArcShape *shapeArc)
|
||||
{
|
||||
QSizeF radius = shapeArc->radius().mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
QRectF rect(shapeArc->center().mapScaledTo(m_scaledOrigin, m_originalSize, m_baseSize, m_size)
|
||||
- QPointF(radius.width(), radius.height()), radius * 2.0);
|
||||
m_path.arcMoveTo(rect, shapeArc->startAngle());
|
||||
m_path.arcTo(rect, shapeArc->startAngle(), shapeArc->spanAngle());
|
||||
}
|
||||
|
||||
void ShapePolygonVisitor::visitPath(const PathShape *shapePath)
|
||||
{
|
||||
QPainterPath path;
|
||||
for (const PathShape::Element &element: shapePath->elements()) {
|
||||
switch (element.m_elementType) {
|
||||
case PathShape::TypeNone:
|
||||
// nothing to do
|
||||
break;
|
||||
case PathShape::TypeMoveto:
|
||||
path.moveTo(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size));
|
||||
break;
|
||||
case PathShape::TypeLineto:
|
||||
path.lineTo(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size));
|
||||
break;
|
||||
case PathShape::TypeArcmoveto:
|
||||
{
|
||||
QSizeF radius = element.m_size.mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
path.arcMoveTo(QRectF(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size)
|
||||
- QPointF(radius.width(), radius.height()),
|
||||
radius * 2.0),
|
||||
element.m_angle1);
|
||||
break;
|
||||
}
|
||||
case PathShape::TypeArcto:
|
||||
{
|
||||
QSizeF radius = element.m_size.mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size);
|
||||
path.arcTo(QRectF(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
|
||||
m_baseSize, m_size)
|
||||
- QPointF(radius.width(), radius.height()),
|
||||
radius * 2.0),
|
||||
element.m_angle1, element.m_angle2);
|
||||
break;
|
||||
}
|
||||
case PathShape::TypeClose:
|
||||
path.closeSubpath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_path.addPath(path);
|
||||
}
|
||||
|
||||
} // namespace qmt
|
||||
|
@@ -31,6 +31,8 @@
|
||||
#include <QPainter>
|
||||
#include <QPointF>
|
||||
#include <QSizeF>
|
||||
#include <QPolygonF>
|
||||
#include <QPainterPath>
|
||||
|
||||
namespace qmt {
|
||||
|
||||
@@ -84,4 +86,31 @@ private:
|
||||
QRectF m_boundingRect;
|
||||
};
|
||||
|
||||
class QMT_EXPORT ShapePolygonVisitor : public ShapeConstVisitor
|
||||
{
|
||||
public:
|
||||
ShapePolygonVisitor(const QPointF &scaledOrigin, const QSizeF &originalSize,
|
||||
const QSizeF &baseSize, const QSizeF &size);
|
||||
|
||||
QPainterPath path() const { return m_path; }
|
||||
QList<QPolygonF> toPolygons() const;
|
||||
|
||||
void visitLine(const LineShape *shapeLine) override;
|
||||
void visitRect(const RectShape *shapeRect) override;
|
||||
void visitRoundedRect(const RoundedRectShape *shapeRoundedRect) override;
|
||||
void visitCircle(const CircleShape *shapeCircle) override;
|
||||
void visitEllipse(const EllipseShape *shapeEllipse) override;
|
||||
void visitDiamond(const DiamondShape *shapeDiamond) override;
|
||||
void visitTriangle(const TriangleShape *shapeTriangle) override;
|
||||
void visitArc(const ArcShape *shapeArc) override;
|
||||
void visitPath(const PathShape *shapePath) override;
|
||||
|
||||
private:
|
||||
QPointF m_scaledOrigin;
|
||||
QSizeF m_originalSize;
|
||||
QSizeF m_baseSize;
|
||||
QSizeF m_size;
|
||||
QPainterPath m_path;
|
||||
};
|
||||
|
||||
} // namespace qmt
|
||||
|
@@ -109,4 +109,9 @@ void StereotypeIcon::setIconShape(const IconShape &iconShape)
|
||||
m_iconShape = iconShape;
|
||||
}
|
||||
|
||||
void StereotypeIcon::setOutlineShape(const IconShape &outlineShape)
|
||||
{
|
||||
m_outlineShape = outlineShape;
|
||||
}
|
||||
|
||||
} // namespace qmt
|
||||
|
@@ -100,6 +100,8 @@ public:
|
||||
void setBaseColor(const QColor &baseColor);
|
||||
IconShape iconShape() const { return m_iconShape; }
|
||||
void setIconShape(const IconShape &iconShape);
|
||||
IconShape outlineShape() const { return m_outlineShape; }
|
||||
void setOutlineShape(const IconShape &outlineShape);
|
||||
|
||||
private:
|
||||
QString m_id;
|
||||
@@ -117,6 +119,7 @@ private:
|
||||
TextAlignment m_textAlignment = TextalignBelow;
|
||||
QColor m_baseColor;
|
||||
IconShape m_iconShape;
|
||||
IconShape m_outlineShape;
|
||||
};
|
||||
|
||||
} // namespace qmt
|
||||
|
Reference in New Issue
Block a user