]> Shamusworld >> Repos - architektonas/blob - src/base/rs_snapper.cpp
Fixed preview rendering for ActionDrawLine...
[architektonas] / src / base / rs_snapper.cpp
1 // rs_snapper.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  05/21/2010  Added this text. :-)
13 //
14
15 #include "rs_snapper.h"
16
17 #include "rs_dialogfactory.h"
18 #include "drawing.h"
19 #include "rs_entitycontainer.h"
20 #include "graphicview.h"
21 #include "rs_grid.h"
22 #include "rs_information.h"
23 #include "paintintf.h"
24 #include "settings.h"
25
26 /**
27  * Constructor.
28  */
29 RS_Snapper::RS_Snapper(RS_EntityContainer & c, GraphicView & gv):
30         container(&c), graphicView(&gv), finished(false)
31 {
32         init();
33 }
34
35 RS_Snapper::RS_Snapper(void):
36         container(NULL), graphicView(NULL), finished(false)
37 {
38         init();
39 }
40
41 /**
42  * Destructor.
43  */
44 RS_Snapper::~RS_Snapper()
45 {
46 }
47
48 /**
49  * Initialize (called by all constructors)
50  */
51 void RS_Snapper::init()
52 {
53         if (graphicView)
54         {
55                 snapMode = graphicView->getDefaultSnapMode();
56                 snapRes = graphicView->getSnapRestriction();
57         }
58
59         keyEntity = NULL;
60         snapSpot = Vector(false);
61         snapCoord = Vector(false);
62         visible = false;
63         distance = 1.0;
64
65         settings.beginGroup("Snap");
66         snapRange = settings.value("Range", 20).toInt();
67         settings.endGroup();
68         settings.beginGroup("Appearance");
69         showCrosshairs = settings.value("ShowCrosshairs", true).toBool();
70         settings.endGroup();
71
72         // Sanity check
73         if (snapRange < 2)
74                 snapRange = 20;
75 }
76
77 void RS_Snapper::finish()
78 {
79         finished = true;
80 }
81
82 //bleh
83 void RS_Snapper::SetContainer(RS_EntityContainer * c)
84 {
85         container = c;
86 }
87
88 //bleh
89 void RS_Snapper::SetGraphicView(GraphicView * v)
90 {
91         graphicView = v;
92 }
93
94 /**
95  * @return Pointer to the entity which was the key entity for the
96  * last successful snapping action. If the snap mode is "end point"
97  * the key entity is the entity whos end point was caught.
98  * If the snap mode didn't require an entity (e.g. free, grid) this
99  * method will return NULL.
100  */
101 RS_Entity * RS_Snapper::getKeyEntity()
102 {
103         return keyEntity;
104 }
105
106 /** Sets a new snap mode. */
107 void RS_Snapper::setSnapMode(RS2::SnapMode snapMode)
108 {
109         this->snapMode = snapMode;
110 }
111
112 /** Sets a new snap restriction. */
113 void RS_Snapper::setSnapRestriction(RS2::SnapRestriction snapRes)
114 {
115         this->snapRes = snapRes;
116 }
117
118 /**
119 * Sets the snap range in pixels for catchEntity().
120 *
121 * @see catchEntity()
122 */
123 void RS_Snapper::setSnapRange(int r)
124 {
125         snapRange = r;
126 }
127
128 /**
129  * Snap to a coordinate in the drawing using the current snap mode.
130  *
131  * @param e A mouse event.
132  * @return The coordinates of the point or an invalid vector.
133  */
134 Vector RS_Snapper::snapPoint(QMouseEvent * e)
135 {
136         RS_DEBUG->print("RS_Snapper::snapPoint");
137         snapSpot = Vector(false);
138
139         if (!e)
140         {
141                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is NULL");
142                 return snapSpot;
143         }
144
145         Vector mouseCoord = graphicView->toGraph(e->x(), e->y());
146
147         switch (snapMode)
148         {
149         case RS2::SnapFree:
150                 snapSpot = snapFree(mouseCoord);
151                 break;
152
153         case RS2::SnapEndpoint:
154                 snapSpot = snapEndpoint(mouseCoord);
155                 break;
156
157         case RS2::SnapGrid:
158                 snapSpot = snapGrid(mouseCoord);
159                 break;
160
161         case RS2::SnapOnEntity:
162                 snapSpot = snapOnEntity(mouseCoord);
163                 break;
164
165         case RS2::SnapCenter:
166                 snapSpot = snapCenter(mouseCoord);
167                 break;
168
169         case RS2::SnapMiddle:
170                 snapSpot = snapMiddle(mouseCoord);
171                 break;
172
173         case RS2::SnapDist:
174                 snapSpot = snapDist(mouseCoord);
175                 break;
176
177         case RS2::SnapIntersection:
178                 snapSpot = snapIntersection(mouseCoord);
179                 break;
180
181         default:
182                 break;
183         }
184
185         // Handle snap restrictions that can be activated in addition to the ones above:
186         switch (snapRes)
187         {
188         case RS2::RestrictOrthogonal:
189                 snapCoord = restrictOrthogonal(snapSpot);
190                 break;
191         case RS2::RestrictHorizontal:
192                 snapCoord = restrictHorizontal(snapSpot);
193                 break;
194         case RS2::RestrictVertical:
195                 snapCoord = restrictVertical(snapSpot);
196                 break;
197         default:
198         case RS2::RestrictNothing:
199                 snapCoord = snapSpot;
200                 break;
201         }
202
203         if (RS_DIALOGFACTORY)
204                 RS_DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero());
205
206         RS_DEBUG->print("RS_Snapper::snapPoint: OK");
207
208         return snapCoord;
209 }
210
211 /**
212  * Snaps to a free coordinate.
213  *
214  * @param coord The mouse coordinate.
215  * @return The coordinates of the point or an invalid vector.
216  */
217 Vector RS_Snapper::snapFree(Vector coord)
218 {
219         keyEntity = NULL;
220         return coord;
221 }
222
223 /**
224  * Snaps to the closest endpoint.
225  *
226  * @param coord The mouse coordinate.
227  * @return The coordinates of the point or an invalid vector.
228  */
229 Vector RS_Snapper::snapEndpoint(Vector coord)
230 {
231         Vector vec(false);
232         vec = container->getNearestEndpoint(coord, NULL/*, &keyEntity*/);
233
234         return vec;
235 }
236
237 /**
238  * Snaps to a grid point.
239  *
240  * @param coord The mouse coordinate.
241  * @return The coordinates of the point or an invalid vector.
242  */
243 Vector RS_Snapper::snapGrid(Vector coord)
244 {
245         RS_DEBUG->print("RS_Snapper::snapGrid begin");
246
247         Vector vec(false);
248         double dist = 0.0;
249
250         RS_Grid * grid = graphicView->getGrid();
251
252         RS_DEBUG->print("RS_Snapper::snapGrid 001");
253
254         if (grid)
255         {
256                 RS_DEBUG->print("RS_Snapper::snapGrid 002");
257                 Vector * pts = grid->getPoints();
258                 RS_DEBUG->print("RS_Snapper::snapGrid 003");
259                 int closest = -1;
260                 dist = 32000.00;
261                 RS_DEBUG->print("RS_Snapper::snapGrid 004");
262
263                 for(int i=0; i<grid->count(); ++i)
264                 {
265                         double d = pts[i].distanceTo(coord);
266
267                         if (d < dist)
268                         {
269                                 closest = i;
270                                 dist = d;
271                         }
272                 }
273
274                 RS_DEBUG->print("RS_Snapper::snapGrid 005");
275
276                 if (closest >= 0)
277                         vec = pts[closest];
278
279                 RS_DEBUG->print("RS_Snapper::snapGrid 006");
280         }
281
282         keyEntity = NULL;
283
284         RS_DEBUG->print("RS_Snapper::snapGrid end");
285
286         return vec;
287 }
288
289 /**
290  * Snaps to a point on an entity.
291  *
292  * @param coord The mouse coordinate.
293  * @return The coordinates of the point or an invalid vector.
294  */
295 Vector RS_Snapper::snapOnEntity(Vector coord)
296 {
297         Vector vec(false);
298         vec = container->getNearestPointOnEntity(coord, true, NULL, &keyEntity);
299
300         return vec;
301 }
302
303 /**
304  * Snaps to the closest center.
305  *
306  * @param coord The mouse coordinate.
307  * @return The coordinates of the point or an invalid vector.
308  */
309 Vector RS_Snapper::snapCenter(Vector coord)
310 {
311         Vector vec(false);
312         vec = container->getNearestCenter(coord, NULL);
313
314         return vec;
315 }
316
317 /**
318  * Snaps to the closest middle.
319  *
320  * @param coord The mouse coordinate.
321  * @return The coordinates of the point or an invalid vector.
322  */
323 Vector RS_Snapper::snapMiddle(Vector coord)
324 {
325         Vector vec(false);
326         vec = container->getNearestMiddle(coord, NULL);
327
328         return vec;
329 }
330
331 /**
332  * Snaps to the closest point with a given distance to the endpoint.
333  *
334  * @param coord The mouse coordinate.
335  * @return The coordinates of the point or an invalid vector.
336  */
337 Vector RS_Snapper::snapDist(Vector coord)
338 {
339         Vector vec(false);
340         vec = container->getNearestDist(distance, coord, NULL);
341
342         return vec;
343 }
344
345 /**
346  * Snaps to the closest intersection point.
347  *
348  * @param coord The mouse coordinate.
349  * @return The coordinates of the point or an invalid vector.
350  */
351 Vector RS_Snapper::snapIntersection(Vector coord)
352 {
353         Vector vec(false);
354         vec = container->getNearestIntersection(coord, NULL);
355
356         return vec;
357 }
358
359 /**
360  * 'Corrects' the given coordinates to 0, 90, 180, 270 degrees relative to
361  * the current relative zero point.
362  *
363  * @param coord The uncorrected coordinates.
364  * @return The corrected coordinates.
365  */
366 Vector RS_Snapper::restrictOrthogonal(Vector coord)
367 {
368         Vector rz = graphicView->getRelativeZero();
369         Vector ret(coord);
370
371         Vector retx = Vector(rz.x, ret.y);
372         Vector rety = Vector(ret.x, rz.y);
373
374         if (retx.distanceTo(ret) > rety.distanceTo(ret))
375                 ret = rety;
376         else
377                 ret = retx;
378
379         return ret;
380 }
381
382 /**
383  * 'Corrects' the given coordinates to 0, 180 degrees relative to
384  * the current relative zero point.
385  *
386  * @param coord The uncorrected coordinates.
387  * @return The corrected coordinates.
388  */
389 Vector RS_Snapper::restrictHorizontal(Vector coord)
390 {
391         Vector rz = graphicView->getRelativeZero();
392
393         return Vector(coord.x, rz.y);
394 }
395
396 /**
397  * 'Corrects' the given coordinates to 90, 270 degrees relative to
398  * the current relative zero point.
399  *
400  * @param coord The uncorrected coordinates.
401  * @return The corrected coordinates.
402  */
403 Vector RS_Snapper::restrictVertical(Vector coord)
404 {
405         Vector rz = graphicView->getRelativeZero();
406
407         return Vector(rz.x, coord.y);
408 }
409
410 /**
411  * Catches an entity which is close to the given position 'pos'.
412  *
413  * @param pos A graphic coordinate.
414  * @param level The level of resolving for iterating through the entity
415  *        container
416  * @return Pointer to the entity or NULL.
417  */
418 RS_Entity * RS_Snapper::catchEntity(const Vector& pos, RS2::ResolveLevel level)
419 {
420         RS_DEBUG->print("RS_Snapper::catchEntity");
421
422         // set default distance for points inside solids
423         double dist = graphicView->toGraphDX(snapRange) * 0.9;
424
425         RS_Entity * entity = container->getNearestEntity(pos, &dist, level);
426
427         int idx = -1;
428
429         if (entity && entity->getParent())
430                 idx = entity->getParent()->findEntity(entity);
431
432         if (entity && dist <= graphicView->toGraphDX(snapRange))
433         {
434                 // highlight:
435                 RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
436                 return entity;
437         }
438         else
439         {
440                 RS_DEBUG->print("RS_Snapper::catchEntity: not found");
441                 return NULL;
442         }
443
444         RS_DEBUG->print("RS_Snapper::catchEntity: OK");
445 }
446
447 /**
448  * Catches an entity which is close to the mouse cursor.
449  *
450  * @param e A mouse event.
451  * @param level The level of resolving for iterating through the entity
452  *        container
453  * @return Pointer to the entity or NULL.
454  */
455 RS_Entity * RS_Snapper::catchEntity(QMouseEvent * e, RS2::ResolveLevel level)
456 {
457     return catchEntity(Vector(graphicView->toGraphX(e->x()),
458                 graphicView->toGraphY(e->y())), level);
459 }
460
461 /**
462  * Suspends this snapper while another action takes place.
463  */
464 /*virtual*/ void RS_Snapper::suspend()
465 {
466         deleteSnapper();
467         snapSpot = snapCoord = Vector(false);
468 }
469
470 /**
471  * Resumes this snapper after it has been suspended.
472  */
473 /*virtual*/ void RS_Snapper::resume()
474 {
475         drawSnapper();
476 }
477
478 /**
479  * Hides the snapper options.
480  */
481 /*virtual*/ void RS_Snapper::hideOptions()
482 {
483         if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
484                 RS_DIALOGFACTORY->requestSnapDistOptions(distance, false);
485 }
486
487 /**
488  * Shows the snapper options.
489  */
490 /*virtual*/ void RS_Snapper::showOptions()
491 {
492         if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
493                 RS_DIALOGFACTORY->requestSnapDistOptions(distance, true);
494 }
495
496 /**
497  * Draws the snapper on the screen.
498  */
499 void RS_Snapper::drawSnapper()
500 {
501 printf("RS_Snapper::drawSnapper(): Using DEPRECATED function!!!\n");
502         if (!visible)
503                 xorSnapper();
504 }
505
506 /**
507  * Deletes the snapper from the screen.
508  */
509 void RS_Snapper::deleteSnapper()
510 {
511 printf("RS_Snapper::deleteSnapper(): Using DEPRECATED function!!!\n");
512         if (visible)
513         {
514                 xorSnapper();
515                 snapSpot = Vector(false);
516                 snapCoord = Vector(false);
517         }
518 }
519
520 /**
521  * Draws / deletes the current snapper spot.
522  */
523 void RS_Snapper::xorSnapper()
524 {
525 #warning "!!! RS_Snapper::xorSnapper() is DEPRECATED !!!"
526 //Not completely true...
527 //#warning "!!! xorSnapper() not working AT ALL !!!"
528 #if 0
529         if (!finished && snapSpot.valid)
530         {
531                 RS_Painter * painter = graphicView->createDirectPainter();
532                 painter->setPreviewMode();
533
534                 if (snapCoord.valid)
535                 {
536                         // snap point
537                         painter->drawCircle(graphicView->toGui(snapCoord), 4);
538
539                         // crosshairs:
540                         if (showCrosshairs == true)
541                         {
542                                 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
543                                 painter->drawLine(Vector(0, graphicView->toGuiY(snapCoord.y)),
544                                         Vector(graphicView->getWidth(), graphicView->toGuiY(snapCoord.y)));
545                                 painter->drawLine(Vector(graphicView->toGuiX(snapCoord.x), 0),
546                                         Vector(graphicView->toGuiX(snapCoord.x), graphicView->getHeight()));
547                         }
548                 }
549
550                 if (snapCoord.valid && snapCoord != snapSpot)
551                 {
552                         painter->drawLine(graphicView->toGui(snapSpot) + Vector(-5, 0),
553                                 graphicView->toGui(snapSpot) + Vector(-1, 4));
554                         painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, 5),
555                                 graphicView->toGui(snapSpot) + Vector(4, 1));
556                         painter->drawLine(graphicView->toGui(snapSpot) + Vector(5, 0),
557                                 graphicView->toGui(snapSpot) + Vector(1, -4));
558                         painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, -5),
559                                 graphicView->toGui(snapSpot) + Vector(-4, -1));
560                 }
561
562                 graphicView->destroyPainter();
563                 visible = !visible;
564         }
565 //#else
566         if (finished || !snapSpot.valid || !graphicView)
567                 return;
568
569         graphicView->SetSnapperDraw(true);
570         graphicView->SetSnapperVars(snapSpot, snapCoord, showCrosshairs);
571 //Apparently, this gets hit anyway by the preview code...
572 //      graphicView->redraw();
573
574         visible = !visible;
575 #endif
576 }
577
578 void RS_Snapper::SetVisible(bool visibility/*= true*/)
579 {
580         visible = visibility;
581 }
582
583 bool RS_Snapper::Visible(void)
584 {
585         return visible;
586 }
587
588 void RS_Snapper::Draw(GraphicView * view, PaintInterface * painter)
589 {
590         if (finished || !snapSpot.valid)
591                 return;
592
593 //hm, I don't like graphicView kicking around in here, especially since it now
594 //lives inside GraphicView... How to !!! FIX !!!?
595 //We'll pass it in for now...
596         if (snapCoord.valid)
597         {
598                 // snap point
599                 painter->setPen(RS_Pen(RS_Color(0, 127, 255), RS2::Width00, RS2::DashLine));
600                 painter->drawCircle(view->toGui(snapCoord), 4);
601
602                 // crosshairs
603                 if (showCrosshairs)
604                 {
605                         painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
606                         painter->drawLine(Vector(0, view->toGuiY(snapCoord.y)),
607                                 Vector(view->getWidth(), view->toGuiY(snapCoord.y)));
608                         painter->drawLine(Vector(view->toGuiX(snapCoord.x), 0),
609                                 Vector(view->toGuiX(snapCoord.x), view->getHeight()));
610                 }
611         }
612
613         if (snapCoord.valid && snapCoord != snapSpot)
614         {
615                 painter->drawLine(view->toGui(snapSpot) + Vector(-5, 0),
616                         view->toGui(snapSpot) + Vector(-1, 4));
617                 painter->drawLine(view->toGui(snapSpot) + Vector(0, 5),
618                         view->toGui(snapSpot) + Vector(4, 1));
619                 painter->drawLine(view->toGui(snapSpot) + Vector(5, 0),
620                         view->toGui(snapSpot) + Vector(1, -4));
621                 painter->drawLine(view->toGui(snapSpot) + Vector(0, -5),
622                         view->toGui(snapSpot) + Vector(-4, -1));
623         }
624 }