How To: Make a scale-independent SearchByDistance tolerance
Make a search distance that works uniformly at any scale.
The SearchByDistance method finds all features in the MapLayer that are within a distance of the input shape:
Set recs = mlyr.SearchByDistance(pt, dist, "")
This will find all features within "dist" distance of "pt" shape. Let's say for this example the "pt" argument is a point clicked by the user with their mouse.
The "dist" argument must be a length expressed in MAP UNITS. If you use a hardcoded value, this could produce undesirable results depending on your scale. For example, if my map units are in feet, and my search distance is 50 feet, then when the map is zoomed in so far that the width of the map display is 100 map units, the search tolerance includes most of the features in the map display. On the other hand, if the width of the map display is 100,000 map units, then the search tolerance is represented on the screen by a distance less than the width of a screen pixel. In either case, hardcoding a distance value for the mouse select tool is impractical.
When making a mouse select tool, it is ergonomically acceptable to make the tolerance a distance roughly equal to three screen pixels. This is a distance small enough to eliminate features that the user probably wants to exclude and still be able to select those features that the user wants to include. Even users who are new to operating a mouse can get their cursor to within a radius of three screen pixels.
So we want our tolerance to be three pixels, but the SearchByDistance method expects the distance argument to be expressed in map units. At large scales, three pixels cover a much smaller area on the map. At small scales, three pixels cover a much larger area.
The solution here is to determine the distance in map units equivalent to three screen pixels immediately before using the SearchByDistance method. Here is one way to accomplish this:
Dim tol As Double
tol = Map1.ToMapDistance(3 * Screen.TwipsPerPixelX)
Set recs = mlyr.SearchByDistance(pt, tol, "")
Most noteworthy here is the line that includes "Screen.TwipsPerPixelX". The Screen object is a class provided to you by Visual Basic. TwipsPerPixelX is a property of the Screen object that provides for you the width of a screen pixel in units of twips. There are:
20 twips in a point
72 points in an inch
1,440 twips in an inch
A twip is a fixed unit of measurement that can easily be converted into other fixed units of measurement such as feet and meters. On the other hand, a pixel is a variable unit of measurement. The size of a pixel varies by device capabilities of the screen, printer, and other pixel-based graphics display devices.
Many printers have different-sized pixels. Often, the resolution of a printer is expressed in terms of "dots per inch." A dot is the same as a pixel. The size of a pixel on a monitor screen is usually much larger than most standard printers. Most printers and video cards provide the user with the ability to choose resolution settings so that even the same device can have different TwipsPerPixel values. Even within one resolution setting, the height and the width of the pixel do not need to be the same. Not all pixels are square. The VB Printer class and the Screen class both have TwipsPerPixelX and TwipsPerPixelY properties to account for rectangular pixels.
The ToMapDistance method is used to convert from twips to map units.
Last Published: 5/5/2016
Article ID: 000002303
Software: MapObjects-Windows 2.0a, 2.0, 1.2