Why do it?

Snapping is a function whereby a user creates or edits an object, and part of the shape automatically connects with another object in its proximity. As a result, the edited object is instantly positioned correctly in relation to the other object. Snapping is a useful way to combine interactive editing with exact precision.

snapping
Figure 1. The edited object snaps to another

However, you might have several kinds of objects, and you only want to enable snapping for some objects with some others. For example, when you are defining a flight plan, you only want to snap to waypoints.

How does it work?

Snapping between objects is a negotiation process between the object you’re creating or editing, the flight plan for instance, and the object you’re trying to snap to, a waypoint for instance. The object you’re trying to snap to is called a snappable. The controller holds a reference to a list of these snappables.

When you’re dragging around an object handle, the controller asks the painter of a snappable if it supports snapping and if it can return a geometry to snap to. This geometry called a snap target. For a waypoint, this would typically be an ILcdPoint.

Next, the controller asks the editor of the object you’re editing if it can snap to the offered target. If the editor responds positively, snapping takes place.

What happens next?

The controller seals the deal by visualizing and executing the snap operation:

  1. The painter of the object you’re trying to snap to is asked to highlight the snap target. Most painters draw a small rectangle around the object.

  2. The editor of the object that’s being edited is asked to perform the snap operation. This is done by calling the edit() method. The passed ILcdGXYContext will have a reference to the snap target.

To learn more about editing and snapping in a GXY view, see interacting with the GXY view

Customizing the behavior to restrict snap targets

Typically you want your editor to decide whether or not it accepts a certain snap target. For example, your flight plan editor could require that any offered snap target originates from a waypoint model:

Program: Restricting snap targets to waypoints
TLcdGXYShapePainter flightPlanPainterEditor = new TLcdGXYShapePainter() {
  @Override
  public boolean acceptSnapTarget(Graphics aGraphics, ILcdGXYContext aGXYContext) {
    // only accept snap targets from waypoint layers
    return isWaypointLayer(aGXYContext.getSnapTargetLayer()) && super.acceptSnapTarget(aGraphics, aGXYContext);
  }
};

Troubleshooting

Because snapping is a negotiation process, it’s sometimes hard to figure out what’s going wrong.

Here are some tips to help you determine the cause of snapping problems:

  • Check if your controller’s list of snappables actually contains the object you’re trying to snap to.

If you don’t want to do the bookkeeping of this list yourself, you can use samples.gxy.common.controller.SnappablesSubsetList from the samples to automatically populate the list based on the configured layers.

  • Check that the painter of the snappable supports snapping and returns a snap target.

  • Finally, check if your editor’s acceptSnapTarget() method makes the right decision.