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 "rs_graphicview.h"
22 #include "rs_information.h"
28 RS_Snapper::RS_Snapper(RS_EntityContainer & c, RS_GraphicView & gv):
29 container(&c), graphicView(&gv), finished(false)
37 RS_Snapper::~RS_Snapper()
42 * Initialize (called by all constructors)
44 void RS_Snapper::init()
46 snapMode = graphicView->getDefaultSnapMode();
47 snapRes = graphicView->getSnapRestriction();
49 snapSpot = Vector(false);
50 snapCoord = Vector(false);
54 settings.beginGroup("Snap");
55 snapRange = settings.value("Range", 20).toInt();
57 settings.beginGroup("Appearance");
58 showCrosshairs = settings.value("ShowCrosshairs", true).toBool();
66 void RS_Snapper::finish()
72 * @return Pointer to the entity which was the key entity for the
73 * last successful snapping action. If the snap mode is "end point"
74 * the key entity is the entity whos end point was caught.
75 * If the snap mode didn't require an entity (e.g. free, grid) this
76 * method will return NULL.
78 RS_Entity * RS_Snapper::getKeyEntity()
83 /** Sets a new snap mode. */
84 void RS_Snapper::setSnapMode(RS2::SnapMode snapMode)
86 this->snapMode = snapMode;
89 /** Sets a new snap restriction. */
90 void RS_Snapper::setSnapRestriction(RS2::SnapRestriction snapRes)
92 this->snapRes = snapRes;
96 * Sets the snap range in pixels for catchEntity().
100 void RS_Snapper::setSnapRange(int r)
106 * Snap to a coordinate in the drawing using the current snap mode.
108 * @param e A mouse event.
109 * @return The coordinates of the point or an invalid vector.
111 Vector RS_Snapper::snapPoint(QMouseEvent * e)
113 RS_DEBUG->print("RS_Snapper::snapPoint");
116 snapSpot = Vector(false);
120 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is NULL");
124 Vector mouseCoord = graphicView->toGraph(e->x(), e->y());
129 snapSpot = snapFree(mouseCoord);
132 case RS2::SnapEndpoint:
133 snapSpot = snapEndpoint(mouseCoord);
137 snapSpot = snapGrid(mouseCoord);
140 case RS2::SnapOnEntity:
141 snapSpot = snapOnEntity(mouseCoord);
144 case RS2::SnapCenter:
145 snapSpot = snapCenter(mouseCoord);
148 case RS2::SnapMiddle:
149 snapSpot = snapMiddle(mouseCoord);
153 snapSpot = snapDist(mouseCoord);
156 case RS2::SnapIntersection:
157 snapSpot = snapIntersection(mouseCoord);
164 // handle snap restrictions that can be activated in addition
165 // to the ones above:
168 case RS2::RestrictOrthogonal:
169 snapCoord = restrictOrthogonal(snapSpot);
171 case RS2::RestrictHorizontal:
172 snapCoord = restrictHorizontal(snapSpot);
174 case RS2::RestrictVertical:
175 snapCoord = restrictVertical(snapSpot);
178 case RS2::RestrictNothing:
179 snapCoord = snapSpot;
183 #warning "!!! THIS IS WHERE THE SNAPPER IS BEING DRAWN... !!!"
186 if (RS_DIALOGFACTORY != NULL)
187 RS_DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero());
189 RS_DEBUG->print("RS_Snapper::snapPoint: OK");
195 * Snaps to a free coordinate.
197 * @param coord The mouse coordinate.
198 * @return The coordinates of the point or an invalid vector.
200 Vector RS_Snapper::snapFree(Vector coord)
207 * Snaps to the closest endpoint.
209 * @param coord The mouse coordinate.
210 * @return The coordinates of the point or an invalid vector.
212 Vector RS_Snapper::snapEndpoint(Vector coord)
215 vec = container->getNearestEndpoint(coord, NULL/*, &keyEntity*/);
221 * Snaps to a grid point.
223 * @param coord The mouse coordinate.
224 * @return The coordinates of the point or an invalid vector.
226 Vector RS_Snapper::snapGrid(Vector coord)
228 RS_DEBUG->print("RS_Snapper::snapGrid begin");
233 RS_Grid * grid = graphicView->getGrid();
235 RS_DEBUG->print("RS_Snapper::snapGrid 001");
239 RS_DEBUG->print("RS_Snapper::snapGrid 002");
240 Vector * pts = grid->getPoints();
241 RS_DEBUG->print("RS_Snapper::snapGrid 003");
244 RS_DEBUG->print("RS_Snapper::snapGrid 004");
246 for(int i=0; i<grid->count(); ++i)
248 double d = pts[i].distanceTo(coord);
257 RS_DEBUG->print("RS_Snapper::snapGrid 005");
262 RS_DEBUG->print("RS_Snapper::snapGrid 006");
267 RS_DEBUG->print("RS_Snapper::snapGrid end");
273 * Snaps to a point on an entity.
275 * @param coord The mouse coordinate.
276 * @return The coordinates of the point or an invalid vector.
278 Vector RS_Snapper::snapOnEntity(Vector coord)
281 vec = container->getNearestPointOnEntity(coord, true, NULL, &keyEntity);
287 * Snaps to the closest center.
289 * @param coord The mouse coordinate.
290 * @return The coordinates of the point or an invalid vector.
292 Vector RS_Snapper::snapCenter(Vector coord)
295 vec = container->getNearestCenter(coord, NULL);
301 * Snaps to the closest middle.
303 * @param coord The mouse coordinate.
304 * @return The coordinates of the point or an invalid vector.
306 Vector RS_Snapper::snapMiddle(Vector coord)
309 vec = container->getNearestMiddle(coord, NULL);
315 * Snaps to the closest point with a given distance to the endpoint.
317 * @param coord The mouse coordinate.
318 * @return The coordinates of the point or an invalid vector.
320 Vector RS_Snapper::snapDist(Vector coord)
323 vec = container->getNearestDist(distance, coord, NULL);
329 * Snaps to the closest intersection point.
331 * @param coord The mouse coordinate.
332 * @return The coordinates of the point or an invalid vector.
334 Vector RS_Snapper::snapIntersection(Vector coord)
337 vec = container->getNearestIntersection(coord, NULL);
343 * 'Corrects' the given coordinates to 0, 90, 180, 270 degrees relative to
344 * the current relative zero point.
346 * @param coord The uncorrected coordinates.
347 * @return The corrected coordinates.
349 Vector RS_Snapper::restrictOrthogonal(Vector coord)
351 Vector rz = graphicView->getRelativeZero();
354 Vector retx = Vector(rz.x, ret.y);
355 Vector rety = Vector(ret.x, rz.y);
357 if (retx.distanceTo(ret) > rety.distanceTo(ret))
366 * 'Corrects' the given coordinates to 0, 180 degrees relative to
367 * the current relative zero point.
369 * @param coord The uncorrected coordinates.
370 * @return The corrected coordinates.
372 Vector RS_Snapper::restrictHorizontal(Vector coord)
374 Vector rz = graphicView->getRelativeZero();
375 Vector ret = Vector(coord.x, rz.y);
380 * 'Corrects' the given coordinates to 90, 270 degrees relative to
381 * the current relative zero point.
383 * @param coord The uncorrected coordinates.
384 * @return The corrected coordinates.
386 Vector RS_Snapper::restrictVertical(Vector coord)
388 Vector rz = graphicView->getRelativeZero();
389 Vector ret = Vector(rz.x, coord.y);
394 * Catches an entity which is close to the given position 'pos'.
396 * @param pos A graphic coordinate.
397 * @param level The level of resolving for iterating through the entity
399 * @return Pointer to the entity or NULL.
401 RS_Entity * RS_Snapper::catchEntity(const Vector& pos, RS2::ResolveLevel level)
403 RS_DEBUG->print("RS_Snapper::catchEntity");
405 // set default distance for points inside solids
406 double dist = graphicView->toGraphDX(snapRange) * 0.9;
408 RS_Entity * entity = container->getNearestEntity(pos, &dist, level);
412 if (entity != NULL && entity->getParent() != NULL)
413 idx = entity->getParent()->findEntity(entity);
415 if (entity != NULL && dist <= graphicView->toGraphDX(snapRange))
418 RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
423 RS_DEBUG->print("RS_Snapper::catchEntity: not found");
427 RS_DEBUG->print("RS_Snapper::catchEntity: OK");
431 * Catches an entity which is close to the mouse cursor.
433 * @param e A mouse event.
434 * @param level The level of resolving for iterating through the entity
436 * @return Pointer to the entity or NULL.
438 RS_Entity * RS_Snapper::catchEntity(QMouseEvent * e, RS2::ResolveLevel level)
440 return catchEntity(Vector(graphicView->toGraphX(e->x()),
441 graphicView->toGraphY(e->y())), level);
445 * Suspends this snapper while another action takes place.
447 void RS_Snapper::suspend()
450 snapSpot = snapCoord = Vector(false);
454 * Resumes this snapper after it has been suspended.
456 void RS_Snapper::resume()
462 * Hides the snapper options. Default implementation does nothing.
464 void RS_Snapper::hideOptions()
466 if (snapMode == RS2::SnapDist)
467 if (RS_DIALOGFACTORY != NULL)
468 RS_DIALOGFACTORY->requestSnapDistOptions(distance, false);
472 * Shows the snapper options. Default implementation does nothing.
474 void RS_Snapper::showOptions()
476 if (snapMode == RS2::SnapDist)
477 if (RS_DIALOGFACTORY != NULL)
478 RS_DIALOGFACTORY->requestSnapDistOptions(distance, true);
482 * Draws the snapper on the screen.
484 void RS_Snapper::drawSnapper()
491 * Deletes the snapper from the screen.
493 void RS_Snapper::deleteSnapper()
498 snapSpot = Vector(false);
499 snapCoord = Vector(false);
504 * Draws / deletes the current snapper spot.
506 void RS_Snapper::xorSnapper()
508 //Not completely true...
509 //#warning "!!! xorSnapper() not working AT ALL !!!"
511 if (!finished && snapSpot.valid)
513 RS_Painter * painter = graphicView->createDirectPainter();
514 painter->setPreviewMode();
519 painter->drawCircle(graphicView->toGui(snapCoord), 4);
522 if (showCrosshairs == true)
524 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
525 painter->drawLine(Vector(0, graphicView->toGuiY(snapCoord.y)),
526 Vector(graphicView->getWidth(), graphicView->toGuiY(snapCoord.y)));
527 painter->drawLine(Vector(graphicView->toGuiX(snapCoord.x), 0),
528 Vector(graphicView->toGuiX(snapCoord.x), graphicView->getHeight()));
532 if (snapCoord.valid && snapCoord != snapSpot)
534 painter->drawLine(graphicView->toGui(snapSpot) + Vector(-5, 0),
535 graphicView->toGui(snapSpot) + Vector(-1, 4));
536 painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, 5),
537 graphicView->toGui(snapSpot) + Vector(4, 1));
538 painter->drawLine(graphicView->toGui(snapSpot) + Vector(5, 0),
539 graphicView->toGui(snapSpot) + Vector(1, -4));
540 painter->drawLine(graphicView->toGui(snapSpot) + Vector(0, -5),
541 graphicView->toGui(snapSpot) + Vector(-4, -1));
544 graphicView->destroyPainter();
548 if (finished || !snapSpot.valid || graphicView == NULL)
551 graphicView->SetSnapperDraw(true);
552 graphicView->SetSnapperVars(snapSpot, snapCoord, showCrosshairs);
553 //Apparently, this gets hit anyway by the preview code...
554 // graphicView->redraw();