User Tools

Site Tools


This is an old revision of the document!

This page attempts to document the snapping system in pcb.

The snapping system is what takes the location of the cursor (the arrow representing the position of the mouse on the screen) and translates it into the coordinates on the board where actions take place. For example, the snapping system currently restricts the position of the crosshair to the closest grid point to the cursor. If you move the cursor near a pin or a pad, the snapping system positions the crosshair at the center of that pin or pad.

Current System


The snapping system in pcb is always active, and cannot be disabled. The snapping order… will be documented the next time I edit this page!


In pcb 4.0.2, snapping is implemented in crosshair.c, towards the end of the file. It is entirely integrated with the crosshair.

First, there is a structure that holds the information about where the crosshair is currently snapped. There is a series of functions that implement snapping.

Proposed System

Presently implemented in the home/cparker/snapping_overhaul branch.


The snapping code is presently located in two places: snap.[c,h] and crosshair.c. snap.[c,h] defines several general types that are used to do the snapping. crosshair.c is where the snapping actually occurs and is where all of the snapping functions are implemented.

There are three new types in snap.[c,h]:

  • SnapSpecType: This type is an index type for things that can be snapped to.
  • SnapListType: A list of SnapSpecType objects
  • SnapType: The result of a snapping test

Snapping occurs by iterating through SnapSpecType objects in a SnapListType. Each SnapSpecType object has a “search” function pointer that calls a function to look for the the object type associated with that particular SnapSpecType. These functions are presently defined in crosshair.c. So, for example, there is a SnapSpecType object associated with pins and pads called pin_pad_snap. It has a function associated with it called snap_to_pins_pads that calls SearchObjectByLocation to look for and pins or pads under the cursor, and decide if there is a valid snapping target. If there is, it passes that back to the calling function (as an object, not a pointer).

The crosshair structure has two related fields:

  • (SnapType*) (*snap)(SnapListType*, Coord, Coord): a function pointer to a function that does the snapping
  • (SnapListType*) snaps: a pointer to a list of things to try snapping to.

Presently, snapping occurs whenever the crosshair is repositioned using MoveCrosshairAbsolute (crosshair.c). This function calls Crosshair.snap(Crosshair.snaps, X, Y). If this returns non-null, we found something to snap to, and we reposition the crosshair to those coordinates.

Both of the crosshair items are implemented as pointers so that they can be changed dynamically. You could, for example, change the snap list when you go into line drawing mode so that you don't snap to elements or other lines, or do so in a different order. Similarly, you could change the snapping function to one that snaps based on which item is closest as opposed to which has the highest priority.


In a nod to the gobject/glib folks, I've tried to adopt some similar naming conventions for functions.


This type contains information about snapping to something. They are identified by a name string, however, they are sorted in a SnapListType by priority. There is an enable flag that can be used to turn off the snap, and there is a radius of effect. Finally, there is a function pointer to a function that looks for the subject object type.

Presently, there are SnapSpecTypes defined for:

  • grid points
  • pins and pads
  • elements
  • vias
  • lines
  • arcs, and
  • polygons

These are all defined in crosshair.c, although eventually if we're ever successful at migrating to a more object oriented structure, these should be defined in their respective type files.

SnapSpecTypes can be created using the snap_spec_new function which takes the name and priority of the spec, or by the snap_spec_copy function which takes a pointer to another SnapSpecType.


SnapListType is a simple container for organizing SnapSpecTypes. It allocates an array of SnapSpecTypes and inserts, removes, or changes the order in that array based on the priority of the SnapSpecType. This priority was perhaps a silly way of organizing them since the actual number is irrelevant, however, it does make it fairly easy to change their order, or insert new ones at a given place in the list.

Lists can be created using snap_list_new and destroyed using snap_list_delete. You can add a SnapSpec to a SnapList using the snap_list_add_snap function. Snaps are referenced by name, so, to get a pointer to a particular snap you can use snap_list_find_snap_by_name. To remove a snap, use snap_list_remove_snap_by_name.

There are two additional functions associated with SnapLists. snap_list_list_snaps will list all of the available snaps in the log window.

snap_list_search_snaps deserves a little more attention. This is the function that will iterate through the SnapSpecs in a SnapList trying to find an object on the board to snap to. Presently, this is the function called by the crosshair to search for a snappable object. This function implements a snap-to-the-highest-priority-object-under-the-cursor policy, but looping through the SnapList until a valid snap is returned. Another possible implementation of this function would be to look for object candidates of all types and then snap to the nearest one.

Crosshair Integration

All of the SnapSpecs are currently defined manually in crosshair.c, as are the snapping functions that search for those types of objects.

The Crosshair structure is a global structure, formerly defined in global.h but now moved to Crosshair.h, that contains crosshair data such as location, and attached objects. Two fields have been added to the Crosshair structure, snap and snaps. The first is a function pointer to a snap search function (such as snap_list_search_snaps) and the second is a SnapList to be searched. Implementing them in this way allows them to be changed out as needed. So, if you want to change snapping functions to one that searches for the closes object instead of the highest priority one, you can do that easily. If you want to change the SnapList, because perhaps you went into LineMode and don't want to snap to other lines, you can do that easily (of course you could always just search the list and disable those snaps too).

These things are all tied together in InitCrosshair which creates the default snap list and adds all of the built in snaps to it, and then links Crosshair.snap to snap_list_search_snaps. The actual snapping is done in MoveCrosshairAbsolute

One thing to note: there is a feature, I think it's called 'Auto Enforce DRC Clearance' in the settings menu. It used to be implemented at the end of the FitCrosshairIntoGrid function that was previously responsible for the snapping. This has been moved into MoveCrosshairAbsolute until a better home can be found for it. I don't think this really belongs as part of the crosshair subsystem.

snapping_in_pcb.1528059630.txt.gz · Last modified: 2018/06/03 17:00 by cparker