25
25
**
26
26
**********************************************************************/
27
27
28
+ #include < cmath>
28
29
#include < QAction>
29
30
#include < QMouseEvent>
30
31
#include " rs_actiondimangular.h"
34
35
#include " rs_graphicview.h"
35
36
#include " rs_commandevent.h"
36
37
#include " rs_information.h"
37
- #include " rs_line.h"
38
38
#include " rs_coordinateevent.h"
39
39
#include " rs_preview.h"
40
40
#include " rs_debug.h"
41
+ #include " rs_math.h"
41
42
42
43
RS_ActionDimAngular::RS_ActionDimAngular (RS_EntityContainer& container,
43
44
RS_GraphicView& graphicView) :
44
- RS_ActionDimension(" Draw Angular Dimensions" , container, graphicView),
45
- center( new RS_Vector{})
45
+ RS_ActionDimension( " Draw Angular Dimensions" , container, graphicView)
46
46
{
47
- actionType= RS2::ActionDimAngular;
48
47
reset ();
49
48
}
50
49
@@ -54,24 +53,22 @@ void RS_ActionDimAngular::reset()
54
53
{
55
54
RS_ActionDimension::reset ();
56
55
57
- edata.reset ( new RS_DimAngularData ( RS_Vector (false ),
58
- RS_Vector (false ),
59
- RS_Vector (false ),
60
- RS_Vector (false )) );
61
- line1 = nullptr ;
62
- line2 = nullptr ;
63
- *center = {}; // default to invalid vector
56
+ actionType = RS2::ActionDimAngular;
57
+ edata.reset ( new RS_DimAngularData ( RS_Vector ( false ),
58
+ RS_Vector ( false ),
59
+ RS_Vector ( false ),
60
+ RS_Vector ( false )) );
64
61
RS_DIALOGFACTORY->requestOptions ( this , true , true );
65
62
}
66
63
67
64
void RS_ActionDimAngular::trigger ()
68
65
{
69
66
RS_PreviewActionInterface::trigger ();
70
67
71
- if (line1 && line2) {
72
- RS_DimAngular* newEntity {new RS_DimAngular (container,
73
- *data,
74
- *edata)};
68
+ if (line1. getStartpoint (). valid && line2. getStartpoint (). valid ) {
69
+ RS_DimAngular* newEntity {new RS_DimAngular ( container,
70
+ *data,
71
+ *edata)};
75
72
76
73
newEntity->setLayerToActive ();
77
74
newEntity->setPenToActive ();
@@ -98,14 +95,12 @@ void RS_ActionDimAngular::trigger()
98
95
99
96
void RS_ActionDimAngular::mouseMoveEvent (QMouseEvent* e)
100
97
{
101
- RS_DEBUG->print (" RS_ActionDimAngular::mouseMoveEvent begin" );
98
+ RS_DEBUG->print ( " RS_ActionDimAngular::mouseMoveEvent begin" );
102
99
103
100
switch (getStatus ()) {
104
101
case SetPos:
105
- if (line1 && line2 && center->valid ) {
106
- edata->definitionPoint4 = snapPoint (e);
107
-
108
- RS_DimAngular* d {new RS_DimAngular (preview.get (), *data, *edata)};
102
+ if ( setData ( snapPoint (e))) {
103
+ RS_DimAngular *d {new RS_DimAngular ( preview.get (), *data, *edata)};
109
104
110
105
deletePreview ();
111
106
preview->addEntity (d);
@@ -126,44 +121,22 @@ void RS_ActionDimAngular::mouseReleaseEvent(QMouseEvent* e)
126
121
if (Qt::LeftButton == e->button ()) {
127
122
switch (getStatus ()) {
128
123
case SetLine1: {
129
- RS_Entity* en {catchEntity ( e, RS2::ResolveAll)};
124
+ RS_Entity * en {catchEntity ( e, RS2::ResolveAll)};
130
125
if (en && RS2::EntityLine == en->rtti ()) {
131
- line1 = dynamic_cast <RS_Line*>(en);
132
- setStatus ( SetLine2);
126
+ line1 = *dynamic_cast <RS_Line*>(en);
127
+ click1 = line1.getNearestPointOnEntity ( graphicView->toGraph ( e->x (), e->y ()));
128
+ setStatus (SetLine2);
133
129
}
134
130
break ; }
135
131
136
132
case SetLine2: {
137
- RS_Entity* en {catchEntity ( e, RS2::ResolveAll)};
138
- if (en && RS2::EntityLine == en->rtti ()) {
139
- line2 = dynamic_cast <RS_Line*>(en);
140
-
141
- RS_VectorSolutions sol {RS_Information::getIntersectionLineLine ( line1, line2)};
142
-
143
- if (sol.get ( 0 ).valid ) {
144
- *center = sol.get ( 0 );
145
-
146
- if (center->distanceTo (line1->getStartpoint ())
147
- < center->distanceTo (line1->getEndpoint ())) {
148
- edata->definitionPoint1 = line1->getStartpoint ();
149
- edata->definitionPoint2 = line1->getEndpoint ();
150
- }
151
- else {
152
- edata->definitionPoint1 = line1->getEndpoint ();
153
- edata->definitionPoint2 = line1->getStartpoint ();
154
- }
155
-
156
- if (center->distanceTo (line2->getStartpoint ())
157
- < center->distanceTo (line2->getEndpoint ())) {
158
- edata->definitionPoint3 = line2->getStartpoint ();
159
- data->definitionPoint = line2->getEndpoint ();
160
- }
161
- else {
162
- edata->definitionPoint3 = line2->getEndpoint ();
163
- data->definitionPoint = line2->getStartpoint ();
164
- }
165
- graphicView->moveRelativeZero ( *center);
166
- setStatus ( SetPos);
133
+ RS_Entity *en{catchEntity (e, RS2::ResolveAll)};
134
+ if (en && en->rtti ()==RS2::EntityLine) {
135
+ line2 = *dynamic_cast <RS_Line*>(en);
136
+ click2 = line2.getNearestPointOnEntity ( graphicView->toGraph ( e->x (), e->y ()));
137
+ if ( setData ( click2, true )) {
138
+ graphicView->moveRelativeZero ( center);
139
+ setStatus (SetPos);
167
140
}
168
141
}
169
142
break ; }
@@ -182,16 +155,17 @@ void RS_ActionDimAngular::mouseReleaseEvent(QMouseEvent* e)
182
155
183
156
void RS_ActionDimAngular::coordinateEvent (RS_CoordinateEvent* e)
184
157
{
185
- if (! e) {
158
+ if ( ! e) {
186
159
return ;
187
160
}
188
161
189
162
switch (getStatus ()) {
190
163
case SetPos:
191
- edata->definitionPoint4 = e->getCoordinate ();
192
- trigger ();
193
- reset ();
194
- setStatus ( SetLine1);
164
+ if ( setData ( e->getCoordinate ())) {
165
+ trigger ();
166
+ reset ();
167
+ setStatus ( SetLine1);
168
+ }
195
169
break ;
196
170
197
171
default :
@@ -286,4 +260,172 @@ void RS_ActionDimAngular::updateMouseButtonHints()
286
260
}
287
261
}
288
262
263
+ /* *
264
+ * Justify one of the angle lines to ensure that the starting point
265
+ * of the line has the same angle from the intersection point as the
266
+ * selection click point and it is further away than the line end point
267
+ *
268
+ * @param line A selected line for the dimension
269
+ * @param click The click pos which selected the line
270
+ * @param center The intersection of the 2 lines to dimension
271
+ */
272
+ void RS_ActionDimAngular::justify (RS_Line &line, const RS_Vector &click)
273
+ {
274
+ RS_Vector vStartPoint ( line.getStartpoint ());
275
+
276
+ if ( ! RS_Math::equal ( vStartPoint.angleTo (center), click.angleTo ( center))
277
+ || vStartPoint.distanceTo ( center) < click.distanceTo ( center)) {
278
+ line.reverse ();
279
+ }
280
+ }
281
+
282
+ /* *
283
+ * Create a sorted array with angles from the lines intersection point
284
+ * to the starting points and their revers angles.
285
+ * Ensure, that line1 and line2 are in CCW order.
286
+ * Compute an offset for quadrant() methode.
287
+ *
288
+ * @param line A selected line for the dimension
289
+ * @param click The click pos which selected the line
290
+ * @param center The intersection of the 2 lines to dimension
291
+ */
292
+ void RS_ActionDimAngular::lineOrder (const RS_Vector &dimPos)
293
+ {
294
+ if ( ! center.valid ) {
295
+ return ;
296
+ }
297
+
298
+ // starting point angles and selection point angle from intersection point
299
+ double a0 {(dimPos - center).angle ()};
300
+ double a1 {(line1.getStartpoint () - center).angle ()};
301
+ double a2 {(line2.getStartpoint () - center).angle ()};
302
+
303
+ // swap lines if necessary to ensure CCW order
304
+ if ( RS_Math::correctAngle2 ( a1 - a0) > RS_Math::correctAngle2 ( a2 - a0)) {
305
+ RS_Line swapLines ( line1);
306
+ line1 = line2;
307
+ line2 = swapLines;
308
+ double swapAngle {a1};
309
+ a1 = a2;
310
+ a2 = swapAngle;
311
+ }
312
+
313
+ // sorted array with starting point and reverse angles
314
+ angles.clear ();
315
+ angles.push_back ( a1);
316
+ angles.push_back ( RS_Math::correctAngle ( a1 + M_PI));
317
+ angles.push_back ( a2);
318
+ angles.push_back ( RS_Math::correctAngle ( a2 + M_PI));
319
+ std::sort ( angles.begin (), angles.end ());
320
+
321
+ // find starting quadrant and compute the offset for quadrant() method
322
+ int startQuadrant = 0 ;
323
+ for ( auto angle : angles) {
324
+ if ( RS_Math::equal ( a1, angle)) {
325
+ break ;
326
+ }
327
+ ++startQuadrant;
328
+ }
329
+ quadrantOffset = 0x03 & (4 - startQuadrant);
330
+ }
331
+
332
+ /* *
333
+ * Find the quadrant of \p angle relative to 1st quadrant.
334
+ * When the angle lines are selected, the starting quadrant
335
+ * is shifted to become 0 by \p quadrantOffset.
336
+ * This is the criterion how the angles dimension is drawn.
337
+ *
338
+ * @param angle The angle, e.g. mouse or coordinate position
339
+ * @return The quadrant of \p angle, relative to the 1st selection quadrant
340
+ */
341
+ int RS_ActionDimAngular::quadrant (const double angle)
342
+ {
343
+ if ( 1 > angles.size ()) {
344
+ return 0 ;
345
+ }
346
+
347
+ double a1 {RS_Math::correctAngle2 ( angles.at (0 ) - angle)};
348
+ double a2 {RS_Math::correctAngle2 ( angles.at (1 ) - angle)};
349
+
350
+ int angleQuadrant {0 };
351
+ if ( 0.0 < a1 && 0.0 < a2) {
352
+ angleQuadrant = 3 ;
353
+ }
354
+ else if ( 0.0 >= a1 && 0.0 >= a2) {
355
+ angleQuadrant = 1 ;
356
+ }
357
+ else if ( 0.0 < a1 && 0.0 >= a2) {
358
+ angleQuadrant = 2 ;
359
+ }
360
+
361
+ return (0x03 & (angleQuadrant + quadrantOffset));
362
+ }
363
+
364
+ /* *
365
+ * On \p mouseMoveEvent, \p mouseReleaseEvent and \p coordinateEvent
366
+ * this methode sets the dimension data appropriate to the mouse
367
+ * cursor/coordinate in \p dimPos.
368
+ * When \p calcCenter is true, the intersection point and other static
369
+ * values are computed. This is only necessary, when line selection changes,
370
+ * e.g. on \p mouseReleaseEvent. For \p mouseMoveEvent calcCenter is false.
371
+ *
372
+ * @param dimPos The mouse/coordinate position
373
+ * @param calcCenter If true, the center and corresponding values are calculated
374
+ * @return true If the dimension data were set, false is a parameter is invalid
375
+ */
376
+ bool RS_ActionDimAngular::setData (const RS_Vector &dimPos, const bool calcCenter /* = false*/ )
377
+ {
378
+ if ( ! line1.getStartpoint ().valid || ! line2.getStartpoint ().valid ) {
379
+ return false ;
380
+ }
381
+
382
+ if ( ! center.valid || calcCenter) {
383
+ RS_VectorSolutions sol = RS_Information::getIntersectionLineLine ( &line1, &line2);
384
+ center = sol.get (0 );
385
+ }
386
+ if ( ! center.valid ) {
387
+ return false ;
388
+ }
389
+
390
+ if ( calcCenter) {
391
+ justify ( line1, click1);
392
+ justify ( line2, click2);
393
+ lineOrder ( dimPos);
394
+ }
395
+
396
+ edata->definitionPoint4 = dimPos;
397
+ switch ( quadrant ( (dimPos - center).angle ())) {
398
+ default :
399
+ case 0 :
400
+ edata->definitionPoint1 = line1.getEndpoint ();
401
+ edata->definitionPoint2 = line1.getStartpoint ();
402
+ edata->definitionPoint3 = line2.getEndpoint ();
403
+ data->definitionPoint = line2.getStartpoint ();
404
+ break ;
405
+
406
+ case 1 :
407
+ edata->definitionPoint1 = line2.getEndpoint ();
408
+ edata->definitionPoint2 = line2.getStartpoint ();
409
+ edata->definitionPoint3 = line1.getStartpoint ();
410
+ data->definitionPoint = line1.getEndpoint ();
411
+ break ;
412
+
413
+ case 2 :
414
+ edata->definitionPoint1 = line2.getEndpoint ();
415
+ edata->definitionPoint2 = line2.getStartpoint ();
416
+ edata->definitionPoint3 = line1.getEndpoint ();
417
+ data->definitionPoint = line1.getStartpoint ();
418
+ break ;
419
+
420
+ case 3 :
421
+ edata->definitionPoint1 = line2.getStartpoint ();
422
+ edata->definitionPoint2 = line2.getEndpoint ();
423
+ edata->definitionPoint3 = line1.getEndpoint ();
424
+ data->definitionPoint = line1.getStartpoint ();
425
+ break ;
426
+ }
427
+
428
+ return true ;
429
+ }
430
+
289
431
// EOF
0 commit comments