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 Snapper::Snapper(EntityContainer & c, GraphicView & gv):
32 container(&c), graphicView(&gv), finished(false)
37 Snapper::Snapper(void):
38 container(NULL), graphicView(NULL), finished(false)
51 * Initialize (called by all constructors)
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 Snapper::finish()
85 void Snapper::SetContainer(EntityContainer * c)
91 void 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 Entity * Snapper::getKeyEntity()
107 /** Sets a new snap mode. */
108 void Snapper::setSnapMode(RS2::SnapMode snapMode)
110 this->snapMode = snapMode;
113 /** Sets a new snap restriction. */
114 void Snapper::setSnapRestriction(RS2::SnapRestriction snapRes)
116 this->snapRes = snapRes;
119 RS2::SnapMode Snapper::getSnapMode(void)
124 RS2::SnapRestriction Snapper::getSnapRestriction(void)
130 * Sets the snap range in pixels for catchEntity().
134 void 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 Snapper::snapPoint(QMouseEvent * e)
147 DEBUG->print("Snapper::snapPoint");
148 snapSpot = Vector(false);
152 DEBUG->print(Debug::D_WARNING, "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;
215 DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero());
217 DEBUG->print("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 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 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 Snapper::snapGrid(Vector coord)
256 DEBUG->print("Snapper::snapGrid begin");
261 Grid * grid = graphicView->getGrid();
263 DEBUG->print("Snapper::snapGrid 001");
267 DEBUG->print("Snapper::snapGrid 002");
268 Vector * pts = grid->getPoints();
269 DEBUG->print("Snapper::snapGrid 003");
272 DEBUG->print("Snapper::snapGrid 004");
274 for(int i=0; i<grid->count(); ++i)
276 double d = pts[i].distanceTo(coord);
285 DEBUG->print("Snapper::snapGrid 005");
290 DEBUG->print("Snapper::snapGrid 006");
295 DEBUG->print("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 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 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 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 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 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 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 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 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 Entity * Snapper::catchEntity(const Vector & pos, RS2::ResolveLevel level)
431 DEBUG->print("Snapper::catchEntity");
433 // set default distance for points inside solids
434 double dist = graphicView->toGraphDX(snapRange) * 0.9;
436 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 DEBUG->print("Snapper::catchEntity: found: %d", idx);
451 DEBUG->print("Snapper::catchEntity: not found");
455 DEBUG->print("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 Entity * 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 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 Snapper::resume()
487 #warning "!!! This may need to have SetVisibility() called !!!"
492 * Hides the snapper options.
494 /*virtual*/ void Snapper::hideOptions()
496 if (snapMode == RS2::SnapDist && DIALOGFACTORY)
497 DIALOGFACTORY->requestSnapDistOptions(distance, false);
501 * Shows the snapper options.
503 /*virtual*/ void Snapper::showOptions()
505 if (snapMode == RS2::SnapDist && DIALOGFACTORY)
506 DIALOGFACTORY->requestSnapDistOptions(distance, true);
509 void Snapper::SetVisible(bool visibility/*= true*/)
511 visible = visibility;
514 bool 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 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(Pen(Color(0, 127, 255), RS2::Width00, RS2::DashLine));
537 painter->setPen(Pen(Color(255, 127, 0), RS2::Width00, RS2::DashLine));
538 painter->drawCircle(view->toGui(snapCoord), 4);
543 painter->setPen(Pen(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));