Skip to content
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

Allow GeoJSONWriter to force polygons to be CCW #694

Merged
merged 16 commits into from
Feb 25, 2021
Merged

Allow GeoJSONWriter to force polygons to be CCW #694

merged 16 commits into from
Feb 25, 2021

Conversation

ruibritopt
Copy link
Contributor

A best-effort PR to enforce the right hand rule for polygon ring orientation in the latest GeoJson specification and discussed in issue #681

Signed-off-by: Rui Brito ruibritopt@gmail.com

@dr-jts
Copy link
Contributor

dr-jts commented Feb 16, 2021

I would prefer to not bake this into the GeoJSONWriter. Instead could create a ForceRHR function to process each geometry beforehand?

@ruibritopt
Copy link
Contributor Author

ruibritopt commented Feb 16, 2021

@dr-jts That is a valid point. If I understand your comment correctly, we would end up with a function like public static Geometry forceHRH(Geometry geometry) { ... }.
Would this function have to be called by the library clients before invoking write or would we extend the write function as well? Like eg: public String write(Geometry geometry, Boolean forceRHR) { ... }

@dr-jts
Copy link
Contributor

dr-jts commented Feb 17, 2021

Actually it will be more efficient if the orientation is modified on a per-ring basis in the writer. In this case, it would be best to not change the current behaviour. So an option can be added to the GeoJSONWriter (called say setForceRHR) which will check and reorient polygon rings as required. The option can be disabled by default.

…e logic

Signed-off-by: Rui Brito <ruibritopt@gmail.com>
…ransformation functions

Signed-off-by: Rui Brito <ruibritopt@gmail.com>
…rays so I switched to use list

Signed-off-by: Rui Brito <ruibritopt@gmail.com>
@ruibritopt
Copy link
Contributor Author

@dr-jts I extended the GeoJsonWriter class to have an attribute isRHREnforced, very similar to how the isEncodeCRS is set up. If I understood you correctly this was your recommendation.
The reason why the transformation function are outside the GeoJsonWriter class is because I believe the same logic could be used on the GeoJsonReader side, for the clients that would like to store geometries under the specification.

Please let me know what you think. I'm willing to make any changes necessary. Also, if the idea of implementing the same logic on the reader side is appealing, let me know and I will make another PR. Thank you


final LinearRing rightHandRuleRing;
if (isExteriorRing) {
rightHandRuleRing = isRingClockWise? ring.reverse() : ring;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to copy the ring if it is unchanged, to avoid aliasing errors

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the change I made resolves this concern.

if (isExteriorRing) {
rightHandRuleRing = isRingClockWise? ring.reverse() : ring;
} else {
rightHandRuleRing = isRingClockWise? ring : ring.reverse();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy here too

import java.util.ArrayList;
import java.util.List;

public class TransformationUtils {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about calling this OrientationTransformer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed this recommendation 👍

* @param geometry to be transformed
* @return Geometry under the Right Hand Rule specifications
*/
public static Geometry enforceRightHandRuleOrientation(final Geometry geometry) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just call this transformRightHandRule.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed this recommendation 👍

@dr-jts
Copy link
Contributor

dr-jts commented Feb 17, 2021

@dr-jts I extended the GeoJsonWriter class to have an attribute isRHREnforced, very similar to how the isEncodeCRS is set up. If I understood you correctly this was your recommendation.

Yes, that looks good.

The reason why the transformation function are outside the GeoJsonWriter class is because I believe the same logic could be used on the GeoJsonReader side, for the clients that would like to store geometries under the specification.

It's good to have the RHR conversion factored out. But I don't think it's necessary to bake it into GeoJSONReader. Clients can simply transform geometries if they want to after reading them.

@dbaston
Copy link
Contributor

dbaston commented Feb 17, 2021

Maybe consider avoiding the term RHR, since it is used by other software such as PostGIS to mean the opposite of what it means here.

@dr-jts
Copy link
Contributor

dr-jts commented Feb 17, 2021

Maybe consider avoiding the term RHR, since it is used by other software such as PostGIS to mean the opposite of what it means here.

This is a good point. To be fair, the GeoJSON spec uses the term "right-hand rule", and defines that to mean "shell is CCW". That seems to be the most commonly accepted definition of RHR. The PostGIS usage is opposite, and is deprecated (discussion here). (SQL Server seems to have the same problem).

But it's good to avoid stepping into that minefield. Also, two important design criteria for an API are consistency and parsimony of terminology. The term "CCW" is already used for this concept in JTS, and it is unambiguous. So this PR should change to using that acronym. So use isEnforceCCW, setEnforceCCW, transformCCW, etc.

The GeoJSONWriter Javadoc can point out that in the GeoJSON context "right-hand rule" = CCW.

…to CCW

Signed-off-by: Rui Brito <ruibritopt@gmail.com>
Signed-off-by: Rui Brito <ruibritopt@gmail.com>
@ruibritopt
Copy link
Contributor Author

ruibritopt commented Feb 18, 2021

Thank you @dr-jts @dbaston. I've implemented your suggestions. Please let me know if it fits your views.

@dr-jts dr-jts changed the title [Enhancement] [jts-io] Enforce right hand rule when writing GeoJSON Allow GeoJSONWriter to force polygons to be CCW Feb 18, 2021
@@ -88,6 +89,16 @@ public void setEncodeCRS(boolean isEncodeCRS) {
this.isEncodeCRS = isEncodeCRS;
}

/**
* Sets whether the GeoJSON should be output following counter-clocked orientation aka Right Hand Rule defined in RFC7946
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be "counter-clockwise".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silly mistake, thank you for spotting it.

import java.util.ArrayList;
import java.util.List;

public class OrientationTransformer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add class Javadoc. Can be something simple like

Utilities to modify the ring orientation of polygonal geometries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took your recommendation verbatim

@dr-jts
Copy link
Contributor

dr-jts commented Feb 18, 2021

Looking good. Just a couple of small things to fix, and it will be good to merge.

Signed-off-by: Rui Brito <ruibritopt@gmail.com>
*
* @param enforceCCW true if the GeoJSON should be output following the RFC7946 counter-clockwise orientation aka Right Hand Rule
*/
public void setEnforceCCW(boolean enforceCCW) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One final request. In the interest of brevity, can this be changed to setForceCCW and isForceCCW?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done and done. Don't hold back on the requests, they have all been on the money and I'm a big fan of things done right 😄👍👍

@dr-jts dr-jts merged commit 279ab3c into locationtech:master Feb 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants