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 "paintinterface.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()
83 void RS_Snapper::SetContainer(RS_EntityContainer * c)
89 void RS_Snapper::SetGraphicView(GraphicView * v)
95 * @return Pointer to the entity which was the key entity for the last
96 * successful snapping action. If the snap mode is "end point" the key entity
97 * is the entity whos end point was caught. If the snap mode didn't require an
98 * entity (e.g. free, grid) this 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;
117 RS2::SnapMode RS_Snapper::getSnapMode(void)
122 RS2::SnapRestriction RS_Snapper::getSnapRestriction(void)
128 * Sets the snap range in pixels for catchEntity().
132 void RS_Snapper::setSnapRange(int r)
138 * Snap to a coordinate in the drawing using the current snap mode.
140 * @param e A mouse event.
141 * @return The coordinates of the point or an invalid vector.
143 Vector RS_Snapper::snapPoint(QMouseEvent * e)
145 RS_DEBUG->print("RS_Snapper::snapPoint");
146 snapSpot = Vector(false);
150 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is NULL");
154 Vector mouseCoord = graphicView->toGraph(e->x(), e->y());
159 snapSpot = snapFree(mouseCoord);
162 case RS2::SnapEndpoint:
163 snapSpot = snapEndpoint(mouseCoord);
167 snapSpot = snapGrid(mouseCoord);
170 case RS2::SnapOnEntity:
171 snapSpot = snapOnEntity(mouseCoord);
174 case RS2::SnapCenter:
175 snapSpot = snapCenter(mouseCoord);
178 case RS2::SnapMiddle:
179 snapSpot = snapMiddle(mouseCoord);
183 snapSpot = snapDist(mouseCoord);
186 case RS2::SnapIntersection:
187 snapSpot = snapIntersection(mouseCoord);
194 // Handle snap restrictions that can be activated in addition to the ones above:
197 case RS2::RestrictOrthogonal:
198 snapCoord = restrictOrthogonal(snapSpot);
200 case RS2::RestrictHorizontal:
201 snapCoord = restrictHorizontal(snapSpot);
203 case RS2::RestrictVertical:
204 snapCoord = restrictVertical(snapSpot);
207 case RS2::RestrictNothing:
208 snapCoord = snapSpot;
212 if (RS_DIALOGFACTORY)
213 RS_DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero());
215 RS_DEBUG->print("RS_Snapper::snapPoint: OK");
221 * Snaps to a free coordinate.
223 * @param coord The mouse coordinate.
224 * @return The coordinates of the point or an invalid vector.
226 Vector RS_Snapper::snapFree(Vector coord)
233 * Snaps to the closest endpoint.
235 * @param coord The mouse coordinate.
236 * @return The coordinates of the point or an invalid vector.
238 Vector RS_Snapper::snapEndpoint(Vector coord)
241 vec = container->getNearestEndpoint(coord, NULL);
247 * Snaps to a grid point.
249 * @param coord The mouse coordinate.
250 * @return The coordinates of the point or an invalid vector.
252 Vector RS_Snapper::snapGrid(Vector coord)
254 RS_DEBUG->print("RS_Snapper::snapGrid begin");
259 RS_Grid * grid = graphicView->getGrid();
261 RS_DEBUG->print("RS_Snapper::snapGrid 001");
265 RS_DEBUG->print("RS_Snapper::snapGrid 002");
266 Vector * pts = grid->getPoints();
267 RS_DEBUG->print("RS_Snapper::snapGrid 003");
270 RS_DEBUG->print("RS_Snapper::snapGrid 004");
272 for(int i=0; i<grid->count(); ++i)
274 double d = pts[i].distanceTo(coord);
283 RS_DEBUG->print("RS_Snapper::snapGrid 005");
288 RS_DEBUG->print("RS_Snapper::snapGrid 006");
293 RS_DEBUG->print("RS_Snapper::snapGrid end");
299 * Snaps to a point on an entity.
301 * @param coord The mouse coordinate.
302 * @return The coordinates of the point or an invalid vector.
304 Vector RS_Snapper::snapOnEntity(Vector coord)
307 vec = container->getNearestPointOnEntity(coord, true, NULL, &keyEntity);
313 * Snaps to the closest center.
315 * @param coord The mouse coordinate.
316 * @return The coordinates of the point or an invalid vector.
318 Vector RS_Snapper::snapCenter(Vector coord)
321 vec = container->getNearestCenter(coord, NULL);
327 * Snaps to the closest middle.
329 * @param coord The mouse coordinate.
330 * @return The coordinates of the point or an invalid vector.
332 Vector RS_Snapper::snapMiddle(Vector coord)
335 vec = container->getNearestMiddle(coord, NULL);
341 * Snaps to the closest point with a given distance to the endpoint.
343 * @param coord The mouse coordinate.
344 * @return The coordinates of the point or an invalid vector.
346 Vector RS_Snapper::snapDist(Vector coord)
349 vec = container->getNearestDist(distance, coord, NULL);
355 * Snaps to the closest intersection point.
357 * @param coord The mouse coordinate.
358 * @return The coordinates of the point or an invalid vector.
360 Vector RS_Snapper::snapIntersection(Vector coord)
363 vec = container->getNearestIntersection(coord, NULL);
369 * 'Corrects' the given coordinates to 0, 90, 180, 270 degrees relative to
370 * the current relative zero point.
372 * @param coord The uncorrected coordinates.
373 * @return The corrected coordinates.
375 Vector RS_Snapper::restrictOrthogonal(Vector coord)
377 Vector rz = graphicView->getRelativeZero();
380 Vector retx = Vector(rz.x, ret.y);
381 Vector rety = Vector(ret.x, rz.y);
383 if (retx.distanceTo(ret) > rety.distanceTo(ret))
392 * 'Corrects' the given coordinates to 0, 180 degrees relative to
393 * the current relative zero point.
395 * @param coord The uncorrected coordinates.
396 * @return The corrected coordinates.
398 Vector RS_Snapper::restrictHorizontal(Vector coord)
400 Vector rz = graphicView->getRelativeZero();
402 return Vector(coord.x, rz.y);
406 * 'Corrects' the given coordinates to 90, 270 degrees relative to
407 * the current relative zero point.
409 * @param coord The uncorrected coordinates.
410 * @return The corrected coordinates.
412 Vector RS_Snapper::restrictVertical(Vector coord)
414 Vector rz = graphicView->getRelativeZero();
416 return Vector(rz.x, coord.y);
420 * Catches an entity which is close to the given position 'pos'.
422 * @param pos A graphic coordinate.
423 * @param level The level of resolving for iterating through the entity
425 * @return Pointer to the entity or NULL.
427 RS_Entity * RS_Snapper::catchEntity(const Vector& pos, RS2::ResolveLevel level)
429 RS_DEBUG->print("RS_Snapper::catchEntity");
431 // set default distance for points inside solids
432 double dist = graphicView->toGraphDX(snapRange) * 0.9;
434 RS_Entity * entity = container->getNearestEntity(pos, &dist, level);
438 if (entity && entity->getParent())
439 idx = entity->getParent()->findEntity(entity);
441 if (entity && dist <= graphicView->toGraphDX(snapRange))
444 RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
449 RS_DEBUG->print("RS_Snapper::catchEntity: not found");
453 RS_DEBUG->print("RS_Snapper::catchEntity: OK");
457 * Catches an entity which is close to the mouse cursor.
459 * @param e A mouse event.
460 * @param level The level of resolving for iterating through the entity
462 * @return Pointer to the entity or NULL.
464 RS_Entity * RS_Snapper::catchEntity(QMouseEvent * e, RS2::ResolveLevel level)
466 return catchEntity(Vector(graphicView->toGraphX(e->x()),
467 graphicView->toGraphY(e->y())), level);
471 * Suspends this snapper while another action takes place.
473 /*virtual*/ void RS_Snapper::suspend()
475 #warning "!!! This may need to have SetVisibility() called !!!"
477 snapSpot = snapCoord = Vector(false);
481 * Resumes this snapper after it has been suspended.
483 /*virtual*/ void RS_Snapper::resume()
485 #warning "!!! This may need to have SetVisibility() called !!!"
490 * Hides the snapper options.
492 /*virtual*/ void RS_Snapper::hideOptions()
494 if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
495 RS_DIALOGFACTORY->requestSnapDistOptions(distance, false);
499 * Shows the snapper options.
501 /*virtual*/ void RS_Snapper::showOptions()
503 if (snapMode == RS2::SnapDist && RS_DIALOGFACTORY)
504 RS_DIALOGFACTORY->requestSnapDistOptions(distance, true);
507 void RS_Snapper::SetVisible(bool visibility/*= true*/)
509 visible = visibility;
512 bool RS_Snapper::Visible(void)
517 void RS_Snapper::Draw(GraphicView * view, PaintInterface * painter)
519 if (finished || !snapSpot.valid)
522 //hm, I don't like graphicView kicking around in here, especially since it now
523 //lives inside GraphicView... How to !!! FIX !!!?
524 //We'll pass it in for now...
528 painter->setPen(RS_Pen(RS_Color(0, 127, 255), RS2::Width00, RS2::DashLine));
529 painter->drawCircle(view->toGui(snapCoord), 4);
534 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
535 painter->drawLine(Vector(0, view->toGuiY(snapCoord.y)),
536 Vector(view->getWidth(), view->toGuiY(snapCoord.y)));
537 painter->drawLine(Vector(view->toGuiX(snapCoord.x), 0),
538 Vector(view->toGuiX(snapCoord.x), view->getHeight()));
542 if (snapCoord.valid && snapCoord != snapSpot)
544 painter->drawLine(view->toGui(snapSpot) + Vector(-5, 0),
545 view->toGui(snapSpot) + Vector(-1, 4));
546 painter->drawLine(view->toGui(snapSpot) + Vector(0, 5),
547 view->toGui(snapSpot) + Vector(4, 1));
548 painter->drawLine(view->toGui(snapSpot) + Vector(5, 0),
549 view->toGui(snapSpot) + Vector(1, -4));
550 painter->drawLine(view->toGui(snapSpot) + Vector(0, -5),
551 view->toGui(snapSpot) + Vector(-4, -1));