Skip to content

Commit a1e84d5

Browse files
committed
[重构图形项几何缓存系统]:优化形状计算和边界矩形管理
-**几何缓存系统重构**: 将GeometryCache改为同时管理边界矩形和形状路径,支持独立缓存和按需更新 -**优化形状计算性能**: 为所有图形项引入形状路径缓存,避免重复计算,提高交互响应速度 -**统一边界矩形计算**: 使用calculateExpandSize统一计算扩展尺寸,支持margin、penWidth和expandSize参数 -**移除冗余shape函数**: 删除各图形项中自定义的shape()函数,统一使用GeometryCache的形状管理 -**改进路径扩展算法**: 新增expandAndUnitePath工具函数,正确处理带笔触的形状路径 -**增强缓存有效性**: 引入dirty标志机制,确保几何数据变更时缓存能正确更新 -**简化图形项接口**: 统一setAnchorPoints调用方式,支持空边界矩形和形状路径的默认处理
1 parent a744897 commit a1e84d5

16 files changed

Lines changed: 102 additions & 104 deletions

src/graphics/geometrycache.hpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#pragma once
22

3-
#include <QPolygonF>
4-
#include <QScopedPointer>
3+
#include "graphicsutils.hpp"
4+
5+
#include <QPainterPath>
56

67
namespace Graphics {
78

@@ -12,37 +13,62 @@ class GeometryCache
1213
GeometryCache() = default;
1314
~GeometryCache() = default;
1415

15-
void setAnchorPoints(const QPolygonF &pts, const QRectF &boundingRect)
16+
void setAnchorPoints(const QPolygonF &pts) { setAnchorPoints(pts, {}, {}); }
17+
18+
void setAnchorPoints(const QPolygonF &pts, const QRectF &boundingRect, const QPainterPath &shape)
1619
{
1720
m_anchorPoints = pts;
1821
m_boundingRect = boundingRect;
19-
m_changed = true;
22+
m_shape = shape;
23+
m_boundingRectDirty = true;
24+
m_shapeDirty = true;
2025
}
2126

2227
QPolygonF anchorPoints() const { return m_anchorPoints; }
2328

24-
QRectF boundingRect(double margin, double penWidth)
29+
QRectF boundingRect(double margin, double penWidth, double expandSize)
30+
{
31+
auto addLen = calculateExpandSize(margin, penWidth, expandSize);
32+
if (addLen != m_rectAddLen || m_boundingRectDirty) {
33+
m_boundingRectDirty = false;
34+
m_rectAddLen = addLen;
35+
m_cacheBoundingRect = m_boundingRect.adjusted(-addLen, -addLen, addLen, addLen);
36+
}
37+
return m_cacheBoundingRect;
38+
}
39+
40+
QPainterPath shape(double margin, double penWidth, double expandSize)
2541
{
26-
auto addLen = qMax(margin / 2, penWidth);
27-
if (addLen == m_lastAddLen && !m_changed) {
28-
return m_lastBoundingRect;
42+
auto addLen = calculateExpandSize(margin, penWidth, expandSize);
43+
if (addLen != m_shapeAddLen || m_shapeDirty) {
44+
m_shapeDirty = false;
45+
m_shapeAddLen = addLen;
46+
m_cachedShape = m_shape;
47+
m_cachedShape = Utils::expandAndUnitePath(m_cachedShape, addLen);
2948
}
30-
m_changed = false;
31-
m_lastAddLen = addLen;
32-
m_lastBoundingRect = m_boundingRect.adjusted(-addLen, -addLen, addLen, addLen);
33-
return m_lastBoundingRect;
49+
return m_cachedShape;
3450
}
3551

3652
bool isValid() const { return !m_boundingRect.isNull() && !m_anchorPoints.isEmpty(); }
3753
void invalidate() { m_boundingRect = QRectF(); }
3854

3955
private:
56+
double calculateExpandSize(double margin, double penWidth, double expandSize) const
57+
{
58+
return std::max({margin * 0.5, penWidth, expandSize});
59+
}
60+
4061
QPolygonF m_anchorPoints; // 用于交互的锚点
4162
QRectF m_boundingRect; // 边界矩形
63+
QPainterPath m_shape; // 路径
64+
65+
bool m_boundingRectDirty = true; // 矩形是否需要重新计算
66+
double m_rectAddLen = 0; // 矩形扩展长度
67+
QRectF m_cacheBoundingRect; // 缓存矩形
4268

43-
bool m_changed = true;
44-
double m_lastAddLen = 0; // 上一次的addLen
45-
QRectF m_lastBoundingRect; // 上一次的boundingRect
69+
bool m_shapeDirty = true; // 路径是否需要重新计算
70+
double m_shapeAddLen = 0; // 路径扩展长度
71+
QPainterPath m_cachedShape; // 缓存路径
4672
};
4773

4874
using GeometryCachePtr = QScopedPointer<GeometryCache>;

src/graphics/graphicsarcitem.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,7 @@ auto GraphicsArcItem::setArc(const Arc &arc) -> bool
236236

237237
prepareGeometryChange();
238238
d_ptr->arch = arc;
239-
240-
geometryCache()->setAnchorPoints(anchorPoints, Utils::createBoundingRect(pts, 0));
239+
geometryCache()->setAnchorPoints(anchorPoints, Utils::createBoundingRect(pts, 0), d_ptr->shape);
241240

242241
return true;
243242
}
@@ -252,11 +251,6 @@ auto GraphicsArcItem::type() const -> int
252251
return GraphicsBasicItem::Shape::ARC;
253252
}
254253

