-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle Elasticsearch GeoJSON circles using interpolation #67
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution. For consistency could you update to use four spaces for indent on all new lines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks close. Some mostly minor feedback below. Thanks again for the contribution.
static { | ||
GEO_HASH_PATTERN = Pattern.compile("[0123456789bcdefghjkmnpqrstuvwxyz]+"); | ||
} | ||
|
||
private static final Pattern ELASTIC_DISTANCE_PATTERN = Pattern.compile("([0-9]+(\\.[0-9]+)?)([a-zA-Z]+)"); | ||
|
||
private final GeodeticCalculator geodeticCalculator = new GeodeticCalculator(DefaultEllipsoid.WGS84); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move geodeticCalculator
initialization to constructor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
case "CIRCLE": { | ||
final List posList; | ||
posList = (List) properties.get("coordinates"); | ||
String radius = (String) properties.get("radius"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assume 'final' means that this is OK?
*/ | ||
private Geometry createCircle(Coordinate centreCoord, String radius) { | ||
|
||
String[] distanceAndUnitStrings = getDistanceAndUnitStrings(radius); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final
here and below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
private Geometry createCircle(Coordinate centreCoord, String radius) { | ||
|
||
String[] distanceAndUnitStrings = getDistanceAndUnitStrings(radius); | ||
double radM = FilterToElasticHelper.convertToMeters(Double.valueOf(distanceAndUnitStrings[0]), distanceAndUnitStrings[1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Split into two lines to keep line length under 120
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed variable to keep on one line
// Interpolate a circle on the surface of the ellipsoid such that the | ||
// distance between interpolated point does not exceed (somewhat | ||
// arbitrarily) 500m with the caveats that a circle must have a minimum | ||
// of 40 points and a maximum of 500. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally do you think the 500m and [40,500] values would be store parameters? If so would you create a separate issue to track that? Don't have to make the update here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that they should be 'store parameters' (not too sure what they are but I'm sure all will become clear if I put the effort in). Not sure if I should create a separate issue when the code I'm submitting has not been merged into the master branch?
*/ | ||
private Geometry createCircle(Coordinate centreCoord, String radius) { | ||
|
||
String[] distanceAndUnitStrings = getDistanceAndUnitStrings(radius); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If radius is invalid ({"",""}
result or exception) geometry should be null
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, done.
assertEquals("mm", distanceAndUnitStrings[1]); | ||
distanceAndUnitStrings = ElasticParserUtil.getDistanceAndUnitStrings("999xyz"); | ||
assertEquals("999", distanceAndUnitStrings[0]); | ||
assertEquals("xyz", distanceAndUnitStrings[1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add test for no unit. Also add test for invalid value/unit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
public static double convertToMeters(double distance, String unit) { | ||
Double conversion = UNITS_MAP.get(unit); | ||
if (conversion == null) { | ||
conversion = new Double(1.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think return of null
would be better for invalid unit and it keeps it in line with previous behavior in toMeters
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On reflection I think I should revert to original to Meters() method and usage (and remove introduced methods) so functionality remains as you expect and I will create a private method in ElasticParserUtil for use when handling circles. Only change would be to make extended UNITS_MAP package private for reuse in ElasticParserUtil. Please ignore latest push, another soon to follow.
delegate.queryBuilder = ImmutableMap.of("bool", ImmutableMap.of("must_not", delegate.queryBuilder)); | ||
} | ||
} | ||
|
||
public static double convertToMeters(double distance, String unit) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add javadoc for public method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n/a as method being removed
static { | ||
GEO_HASH_PATTERN = Pattern.compile("[0123456789bcdefghjkmnpqrstuvwxyz]+"); | ||
} | ||
|
||
private static final Pattern ELASTIC_DISTANCE_PATTERN = Pattern.compile("([0-9]+(\\.[0-9]+)?)([a-zA-Z]+)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs suggest units are optional but pattern looks like it's required. Can you add a test for the missing/default unit case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates and additional tests. A few more minor comments below. The project follows the Sun Coding Conventions for consistency with GeoServer (see here) and the code style update requests below are based on those conventions.
private static final int MIN_CIRCLE_POINTS = 40; | ||
private static final double MIN_CIRCLE_RADIUS_M = 0.001; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove extra line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
case "CIRCLE": { | ||
final List posList; | ||
posList = (List) properties.get("coordinates"); | ||
String radius = (String) properties.get("radius"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add final
modifier (e.g. final String radius = ...
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return null; | ||
} | ||
|
||
double radM; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use final
modifier (final double radM
). Same comment on all variable declarations in this code block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
|
||
// Reject circles with radii below an arbitrary minimum. | ||
if(radM < MIN_CIRCLE_RADIUS_M) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add space (e.g. if (radM...
) for consistency with style in file/project. Same comment on other if
statements below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
throw new IllegalArgumentException(); | ||
} | ||
Matcher matcher = ELASTIC_DISTANCE_PATTERN.matcher(distanceWithUnit); | ||
double distance; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can declare and initialize distance
on one line below (e.g. final double distance = Double...
). Same comment for unit
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (unit != null && ! unit.isEmpty()) { | ||
throw new IllegalArgumentException("Illegal unit: " + unit); | ||
} | ||
else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One line } else {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
return distance * conversion; | ||
} else { | ||
throw new IllegalArgumentException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add message
|
||
private static final long serialVersionUID = 1L; | ||
|
||
{ | ||
// Metric |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix indentation on comment (here and for // Other
below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
public Geometry createGeometry(final Map<String, Object> properties) { | ||
final Geometry geometry; | ||
switch (String.valueOf(properties.get("type")).toUpperCase()) { | ||
case "POINT": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep case statement aligned with switch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thanks for your patience on the review. Could you squash your commits for merge?
…interpolation with a great circle line radius.
I think the squashing has worked OK but as it's the first time I have done it and there was an issue when pushing to 'origin' (had to redo and put a '+' in front of the branch name to get it to work) you might like to check. |
Proposed code to be able to render Elasticsearch GeoJSON circle geometry in GeoServer. The interpolation angular interval is varied according to the circumference of the circle (in ellipsoid surface units as opposed to pixels) and kept between upper and lower bounds.
An example output of NOTAMs over Cyprus is shown below. Note that the circles are displayed as 'sort-of' ellipses due to the latitude.