1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.geojson.converter.serialization;
18
19 import static java.util.Collections.unmodifiableList;
20 import static java.util.Objects.nonNull;
21
22 import java.io.Serial;
23 import java.io.Serializable;
24 import java.math.BigDecimal;
25 import java.math.RoundingMode;
26 import java.text.NumberFormat;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.regex.Pattern;
31 import org.locationtech.jts.geom.Coordinate;
32
33
34
35
36
37
38 class CoordinateToListConverter implements Serializable {
39
40 @Serial
41 private static final long serialVersionUID = 1L;
42
43 private static final int MAXIMUM_INTEGER_DIGITS = 17;
44
45 private static final int MAXIMUM_FRACTION_DIGITS = 9;
46
47 private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
48
49 private static final NumberFormat TEST_NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
50
51 static {
52 NUMBER_FORMAT.setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
53 NUMBER_FORMAT.setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
54 NUMBER_FORMAT.setRoundingMode(RoundingMode.HALF_UP);
55 NUMBER_FORMAT.setGroupingUsed(false);
56
57 TEST_NUMBER_FORMAT.setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS + 1);
58 TEST_NUMBER_FORMAT.setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS + 1);
59 TEST_NUMBER_FORMAT.setRoundingMode(RoundingMode.HALF_UP);
60 TEST_NUMBER_FORMAT.setGroupingUsed(false);
61 }
62
63 private final boolean useBigDecimal;
64
65
66
67
68
69
70 CoordinateToListConverter(boolean useBigDecimal) {
71 this.useBigDecimal = useBigDecimal;
72 }
73
74
75
76
77
78
79
80 List<Number> convert(Coordinate source) {
81 int size = nonNull(source) ? 2 : 0;
82 List<Number> list = new ArrayList<>(size);
83 if (size > 0) {
84 Number x = round(source.getX());
85 Number y = round(source.getY());
86 if (nonNull(x) && nonNull(y)) {
87 list.add(x);
88 list.add(y);
89 }
90 }
91 return unmodifiableList(list);
92 }
93
94 private Number round(double value) {
95 if (Double.isNaN(value)) {
96 return null;
97 }
98 if (formatValue(value)) {
99 String strValue = NUMBER_FORMAT.format(value);
100 return useBigDecimal ? new BigDecimal(strValue) : new BigDecimal(strValue).doubleValue();
101 }
102 return useBigDecimal ? BigDecimal.valueOf(value) : value;
103 }
104
105 private boolean formatValue(final double value) {
106 String[] testValues = TEST_NUMBER_FORMAT.format(value).split(Pattern.quote("."));
107 return testValues[0].length() > MAXIMUM_INTEGER_DIGITS
108 || (testValues.length > 1 && testValues[1].length() > MAXIMUM_FRACTION_DIGITS);
109 }
110
111 }