up follow livre
This commit is contained in:
parent
b4b4398bb0
commit
3a7a3849ae
12242 changed files with 2564461 additions and 6914 deletions
110
venv/lib/python3.13/site-packages/fontTools/misc/roundTools.py
Normal file
110
venv/lib/python3.13/site-packages/fontTools/misc/roundTools.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
"""
|
||||
Various round-to-integer helpers.
|
||||
"""
|
||||
|
||||
import math
|
||||
import functools
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__all__ = [
|
||||
"noRound",
|
||||
"otRound",
|
||||
"maybeRound",
|
||||
"roundFunc",
|
||||
"nearestMultipleShortestRepr",
|
||||
]
|
||||
|
||||
|
||||
def noRound(value):
|
||||
return value
|
||||
|
||||
|
||||
def otRound(value):
|
||||
"""Round float value to nearest integer towards ``+Infinity``.
|
||||
|
||||
The OpenType spec (in the section on `"normalization" of OpenType Font Variations <https://docs.microsoft.com/en-us/typography/opentype/spec/otvaroverview#coordinate-scales-and-normalization>`_)
|
||||
defines the required method for converting floating point values to
|
||||
fixed-point. In particular it specifies the following rounding strategy:
|
||||
|
||||
for fractional values of 0.5 and higher, take the next higher integer;
|
||||
for other fractional values, truncate.
|
||||
|
||||
This function rounds the floating-point value according to this strategy
|
||||
in preparation for conversion to fixed-point.
|
||||
|
||||
Args:
|
||||
value (float): The input floating-point value.
|
||||
|
||||
Returns
|
||||
float: The rounded value.
|
||||
"""
|
||||
# See this thread for how we ended up with this implementation:
|
||||
# https://github.com/fonttools/fonttools/issues/1248#issuecomment-383198166
|
||||
return int(math.floor(value + 0.5))
|
||||
|
||||
|
||||
def maybeRound(v, tolerance, round=otRound):
|
||||
rounded = round(v)
|
||||
return rounded if abs(rounded - v) <= tolerance else v
|
||||
|
||||
|
||||
def roundFunc(tolerance, round=otRound):
|
||||
if tolerance < 0:
|
||||
raise ValueError("Rounding tolerance must be positive")
|
||||
|
||||
if tolerance == 0:
|
||||
return noRound
|
||||
|
||||
if tolerance >= 0.5:
|
||||
return round
|
||||
|
||||
return functools.partial(maybeRound, tolerance=tolerance, round=round)
|
||||
|
||||
|
||||
def nearestMultipleShortestRepr(value: float, factor: float) -> str:
|
||||
"""Round to nearest multiple of factor and return shortest decimal representation.
|
||||
|
||||
This chooses the float that is closer to a multiple of the given factor while
|
||||
having the shortest decimal representation (the least number of fractional decimal
|
||||
digits).
|
||||
|
||||
For example, given the following:
|
||||
|
||||
>>> nearestMultipleShortestRepr(-0.61883544921875, 1.0/(1<<14))
|
||||
'-0.61884'
|
||||
|
||||
Useful when you need to serialize or print a fixed-point number (or multiples
|
||||
thereof, such as F2Dot14 fractions of 180 degrees in COLRv1 PaintRotate) in
|
||||
a human-readable form.
|
||||
|
||||
Args:
|
||||
value (value): The value to be rounded and serialized.
|
||||
factor (float): The value which the result is a close multiple of.
|
||||
|
||||
Returns:
|
||||
str: A compact string representation of the value.
|
||||
"""
|
||||
if not value:
|
||||
return "0.0"
|
||||
|
||||
value = otRound(value / factor) * factor
|
||||
eps = 0.5 * factor
|
||||
lo = value - eps
|
||||
hi = value + eps
|
||||
# If the range of valid choices spans an integer, return the integer.
|
||||
if int(lo) != int(hi):
|
||||
return str(float(round(value)))
|
||||
|
||||
fmt = "%.8f"
|
||||
lo = fmt % lo
|
||||
hi = fmt % hi
|
||||
assert len(lo) == len(hi) and lo != hi
|
||||
for i in range(len(lo)):
|
||||
if lo[i] != hi[i]:
|
||||
break
|
||||
period = lo.find(".")
|
||||
assert period < i
|
||||
fmt = "%%.%df" % (i - period)
|
||||
return fmt % value
|
||||
Loading…
Add table
Add a link
Reference in a new issue