It seems pretty straight-forward to:
- Take the absolute (to get rid of the sign) difference between two values, that's your traditional difference.
- For each of the two values:
- take distance to (as in p.1. absolute difference) the minimum
- take distance to maximum
- take the minimum of the two distances above
- sum up the both minimums, that's the wrapping difference; obviously you could only consider distance to minimum + distance to maximum vs distance to maximum + distance to minimum, but I think this way doesn't hurt and is simpler...
- Take the minimum of the two: traditional and wrapping difference.
There is possibly an even simpler way to look at the problem: rotate your circle so that the closer point to the minimum is at the minimum - now if both values were already within range, you now know the bigger value has to either move to the minimum or to maximum in order to touch the smaller value.
Here's Python code to test both approaches and compare with lemon's:
def lemon(a, b, v_min, v_max):
return min(
max(a, b) - min(a, b),
min(a, b) + v_max - max(a, b) - v_min
)
def obvious(a, b, v_min, v_max):
traditional_difference = abs(a-b)
to_boundary = lambda x: min(abs(x-v_min), abs(x-v_max))
a_to_boundary = to_boundary(a)
b_to_boundary = to_boundary(b)
wrapping_difference = a_to_boundary + b_to_boundary
return min(traditional_difference, wrapping_difference)
def simple(a, b, v_min, v_max):
a, b = sorted((a, b))
b -= a - v_min
return min(b - v_min, v_max - b)
v_min, v_max = -3, 5
print(f"{v_min=}, {v_max=}")
col_titles = ("a", "b", "obvious", "lemon", "simple", "equal?")
cols = len(col_titles)
row = "| {:>7} " * cols + "|"
header = row.replace('>','^').replace('<','^')
line = header.replace(' ','-').replace('^','-^').replace('|','+').format(*'-'*cols)
print(line)
print(header.format(*col_titles))
print(line)
for a in range(v_min, v_max+1):
for b in range(v_min, v_max+1):
args = a, b, v_min, v_max
o, l, s = obvious(*args), lemon(*args), simple(*args)
print(row.format(a, b, o, l, s, "yes" if o==l==s else "no"))
print(line)
v_min=-3, v_max=5
+---------+---------+---------+---------+---------+---------+
| a | b | obvious | lemon | simple | equal? |
+---------+---------+---------+---------+---------+---------+
| -3 | -3 | 0 | 0 | 0 | yes |
| -3 | -2 | 1 | 1 | 1 | yes |
| -3 | -1 | 2 | 2 | 2 | yes |
| -3 | 0 | 3 | 3 | 3 | yes |
| -3 | 1 | 4 | 4 | 4 | yes |
| -3 | 2 | 3 | 3 | 3 | yes |
| -3 | 3 | 2 | 2 | 2 | yes |
| -3 | 4 | 1 | 1 | 1 | yes |
| -3 | 5 | 0 | 0 | 0 | yes |
| -2 | -3 | 1 | 1 | 1 | yes |
| -2 | -2 | 0 | 0 | 0 | yes |
| -2 | -1 | 1 | 1 | 1 | yes |
| -2 | 0 | 2 | 2 | 2 | yes |
| -2 | 1 | 3 | 3 | 3 | yes |
| -2 | 2 | 4 | 4 | 4 | yes |
| -2 | 3 | 3 | 3 | 3 | yes |
| -2 | 4 | 2 | 2 | 2 | yes |
| -2 | 5 | 1 | 1 | 1 | yes |
| -1 | -3 | 2 | 2 | 2 | yes |
| -1 | -2 | 1 | 1 | 1 | yes |
| -1 | -1 | 0 | 0 | 0 | yes |
| -1 | 0 | 1 | 1 | 1 | yes |
| -1 | 1 | 2 | 2 | 2 | yes |
| -1 | 2 | 3 | 3 | 3 | yes |
| -1 | 3 | 4 | 4 | 4 | yes |
| -1 | 4 | 3 | 3 | 3 | yes |
| -1 | 5 | 2 | 2 | 2 | yes |
| 0 | -3 | 3 | 3 | 3 | yes |
| 0 | -2 | 2 | 2 | 2 | yes |
| 0 | -1 | 1 | 1 | 1 | yes |
| 0 | 0 | 0 | 0 | 0 | yes |
| 0 | 1 | 1 | 1 | 1 | yes |
| 0 | 2 | 2 | 2 | 2 | yes |
| 0 | 3 | 3 | 3 | 3 | yes |
| 0 | 4 | 4 | 4 | 4 | yes |
| 0 | 5 | 3 | 3 | 3 | yes |
| 1 | -3 | 4 | 4 | 4 | yes |
| 1 | -2 | 3 | 3 | 3 | yes |
| 1 | -1 | 2 | 2 | 2 | yes |
| 1 | 0 | 1 | 1 | 1 | yes |
| 1 | 1 | 0 | 0 | 0 | yes |
| 1 | 2 | 1 | 1 | 1 | yes |
| 1 | 3 | 2 | 2 | 2 | yes |
| 1 | 4 | 3 | 3 | 3 | yes |
| 1 | 5 | 4 | 4 | 4 | yes |
| 2 | -3 | 3 | 3 | 3 | yes |
| 2 | -2 | 4 | 4 | 4 | yes |
| 2 | -1 | 3 | 3 | 3 | yes |
| 2 | 0 | 2 | 2 | 2 | yes |
| 2 | 1 | 1 | 1 | 1 | yes |
| 2 | 2 | 0 | 0 | 0 | yes |
| 2 | 3 | 1 | 1 | 1 | yes |
| 2 | 4 | 2 | 2 | 2 | yes |
| 2 | 5 | 3 | 3 | 3 | yes |
| 3 | -3 | 2 | 2 | 2 | yes |
| 3 | -2 | 3 | 3 | 3 | yes |
| 3 | -1 | 4 | 4 | 4 | yes |
| 3 | 0 | 3 | 3 | 3 | yes |
| 3 | 1 | 2 | 2 | 2 | yes |
| 3 | 2 | 1 | 1 | 1 | yes |
| 3 | 3 | 0 | 0 | 0 | yes |
| 3 | 4 | 1 | 1 | 1 | yes |
| 3 | 5 | 2 | 2 | 2 | yes |
| 4 | -3 | 1 | 1 | 1 | yes |
| 4 | -2 | 2 | 2 | 2 | yes |
| 4 | -1 | 3 | 3 | 3 | yes |
| 4 | 0 | 4 | 4 | 4 | yes |
| 4 | 1 | 3 | 3 | 3 | yes |
| 4 | 2 | 2 | 2 | 2 | yes |
| 4 | 3 | 1 | 1 | 1 | yes |
| 4 | 4 | 0 | 0 | 0 | yes |
| 4 | 5 | 1 | 1 | 1 | yes |
| 5 | -3 | 0 | 0 | 0 | yes |
| 5 | -2 | 1 | 1 | 1 | yes |
| 5 | -1 | 2 | 2 | 2 | yes |
| 5 | 0 | 3 | 3 | 3 | yes |
| 5 | 1 | 4 | 4 | 4 | yes |
| 5 | 2 | 3 | 3 | 3 | yes |
| 5 | 3 | 2 | 2 | 2 | yes |
| 5 | 4 | 1 | 1 | 1 | yes |
| 5 | 5 | 0 | 0 | 0 | yes |
+---------+---------+---------+---------+---------+---------+
Reproducing the formulas in geonodes should be easy...