Millimeters and arcminutes
The unit vocabulary of layoutc, a codec for paintball field layouts, is one enum:
class Unit(enum.IntEnum):
"""Spatial units conversion factors."""
UNIT, METER, DEGREE, TURN = 1, 1000, 60, 21600Lengths are stored in millimeters; angles in arcminutes. METER = 1000 and DEGREE = 60 convert those scales, while TURN = 21600 records 360 degrees times 60 arcminutes. A stored length of 45720 represents 45.72 meters. The values carry no dimensional type, so the caller must know which scale a channel uses.
Conversion is spelled with the matrix-multiply operator:
def __matmul__(self, /, *scales:Unit):
"""Scale the entity to the specified units."""
...
scale = a / b
match a, b:
case (Unit.METER, _) | (_, Unit.METER):
self = self._replace(x=self.x * scale, y=self.y * scale)
case (Unit.DEGREE, _) | (_, Unit.DEGREE):
self = self._replace(z=self.z * scale)So entity @ Unit.METER reads as “this entity, scaled to meters,” and the length and angle channels scale independently—@ Unit.METER touches x and y, @ Unit.DEGREE touches z.
scale = a / b uses floating-point division, with explicit rounding to control the converted precision. Only two enum members trigger conversion. The match handles pairs containing METER or DEGREE, so entity @ Unit.TURN returns the entity unchanged. TURN is the integral full-circle constant used by the folding and modulo code. The enum’s narrower contribution is keeping those scale definitions centralized and free of hand-copied constants.
Two gotchas. First, @ primes readers for matrix multiplication; here it is unit application, and nothing but the docstring says so. Second, the members are conversion factors rather than tags—DEGREE is not “this value is in degrees” but “arcminutes per degree,” and misreading it the first way makes the enum look off by a factor of 60. Both are the price of a unit table that fits in one line.