Ignore:
Timestamp:
2013-02-13T19:12:38+01:00 (11 years ago)
Author:
akks
Message:

see #8416. GpxLayer refactoring: inner classes goes to org.openstreetmap.josm.gui.layer.gpx
Any change of behavior is a bug!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java

    r5681 r5715  
    77import java.util.LinkedList;
    88import java.util.Map;
     9import org.openstreetmap.josm.Main;
    910
    1011import org.openstreetmap.josm.data.Bounds;
     12import org.openstreetmap.josm.data.coor.EastNorth;
    1113
    1214/**
     
    122124        return result;
    123125    }
     126   
     127     /**
     128     * Makes a WayPoint at the projection of point P onto the track providing P is less than
     129     * tolerance away from the track
     130     *
     131     * @param P : the point to determine the projection for
     132     * @param tolerance : must be no further than this from the track
     133     * @return the closest point on the track to P, which may be the first or last point if off the
     134     * end of a segment, or may be null if nothing close enough
     135     */
     136    public WayPoint nearestPointOnTrack(EastNorth P, double tolerance) {
     137        /*
     138         * assume the coordinates of P are xp,yp, and those of a section of track between two
     139         * trackpoints are R=xr,yr and S=xs,ys. Let N be the projected point.
     140         *
     141         * The equation of RS is Ax + By + C = 0 where A = ys - yr B = xr - xs C = - Axr - Byr
     142         *
     143         * Also, note that the distance RS^2 is A^2 + B^2
     144         *
     145         * If RS^2 == 0.0 ignore the degenerate section of track
     146         *
     147         * PN^2 = (Axp + Byp + C)^2 / RS^2 that is the distance from P to the line
     148         *
     149         * so if PN^2 is less than PNmin^2 (initialized to tolerance) we can reject the line;
     150         * otherwise... determine if the projected poijnt lies within the bounds of the line: PR^2 -
     151         * PN^2 <= RS^2 and PS^2 - PN^2 <= RS^2
     152         *
     153         * where PR^2 = (xp - xr)^2 + (yp-yr)^2 and PS^2 = (xp - xs)^2 + (yp-ys)^2
     154         *
     155         * If so, calculate N as xn = xr + (RN/RS) B yn = y1 + (RN/RS) A
     156         *
     157         * where RN = sqrt(PR^2 - PN^2)
     158         */
     159
     160        double PNminsq = tolerance * tolerance;
     161        EastNorth bestEN = null;
     162        double bestTime = 0.0;
     163        double px = P.east();
     164        double py = P.north();
     165        double rx = 0.0, ry = 0.0, sx, sy, x, y;
     166        if (tracks == null)
     167            return null;
     168        for (GpxTrack track : tracks) {
     169            for (GpxTrackSegment seg : track.getSegments()) {
     170                WayPoint R = null;
     171                for (WayPoint S : seg.getWayPoints()) {
     172                    EastNorth c = S.getEastNorth();
     173                    if (R == null) {
     174                        R = S;
     175                        rx = c.east();
     176                        ry = c.north();
     177                        x = px - rx;
     178                        y = py - ry;
     179                        double PRsq = x * x + y * y;
     180                        if (PRsq < PNminsq) {
     181                            PNminsq = PRsq;
     182                            bestEN = c;
     183                            bestTime = R.time;
     184                        }
     185                    } else {
     186                        sx = c.east();
     187                        sy = c.north();
     188                        double A = sy - ry;
     189                        double B = rx - sx;
     190                        double C = -A * rx - B * ry;
     191                        double RSsq = A * A + B * B;
     192                        if (RSsq == 0.0) {
     193                            continue;
     194                        }
     195                        double PNsq = A * px + B * py + C;
     196                        PNsq = PNsq * PNsq / RSsq;
     197                        if (PNsq < PNminsq) {
     198                            x = px - rx;
     199                            y = py - ry;
     200                            double PRsq = x * x + y * y;
     201                            x = px - sx;
     202                            y = py - sy;
     203                            double PSsq = x * x + y * y;
     204                            if (PRsq - PNsq <= RSsq && PSsq - PNsq <= RSsq) {
     205                                double RNoverRS = Math.sqrt((PRsq - PNsq) / RSsq);
     206                                double nx = rx - RNoverRS * B;
     207                                double ny = ry + RNoverRS * A;
     208                                bestEN = new EastNorth(nx, ny);
     209                                bestTime = R.time + RNoverRS * (S.time - R.time);
     210                                PNminsq = PNsq;
     211                            }
     212                        }
     213                        R = S;
     214                        rx = sx;
     215                        ry = sy;
     216                    }
     217                }
     218                if (R != null) {
     219                    EastNorth c = R.getEastNorth();
     220                    /* if there is only one point in the seg, it will do this twice, but no matter */
     221                    rx = c.east();
     222                    ry = c.north();
     223                    x = px - rx;
     224                    y = py - ry;
     225                    double PRsq = x * x + y * y;
     226                    if (PRsq < PNminsq) {
     227                        PNminsq = PRsq;
     228                        bestEN = c;
     229                        bestTime = R.time;
     230                    }
     231                }
     232            }
     233        }
     234        if (bestEN == null)
     235            return null;
     236        WayPoint best = new WayPoint(Main.getProjection().eastNorth2latlon(bestEN));
     237        best.time = bestTime;
     238        return best;
     239    }
    124240}
Note: See TracChangeset for help on using the changeset viewer.