Modify

Opened 6 years ago

Closed 6 years ago

#17131 closed enhancement (fixed)

[Patch] mapcss should have the ability to get the distance to a gpx track

Reported by: taylor.smock Owned by: team
Priority: normal Milestone: 19.02
Component: Core validator Version: latest
Keywords: mapcss Cc:

Description

way[highway][!surface][gpx_distance() < 30] {
    throwError: tr("A highway doesn't have a surface type");
}

Change History (19)

by taylor.smock, 6 years ago

Attachment: gpx_distance.patch added

Possible implementation

comment:1 by Don-vip, 6 years ago

Milestone: 18.12
Summary: mapcss should have the ability to get the distance to a gpx track[Patch] mapcss should have the ability to get the distance to a gpx track

Thanks for the patch!
Some things to do to include it:

  • please run ant pmd checkstyle and fix all reported issues
  • The methods should be static, there's no need to instantiate an object just to get a list of current layers
  • you can use LayerManager.getLayersOfType(GpxLayer.class)
  • the code must be robust to incomplete primitives (for example: a node without coordinate will throw an NPE here)
  • you don't use any method of org.openstreetmap.josm.tools.Geometry, I'm sure there are distance methods there you should use rather than make the calculation in GpxDistance

comment:2 by taylor.smock, 6 years ago

I think I managed to get the methods to be static, I switched to using LayerManager (but in an odd way due to switching to static methods -- I don't know if it will work), I made the code a bit more robust for incomplete primitives.

As far as org.openstreetmap.josm.tools.Geometry, I didn't see any distance methods in it. I should probably look at moving many (or all) of the methods in GpxDistance to Geometry.

As far as ant pmd checkstyle goes, I couldn't run it. This is probably due to a hardcoded path somewhere in build.xml for ant. I fixed it with ln -s "$(which ant)" /usr/local/share/ant, and the patch no longer has warnings from it.

iMacs-iMac-6:core tsmock$ ant pmd checkstyle
Buildfile: /Users/tsmock/workspace/josm/core/build.xml

init-properties:

pmd:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by net.sourceforge.pmd.ant.Formatter (file:/Users/tsmock/workspace/josm/core/tools/pmd/pmd-core-6.6.0.jar) to field java.io.Console.cs
WARNING: Please consider reporting this to the maintainers of net.sourceforge.pmd.ant.Formatter
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Analysis cache invalidated, rulesets changed.
Incremental analysis can't check execution classpath contents
java.nio.file.NoSuchFileException: /usr/local/share/ant
<TRIMMED>
iMacs-iMac-6:core tsmock$ which ant
/usr/local/bin/ant
Last edited 6 years ago by taylor.smock (previous) (diff)

by taylor.smock, 6 years ago

Attachment: gpx_distance_v2.patch added

Patch after feedback (ant pmd checkstyle NOT run)

comment:3 by Don-vip, 6 years ago

Thanks. In getDistanceWay you should call LatLon.greatCircleDistance instead of the complex calculation. Otherwise looks fine.

comment:4 by taylor.smock, 6 years ago

I'm not certain how to use LatLon.greatCircleDistance to get the distance between a point and a way. It only takes a latlon, right?

So I would do something like this:

                double tdistance = ((coords.getX() - first.getX()) * (second.getX() - first.getX()) + (coords.getY() - first.getY()) * (second.getY() - first.getY()))
                        / (Math.pow(second.getX() - first.getX(), 2) + Math.pow(second.getY() - first.getY(), 2));
                double x = first.getX() + tdistance * (second.getX() - first.getX());
                double y = first.getY() + tdistance * (second.getY() - first.getY());
                LatLon npoint = new LatLon(y, x);
                distance = npoint.greatCircleDistance(coords);

instead of

                distance = Math.abs((second.getY() - first.getY()) * coords.getX() - (second.getX() - first.getX()) * coords.getY()
                        + second.getX() * first.getY() - second.getY() - first.getX()) /
                        Math.sqrt(Math.pow(second.getY() - first.getY(), 2) + Math.pow(second.getX() - first.getX(), 2));

In my local copy, I did modify getDistanceLatLon to use LatLon.greatCircleDistance, since that makes more sense than LatLon.distance for OpenStreetMap.

by taylor.smock, 6 years ago

Attachment: gpx_distance_v3.patch added

Modified to use greatCircleDistance where possible and ant pmd checkstyle has been run

comment:5 by Don-vip, 6 years ago

I think you could still replace this calculation by a call to Geometry.closestPointToSegment:

    /**
     * Calculates closest point to a line segment.
     * @param segmentP1 First point determining line segment
     * @param segmentP2 Second point determining line segment
     * @param point Point for which a closest point is searched on line segment [P1,P2]
     * @return segmentP1 if it is the closest point, segmentP2 if it is the closest point,
     * a new point if closest point is between segmentP1 and segmentP2.
     * @see #closestPointToLine
     * @since 3650
     */
    public static EastNorth closestPointToSegment(EastNorth segmentP1, EastNorth segmentP2, EastNorth point)

comment:6 by Don-vip, 6 years ago

Milestone: 18.1219.01

by taylor.smock, 6 years ago

Attachment: gpx_distance_v4.patch added

Now uses Geometry.closestPointToSegment for getting the shortest distance from a point to a way.

comment:7 by Don-vip, 6 years ago

OK we're almost there :) Be careful with calling getCoor() method on the same object, several times. It will create a new LatLon instance at each call and thus the code will be memory-hungry, this must be avoided in rendering code by making sure the method is called only once per object:

                    EastNorth first = new EastNorth(way.getNode(i).getCoor().getX(),
                            way.getNode(i).getCoor().getY()); // <--
                    EastNorth second = new EastNorth(way.getNode(i+1).getCoor().getX(),
                            way.getNode(i+1).getCoor().getY()); // <--
                    if (first.isValid() && second.isValid()) {
                        EastNorth closestPoint = Geometry.closestPointToSegment(first, second, enwaypoint);
                        distance = closestPoint.distance(waypoint.getCoor().getX(), waypoint.getCoor().getY()); // <--

Also, please add a @since xxx in javadoc of new public class GpxDistance and new public method ExpressionFactory.gpx_distance. And then we're done :)

by taylor.smock, 6 years ago

Attachment: gpx_distance_v5.patch added

Add @since xxx to javadocs and make calls to getCoor() once per object

by taylor.smock, 6 years ago

Attachment: GpxDistance_v6.patch added

Add tests and fix some bugs that were exposed

by taylor.smock, 6 years ago

Attachment: GpxDistance_v6.2.patch added

Fix some issues I noticed during testing and start work on method for GeoImage layers

by taylor.smock, 6 years ago

Attachment: GpxDistance_v7.patch added

Creates a new gpxdata object from image gps points where it is not already associated with a gpx track

comment:8 by Don-vip, 6 years ago

Milestone: 19.0119.02

by taylor.smock, 6 years ago

Attachment: GpxDistance_v8.patch added

Significantly improve performance by not rebuilding the same fake gpxlayer everytime -- it now stores the fake layer in the GeoImageLayer.

comment:10 by Don-vip, 6 years ago

Resolution: fixed
Status: newclosed

In 14802/josm:

fix #17131 - add mapcss function gpx_distance to get the distance to a gpx track (patch by Taylor Smock, modified)

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.