-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshapes.cpp
More file actions
288 lines (234 loc) · 10.6 KB
/
Copy pathshapes.cpp
File metadata and controls
288 lines (234 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#include "shapes.h" // 包含形状类的头文件
#include <cmath> // 包含数学函数库
#include <QPainterPath> // Qt绘图路径类
// 如果系统没有定义M_PI(π的值),则手动定义
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* ========== Shape 基类实现 ========== */
// Shape构造函数
// 参数:start - 起始点坐标;color - 画笔颜色;width - 画笔宽度
Shape::Shape(const QPoint& start, const QColor& color, int width)
: startPoint(start), endPoint(start), penColor(color), penWidth(width) {}
// 获取形状的边界矩形
QRect Shape::boundingRect() const {
// 根据起点和终点创建矩形,并返回规范化后的矩形(确保左上角在左上方)
return QRect(startPoint, endPoint).normalized();
}
// 更新形状的终点坐标
void Shape::update(const QPoint& toPoint) {
endPoint = toPoint; // 将终点更新为指定点
}
/* ========== LineShape 直线实现 ========== */
// LineShape构造函数,调用基类构造函数
LineShape::LineShape(const QPoint& start, const QColor& color, int width)
: Shape(start, color, width) {}
// 绘制直线
void LineShape::draw(QPainter& painter) const {
QPen pen(penColor, penWidth); // 创建指定颜色和宽度的画笔
pen.setCapStyle(Qt::RoundCap); // 设置线帽为圆角
painter.setPen(pen); // 将画笔设置给绘制器
painter.drawLine(startPoint, endPoint); // 绘制从起点到终点的直线
}
// 克隆直线对象
Shape* LineShape::clone() const {
return new LineShape(*this); // 返回当前对象的副本
}
/* ========== RectangleShape 矩形实现 ========== */
// 矩形构造函数
RectangleShape::RectangleShape(const QPoint& start, const QColor& color, int width)
: Shape(start, color, width) {}
// 绘制矩形
void RectangleShape::draw(QPainter& painter) const {
QPen pen(penColor, penWidth); // 创建画笔
pen.setJoinStyle(Qt::RoundJoin); // 设置连接点为圆角
painter.setPen(pen); // 设置画笔
painter.setBrush(QBrush(penColor)); // 设置填充画刷
// 绘制规范化后的矩形(确保宽度和高度为正)
painter.drawRect(QRect(startPoint, endPoint).normalized());
}
// 克隆矩形对象
Shape* RectangleShape::clone() const {
return new RectangleShape(*this);
}
/* ========== EllipseShape 椭圆实现 ========== */
// 椭圆构造函数
EllipseShape::EllipseShape(const QPoint& start, const QColor& color, int width)
: Shape(start, color, width) {}
// 绘制椭圆
void EllipseShape::draw(QPainter& painter) const {
QPen pen(penColor, penWidth); // 创建画笔
painter.setPen(pen); // 设置画笔
painter.setBrush(QBrush(penColor)); // 设置填充画刷
// 在规范化后的矩形内绘制椭圆
painter.drawEllipse(QRect(startPoint, endPoint).normalized());
}
// 克隆椭圆对象
Shape* EllipseShape::clone() const {
return new EllipseShape(*this);
}
/* ========== ArrowShape 箭头实现 ========== */
// 箭头构造函数
ArrowShape::ArrowShape(const QPoint& start, const QColor& color, int width)
: Shape(start, color, width) {}
// 绘制箭头
void ArrowShape::draw(QPainter& painter) const {
QPen pen(penColor, penWidth); // 创建画笔
pen.setCapStyle(Qt::RoundCap); // 设置线帽为圆角
painter.setPen(pen); // 设置画笔
// 1. 绘制主线条(箭头杆)
painter.drawLine(startPoint, endPoint);
// 2. 绘制箭头头部
qreal arrowSize = penWidth * 4; // 箭头大小与线宽成正比
QLineF line(endPoint, startPoint); // 创建从终点到起点的线(用于计算角度)
double angle = std::atan2(-line.dy(), line.dx()); // 计算线的角度(弧度)
// 计算箭头两个分支点的位置
QPointF arrowP1 = endPoint + QPointF(
std::sin(angle + M_PI/3) * arrowSize, // 第一个分支点x坐标
std::cos(angle + M_PI/3) * arrowSize // 第一个分支点y坐标
);
QPointF arrowP2 = endPoint + QPointF(
std::sin(angle + M_PI - M_PI/3) * arrowSize, // 第二个分支点x坐标
std::cos(angle + M_PI - M_PI/3) * arrowSize // 第二个分支点y坐标
);
// 绘制箭头两个分支线
painter.drawLine(endPoint, arrowP1);
painter.drawLine(endPoint, arrowP2);
}
// 克隆箭头对象
Shape* ArrowShape::clone() const {
return new ArrowShape(*this);
}
/* ========== StarShape 五角星实现 ========== */
// 五角星构造函数
StarShape::StarShape(const QPoint& start, const QColor& color, int width)
: Shape(start, color, width) {}
// 绘制五角星
void StarShape::draw(QPainter& painter) const {
QPen pen(penColor, penWidth); // 创建画笔
painter.setPen(pen); // 设置画笔
painter.setBrush(QBrush(penColor)); // 设置填充画刷
QRect rect = QRect(startPoint, endPoint).normalized(); // 获取规范化矩形
qreal radius = qMin(rect.width(), rect.height()) / 2; // 计算外接圆半径(取宽高较小者的一半)
QPoint center = rect.center(); // 获取中心点
QPainterPath path; // 创建绘图路径
// 绘制五角星的五个顶点
for (int i = 0; i < 5; ++i) {
// 计算外顶点角度(均匀分布在圆周上,从12点钟方向开始)
qreal angle = 2 * M_PI * i / 5 - M_PI/2;
// 计算外顶点坐标
QPointF outerPoint = center + QPointF(radius * cos(angle), radius * sin(angle));
if (i == 0) {
path.moveTo(outerPoint); // 第一个点移动画笔
} else {
path.lineTo(outerPoint); // 其他点画线连接
}
// 计算内顶点角度(在外顶点之间)
angle += M_PI / 5;
// 计算内顶点坐标(半径为外半径的一半)
QPointF innerPoint = center + QPointF(radius/2 * cos(angle), radius/2 * sin(angle));
path.lineTo(innerPoint); // 画线到内顶点
}
path.closeSubpath(); // 闭合路径
painter.drawPath(path); // 绘制完整路径
}
// 克隆五角星对象
Shape* StarShape::clone() const {
return new StarShape(*this);
}
/* ========== DiamondShape 菱形实现 ========== */
// 菱形构造函数
DiamondShape::DiamondShape(const QPoint& start, const QColor& color, int width)
: Shape(start, color, width) {}
// 绘制菱形
void DiamondShape::draw(QPainter& painter) const {
QPen pen(penColor, penWidth); // 创建画笔
painter.setPen(pen); // 设置画笔
painter.setBrush(QBrush(penColor)); // 设置填充画刷
QRect rect = QRect(startPoint, endPoint).normalized(); // 获取规范化矩形
QPolygon diamond; // 创建多边形
// 添加菱形的四个顶点(上、右、下、左)
diamond << QPoint(rect.center().x(), rect.top()) // 上顶点
<< QPoint(rect.right(), rect.center().y()) // 右顶点
<< QPoint(rect.center().x(), rect.bottom()) // 下顶点
<< QPoint(rect.left(), rect.center().y()); // 左顶点
painter.drawPolygon(diamond); // 绘制菱形多边形
}
// 克隆菱形对象
Shape* DiamondShape::clone() const {
return new DiamondShape(*this);
}
/* ========== HeartShape 心形实现 ========== */
// 心形构造函数
HeartShape::HeartShape(const QPoint& start, const QColor& color, int width)
: Shape(start, color, width) {}
// 绘制心形
void HeartShape::draw(QPainter& painter) const {
QRect rect = QRect(startPoint, endPoint).normalized(); // 获取规范化矩形
qreal scale = qMin(rect.width(), rect.height()) / 100; // 计算缩放比例(基于100像素基准)
QPoint center = rect.center(); // 获取中心点
QPainterPath path; // 创建绘图路径
// 从心形底部开始
path.moveTo(center.x(), center.y() + 25*scale);
// 绘制右侧贝塞尔曲线
path.cubicTo(center.x() + 45*scale, center.y() - 55*scale, // 控制点1
center.x() + 95*scale, center.y() - 35*scale, // 控制点2
center.x(), center.y() + 45*scale); // 终点
// 绘制左侧贝塞尔曲线
path.cubicTo(center.x() - 95*scale, center.y() - 35*scale, // 控制点1
center.x() - 45*scale, center.y() - 55*scale, // 控制点2
center.x(), center.y() + 25*scale); // 终点
painter.fillPath(path, penColor); // 填充心形路径
}
// 克隆心形对象
Shape* HeartShape::clone() const {
return new HeartShape(*this);
}
/* ========== PathShape 路径实现(用于自由绘制和橡皮擦) ========== */
// 路径构造函数
// 参数:isEraser - 是否为橡皮擦模式
PathShape::PathShape(const QPoint& start, const QColor& color, int width, bool isEraser)
: Shape(start, color, width), eraser(isEraser) {}
// 绘制路径
void PathShape::draw(QPainter& painter) const {
if (points.empty()) return; // 如果没有点则直接返回
// 设置画笔:橡皮擦模式使用白色,否则使用指定颜色
QPen pen(eraser ? Qt::white : penColor, penWidth);
pen.setCapStyle(Qt::RoundCap); // 设置圆角线帽
painter.setPen(pen); // 设置画笔
// 连接所有点形成路径
for (int i = 1; i < points.size(); ++i) {
painter.drawLine(points[i-1], points[i]);
}
}
// 更新路径,添加新点
void PathShape::update(const QPoint& toPoint) {
points.append(toPoint); // 将新点添加到路径中
endPoint = toPoint; // 更新终点
}
// 获取路径的边界矩形
QRect PathShape::boundingRect() const {
if (points.empty()) return QRect(); // 如果没有点则返回空矩形
// 初始化最小/最大坐标
int minX = points[0].x();
int minY = points[0].y();
int maxX = minX;
int maxY = minY;
// 遍历所有点找到边界
for (const QPoint& p : points) {
if (p.x() < minX) minX = p.x();
if (p.y() < minY) minY = p.y();
if (p.x() > maxX) maxX = p.x();
if (p.y() > maxY) maxY = p.y();
}
// 返回包含所有点的矩形,并考虑线宽向外扩展
return QRect(QPoint(minX, minY), QPoint(maxX, maxY))
.adjusted(-penWidth, -penWidth, penWidth, penWidth);
}
// 克隆路径对象
Shape* PathShape::clone() const {
PathShape* clone = new PathShape(startPoint, penColor, penWidth, eraser);
clone->points = points; // 复制所有点
clone->endPoint = endPoint; // 复制终点
return clone;
}