aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/modelinglib
diff options
context:
space:
mode:
authorJochen Becher <jochen_becher@gmx.de>2019-11-16 17:43:31 +0100
committerJochen Becher <jochen_becher@gmx.de>2020-02-25 19:21:48 +0000
commit23946de45755ce58d55004bf3e508a83d6299573 (patch)
treec284eadf8f2df71e309017a1b949e79292e4515d /src/libs/modelinglib
parent7dbf2c01c79e1e7ee78de4df3cb25bc54df21949 (diff)
modeleditor: Intersect relations with shape of item
Change-Id: I40d898715772f74ffa225ac27b91ee7ad4d8fedc Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/libs/modelinglib')
-rw-r--r--src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp5
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp7
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp13
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp18
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp17
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp25
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp23
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h2
-rw-r--r--src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp43
-rw-r--r--src/libs/modelinglib/qmt/infrastructure/geometryutilities.h3
-rw-r--r--src/libs/modelinglib/qmt/stereotype/iconshape.cpp5
-rw-r--r--src/libs/modelinglib/qmt/stereotype/iconshape.h1
-rw-r--r--src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp148
-rw-r--r--src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h29
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp5
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.h3
16 files changed, 309 insertions, 38 deletions
diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
index fe070fc08ae..121fd1ff69d 100644
--- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
+++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
@@ -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);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
index 3e65c36daee..bf891a855b4 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
@@ -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();
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
index 92b94a1b9ad..18e0fc5622e 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
@@ -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();
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
index c3cce6a2972..a8e719b8d8e 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
@@ -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);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
index e3b50bab1b6..3d623d40b5e 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
@@ -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);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
index 8cc4f7ed927..b5526e54239 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
@@ -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);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
index 374f1e786a9..13a8e4cbce4 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
@@ -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
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
index 93e083b9625..ce4ea972604 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
@@ -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;
diff --git a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
index 6f9b34aa0c2..91886cf49ed 100644
--- a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
+++ b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
@@ -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
diff --git a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h
index 2ec1701aa09..6f39352f3f7 100644
--- a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h
+++ b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h
@@ -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);
diff --git a/src/libs/modelinglib/qmt/stereotype/iconshape.cpp b/src/libs/modelinglib/qmt/stereotype/iconshape.cpp
index 172bb369841..fc8e076ac8a 100644
--- a/src/libs/modelinglib/qmt/stereotype/iconshape.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/iconshape.cpp
@@ -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));
diff --git a/src/libs/modelinglib/qmt/stereotype/iconshape.h b/src/libs/modelinglib/qmt/stereotype/iconshape.h
index 215dc8adecf..87880f2c5cf 100644
--- a/src/libs/modelinglib/qmt/stereotype/iconshape.h
+++ b/src/libs/modelinglib/qmt/stereotype/iconshape.h
@@ -46,6 +46,7 @@ public:
IconShape &operator=(const IconShape &rhs);
+ bool isEmpty() const;
QSizeF size() const;
void setSize(const QSizeF &size);
diff --git a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp
index 880835287ad..04c5a0a32c4 100644
--- a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp
@@ -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
diff --git a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h
index 92e340e3e94..8ad4074764e 100644
--- a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h
+++ b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h
@@ -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
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
index d11cace46bc..f9610851f3b 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
@@ -109,4 +109,9 @@ void StereotypeIcon::setIconShape(const IconShape &iconShape)
m_iconShape = iconShape;
}
+void StereotypeIcon::setOutlineShape(const IconShape &outlineShape)
+{
+ m_outlineShape = outlineShape;
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
index 4465734cfdd..ab837bd333d 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
@@ -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