255-
auto GraphicsArcItem::shape() const -> QPainterPath
256-
{
257-
return isValid() ? d_ptr->shape : GraphicsBasicItem::shape();
258-
}
259-
260254
inline auto lineSetLength(const QPointF p1, const QPointF p2, const double len) -> QPointF
261255
{
262256
QLineF line(p1, p2);
@@ -443,7 +437,7 @@ void GraphicsArcItem::pointsChanged(const QPolygonF &ply)
443437

444438
switch (ply.size()) {
445439
case 1:
446-
case 2: geometryCache()->setAnchorPoints(ply, {}); break;
440+
case 2: geometryCache()->setAnchorPoints(ply); break;
447441
case 3: {
448442
if (!calculateHalfArc(ply, d_ptr->cachePath)) {
449443
return;
@@ -452,7 +446,7 @@ void GraphicsArcItem::pointsChanged(const QPolygonF &ply)
452446
if (!rect.contains(polygon.boundingRect())) {
453447
return;
454448
}
455-
geometryCache()->setAnchorPoints(ply, {});
449+
geometryCache()->setAnchorPoints(ply);
456450
} break;
457451
case 4: {
458452
if (!calculateAllArc(ply, d_ptr->arcPath, d_ptr->shape, margin())) {

src/graphics/graphicsarcitem.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class GRAPHICS_EXPORT GraphicsArcItem : public GraphicsBasicItem
2828
[[nodiscard]] auto arch() const -> Arc;
2929

3030
[[nodiscard]] auto type() const -> int override;
31-
[[nodiscard]] auto shape() const -> QPainterPath override;
3231

3332
protected:
3433
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;

src/graphics/graphicsbasicitem.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class GraphicsBasicItem::GraphicsBasicItemPrivate
3030
QPointF clickedPos;
3131
double margin = 6;
3232
bool showBoundingRect = true;
33-
const double minAddLen = 10;
33+
const double minExpandSize = 10;
3434

3535
GeometryCachePtr geometryCachePtr;
3636
};
@@ -57,10 +57,17 @@ auto GraphicsBasicItem::isValid() const -> bool
5757
auto GraphicsBasicItem::boundingRect() const -> QRectF
5858
{
5959
return d_ptr->geometryCachePtr->isValid()
60-
? d_ptr->geometryCachePtr->boundingRect(margin() + addLen(), pen().width())
60+
? d_ptr->geometryCachePtr->boundingRect(margin(), pen().width(), d_ptr->minExpandSize)
6161
: scene()->sceneRect();
6262
}
6363

64+
auto GraphicsBasicItem::shape() const -> QPainterPath
65+
{
66+
return d_ptr->geometryCachePtr->isValid()
67+
? d_ptr->geometryCachePtr->shape(margin(), pen().width(), d_ptr->minExpandSize)
68+
: QAbstractGraphicsShapeItem::shape();
69+
}
70+
6471
void GraphicsBasicItem::setName(const QString &name)
6572
{
6673
d_ptr->name = name;
@@ -262,9 +269,4 @@ void GraphicsBasicItem::setMyCursor(const QPointF &center, const QPointF &pos)
262269
setCursor(Utils::cursorForDirection(angle - 90));
263270
}
264271

265-
auto GraphicsBasicItem::addLen() const -> int
266-
{
267-
return std::max({d_ptr->margin, pen().widthF(), d_ptr->minAddLen});
268-
}
269-
270272
} // namespace Graphics

src/graphics/graphicsbasicitem.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class GRAPHICS_EXPORT GraphicsBasicItem : public QObject, public QAbstractGraphi
2424
[[nodiscard]] virtual auto isValid() const -> bool;
2525
[[nodiscard]] auto type() const -> int override = 0;
2626
[[nodiscard]] auto boundingRect() const -> QRectF override;
27+
[[nodiscard]] auto shape() const -> QPainterPath override;
2728

2829
void setName(const QString &name);
2930
[[nodiscard]] auto name() const -> QString;
@@ -47,8 +48,6 @@ class GRAPHICS_EXPORT GraphicsBasicItem : public QObject, public QAbstractGraphi
4748
const QStyleOptionGraphicsItem *option,
4849
QWidget *widget = nullptr) override;
4950

50-
[[nodiscard]] auto addLen() const -> int;
51-
5251
void setMyCursor(const QPointF &center, const QPointF &pos);
5352

5453
void setClickedPos(const QPointF &p);

src/graphics/graphicscircleitem.cpp

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ class GraphicsCircleItem::GraphicsCircleItemPrivate
4646

4747
Circle circle;
4848
Circle tempCircle;
49-
QPainterPath shape;
50-
int lastAddLen = 0;
5149
};
5250

5351
GraphicsCircleItem::GraphicsCircleItem(QGraphicsItem *parent)
@@ -76,15 +74,12 @@ auto GraphicsCircleItem::setCircle(const Circle &circle) -> bool
7674
}
7775
rect = circle.boundingRect(0);
7876

