Skip to content

Commit 8c94271

Browse files
authored
Merge pull request #139 from bunkenburg/issues/JPX-72-parse-location
#72: Parse location
2 parents 62e4150 + 438bf2c commit 8c94271

31 files changed

+1558
-1297
lines changed

jpx/src/main/java/io/jenetics/jpx/format/CompositeFormat.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package io.jenetics.jpx.format;
2121

22+
import java.text.ParsePosition;
2223
import java.util.List;
2324
import java.util.Objects;
2425
import java.util.Optional;
@@ -29,16 +30,15 @@
2930
* @version 1.4
3031
* @since 1.4
3132
*/
32-
final class CompositeFormat<T> implements Format<T> {
33+
class CompositeFormat implements Format {
3334

34-
private final List<Format<T>> _formats;
35+
private final List<Format> _formats;
3536

36-
private CompositeFormat(final List<Format<T>> formats) {
37+
private CompositeFormat(List<Format> formats) {
3738
_formats = List.copyOf(formats);
3839
}
3940

40-
@Override
41-
public Optional<String> format(final T value) {
41+
@Override public Optional<String> format(Location value) {
4242
final List<Optional<String>> strings = _formats.stream()
4343
.map(format -> format.format(value))
4444
.collect(Collectors.toList());
@@ -52,15 +52,18 @@ public Optional<String> format(final T value) {
5252
: Optional.empty();
5353
}
5454

55-
@Override
56-
public String toString() {
55+
@Override public void parse(CharSequence in, ParsePosition pos, LocationBuilder b) throws ParseException {
56+
for( Format f : _formats ) f.parse(in, pos, b);
57+
}
58+
59+
@Override public String toPattern() {
5760
return _formats.stream()
58-
.map(Objects::toString)
61+
.map( f -> f.toPattern() )
5962
.collect(Collectors.joining());
6063
}
6164

62-
static <T> CompositeFormat<T> of(final List<Format<T>> formats) {
63-
return new CompositeFormat<>(formats);
65+
static CompositeFormat of(List<Format> formats) {
66+
return new CompositeFormat(formats);
6467
}
6568

6669
}

jpx/src/main/java/io/jenetics/jpx/format/ConstFormat.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static java.util.Objects.requireNonNull;
2323
import static io.jenetics.jpx.format.LocationFormatter.PROTECTED_CHARS;
2424

25+
import java.text.ParsePosition;
2526
import java.util.Optional;
2627

2728
/**
@@ -31,7 +32,7 @@
3132
* @version 1.4
3233
* @since 1.4
3334
*/
34-
final class ConstFormat<T> implements Format<T> {
35+
final class ConstFormat implements Format {
3536

3637
private final String _value;
3738

@@ -45,16 +46,28 @@ private ConstFormat(final String value) {
4546
_value = requireNonNull(value);
4647
}
4748

48-
@Override
49-
public Optional<String> format(final T value) {
49+
@Override public Optional<String> format(Location value) {
5050
return Optional.of(_value);
5151
}
5252

53-
@Override
54-
public String toString() {
55-
return escape(_value);
53+
/** parse _value */
54+
@Override public void parse(CharSequence in, ParsePosition pos, LocationBuilder b) throws ParseException {
55+
int start = pos.getIndex();
56+
int end = start + _value.length();
57+
if( end <= in.length()){
58+
String s = in.subSequence(start, end).toString();
59+
if(s.equals(_value)){
60+
pos.setIndex(end);
61+
// but no call to builder
62+
return;
63+
}
64+
}
65+
pos.setErrorIndex(start);
66+
throw new ParseException("Not found constant \"" + _value + "\"", in, start);
5667
}
5768

69+
@Override public String toPattern() { return escape(_value); }
70+
5871
private static String escape(final String value) {
5972
final StringBuilder out = new StringBuilder();
6073
boolean quote = false;
@@ -74,8 +87,8 @@ private static String escape(final String value) {
7487
: out.toString();
7588
}
7689

77-
static <T> ConstFormat<T> of(final String value) {
78-
return new ConstFormat<>(value);
90+
static ConstFormat of(final String value) {
91+
return new ConstFormat(value);
7992
}
8093

8194
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package io.jenetics.jpx.format;
2+
3+
import java.text.DecimalFormat;
4+
import java.text.ParsePosition;
5+
import java.util.Optional;
6+
7+
import static io.jenetics.jpx.Length.Unit.METER;
8+
9+
/**
10+
* This field allows to access the elevation (in meter) of a given
11+
* location.
12+
*/
13+
class Elevation extends Field {
14+
15+
private boolean prefixSign = false;
16+
17+
Elevation(String pattern){super(pattern);}
18+
19+
void setPrefixSign(boolean b){
20+
prefixSign = b;
21+
String decimalPattern = toDecimalPattern(pattern);
22+
String p = b ? ("+" + decimalPattern + ";" + "-" + decimalPattern) : decimalPattern;
23+
nf = new DecimalFormat(p, symbols);
24+
}
25+
26+
char type() { return 'E'; }
27+
28+
/** parse elevation as double */
29+
@Override public void parse(CharSequence in, ParsePosition pos, LocationBuilder b) throws ParseException {
30+
double d = parseDouble(in,pos);
31+
b.setElevation(d);
32+
}
33+
34+
@Override public Optional<String> format( Location loc) {
35+
return loc.elevation()
36+
.map( l -> l.to(METER) )
37+
.map( d -> nf.format(d) );
38+
}
39+
40+
@Override public String toPattern(){ return prefixSign ? "+" + pattern : pattern; }
41+
42+
}

jpx/src/main/java/io/jenetics/jpx/format/ElevationSignFormat.java

Lines changed: 0 additions & 47 deletions
This file was deleted.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package io.jenetics.jpx.format;
2+
3+
import java.text.DecimalFormat;
4+
import java.text.DecimalFormatSymbols;
5+
import java.text.NumberFormat;
6+
import java.text.ParsePosition;
7+
import java.util.Locale;
8+
import java.util.Optional;
9+
10+
import static java.lang.Math.*;
11+
12+
/**
13+
* Represents one of the existing location fields: latitude, longitude and
14+
* elevation.
15+
*
16+
* @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
17+
* @version 1.4
18+
* @since 1.4
19+
*/
20+
abstract class Field implements Format {
21+
22+
protected final static DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.US);
23+
24+
protected NumberFormat nf;
25+
protected final String pattern;
26+
27+
protected Field(String pattern){
28+
String decimalPattern = toDecimalPattern(pattern);
29+
this.nf = new DecimalFormat(decimalPattern, symbols);
30+
this.pattern = pattern;
31+
}
32+
33+
void setPrefixSign(boolean b){}
34+
35+
abstract char type();
36+
37+
protected double toMinutes(double degrees) {
38+
double dd = abs(degrees);
39+
return (dd - floor(dd)) * 60.0;
40+
}
41+
42+
protected double toSeconds(double degrees) {
43+
double dd = abs(degrees);
44+
double d = floor(dd);
45+
double m = floor((dd - d) * 60.0);
46+
return (dd - d - m / 60.0) * 3600.0;
47+
}
48+
49+
static Optional<Field> ofPattern(String pattern) {
50+
// TODO better?
51+
for (int i = 0; i < pattern.length(); ++i) {
52+
char c = pattern.charAt(i);
53+
switch (c){
54+
case 'L': {
55+
String p = pattern.replace('L', 'D');
56+
return Optional.of(new LatitudeDegree(p));
57+
}
58+
case 'D': return Optional.of(new LatitudeDegree(pattern));
59+
case 'M': return Optional.of(new LatitudeMinute(pattern));
60+
case 'S': return Optional.of(new LatitudeSecond(pattern));
61+
case 'l': {
62+
String p = pattern.replace('l','d');
63+
return Optional.of(new LongitudeDegree(p));
64+
}
65+
case 'd': return Optional.of(new LongitudeDegree(pattern));
66+
case 'm': return Optional.of(new LongitudeMinute(pattern));
67+
case 's': return Optional.of(new LongitudeSecond(pattern));
68+
case 'E': return Optional.of(new Elevation(pattern));
69+
case 'H': {
70+
String p = pattern.replace('H', 'E');
71+
return Optional.of(new Elevation(p));
72+
}
73+
}
74+
}
75+
return Optional.empty();
76+
}
77+
78+
protected String toDecimalPattern(String pattern) { return pattern.replace(type(), '0'); }
79+
80+
@Override public String toPattern() { return pattern; }
81+
82+
protected double parseDouble(CharSequence in, ParsePosition pos){
83+
int i = pos.getIndex();
84+
String s = in.toString();
85+
boolean strictWidth = 1 < nf.getMinimumIntegerDigits(); //better?
86+
if(strictWidth) {
87+
int end = i + toPattern().length(); // toPattern() rather than pattern because LatitudeDegree.toPattern()
88+
s = in.subSequence(0, end).toString(); // don't eat more digits
89+
}
90+
Number n = nf.parse(s, pos);//Does not throw an exception; if no object can be parsed, index is unchanged.
91+
if(i==pos.getIndex()) {
92+
pos.setErrorIndex(i);
93+
throw new ParseException("Not found " + pattern, in, i);
94+
}
95+
double d = n.doubleValue();
96+
return d;
97+
}
98+
}

jpx/src/main/java/io/jenetics/jpx/format/Format.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,25 @@
1919
*/
2020
package io.jenetics.jpx.format;
2121

22+
import java.text.ParsePosition;
2223
import java.util.Optional;
2324

24-
/**
25-
* Base interface for formatting (converting) a given type to it's string
26-
* representation.
25+
/** Base interface for formatting and parsing a location.
2726
*
2827
* @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
2928
* @version 1.4
30-
* @since 1.4
31-
*/
32-
interface Format<T> {
29+
* @since 1.4 */
30+
interface Format {
3331

34-
/**
35-
* Formats the given {@code value} to it's string representation. If it is
32+
/** Formats the given {@code value} to its string representation. If it is
3633
* not possible to convert the {@code value} to a string,
3734
* {@link Optional#empty()} is returned.
38-
*
3935
* @param value the value which is converted to a string.
4036
* @return the converted value, or {@link Optional#empty()} if the format
41-
* fails
42-
*/
43-
Optional<String> format(final T value);
37+
* fails */
38+
Optional<String> format(Location value);
39+
40+
void parse(CharSequence in, ParsePosition pos, LocationBuilder b) throws ParseException;
4441

42+
String toPattern();
4543
}

0 commit comments

Comments
 (0)