3 // Originally part of QCad Community Edition by Andrew Mustun
4 // Extensively rewritten and refactored by James L. Hammons
5 // (C) 2010 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- -----------------------------------------------------------
11 // JLH 05/21/2010 Added this text. :-)
14 #include "rs_snapper.h"
16 #include "rs_dialogfactory.h"
17 #include "rs_entitycontainer.h"
18 #include "rs_graphic.h"
19 #include "rs_graphicview.h"
21 #include "rs_information.h"
27 RS_Snapper::RS_Snapper(RS_EntityContainer & c, RS_GraphicView & gv):
28 container(&c), graphicView(&gv), finished(false)
36 RS_Snapper::~RS_Snapper()
41 * Initialize (called by all constructors)
43 void RS_Snapper::init()
45 snapMode = graphicView->getDefaultSnapMode();
46 snapRes = graphicView->getSnapRestriction();
48 snapSpot = Vector(false);
49 snapCoord = Vector(false);
53 settings.beginGroup("Snap");
54 snapRange = settings.value("Range", 20).toInt();
56 settings.beginGroup("Appearance");
57 showCrosshairs = settings.value("ShowCrosshairs", true).toBool();
65 void RS_Snapper::finish()
71 * @return Pointer to the entity which was the key entity for the
72 * last successful snapping action. If the snap mode is "end point"
73 * the key entity is the entity whos end point was caught.
74 * If the snap mode didn't require an entity (e.g. free, grid) this
75 * method will return NULL.
77 RS_Entity * RS_Snapper::getKeyEntity()
82 /** Sets a new snap mode. */
83 void RS_Snapper::setSnapMode(RS2::SnapMode snapMode)
85 this->snapMode = snapMode;
88 /** Sets a new snap restriction. */
89 void RS_Snapper::setSnapRestriction(RS2::SnapRestriction snapRes)
91 this->snapRes = snapRes;
95 * Sets the snap range in pixels for catchEntity().
99 void RS_Snapper::setSnapRange(int r)
105 * Snap to a coordinate in the drawing using the current snap mode.
107 * @param e A mouse event.
108 * @return The coordinates of the point or an invalid vector.
110 Vector RS_Snapper::snapPoint(QMouseEvent * e)
112 RS_DEBUG->print("RS_Snapper::snapPoint");
115 snapSpot = Vector(false);
119 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is NULL");
123 Vector mouseCoord = graphicView->toGraph(e->x(), e->y());
128 snapSpot = snapFree(mouseCoord);
131 case RS2::SnapEndpoint:
132 snapSpot = snapEndpoint(mouseCoord);
136 snapSpot = snapGrid(mouseCoord);
139 case RS2::SnapOnEntity:
140 snapSpot = snapOnEntity(mouseCoord);
143 case RS2::SnapCenter:
144 snapSpot = snapCenter(mouseCoord);
147 case RS2::SnapMiddle:
148 snapSpot = snapMiddle(mouseCoord);
152 snapSpot = snapDist(mouseCoord);
155 case RS2::SnapIntersection:
156 snapSpot = snapIntersection(mouseCoord);
163 // handle snap restrictions that can be activated in addition
164 // to the ones above:
167 case RS2::RestrictOrthogonal:
168 snapCoord = restrictOrthogonal(snapSpot);
170 case RS2::RestrictHorizontal:
171 snapCoord = restrictHorizontal(snapSpot);
173 case RS2::RestrictVertical:
174 snapCoord = restrictVertical(snapSpot);
177 case RS2::RestrictNothing:
178 snapCoord = snapSpot;
182 #warning "!!! THIS IS WHERE THE SNAPPER IS BEING DRAWN... !!!"
185 if (RS_DIALOGFACTORY != NULL)
186 RS_DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero());
188 RS_DEBUG->print("RS_Snapper::snapPoint: OK");
194 * Snaps to a free coordinate.
196 * @param coord The mouse coordinate.
197 * @return The coordinates of the point or an invalid vector.
199 Vector RS_Snapper::snapFree(Vector coord)
206 * Snaps to the closest endpoint.
208 * @param coord The mouse coordinate.
209 * @return The coordinates of the point or an invalid vector.
211 Vector RS_Snapper::snapEndpoint(Vector coord)
215 vec = container->getNearestEndpoint(coord, NULL/*, &keyEntity*/);
220 * Snaps to a grid point.
222 * @param coord The mouse coordinate.
223 * @return The coordinates of the point or an invalid vector.
225 Vector RS_Snapper::snapGrid(Vector coord)
227 RS_DEBUG->print("RS_Snapper::snapGrid begin");
232 RS_Grid * grid = graphicView->getGrid();
234 RS_DEBUG->print("RS_Snapper::snapGrid 001");
238 RS_DEBUG->print("RS_Snapper::snapGrid 002");
239 Vector * pts = grid->getPoints();
240 RS_DEBUG->print("RS_Snapper::snapGrid 003");
243 RS_DEBUG->print("RS_Snapper::snapGrid 004");
245 for(int i=0; i<grid->count(); ++i)
247 double d = pts[i].distanceTo(coord);
256 RS_DEBUG->print("RS_Snapper::snapGrid 005");
261 RS_DEBUG->print("RS_Snapper::snapGrid 006");
266 RS_DEBUG->print("RS_Snapper::snapGrid end");
272 * Snaps to a point on an entity.
274 * @param coord The mouse coordinate.
275 * @return The coordinates of the point or an invalid vector.
277 Vector RS_Snapper::snapOnEntity(Vector coord)
280 vec = container->getNearestPointOnEntity(coord, true, NULL, &keyEntity);
285 * Snaps to the closest center.
287 * @param coord The mouse coordinate.
288 * @return The coordinates of the point or an invalid vector.
290 Vector RS_Snapper::snapCenter(Vector coord)
294 vec = container->getNearestCenter(coord, NULL);
299 * Snaps to the closest middle.
301 * @param coord The mouse coordinate.
302 * @return The coordinates of the point or an invalid vector.
304 Vector RS_Snapper::snapMiddle(Vector coord)
308 vec = container->getNearestMiddle(coord, NULL);
313 * Snaps to the closest point with a given distance to the endpoint.
315 * @param coord The mouse coordinate.
316 * @return The coordinates of the point or an invalid vector.
318 Vector RS_Snapper::snapDist(Vector coord)
322 vec = container->getNearestDist(distance, coord, NULL);
327 * Snaps to the closest intersection point.
329 * @param coord The mouse coordinate.
330 * @return The coordinates of the point or an invalid vector.
332 Vector RS_Snapper::snapIntersection(Vector coord)
336 vec = container->getNearestIntersection(coord, NULL);
341 * 'Corrects' the given coordinates to 0, 90, 180, 270 degrees relative to
342 * the current relative zero point.
344 * @param coord The uncorrected coordinates.
345 * @return The corrected coordinates.
347 Vector RS_Snapper::restrictOrthogonal(Vector coord)
349 Vector rz = graphicView->getRelativeZero();
352 Vector retx = Vector(rz.x, ret.y);
353 Vector rety = Vector(ret.x, rz.y);
355 if (retx.distanceTo(ret) > rety.distanceTo(ret))
364 * 'Corrects' the given coordinates to 0, 180 degrees relative to
365 * the current relative zero point.
367 * @param coord The uncorrected coordinates.
368 * @return The corrected coordinates.
370 Vector RS_Snapper::restrictHorizontal(Vector coord)
372 Vector rz = graphicView->getRelativeZero();
373 Vector ret = Vector(coord.x, rz.y);
378 * 'Corrects' the given coordinates to 90, 270 degrees relative to
379 * the current relative zero point.
381 * @param coord The uncorrected coordinates.
382 * @return The corrected coordinates.
384 Vector RS_Snapper::restrictVertical(Vector coord)
386 Vector rz = graphicView->getRelativeZero();
387 Vector ret = Vector(rz.x, coord.y);
392 * Catches an entity which is close to the given position 'pos'.
394 * @param pos A graphic coordinate.
395 * @param level The level of resolving for iterating through the entity
397 * @return Pointer to the entity or NULL.
399 RS_Entity * RS_Snapper::catchEntity(const Vector& pos, RS2::ResolveLevel level)
401 RS_DEBUG->print("RS_Snapper::catchEntity");
403 // set default distance for points inside solids
404 double dist = graphicView->toGraphDX(snapRange) * 0.9;
406 RS_Entity * entity = container->getNearestEntity(pos, &dist, level);
410 if (entity != NULL && entity->getParent() != NULL)
411 idx = entity->getParent()->findEntity(entity);
413 if (entity != NULL && dist <= graphicView->toGraphDX(snapRange))
416 RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
421 RS_DEBUG->print("RS_Snapper::catchEntity: not found");
425 RS_DEBUG->print("RS_Snapper::catchEntity: OK");
429 * Catches an entity which is close to the mouse cursor.
431 * @param e A mouse event.
432 * @param level The level of resolving for iterating through the entity
434 * @return Pointer to the entity or NULL.
436 RS_Entity * RS_Snapper::catchEntity(QMouseEvent * e, RS2::ResolveLevel level)
438 return catchEntity(Vector(graphicView->toGraphX(e->x()),
439 graphicView->toGraphY(e->y())), level);
443 * Suspends this snapper while another action takes place.
445 void RS_Snapper::suspend()
448 snapSpot = snapCoord = Vector(false);
452 * Resumes this snapper after it has been suspended.
454 void RS_Snapper::resume()
460 * Hides the snapper options. Default implementation does nothing.
462 void RS_Snapper::hideOptions()
464 if (snapMode == RS2::SnapDist)
465 if (RS_DIALOGFACTORY!=NULL)
466 RS_DIALOGFACTORY->requestSnapDistOptions(distance, false);
470 * Shows the snapper options. Default implementation does nothing.
472 void RS_Snapper::showOptions()
474 if (snapMode == RS2::SnapDist)
475 if (RS_DIALOGFACTORY != NULL)
476 RS_DIALOGFACTORY->requestSnapDistOptions(distance, true);
480 * Draws the snapper on the screen.
482 void RS_Snapper::drawSnapper()
489 * Deletes the snapper from the screen.
491 void RS_Snapper::deleteSnapper()
496 snapSpot = Vector(false);
497 snapCoord = Vector(false);
502 * Draws / deletes the current snapper spot.
504 void RS_Snapper::xorSnapper()
506 //Not completely true...
507 //#warning "!!! xorSnapper() not working AT ALL !!!"
509 if (!finished && snapSpot.valid)
511 RS_Painter * painter = graphicView->createDirectPainter();
512 painter->setPreviewMode();
517 painter->drawCircle(graphicView->toGui(snapCoord), 4);
520 if (showCrosshairs == true)
522 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
523 painter->drawLine(Vector(0, graphicView->toGuiY(snapCoord.y)),
524 Vector(graphicView->getWidth(), graphicView->toGuiY(snapCoord.y)));
525 painter->drawLine(Vector(graphicView->toGuiX(snapCoord.x), 0),
526 Vector(graphicView->toGuiX(snapCoord.x), graphicView->getHeight()));
530 if (snapCoord.valid && snapCoord != snapSpot)
532 painter->drawLine(graphicView->toGui(snapSpot) + Vector(-5, 0),
533 graphicView->toGui(snapSpot) + Vector(-1, 4));
534 painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, 5),
535 graphicView->toGui(snapSpot) + Vector(4, 1));
536 painter->drawLine(graphicView->toGui(snapSpot) + Vector(5, 0),
537 graphicView->toGui(snapSpot) + Vector(1, -4));
538 painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, -5),
539 graphicView->toGui(snapSpot) + Vector(-4, -1));
542 graphicView->destroyPainter();
546 if (finished || !snapSpot.valid || graphicView == NULL)
549 graphicView->SetSnapperDraw(true);
550 graphicView->SetSnapperVars(snapSpot, snapCoord, showCrosshairs);
551 //Apparently, this gets hit anyway by the preview code...
552 // graphicView->redraw();