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> }
|
// ArcTo { x: <center_x>; y: <center_y>; radiusX: <radius_x>; radiusY: <radius_y>; start: <start_angle>; span: <span_angle> }
|
||||||
// Close
|
// 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: 0.0; x1: 0.0; y1: 20.0 }
|
||||||
Line { x0: 0.0; y0: 10.0; x1: 4.0; y1: 10.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 {
|
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: -2.0 }
|
||||||
Line { x0: 10.0; y0: 0.0; x1: 14.0; y1: 4.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 {
|
Icon {
|
||||||
@@ -190,6 +201,10 @@ Icon {
|
|||||||
Circle { x: 10.0; y: 10.0; radius: 10.0 }
|
Circle { x: 10.0; y: 10.0; radius: 10.0 }
|
||||||
Line { x0: 0.0; y0: 20.0; x1: 20.0; y1: 20.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 {
|
Association {
|
||||||
@@ -313,6 +328,10 @@ Icon {
|
|||||||
Line { x0: 10; y0: 25; x1: 3; y1: 40 }
|
Line { x0: 10; y0: 25; x1: 3; y1: 40 }
|
||||||
Line { x0: 10; y0: 25; x1: 17; 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 {
|
Relation {
|
||||||
@@ -522,6 +541,9 @@ Icon {
|
|||||||
Line { x0: 0; y0: 0; x1: 10; y1: 10 }
|
Line { x0: 0; y0: 0; x1: 10; y1: 10 }
|
||||||
Line { x0: 0; y0: 10; x1: 10; y1: 0 }
|
Line { x0: 0; y0: 10; x1: 10; y1: 0 }
|
||||||
}
|
}
|
||||||
|
Outline {
|
||||||
|
Circle { x: 5; y: 5; radius: 2 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Icon {
|
Icon {
|
||||||
|
@@ -55,6 +55,7 @@ static const int KEYWORD_DISPLAY = 11;
|
|||||||
static const int KEYWORD_TEXTALIGN = 12;
|
static const int KEYWORD_TEXTALIGN = 12;
|
||||||
static const int KEYWORD_BASECOLOR = 13;
|
static const int KEYWORD_BASECOLOR = 13;
|
||||||
static const int KEYWORD_SHAPE = 14;
|
static const int KEYWORD_SHAPE = 14;
|
||||||
|
static const int KEYWORD_OUTLINE = 15;
|
||||||
|
|
||||||
// Shape items
|
// Shape items
|
||||||
static const int KEYWORD_CIRCLE = 30;
|
static const int KEYWORD_CIRCLE = 30;
|
||||||
@@ -245,6 +246,7 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
|
|||||||
<< qMakePair(QString("textalignment"), KEYWORD_TEXTALIGN)
|
<< qMakePair(QString("textalignment"), KEYWORD_TEXTALIGN)
|
||||||
<< qMakePair(QString("basecolor"), KEYWORD_BASECOLOR)
|
<< qMakePair(QString("basecolor"), KEYWORD_BASECOLOR)
|
||||||
<< qMakePair(QString("shape"), KEYWORD_SHAPE)
|
<< qMakePair(QString("shape"), KEYWORD_SHAPE)
|
||||||
|
<< qMakePair(QString("outline"), KEYWORD_OUTLINE)
|
||||||
<< qMakePair(QString("circle"), KEYWORD_CIRCLE)
|
<< qMakePair(QString("circle"), KEYWORD_CIRCLE)
|
||||||
<< qMakePair(QString("ellipse"), KEYWORD_ELLIPSE)
|
<< qMakePair(QString("ellipse"), KEYWORD_ELLIPSE)
|
||||||
<< qMakePair(QString("line"), KEYWORD_LINE)
|
<< qMakePair(QString("line"), KEYWORD_LINE)
|
||||||
@@ -436,6 +438,9 @@ void StereotypeDefinitionParser::parseIcon()
|
|||||||
case KEYWORD_SHAPE:
|
case KEYWORD_SHAPE:
|
||||||
stereotypeIcon.setIconShape(parseIconShape());
|
stereotypeIcon.setIconShape(parseIconShape());
|
||||||
break;
|
break;
|
||||||
|
case KEYWORD_OUTLINE:
|
||||||
|
stereotypeIcon.setOutlineShape(parseIconShape());
|
||||||
|
break;
|
||||||
case KEYWORD_NAME:
|
case KEYWORD_NAME:
|
||||||
stereotypeIcon.setName(parseStringProperty());
|
stereotypeIcon.setName(parseStringProperty());
|
||||||
stereotypeIcon.setHasName(true);
|
stereotypeIcon.setHasName(true);
|
||||||
|
@@ -287,8 +287,13 @@ void ClassItem::update()
|
|||||||
|
|
||||||
bool ClassItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
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;
|
QPolygonF polygon;
|
||||||
// TODO if m_customIcon then use that shape + label's shape as intersection path
|
|
||||||
QRectF rect = object()->rect();
|
QRectF rect = object()->rect();
|
||||||
rect.translate(object()->pos());
|
rect.translate(object()->pos());
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
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
|
bool ComponentItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||||
{
|
{
|
||||||
QPolygonF polygon;
|
|
||||||
if (m_customIcon) {
|
if (m_customIcon) {
|
||||||
// TODO use customIcon path as shape
|
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||||
QRectF rect = object()->rect();
|
for (int i = 0; i < polygons.size(); ++i)
|
||||||
rect.translate(object()->pos());
|
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||||
} else if (hasPlainShape()) {
|
}
|
||||||
|
QPolygonF polygon;
|
||||||
|
if (hasPlainShape()) {
|
||||||
QRectF rect = object()->rect();
|
QRectF rect = object()->rect();
|
||||||
rect.translate(object()->pos());
|
rect.translate(object()->pos());
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
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
|
bool DiagramItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||||
{
|
{
|
||||||
QPolygonF polygon;
|
|
||||||
if (m_customIcon) {
|
if (m_customIcon) {
|
||||||
// TODO use customIcon path as shape
|
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||||
QRectF rect = object()->rect();
|
for (int i = 0; i < polygons.size(); ++i)
|
||||||
rect.translate(object()->pos());
|
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||||
} else {
|
|
||||||
QRectF rect = object()->rect();
|
|
||||||
rect.translate(object()->pos());
|
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
|
||||||
}
|
}
|
||||||
|
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);
|
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
|
bool ItemItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||||
{
|
{
|
||||||
QPolygonF polygon;
|
|
||||||
if (m_customIcon) {
|
if (m_customIcon) {
|
||||||
// TODO use customIcon path as shape
|
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||||
QRectF rect = object()->rect();
|
for (int i = 0; i < polygons.size(); ++i)
|
||||||
rect.translate(object()->pos());
|
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||||
} else {
|
|
||||||
QRectF rect = object()->rect();
|
|
||||||
rect.translate(object()->pos());
|
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
|
||||||
}
|
}
|
||||||
|
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);
|
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -141,13 +141,13 @@ void PackageItem::update()
|
|||||||
|
|
||||||
bool PackageItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
bool PackageItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
|
||||||
{
|
{
|
||||||
QPolygonF polygon;
|
|
||||||
if (m_customIcon) {
|
if (m_customIcon) {
|
||||||
// TODO use customIcon path as shape
|
QList<QPolygonF> polygons = m_customIcon->outline();
|
||||||
QRectF rect = object()->rect();
|
for (int i = 0; i < polygons.size(); ++i)
|
||||||
rect.translate(object()->pos());
|
polygons[i].translate(object()->pos() + object()->rect().topLeft());
|
||||||
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
|
||||||
} else {
|
}
|
||||||
|
QPolygonF polygon;
|
||||||
QRectF rect = object()->rect();
|
QRectF rect = object()->rect();
|
||||||
rect.translate(object()->pos());
|
rect.translate(object()->pos());
|
||||||
ShapeGeometry shape = calcMinimumGeometry();
|
ShapeGeometry shape = calcMinimumGeometry();
|
||||||
@@ -155,7 +155,6 @@ bool PackageItem::intersectShapeWithLine(const QLineF &line, QPointF *intersecti
|
|||||||
<< (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), shape.m_minimumTabSize.height()))
|
<< (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), shape.m_minimumTabSize.height()))
|
||||||
<< rect.topRight() + QPointF(0.0, shape.m_minimumTabSize.height())
|
<< rect.topRight() + QPointF(0.0, shape.m_minimumTabSize.height())
|
||||||
<< rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
<< rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
|
||||||
}
|
|
||||||
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
|
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
|
//#define DEBUG_OUTLINE
|
||||||
|
|
||||||
namespace qmt {
|
namespace qmt {
|
||||||
|
|
||||||
CustomIconItem::CustomIconItem(DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent)
|
CustomIconItem::CustomIconItem(DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent)
|
||||||
@@ -102,9 +104,30 @@ void CustomIconItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *op
|
|||||||
painter->save();
|
painter->save();
|
||||||
painter->setBrush(m_brush);
|
painter->setBrush(m_brush);
|
||||||
painter->setPen(m_pen);
|
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);
|
ShapePaintVisitor visitor(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
|
||||||
m_stereotypeIcon.iconShape().visitShapes(&visitor);
|
m_stereotypeIcon.iconShape().visitShapes(&visitor);
|
||||||
|
#endif
|
||||||
painter->restore();
|
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
|
} // namespace qmt
|
||||||
|
@@ -55,6 +55,8 @@ public:
|
|||||||
QRectF boundingRect() const override;
|
QRectF boundingRect() const override;
|
||||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
|
|
||||||
|
QList<QPolygonF> outline() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DiagramSceneModel *m_diagramSceneModel = nullptr;
|
DiagramSceneModel *m_diagramSceneModel = nullptr;
|
||||||
QString m_stereotypeIconId;
|
QString m_stereotypeIconId;
|
||||||
|
@@ -88,6 +88,49 @@ bool GeometryUtilities::intersect(const QPolygonF &polygon, const QLineF &line,
|
|||||||
return found;
|
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 {
|
namespace {
|
||||||
|
|
||||||
class Candidate
|
class Candidate
|
||||||
|
@@ -54,6 +54,9 @@ public:
|
|||||||
static bool intersect(const QPolygonF &polygon, const QLineF &line,
|
static bool intersect(const QPolygonF &polygon, const QLineF &line,
|
||||||
QPointF *intersectionPoint = nullptr, QLineF *intersectionLine = nullptr,
|
QPointF *intersectionPoint = nullptr, QLineF *intersectionLine = nullptr,
|
||||||
int nearestPoint = 1);
|
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,
|
static bool placeRectAtLine(const QRectF &rect, const QLineF &line, double lineOffset,
|
||||||
double distance, const QLineF &intersectionLine, QPointF *placement,
|
double distance, const QLineF &intersectionLine, QPointF *placement,
|
||||||
Side *horizontalAlignedSide);
|
Side *horizontalAlignedSide);
|
||||||
|
@@ -107,6 +107,11 @@ IconShape &IconShape::operator=(const IconShape &rhs)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IconShape::isEmpty() const
|
||||||
|
{
|
||||||
|
return d->m_shapes.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
void IconShape::addLine(const ShapePointF &pos1, const ShapePointF &pos2)
|
void IconShape::addLine(const ShapePointF &pos1, const ShapePointF &pos2)
|
||||||
{
|
{
|
||||||
d->m_shapes.append(new LineShape(pos1, pos2));
|
d->m_shapes.append(new LineShape(pos1, pos2));
|
||||||
|
@@ -46,6 +46,7 @@ public:
|
|||||||
|
|
||||||
IconShape &operator=(const IconShape &rhs);
|
IconShape &operator=(const IconShape &rhs);
|
||||||
|
|
||||||
|
bool isEmpty() const;
|
||||||
QSizeF size() const;
|
QSizeF size() const;
|
||||||
void setSize(const QSizeF &size);
|
void setSize(const QSizeF &size);
|
||||||
|
|
||||||
|
@@ -261,4 +261,152 @@ void ShapeSizeVisitor::visitPath(const PathShape *shapePath)
|
|||||||
m_boundingRect |= path.boundingRect();
|
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
|
} // namespace qmt
|
||||||
|
@@ -31,6 +31,8 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
#include <QSizeF>
|
#include <QSizeF>
|
||||||
|
#include <QPolygonF>
|
||||||
|
#include <QPainterPath>
|
||||||
|
|
||||||
namespace qmt {
|
namespace qmt {
|
||||||
|
|
||||||
@@ -84,4 +86,31 @@ private:
|
|||||||
QRectF m_boundingRect;
|
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
|
} // namespace qmt
|
||||||
|
@@ -109,4 +109,9 @@ void StereotypeIcon::setIconShape(const IconShape &iconShape)
|
|||||||
m_iconShape = iconShape;
|
m_iconShape = iconShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StereotypeIcon::setOutlineShape(const IconShape &outlineShape)
|
||||||
|
{
|
||||||
|
m_outlineShape = outlineShape;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace qmt
|
} // namespace qmt
|
||||||
|
@@ -100,6 +100,8 @@ public:
|
|||||||
void setBaseColor(const QColor &baseColor);
|
void setBaseColor(const QColor &baseColor);
|
||||||
IconShape iconShape() const { return m_iconShape; }
|
IconShape iconShape() const { return m_iconShape; }
|
||||||
void setIconShape(const IconShape &iconShape);
|
void setIconShape(const IconShape &iconShape);
|
||||||
|
IconShape outlineShape() const { return m_outlineShape; }
|
||||||
|
void setOutlineShape(const IconShape &outlineShape);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_id;
|
QString m_id;
|
||||||
@@ -117,6 +119,7 @@ private:
|
|||||||
TextAlignment m_textAlignment = TextalignBelow;
|
TextAlignment m_textAlignment = TextalignBelow;
|
||||||
QColor m_baseColor;
|
QColor m_baseColor;
|
||||||
IconShape m_iconShape;
|
IconShape m_iconShape;
|
||||||
|
IconShape m_outlineShape;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace qmt
|
} // namespace qmt
|
||||||
|
Reference in New Issue
Block a user