SelDup is not practically tolerant near the World origin

Test macro

_Point w-10.0,0.0
_Point w-9.99999999,0.0
_Point w-1.0,0.0
_Point w-0.99999999,0.0
_Point w0.0,0.0
_Point w1e-08,0.0
_Point w1.0,0.0
_Point w1.00000001,0.0
_Point w10.0,0.0
_Point w10.00000001,0.0
_SelNone
_SelDupAll

Even though there is only 1e-8 deviation within each point pair, only the points closest to the World origin are not selected by _SelDupAll.

Below is a report of maximum distance thresholds of GeometryEquals for Points at various coordinates.

Nominal x       | Max dist where GeometryEquals still returns True
------------------------------------------------------------------
-100            | 3.8146972727304300e-06
-10             | 4.7683715909130300e-07
-2              | 5.9604644886412900e-08
-1.5            | 5.9604644886412900e-08
-1              | 2.9802322443206500e-08
-0.1            | 2.2351741776893700e-09
-0.01           | 6.8917870629098300e-10
-0.001          | 1.0710209520474500e-11
0               | 7.0064923216240900e-46
0.001           | 1.0570511208962000e-10
0.01            | 2.4214387005921900e-10
0.1             | 5.2154064053566700e-09
1               | 5.9604644886412900e-08
1.5             | 5.9604644886412900e-08
2               | 1.1920928977282600e-07
10              | 4.7683715909130300e-07
100             | 3.8146972727304300e-06
1000            | 3.0517578181843400e-05
10000           | 4.8828125090949500e-04

Script for GeometryEquals study
#! python 2 
from __future__ import absolute_import, division, print_function, unicode_literals

import Rhino.Geometry as rg


def get_max_geometry_equals_distance(x):
    """
    Finds the maximum distance (delta) added to x where 
    pt1.GeometryEquals(pt2) still returns True.
    """
    p3d1 = rg.Point3d(x, 0.0, 0.0)
    pt1 = rg.Point(p3d1)
    
    low_delta = 0.0
    high_delta = 1.0
    
    pt2_high = rg.Point(rg.Point3d(x + high_delta, 0.0, 0.0))
    while rg.Point.GeometryEquals(pt1, pt2_high) and high_delta < 1e10:
        high_delta *= 2.0
        pt2_high = rg.Point(rg.Point3d(x + high_delta, 0.0, 0.0))
    
    i = 0
    while True:
        mid_delta = (low_delta + high_delta) / 2.0

        if low_delta == mid_delta or high_delta == mid_delta:
            break

        p3d2_mid = rg.Point3d(x + mid_delta, 0.0, 0.0)
        pt2_mid = rg.Point(p3d2_mid)

        if rg.Point.GeometryEquals(pt1, pt2_mid):
            low_delta = mid_delta
        else:
            high_delta = mid_delta

        i += 1

    return low_delta


def main():
    x_values = (
        -100.0,
        -10.0,
        -2.0,
        -1.5,
        -1.0,
        -0.1,
        -0.01,
        -0.001,
        0.0,
        0.001,
        0.01,
        0.1,
        1.0,
        1.5,
        2.0,
        10.0,
        100.0,
        1000.0,
        10000.0,
        )
    
    print("{:<15} | {:<22}".format("Nominal x", "Max dist where GeometryEquals still returns True"))
    print("-" * 66)
    
    for x in x_values:
        max_dist = get_max_geometry_equals_distance(x)
        print("{:<15g} | {:<22.16e}".format(x, max_dist))


if __name__ == '__main__': main()

Is your Python script is calculating point coordinates with single precision floating point numbers? Your results are consistent with single precision coordinates, not the double precision coordinates used internally in Rhino.

My understanding is GeometryEquals, SelDup, SelDupAll, etc find objects where the geometry is exactly equal. Objects in Rhino, other than meshes, are stored as double precision floating point numbers. So the comparision is done as double precision floating point numbers, and Rhino checks if every bit in the coordinates is exactly the same.

If your Python script is doing calculations with single precision then what you’re finding is how small you can increment single precision floating numbers and have the numbers change. In other words the size of the truncation error in single precision floating point math.

Add a small number to a large number with the small number smaller than the significant precision of the larger number and the truncation error in the math means the larger number does not change. The result would be the coordinates of the points calculated in Python would not change if the increments are small enough. Your results are consistent with the increment size in single precision which would not change the coordinates.

Double precision floating point numbers are 64 bits with a 53 bit mantissa. That results in 15 to 17 significant decimal digits.

In contrast single precision floating point numbers are 32 bit with a 24 mantissa. That results in 6 to 9 significant decimal digits.
.

The script calculates using only doubles, but the results indicate that the equality checks done by _SelDup (and RhinoCommon’s GeometryEquals), at least for points, are of single-precision accuracy.

I just found this YouTrack comment concerning this.

The documentation for SelDup states that the “command selects objects that are geometrically identical”. In the case of points, “identical” is within a single-precision tolerance, which ends up being a scale of the points’ World coordinates.