Opened 5 years ago
Closed 3 years ago
#868 closed enhancement (fixed)
Feature request: improve WKTWriter::writeNumber
Reported by: | Mike Taves | Owned by: | strk |
---|---|---|---|
Priority: | major | Milestone: | GEOS Fund Me |
Component: | Core | Version: | main |
Severity: | Feature Request | Keywords: | |
Cc: |
Description
Numpy recently switched their default floating precision formatter to use a Dragon4 algorithm by Ryan Juckett to print floating point numbers with the shortest decimal representation. This feature request is to use Ryan's library (or similar) for WKTWriter, and implement it for the private WKTWriter::writeNumber
, replacing std::fixed
and std::setprecision
.
There are probably a few ways that such a library could be adapted to better format coordinate data, using WKTWriter's existing setRoundingPrecision and trim options. For instance PrintFloatFormat_Positional
can be used to always format numbers in positional notation, which I think is the preferred format for coordinates if setRoundingPrecision>-1 is specified. Also if trim=True and setRoundingPrecision=-1 are set, then the shortest representation which uniquely identifies the floating-point number can be used.
See numpy's format_float_positional see how they implemented their interface.
To see how this matters with shapely and numpy 1.14.2, see this demo (adapted from Shapely issue#586):
import numpy as np from shapely.wkt import dumps from shapely.geometry import Point p = Point(527626.93, 0.00) # Using GEOS' WKTWriter -- takes up more space than is necessary print(p.wkt) # POINT (527626.9300000001 0) # not sure what's going on here.. print(dumps(p, trim=True, rounding_precision=4)) # POINT (5.276e+005 0) # Numpy's Dragon4 decimal formatter pa = np.array(p) print(np.format_float_positional(pa[0])) # 527626.93 # show that the binary representation is the same: print(np.float64('527626.9300000001').tostring()) print(np.float64('527626.93').tostring()) # both show '\xc3\xf5(\xdc\x15\x1a A' # getting fancy -- this should be the default output with trim=True print('POINT (' + ' '.join([np.format_float_positional(x, trim='-') for x in pa]) + ')') # POINT (527626.93 0)
Probably a better double -> string library is Google's double-conversion a.k.a. libdouble-conversion-dev, as it is in widespread use (e.g. V8, Firefox, etc.). Examples are in (e.g.) test/cctest/test-conversions.cc