@@ -77,6 +77,14 @@ auto Arc::controlPoints() const -> QPolygonF
7777class GraphicsArcItem ::GraphicsArcItemPrivate
7878{
7979public:
80+ enum class MouseEdgeRegion : int {
81+ NoSelection,
82+ InnerEdge,
83+ OuterEdge,
84+ StartAngleSide,
85+ EndAngleSide
86+ };
87+
8088 explicit GraphicsArcItemPrivate (GraphicsArcItem *q)
8189 : q_ptr(q)
8290 {}
@@ -86,7 +94,7 @@ class GraphicsArcItem::GraphicsArcItemPrivate
8694 Arc arch;
8795 QPainterPath arcPath;
8896 QPainterPath cachePath;
89- GraphicsArcItem::MouseRegion mouseRegion = GraphicsArcItem::None ;
97+ MouseEdgeRegion mouseRegion = MouseEdgeRegion::NoSelection ;
9098};
9199
92100GraphicsArcItem::GraphicsArcItem (QGraphicsItem *parent)
@@ -136,11 +144,6 @@ auto GraphicsArcItem::arch() const -> Arc
136144 return d_ptr->arch ;
137145}
138146
139- auto GraphicsArcItem::type () const -> int
140- {
141- return GraphicsBasicItem::Shape::ARC;
142- }
143-
144147inline auto lineSetLength (const QPointF p1, const QPointF p2, const double len) -> QPointF
145148{
146149 QLineF line (p1, p2);
@@ -150,41 +153,41 @@ inline auto lineSetLength(const QPointF p1, const QPointF p2, const double len)
150153
151154void GraphicsArcItem::mouseMoveEvent (QGraphicsSceneMouseEvent *event)
152155{
153- if (!isValid ()) {
156+ if ((event-> buttons () & Qt::LeftButton) == 0 || !isValid ()) {
154157 return ;
155158 }
156159 if (!isSelected ()) {
157160 setSelected (true );
158161 }
162+ auto scenePos = event->scenePos ();
163+ auto dp = scenePos - clickedPos ();
164+ setClickedPos (scenePos);
159165
160- QPointF point = event->scenePos ();
161- QPointF dp = point - clickedPos ();
162- setClickedPos (event->scenePos ());
163- auto pts_tmp = geometryCache ()->controlPoints ();
164- double distance = Utils::distance (d_ptr->arch .center , point);
166+ auto controlPoints = geometryCache ()->controlPoints ();
167+ double distance = Utils::distance (d_ptr->arch .center , scenePos);
165168
166169 switch (mouseRegion ()) {
167- case GraphicsBasicItem::MouseRegion::All: pts_tmp .translate (dp); break ;
168- case GraphicsBasicItem::MouseRegion::None : {
170+ case GraphicsBasicItem::MouseRegion::EntireShape: controlPoints .translate (dp); break ;
171+ case GraphicsBasicItem::MouseRegion::EdgeArea : {
169172 switch (d_ptr->mouseRegion ) {
170- case InEdge0 :
171- setMyCursor (d_ptr->arch .center , event-> scenePos () );
173+ case GraphicsArcItemPrivate::MouseEdgeRegion::InnerEdge :
174+ setMyCursor (d_ptr->arch .center , scenePos);
172175 for (int i = 0 ; i < 3 ; ++i) {
173- pts_tmp [i] = lineSetLength (d_ptr->arch .center , pts_tmp [i], distance);
176+ controlPoints [i] = lineSetLength (d_ptr->arch .center , controlPoints [i], distance);
174177 }
175178 break ;
176- case InEdge1 :
177- setMyCursor (d_ptr->arch .center , event-> scenePos () );
178- pts_tmp [3 ] = lineSetLength (d_ptr->arch .center , pts_tmp [3 ], distance);
179+ case GraphicsArcItemPrivate::MouseEdgeRegion::OuterEdge :
180+ setMyCursor (d_ptr->arch .center , scenePos);
181+ controlPoints [3 ] = lineSetLength (d_ptr->arch .center , controlPoints [3 ], distance);
179182 break ;
180- case InEdgeH :
181- case InEdgeL : {
183+ case GraphicsArcItemPrivate::MouseEdgeRegion::EndAngleSide :
184+ case GraphicsArcItemPrivate::MouseEdgeRegion::StartAngleSide : {
182185 Arc arch = d_ptr->arch ;
183- if (d_ptr->mouseRegion == InEdgeL ) {
184- arch.startAngle = QLineF (arch.center , event-> scenePos () ).angle ();
186+ if (d_ptr->mouseRegion == GraphicsArcItemPrivate::MouseEdgeRegion::StartAngleSide ) {
187+ arch.startAngle = QLineF (arch.center , scenePos).angle ();
185188 setCursor (Utils::cursorForDirection (arch.startAngle ));
186189 } else {
187- arch.endAngle = QLineF (arch.center , event-> scenePos () ).angle ();
190+ arch.endAngle = QLineF (arch.center , scenePos).angle ();
188191 setCursor (Utils::cursorForDirection (arch.endAngle ));
189192 }
190193 while (arch.startAngle > arch.endAngle ) {
@@ -193,63 +196,17 @@ void GraphicsArcItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
193196 if (arch.endAngle - arch.startAngle > 360 ) {
194197 arch.endAngle -= 360 ;
195198 }
196- pts_tmp = arch.controlPoints ();
199+ controlPoints = arch.controlPoints ();
197200 } break ;
198201 default : return ;
199202 }
200203 break ;
201204 }
202- case GraphicsBasicItem::MouseRegion::DotRegion: pts_tmp [hoveredDotIndex ()] += dp; break ;
205+ case GraphicsBasicItem::MouseRegion::AnchorPoint: controlPoints [hoveredDotIndex ()] += dp; break ;
203206 default : return ;
204207 }
205208
206- pointsChanged (pts_tmp);
207- }
208-
209- void GraphicsArcItem::hoverMoveEvent (QGraphicsSceneHoverEvent *event)
210- {
211- auto pts_tmp = geometryCache ()->controlPoints ();
212- QPointF point = event->scenePos ();
213- if (pts_tmp.size () == 2 || pts_tmp.size () == 3 ) {
214- pts_tmp.append (point);
215- showHoverArc (pts_tmp);
216- }
217- if (!isValid ()) {
218- return ;
219- }
220- GraphicsBasicItem::hoverMoveEvent (event);
221- if (mouseRegion () == GraphicsBasicItem::MouseRegion::DotRegion) {
222- return ;
223- }
224- setMouseRegion (GraphicsBasicItem::MouseRegion::None);
225-
226- QPointF p1 = Utils::pointFromCenter (d_ptr->arch .center ,
227- d_ptr->arch .maxRadius ,
228- d_ptr->arch .startAngle );
229- QPointF p2 = Utils::pointFromCenter (d_ptr->arch .center ,
230- d_ptr->arch .maxRadius ,
231- d_ptr->arch .endAngle );
232- QLineF line1 (p1, pts_tmp.at (0 ));
233- QLineF line2 (p2, pts_tmp.at (1 ));
234- if (qAbs (Utils::distance (point, d_ptr->arch .center ) - d_ptr->arch .minRadius ) < margin () / 3 ) {
235- d_ptr->mouseRegion = InEdge0;
236- setMyCursor (d_ptr->arch .center , point);
237- } else if (qAbs (Utils::distance (point, d_ptr->arch .center ) - d_ptr->arch .maxRadius )
238- < margin () / 3 ) {
239- d_ptr->mouseRegion = InEdge1;
240- setMyCursor (d_ptr->arch .center , point);
241- } else if (Utils::boundingFromLine (line1, margin () / 4 ).containsPoint (point, Qt::OddEvenFill)) {
242- d_ptr->mouseRegion = InEdgeL;
243- setCursor (Utils::cursorForDirection (line1.angle ()));
244- } else if (Utils::boundingFromLine (line2, margin () / 4 ).containsPoint (point, Qt::OddEvenFill)) {
245- d_ptr->mouseRegion = InEdgeH;
246- setCursor (Utils::cursorForDirection (line2.angle ()));
247- } else if (d_ptr->arcPath .contains (point)) {
248- setMouseRegion (GraphicsBasicItem::MouseRegion::All);
249- setCursor (Qt::SizeAllCursor);
250- } else {
251- unsetCursor ();
252- }
209+ pointsChanged (controlPoints);
253210}
254211
255212void GraphicsArcItem::drawContent (QPainter *painter)
@@ -259,18 +216,15 @@ void GraphicsArcItem::drawContent(QPainter *painter)
259216
260217void GraphicsArcItem::pointsChanged (const QPolygonF &ply)
261218{
262- auto rect = scene ()->sceneRect ();
263- if (!rect.contains (ply.last ())) {
264- return ;
265- }
266-
267219 if (ply.size () == 3 ) {
268220 double deltaAngle = QLineF (ply[0 ], ply[1 ]).angleTo (QLineF (ply[0 ], ply[2 ]));
269221 if (deltaAngle < 0.00001 || deltaAngle > 355.99999 ) {
270222 return ;
271223 }
272224 }
273225
226+ auto sceneRect = scene ()->sceneRect ();
227+
274228 switch (ply.size ()) {
275229 case 1 :
276230 case 2 : geometryCache ()->setControlPoints (ply); break ;
@@ -279,7 +233,7 @@ void GraphicsArcItem::pointsChanged(const QPolygonF &ply)
279233 return ;
280234 }
281235 QPolygonF polygon = d_ptr->cachePath .toFillPolygon () + ply;
282- if (!rect .contains (polygon.boundingRect ())) {
236+ if (!sceneRect .contains (polygon.boundingRect ())) {
283237 return ;
284238 }
285239 geometryCache ()->setControlPoints (ply);
@@ -295,21 +249,83 @@ void GraphicsArcItem::pointsChanged(const QPolygonF &ply)
295249 update ();
296250}
297251
298- void GraphicsArcItem::showHoverArc (const QPolygonF &ply )
252+ void GraphicsArcItem::updateHoverPreview (const QPointF &scenePos )
299253{
300- switch (ply.size ()) {
254+ auto controlPoints = geometryCache ()->controlPoints ();
255+ auto size = controlPoints.size ();
256+ if (size < 2 || size > 3 ) {
257+ return ;
258+ }
259+
260+ controlPoints.append (scenePos);
261+ size = controlPoints.size ();
262+
263+ switch (size) {
301264 case 3 :
302265 // QPainterPath::arcTo: Adding point with invalid coordinates, ignoring call
303- if (Utils::distance (ply [1 ], ply [2 ]) < margin ()) {
266+ if (Utils::distance (controlPoints [1 ], controlPoints [2 ]) < margin ()) {
304267 return ;
305268 }
306- Utils::calculateHalfArc (ply , d_ptr->cachePath );
269+ Utils::calculateHalfArc (controlPoints , d_ptr->cachePath );
307270 break ;
308- case 4 : Utils::calculateAllArc (ply , d_ptr->cachePath , margin ()); break ;
271+ case 4 : Utils::calculateAllArc (controlPoints , d_ptr->cachePath , margin ()); break ;
309272 default : return ;
310273 }
311274
312275 update ();
313276}
314277
278+ GraphicsBasicItem::MouseRegion GraphicsArcItem::detectEdgeRegion (const QPointF &scenePos)
279+ {
280+ const double edgeMargin = margin () / 2.0 ;
281+ const Arc &arc = d_ptr->arch ;
282+
283+ // 计算点到圆心的距离
284+ const double distanceToCenter = Utils::distance (scenePos, arc.center );
285+
286+ // 分别检查内外圆弧边缘 - 更清晰的逻辑
287+ if (qAbs (distanceToCenter - arc.minRadius ) < edgeMargin) {
288+ d_ptr->mouseRegion = GraphicsArcItemPrivate::MouseEdgeRegion::InnerEdge;
289+ setMyCursor (arc.center , scenePos);
290+ setMouseRegion (GraphicsBasicItem::MouseRegion::EdgeArea);
291+ return GraphicsBasicItem::MouseRegion::EdgeArea;
292+ }
293+
294+ if (qAbs (distanceToCenter - arc.maxRadius ) < edgeMargin) {
295+ d_ptr->mouseRegion = GraphicsArcItemPrivate::MouseEdgeRegion::OuterEdge;
296+ setMyCursor (arc.center , scenePos);
297+ setMouseRegion (GraphicsBasicItem::MouseRegion::EdgeArea);
298+ return GraphicsBasicItem::MouseRegion::EdgeArea;
299+ }
300+
301+ // 计算侧边端点
302+ const QPointF innerStart = Utils::pointFromCenter (arc.center , arc.minRadius , arc.startAngle );
303+ const QPointF outerStart = Utils::pointFromCenter (arc.center , arc.maxRadius , arc.startAngle );
304+
305+ // 分别检查两个侧边
306+ const QLineF startEdge (innerStart, outerStart);
307+ if (Utils::isPointNearEdge (scenePos, startEdge, edgeMargin)) {
308+ d_ptr->mouseRegion = GraphicsArcItemPrivate::MouseEdgeRegion::StartAngleSide;
309+ setCursor (Utils::cursorForDirection (startEdge.angle ()));
310+ setMouseRegion (GraphicsBasicItem::MouseRegion::EdgeArea);
311+ return GraphicsBasicItem::MouseRegion::EdgeArea;
312+ }
313+
314+ const QPointF innerEnd = Utils::pointFromCenter (arc.center , arc.minRadius , arc.endAngle );
315+ const QPointF outerEnd = Utils::pointFromCenter (arc.center , arc.maxRadius , arc.endAngle );
316+
317+ const QLineF endEdge (innerEnd, outerEnd);
318+ if (Utils::isPointNearEdge (scenePos, endEdge, edgeMargin)) {
319+ d_ptr->mouseRegion = GraphicsArcItemPrivate::MouseEdgeRegion::EndAngleSide;
320+ setCursor (Utils::cursorForDirection (endEdge.angle ()));
321+ setMouseRegion (GraphicsBasicItem::MouseRegion::EdgeArea);
322+ return GraphicsBasicItem::MouseRegion::EdgeArea;
323+ }
324+
325+ // 不在任何区域
326+ d_ptr->mouseRegion = GraphicsArcItemPrivate::MouseEdgeRegion::NoSelection;
327+ setMouseRegion (GraphicsBasicItem::MouseRegion::NoSelection);
328+ return GraphicsBasicItem::MouseRegion::NoSelection;
329+ }
330+
315331} // namespace Graphics
0 commit comments