79-
prepareGeometryChange();
77+
QPainterPath shape;
78+
shape.addEllipse(rect);
8079

80+
prepareGeometryChange();
8181
d_ptr->circle = circle;
82-
geometryCache()->setAnchorPoints(d_ptr->circle.controlPoints(), rect);
83-
84-
d_ptr->lastAddLen = addLen();
85-
d_ptr->shape.clear();
86-
d_ptr->shape.addEllipse(
87-
rect.adjusted(-d_ptr->lastAddLen, -d_ptr->lastAddLen, d_ptr->lastAddLen, d_ptr->lastAddLen));
82+
geometryCache()->setAnchorPoints(d_ptr->circle.controlPoints(), rect, shape);
8883

8984
return true;
9085
}
@@ -99,20 +94,6 @@ auto GraphicsCircleItem::type() const -> int
9994
return Shape::CIRCLE;
10095
}
10196

102-
auto GraphicsCircleItem::shape() const -> QPainterPath
103-
{
104-
if (isValid()) {
105-
auto add = addLen();
106-
if (d_ptr->lastAddLen != add) {
107-
d_ptr->lastAddLen = add;
108-
d_ptr->shape.clear();
109-
d_ptr->shape.addEllipse(d_ptr->circle.boundingRect(0).adjusted(-add, -add, add, add));
110-
}
111-
return d_ptr->shape;
112-
}
113-
return GraphicsBasicItem::shape();
114-
}
115-
11697
void GraphicsCircleItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
11798
{
11899
if ((event->buttons() & Qt::LeftButton) == 0 || !isValid()) {
@@ -195,7 +176,7 @@ void GraphicsCircleItem::pointsChanged(const QPolygonF &ply)
195176
}
196177

197178
switch (ply.size()) {
198-
case 1: geometryCache()->setAnchorPoints(ply, {}); break;
179+
case 1: geometryCache()->setAnchorPoints(ply); break;
199180
case 2:
200181
if (!setCircle({ply.first(), Utils::distance(ply.first(), ply.last())})) {
201182
return;

src/graphics/graphicscircleitem.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class GRAPHICS_EXPORT GraphicsCircleItem : public GraphicsBasicItem
2525
[[nodiscard]] auto circle() const -> Circle;
2626

2727
[[nodiscard]] auto type() const -> int override;
28-
[[nodiscard]] auto shape() const -> QPainterPath override;
2928

3029
protected:
3130
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;

src/graphics/graphicslineitem.cpp

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ class GraphicsLineItem::GraphicsLineItemPrivate
6565

6666
QLineF line;
6767
QLineF tempLine;
68-
QPainterPath shape;
69-
int lastAddLen = 0;
7068
};
7169

7270
GraphicsLineItem::GraphicsLineItem(QGraphicsItem *parent)
@@ -96,14 +94,12 @@ auto GraphicsLineItem::setLine(const QLineF &line) -> bool
9694
}
9795

9896
prepareGeometryChange();
99-
10097
d_ptr->line = line;
101-
geometryCache()->setAnchorPoints(anchorPoints, Utils::createBoundingRect(anchorPoints, 0));
98+
geometryCache()->setAnchorPoints(anchorPoints,
99+
Utils::createBoundingRect(anchorPoints, 0),
100+
lineShape(d_ptr->line, 6));
102101
emit lineChanged(line);
103102

104-
d_ptr->lastAddLen = addLen(); // 线段的宽度
105-
d_ptr->shape = lineShape(line, d_ptr->lastAddLen);
106-
107103
return true;
108104
}
109105

