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
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 05/21/2010 Added this text. :-)
15 #include "rs_snapper.h"
17 #include "rs_dialogfactory.h"
19 #include "rs_entitycontainer.h"
20 #include "graphicview.h"
22 #include "rs_information.h"
23 #include "paintintf.h"
29 RS_Snapper::RS_Snapper(RS_EntityContainer & c, GraphicView & gv):
30 container(&c), graphicView(&gv), finished(false)
35 RS_Snapper::RS_Snapper(void):
36 container(NULL), graphicView(NULL), finished(false)
44 RS_Snapper::~RS_Snapper()
49 * Initialize (called by all constructors)
51 void RS_Snapper::init()
55 snapMode = graphicView->getDefaultSnapMode();
56 snapRes = graphicView->getSnapRestriction();
60 snapSpot = Vector(false);
61 snapCoord = Vector(false);
65 settings.beginGroup("Snap");
66 snapRange = settings.value("Range", 20).toInt();
68 settings.beginGroup("Appearance");
69 showCrosshairs = settings.value("ShowCrosshairs", true).toBool();
77 void RS_Snapper::finish()
82 void RS_Snapper::SetContainer(RS_EntityContainer * c)
88 void RS_Snapper::SetGraphicView(GraphicView * v)
94 * @return Pointer to the entity which was the key entity for the
95 * last successful snapping action. If the snap mode is "end point"
96 * the key entity is the entity whos end point was caught.
97 * If the snap mode didn't require an entity (e.g. free, grid) this
98 * method will return NULL.
100 RS_Entity * RS_Snapper::getKeyEntity()
105 /** Sets a new snap mode. */
106 void RS_Snapper::setSnapMode(RS2::SnapMode snapMode)
108 this->snapMode = snapMode;
111 /** Sets a new snap restriction. */
112 void RS_Snapper::setSnapRestriction(RS2::SnapRestriction snapRes)
114 this->snapRes = snapRes;
118 * Sets the snap range in pixels for catchEntity().
122 void RS_Snapper::setSnapRange(int r)
128 * Snap to a coordinate in the drawing using the current snap mode.
130 * @param e A mouse event.
131 * @return The coordinates of the point or an invalid vector.
133 Vector RS_Snapper::snapPoint(QMouseEvent * e)
135 RS_DEBUG->print("RS_Snapper::snapPoint");
137 //meh deleteSnapper();
138 snapSpot = Vector(false);
142 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is NULL");
146 Vector mouseCoord = graphicView->toGraph(e->x(), e->y());
151 snapSpot = snapFree(mouseCoord);
154 case RS2::SnapEndpoint:
155 snapSpot = snapEndpoint(mouseCoord);
159 snapSpot = snapGrid(mouseCoord);
162 case RS2::SnapOnEntity:
163 snapSpot = snapOnEntity(mouseCoord);
166 case RS2::SnapCenter:
167 snapSpot = snapCenter(mouseCoord);
170 case RS2::SnapMiddle:
171 snapSpot = snapMiddle(mouseCoord);
175 snapSpot = snapDist(mouseCoord);
178 case RS2::SnapIntersection:
179 snapSpot = snapIntersection(mouseCoord);
186 // handle snap restrictions that can be activated in addition
187 // to the ones above:
190 case RS2::RestrictOrthogonal:
191 snapCoord = restrictOrthogonal(snapSpot);
193 case RS2::RestrictHorizontal:
194 snapCoord = restrictHorizontal(snapSpot);
196 case RS2::RestrictVertical:
197 snapCoord = restrictVertical(snapSpot);
200 case RS2::RestrictNothing:
201 snapCoord = snapSpot;
205 //#warning "!!! THIS IS WHERE THE SNAPPER IS BEING DRAWN... !!!"
208 if (RS_DIALOGFACTORY)
209 RS_DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero());
211 RS_DEBUG->print("RS_Snapper::snapPoint: OK");
217 * Snaps to a free coordinate.
219 * @param coord The mouse coordinate.
220 * @return The coordinates of the point or an invalid vector.
222 Vector RS_Snapper::snapFree(Vector coord)
229 * Snaps to the closest endpoint.
231 * @param coord The mouse coordinate.
232 * @return The coordinates of the point or an invalid vector.
234 Vector RS_Snapper::snapEndpoint(Vector coord)
237 vec = container->getNearestEndpoint(coord, NULL/*, &keyEntity*/);
243 * Snaps to a grid point.
245 * @param coord The mouse coordinate.
246 * @return The coordinates of the point or an invalid vector.
248 Vector RS_Snapper::snapGrid(Vector coord)
250 RS_DEBUG->print("RS_Snapper::snapGrid begin");
255 RS_Grid * grid = graphicView->getGrid();
257 RS_DEBUG->print("RS_Snapper::snapGrid 001");
261 RS_DEBUG->print("RS_Snapper::snapGrid 002");
262 Vector * pts = grid->getPoints();
263 RS_DEBUG->print("RS_Snapper::snapGrid 003");
266 RS_DEBUG->print("RS_Snapper::snapGrid 004");
268 for(int i=0; i<grid->count(); ++i)
270 double d = pts[i].distanceTo(coord);
279 RS_DEBUG->print("RS_Snapper::snapGrid 005");
284 RS_DEBUG->print("RS_Snapper::snapGrid 006");
289 RS_DEBUG->print("RS_Snapper::snapGrid end");
295 * Snaps to a point on an entity.
297 * @param coord The mouse coordinate.
298 * @return The coordinates of the point or an invalid vector.
300 Vector RS_Snapper::snapOnEntity(Vector coord)
303 vec = container->getNearestPointOnEntity(coord, true, NULL, &keyEntity);
309 * Snaps to the closest center.
311 * @param coord The mouse coordinate.
312 * @return The coordinates of the point or an invalid vector.
314 Vector RS_Snapper::snapCenter(Vector coord)
317 vec = container->getNearestCenter(coord, NULL);
323 * Snaps to the closest middle.
325 * @param coord The mouse coordinate.
326 * @return The coordinates of the point or an invalid vector.
328 Vector RS_Snapper::snapMiddle(Vector coord)
331 vec = container->getNearestMiddle(coord, NULL);
337 * Snaps to the closest point with a given distance to the endpoint.
339 * @param coord The mouse coordinate.
340 * @return The coordinates of the point or an invalid vector.
342 Vector RS_Snapper::snapDist(Vector coord)
345 vec = container->getNearestDist(distance, coord, NULL);
351 * Snaps to the closest intersection point.
353 * @param coord The mouse coordinate.
354 * @return The coordinates of the point or an invalid vector.
356 Vector RS_Snapper::snapIntersection(Vector coord)
359 vec = container->getNearestIntersection(coord, NULL);
365 * 'Corrects' the given coordinates to 0, 90, 180, 270 degrees relative to
366 * the current relative zero point.
368 * @param coord The uncorrected coordinates.
369 * @return The corrected coordinates.
371 Vector RS_Snapper::restrictOrthogonal(Vector coord)
373 Vector rz = graphicView->getRelativeZero();
376 Vector retx = Vector(rz.x, ret.y);
377 Vector rety = Vector(ret.x, rz.y);
379 if (retx.distanceTo(ret) > rety.distanceTo(ret))
388 * 'Corrects' the given coordinates to 0, 180 degrees relative to
389 * the current relative zero point.
391 * @param coord The uncorrected coordinates.
392 * @return The corrected coordinates.
394 Vector RS_Snapper::restrictHorizontal(Vector coord)
396 Vector rz = graphicView->getRelativeZero();
397 // Vector ret = Vector(coord.x, rz.y);
399 return Vector(coord.x, rz.y);
403 * 'Corrects' the given coordinates to 90, 270 degrees relative to
404 * the current relative zero point.
406 * @param coord The uncorrected coordinates.
407 * @return The corrected coordinates.
409 Vector RS_Snapper::restrictVertical(Vector coord)
411 Vector rz = graphicView->getRelativeZero();
412 // Vector ret = Vector(rz.x, coord.y);
414 return Vector(rz.x, coord.y);
418 * Catches an entity which is close to the given position 'pos'.
420 * @param pos A graphic coordinate.
421 * @param level The level of resolving for iterating through the entity
423 * @return Pointer to the entity or NULL.
425 RS_Entity * RS_Snapper::catchEntity(const Vector& pos, RS2::ResolveLevel level)
427 RS_DEBUG->print("RS_Snapper::catchEntity");
429 // set default distance for points inside solids
430 double dist = graphicView->toGraphDX(snapRange) * 0.9;
432 RS_Entity * entity = container->getNearestEntity(pos, &dist, level);
436 if (entity && entity->getParent())
437 idx = entity->getParent()->findEntity(entity);
439 if (entity && dist <= graphicView->toGraphDX(snapRange))
442 RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
447 RS_DEBUG->print("RS_Snapper::catchEntity: not found");
451 RS_DEBUG->print("RS_Snapper::catchEntity: OK");
455 * Catches an entity which is close to the mouse cursor.
457 * @param e A mouse event.
458 * @param level The level of resolving for iterating through the entity
460 * @return Pointer to the entity or NULL.
462 RS_Entity * RS_Snapper::catchEntity(QMouseEvent * e, RS2::ResolveLevel level)
464 return catchEntity(Vector(graphicView->toGraphX(e->x()),
465 graphicView->toGraphY(e->y())), level);
469 * Suspends this snapper while another action takes place.
471 /*virtual*/ void RS_Snapper::suspend()
474 snapSpot = snapCoord = Vector(false);
478 * Resumes this snapper after it has been suspended.
480 /*virtual*/ void RS_Snapper::resume()
486 * Hides the snapper options.
488 /*virtual*/ void RS_Snapper::hideOptions()
490 if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
491 RS_DIALOGFACTORY->requestSnapDistOptions(distance, false);
495 * Shows the snapper options.
497 /*virtual*/ void RS_Snapper::showOptions()
499 if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
500 RS_DIALOGFACTORY->requestSnapDistOptions(distance, true);
504 * Draws the snapper on the screen.
506 void RS_Snapper::drawSnapper()
508 printf("RS_Snapper::drawSnapper(): Using DEPRECATED function!!!\n");
514 * Deletes the snapper from the screen.
516 void RS_Snapper::deleteSnapper()
518 printf("RS_Snapper::deleteSnapper(): Using DEPRECATED function!!!\n");
522 snapSpot = Vector(false);
523 snapCoord = Vector(false);
528 * Draws / deletes the current snapper spot.
530 void RS_Snapper::xorSnapper()
532 //Not completely true...
533 //#warning "!!! xorSnapper() not working AT ALL !!!"
535 if (!finished && snapSpot.valid)
537 RS_Painter * painter = graphicView->createDirectPainter();
538 painter->setPreviewMode();
543 painter->drawCircle(graphicView->toGui(snapCoord), 4);
546 if (showCrosshairs == true)
548 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
549 painter->drawLine(Vector(0, graphicView->toGuiY(snapCoord.y)),
550 Vector(graphicView->getWidth(), graphicView->toGuiY(snapCoord.y)));
551 painter->drawLine(Vector(graphicView->toGuiX(snapCoord.x), 0),
552 Vector(graphicView->toGuiX(snapCoord.x), graphicView->getHeight()));
556 if (snapCoord.valid && snapCoord != snapSpot)
558 painter->drawLine(graphicView->toGui(snapSpot) + Vector(-5, 0),
559 graphicView->toGui(snapSpot) + Vector(-1, 4));
560 painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, 5),
561 graphicView->toGui(snapSpot) + Vector(4, 1));
562 painter->drawLine(graphicView->toGui(snapSpot) + Vector(5, 0),
563 graphicView->toGui(snapSpot) + Vector(1, -4));
564 painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, -5),
565 graphicView->toGui(snapSpot) + Vector(-4, -1));
568 graphicView->destroyPainter();
572 if (finished || !snapSpot.valid || !graphicView)
575 graphicView->SetSnapperDraw(true);
576 graphicView->SetSnapperVars(snapSpot, snapCoord, showCrosshairs);
577 //Apparently, this gets hit anyway by the preview code...
578 // graphicView->redraw();
584 void RS_Snapper::SetVisible(bool visibility/*= true*/)
586 // graphicView->SetSnapperDraw(visibility);
587 visible = visibility;
590 bool RS_Snapper::Visible(void)
592 // graphicView->SetSnapperDraw(visibility);
596 void RS_Snapper::Draw(GraphicView * view, PaintInterface * painter)
598 //printf("RS_Snapper::Draw()...");
599 if (finished || !snapSpot.valid)
603 //meh painter->setPreviewMode();
605 //hm, I don't like graphicView kicking around in here, especially since it now
606 //lives inside GraphicView... How to !!! FIX !!!?
607 //We'll pass it in for now...
611 painter->drawCircle(view->toGui(snapCoord), 4);
616 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
617 painter->drawLine(Vector(0, view->toGuiY(snapCoord.y)),
618 Vector(view->getWidth(), view->toGuiY(snapCoord.y)));
619 painter->drawLine(Vector(view->toGuiX(snapCoord.x), 0),
620 Vector(view->toGuiX(snapCoord.x), view->getHeight()));
624 if (snapCoord.valid && snapCoord != snapSpot)
626 painter->drawLine(view->toGui(snapSpot) + Vector(-5, 0),
627 view->toGui(snapSpot) + Vector(-1, 4));
628 painter->drawLine(view->toGui(snapSpot) + Vector(0, 5),
629 view->toGui(snapSpot) + Vector(4, 1));
630 painter->drawLine(view->toGui(snapSpot) + Vector(5, 0),
631 view->toGui(snapSpot) + Vector(1, -4));
632 painter->drawLine(view->toGui(snapSpot) + Vector(0, -5),
633 view->toGui(snapSpot) + Vector(-4, -1));