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. :-)
19 #include "dialogfactory.h"
21 #include "entitycontainer.h"
22 #include "graphicview.h"
24 #include "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)
520 We need to figure out how to kick the GraphicView out of this class. Perhaps we
521 need to move the toGuiX/Y() functions into another class as static functions.
522 Further inspection seems to rule this out as they are pretty well coupled to the
523 GraphicView class... What to do?
525 void RS_Snapper::Draw(GraphicView * view, PaintInterface * painter)
527 if (finished || !snapSpot.valid || !snapCoord.valid)
530 //hm, I don't like graphicView kicking around in here, especially since it now
531 //lives inside GraphicView... How to !!! FIX !!!?
532 //We'll pass it in for now...
533 // if (snapCoord.valid)
535 // Snap point (need to make sure the brush is NULL!)
536 // painter->setPen(RS_Pen(RS_Color(0, 127, 255), RS2::Width00, RS2::DashLine));
537 painter->setPen(RS_Pen(RS_Color(255, 127, 0), RS2::Width00, RS2::DashLine));
538 painter->drawCircle(view->toGui(snapCoord), 4);
543 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
544 painter->drawLine(Vector(0, view->toGuiY(snapCoord.y)),
545 Vector(view->getWidth(), view->toGuiY(snapCoord.y)));
546 painter->drawLine(Vector(view->toGuiX(snapCoord.x), 0),
547 Vector(view->toGuiX(snapCoord.x), view->getHeight()));
551 if (/*snapCoord.valid &&*/ snapCoord != snapSpot)
553 painter->drawLine(view->toGui(snapSpot) + Vector(-5, 0),
554 view->toGui(snapSpot) + Vector(-1, 4));
555 painter->drawLine(view->toGui(snapSpot) + Vector(0, 5),
556 view->toGui(snapSpot) + Vector(4, 1));
557 painter->drawLine(view->toGui(snapSpot) + Vector(5, 0),
558 view->toGui(snapSpot) + Vector(1, -4));
559 painter->drawLine(view->toGui(snapSpot) + Vector(0, -5),
560 view->toGui(snapSpot) + Vector(-4, -1));