@@ -112,19 +108,6 @@ auto GraphicsLineItem::line() const -> QLineF
112108
return d_ptr->line;
113109
}
114110

115-
auto GraphicsLineItem::shape() const -> QPainterPath
116-
{
117-
if (isValid()) {
118-
auto add = addLen(); // 线段的宽度
119-
if (add != d_ptr->lastAddLen) {
120-
d_ptr->shape = lineShape(d_ptr->line, add);
121-
d_ptr->lastAddLen = add;
122-
}
123-
return d_ptr->shape;
124-
}
125-
return GraphicsBasicItem::shape();
126-
}
127-
128111
auto GraphicsLineItem::type() const -> int
129112
{
130113
return Shape::LINE;
@@ -175,7 +158,7 @@ void GraphicsLineItem::pointsChanged(const QPolygonF &ply)
175158
}
176159

177160
switch (ply.size()) {
178-
case 1: geometryCache()->setAnchorPoints(ply, {}); break;
161+
case 1: geometryCache()->setAnchorPoints(ply); break;
179162
case 2:
180163
if (!setLine(QLineF(ply[0], ply[1]))) {
181164
return;

src/graphics/graphicslineitem.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class GRAPHICS_EXPORT GraphicsLineItem : public GraphicsBasicItem
1515
[[nodiscard]] auto setLine(const QLineF &line) -> bool;
1616
[[nodiscard]] auto line() const -> QLineF;
1717

18-
[[nodiscard]] auto shape() const -> QPainterPath override;
1918
[[nodiscard]] auto type() const -> int override;
2019

2120
signals:

src/graphics/graphicspolygonitem.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,14 @@ auto GraphicsPolygonItem::setPolygon(const QPolygonF &ply) -> bool
5252
return false;
5353
}
5454

55-
prepareGeometryChange();
55+
QPainterPath originalPath;
56+
originalPath.addPolygon(ply);
57+
QPainterPath simplifiedPath = originalPath.simplified();
58+
simplifiedPath.setFillRule(Qt::WindingFill);
5659

60+
prepareGeometryChange();
5761
d_ptr->polygon = ply;
58-
59-
geometryCache()->setAnchorPoints(ply, Utils::createBoundingRect(ply, 0));
62+
geometryCache()->setAnchorPoints(ply, Utils::createBoundingRect(ply, 0), simplifiedPath);
6063

6164
return true;
6265
}
@@ -124,16 +127,16 @@ void GraphicsPolygonItem::pointsChanged(const QPolygonF &ply)
124127
}
125128

126129
if (ply.size() < 3) {
127-
geometryCache()->setAnchorPoints(ply, {});
130+
geometryCache()->setAnchorPoints(ply);
128131
} else {
129132
if (Utils::distance(ply.first(), ply.last()) < margin()) {
130133
QPolygonF pts_tmp = ply;
131134
pts_tmp.removeLast();
132135
if (!setPolygon(pts_tmp)) {
133-
geometryCache()->setAnchorPoints(ply, {});
136+
geometryCache()->setAnchorPoints(ply);
134137
}
135138
} else {
136-
geometryCache()->setAnchorPoints(ply, {});
139+
geometryCache()->setAnchorPoints(ply);
137140
}
138141
}
139142
update();

0 commit comments

Comments
 (0)