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 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 05/21/2010 Added this text. :-)
17 #include "rs_snapper.h"
19 #include "rs_dialogfactory.h"
21 #include "rs_entitycontainer.h"
22 #include "graphicview.h"
24 #include "rs_information.h"
25 #include "paintinterface.h"
31 RS_Snapper::RS_Snapper(RS_EntityContainer & c, GraphicView & gv):
32 container(&c), graphicView(&gv), finished(false)
37 RS_Snapper::RS_Snapper(void):
38 container(NULL), graphicView(NULL), finished(false)
46 RS_Snapper::~RS_Snapper()
51 * Initialize (called by all constructors)
53 void RS_Snapper::init()
57 snapMode = graphicView->getDefaultSnapMode();
58 snapRes = graphicView->getSnapRestriction();
62 snapSpot = Vector(false);
63 snapCoord = Vector(false);
67 settings.beginGroup("Snap");
68 snapRange = settings.value("Range", 20).toInt();
70 settings.beginGroup("Appearance");
71 showCrosshairs = settings.value("ShowCrosshairs", true).toBool();
79 void RS_Snapper::finish()
85 void RS_Snapper::SetContainer(RS_EntityContainer * c)
91 void RS_Snapper::SetGraphicView(GraphicView * v)
97 * @return Pointer to the entity which was the key entity for the last
98 * successful snapping action. If the snap mode is "end point" the key entity
99 * is the entity whos end point was caught. If the snap mode didn't require an
100 * entity (e.g. free, grid) this method will return NULL.
102 RS_Entity * RS_Snapper::getKeyEntity()
107 /** Sets a new snap mode. */
108 void RS_Snapper::setSnapMode(RS2::SnapMode snapMode)
110 this->snapMode = snapMode;
113 /** Sets a new snap restriction. */
114 void RS_Snapper::setSnapRestriction(RS2::SnapRestriction snapRes)
116 this->snapRes = snapRes;
119 RS2::SnapMode RS_Snapper::getSnapMode(void)
124 RS2::SnapRestriction RS_Snapper::getSnapRestriction(void)
130 * Sets the snap range in pixels for catchEntity().
134 void RS_Snapper::setSnapRange(int r)
140 * Snap to a coordinate in the drawing using the current snap mode.
142 * @param e A mouse event.
143 * @return The coordinates of the point or an invalid vector.
145 Vector RS_Snapper::snapPoint(QMouseEvent * e)
147 RS_DEBUG->print("RS_Snapper::snapPoint");
148 snapSpot = Vector(false);
152 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is NULL");
156 Vector mouseCoord = graphicView->toGraph(e->x(), e->y());
161 snapSpot = snapFree(mouseCoord);
164 case RS2::SnapEndpoint:
165 snapSpot = snapEndpoint(mouseCoord);
169 snapSpot = snapGrid(mouseCoord);
172 case RS2::SnapOnEntity:
173 snapSpot = snapOnEntity(mouseCoord);
176 case RS2::SnapCenter:
177 snapSpot = snapCenter(mouseCoord);
180 case RS2::SnapMiddle:
181 snapSpot = snapMiddle(mouseCoord);
185 snapSpot = snapDist(mouseCoord);
188 case RS2::SnapIntersection:
189 snapSpot = snapIntersection(mouseCoord);
196 // Handle snap restrictions that can be activated in addition to the ones above:
199 case RS2::RestrictOrthogonal:
200 snapCoord = restrictOrthogonal(snapSpot);
202 case RS2::RestrictHorizontal:
203 snapCoord = restrictHorizontal(snapSpot);
205 case RS2::RestrictVertical:
206 snapCoord = restrictVertical(snapSpot);
209 case RS2::RestrictNothing:
210 snapCoord = snapSpot;
214 if (RS_DIALOGFACTORY)
215 RS_DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero());
217 RS_DEBUG->print("RS_Snapper::snapPoint: OK");
223 * Snaps to a free coordinate.
225 * @param coord The mouse coordinate.
226 * @return The coordinates of the point or an invalid vector.
228 Vector RS_Snapper::snapFree(Vector coord)
235 * Snaps to the closest endpoint.
237 * @param coord The mouse coordinate.
238 * @return The coordinates of the point or an invalid vector.
240 Vector RS_Snapper::snapEndpoint(Vector coord)
243 vec = container->getNearestEndpoint(coord, NULL);
249 * Snaps to a grid point.
251 * @param coord The mouse coordinate.
252 * @return The coordinates of the point or an invalid vector.
254 Vector RS_Snapper::snapGrid(Vector coord)
256 RS_DEBUG->print("RS_Snapper::snapGrid begin");
261 RS_Grid * grid = graphicView->getGrid();
263 RS_DEBUG->print("RS_Snapper::snapGrid 001");
267 RS_DEBUG->print("RS_Snapper::snapGrid 002");
268 Vector * pts = grid->getPoints();
269 RS_DEBUG->print("RS_Snapper::snapGrid 003");
272 RS_DEBUG->print("RS_Snapper::snapGrid 004");
274 for(int i=0; i<grid->count(); ++i)
276 double d = pts[i].distanceTo(coord);
285 RS_DEBUG->print("RS_Snapper::snapGrid 005");
290 RS_DEBUG->print("RS_Snapper::snapGrid 006");
295 RS_DEBUG->print("RS_Snapper::snapGrid end");
301 * Snaps to a point on an entity.
303 * @param coord The mouse coordinate.
304 * @return The coordinates of the point or an invalid vector.
306 Vector RS_Snapper::snapOnEntity(Vector coord)
309 vec = container->getNearestPointOnEntity(coord, true, NULL, &keyEntity);
315 * Snaps to the closest center.
317 * @param coord The mouse coordinate.
318 * @return The coordinates of the point or an invalid vector.
320 Vector RS_Snapper::snapCenter(Vector coord)
323 vec = container->getNearestCenter(coord, NULL);
329 * Snaps to the closest middle.
331 * @param coord The mouse coordinate.
332 * @return The coordinates of the point or an invalid vector.
334 Vector RS_Snapper::snapMiddle(Vector coord)
337 vec = container->getNearestMiddle(coord, NULL);
343 * Snaps to the closest point with a given distance to the endpoint.
345 * @param coord The mouse coordinate.
346 * @return The coordinates of the point or an invalid vector.
348 Vector RS_Snapper::snapDist(Vector coord)
351 vec = container->getNearestDist(distance, coord, NULL);
357 * Snaps to the closest intersection point.
359 * @param coord The mouse coordinate.
360 * @return The coordinates of the point or an invalid vector.
362 Vector RS_Snapper::snapIntersection(Vector coord)
365 vec = container->getNearestIntersection(coord, NULL);
371 * 'Corrects' the given coordinates to 0, 90, 180, 270 degrees relative to
372 * the current relative zero point.
374 * @param coord The uncorrected coordinates.
375 * @return The corrected coordinates.
377 Vector RS_Snapper::restrictOrthogonal(Vector coord)
379 Vector rz = graphicView->getRelativeZero();
382 Vector retx = Vector(rz.x, ret.y);
383 Vector rety = Vector(ret.x, rz.y);
385 if (retx.distanceTo(ret) > rety.distanceTo(ret))
394 * 'Corrects' the given coordinates to 0, 180 degrees relative to
395 * the current relative zero point.
397 * @param coord The uncorrected coordinates.
398 * @return The corrected coordinates.
400 Vector RS_Snapper::restrictHorizontal(Vector coord)
402 Vector rz = graphicView->getRelativeZero();
404 return Vector(coord.x, rz.y);
408 * 'Corrects' the given coordinates to 90, 270 degrees relative to
409 * the current relative zero point.
411 * @param coord The uncorrected coordinates.
412 * @return The corrected coordinates.
414 Vector RS_Snapper::restrictVertical(Vector coord)
416 Vector rz = graphicView->getRelativeZero();
418 return Vector(rz.x, coord.y);
422 * Catches an entity which is close to the given position 'pos'.
424 * @param pos A graphic coordinate.
425 * @param level The level of resolving for iterating through the entity
427 * @return Pointer to the entity or NULL.
429 RS_Entity * RS_Snapper::catchEntity(const Vector& pos, RS2::ResolveLevel level)
431 RS_DEBUG->print("RS_Snapper::catchEntity");
433 // set default distance for points inside solids
434 double dist = graphicView->toGraphDX(snapRange) * 0.9;
436 RS_Entity * entity = container->getNearestEntity(pos, &dist, level);
440 if (entity && entity->getParent())
441 idx = entity->getParent()->findEntity(entity);
443 if (entity && dist <= graphicView->toGraphDX(snapRange))
446 RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
451 RS_DEBUG->print("RS_Snapper::catchEntity: not found");
455 RS_DEBUG->print("RS_Snapper::catchEntity: OK");
459 * Catches an entity which is close to the mouse cursor.
461 * @param e A mouse event.
462 * @param level The level of resolving for iterating through the entity
464 * @return Pointer to the entity or NULL.
466 RS_Entity * RS_Snapper::catchEntity(QMouseEvent * e, RS2::ResolveLevel level)
468 return catchEntity(Vector(graphicView->toGraphX(e->x()),
469 graphicView->toGraphY(e->y())), level);
473 * Suspends this snapper while another action takes place.
475 /*virtual*/ void RS_Snapper::suspend()
477 #warning "!!! This may need to have SetVisibility() called !!!"
479 snapSpot = snapCoord = Vector(false);
483 * Resumes this snapper after it has been suspended.
485 /*virtual*/ void RS_Snapper::resume()
487 #warning "!!! This may need to have SetVisibility() called !!!"
492 * Hides the snapper options.
494 /*virtual*/ void RS_Snapper::hideOptions()
496 if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
497 RS_DIALOGFACTORY->requestSnapDistOptions(distance, false);
501 * Shows the snapper options.
503 /*virtual*/ void RS_Snapper::showOptions()
505 if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
506 RS_DIALOGFACTORY->requestSnapDistOptions(distance, true);
509 void RS_Snapper::SetVisible(bool visibility/*= true*/)
511 visible = visibility;
514 bool RS_Snapper::Visible(void)
519 void RS_Snapper::Draw(GraphicView * view, PaintInterface * painter)
521 if (finished || !snapSpot.valid)
524 //hm, I don't like graphicView kicking around in here, especially since it now
525 //lives inside GraphicView... How to !!! FIX !!!?
526 //We'll pass it in for now...
530 painter->setPen(RS_Pen(RS_Color(0, 127, 255), RS2::Width00, RS2::DashLine));
531 painter->drawCircle(view->toGui(snapCoord), 4);
536 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
537 painter->drawLine(Vector(0, view->toGuiY(snapCoord.y)),
538 Vector(view->getWidth(), view->toGuiY(snapCoord.y)));
539 painter->drawLine(Vector(view->toGuiX(snapCoord.x), 0),
540 Vector(view->toGuiX(snapCoord.x), view->getHeight()));
544 if (snapCoord.valid && snapCoord != snapSpot)
546 painter->drawLine(view->toGui(snapSpot) + Vector(-5, 0),
547 view->toGui(snapSpot) + Vector(-1, 4));
548 painter->drawLine(view->toGui(snapSpot) + Vector(0, 5),
549 view->toGui(snapSpot) + Vector(4, 1));
550 painter->drawLine(view->toGui(snapSpot) + Vector(5, 0),
551 view->toGui(snapSpot) + Vector(1, -4));
552 painter->drawLine(view->toGui(snapSpot) + Vector(0, -5),
553 view->toGui(snapSpot) + Vector(-4, -1));