Ticket #13385: 13385.patch

File 13385.patch, 5.8 KB (added by GerdP, 8 years ago)
  • src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

     
    108108        private MapViewPoint prev;
    109109        /* 'prev0' is a point that has distance 'offset' from 'prev' and the
    110110         * line from 'prev' to 'prev0' is perpendicular to the way segment from
    111          * 'prev' to the next point.
     111         * 'prev' to the current point.
    112112         */
    113113        private double xPrev0;
    114114        private double yPrev0;
     
    136136                return current;
    137137            }
    138138
     139            double xCurrent = current.getInViewX();
     140            double yCurrent = current.getInViewY();
    139141            if (idx == nodes.size() - 1) {
    140142                ++idx;
    141143                if (prev != null) {
    142                     return mapState.getForView(xPrev0 + current.getInViewX() - prev.getInViewX(),
    143                                                yPrev0 + current.getInViewY() - prev.getInViewY());
     144                    return mapState.getForView(xPrev0 + xCurrent - prev.getInViewX(),
     145                                               yPrev0 + yCurrent - prev.getInViewY());
    144146                } else {
    145147                    return current;
    146148                }
     
    147149            }
    148150
    149151            MapViewPoint next = getForIndex(idx + 1);
    150 
    151             double dxNext = next.getInViewX() - current.getInViewX();
    152             double dyNext = next.getInViewY() - current.getInViewY();
     152            double dxNext = next.getInViewX() - xCurrent;
     153            double dyNext = next.getInViewY() - yCurrent;
    153154            double lenNext = Math.sqrt(dxNext*dxNext + dyNext*dyNext);
    154155
    155             if (lenNext < 1e-3) {
     156            if (lenNext < 1e-11) {
    156157                lenNext = 1; // value does not matter, because dy_next and dx_next is 0
    157158            }
    158159
    159             double xCurrent0 = current.getInViewX() + offset * dyNext / lenNext;
    160             double yCurrent0 = current.getInViewY() - offset * dxNext / lenNext;
     160            // calculate the position of the translated current point
     161            double om = offset / lenNext;
     162            double xCurrent0 = xCurrent + om * dyNext;
     163            double yCurrent0 = yCurrent - om * dxNext;
    161164
    162165            if (idx == 0) {
    163166                ++idx;
     
    166169                yPrev0 = yCurrent0;
    167170                return mapState.getForView(xCurrent0, yCurrent0);
    168171            } else {
    169                 double dxPrev = current.getInViewX() - prev.getInViewX();
    170                 double dyPrev = current.getInViewY() - prev.getInViewY();
    171 
     172                double dxPrev = xCurrent - prev.getInViewX();
     173                double dyPrev = yCurrent - prev.getInViewY();
    172174                // determine intersection of the lines parallel to the two segments
    173175                double det = dxNext*dyPrev - dxPrev*dyNext;
     176                double m = dxNext*(yCurrent0 - yPrev0) - dyNext*(xCurrent0 - xPrev0);
    174177
    175                 if (Utils.equalsEpsilon(det, 0)) {
     178                if (Utils.equalsEpsilon(det, 0) || Math.signum(det) != Math.signum(m)) {
    176179                    ++idx;
    177180                    prev = current;
    178181                    xPrev0 = xCurrent0;
     
    180183                    return mapState.getForView(xCurrent0, yCurrent0);
    181184                }
    182185
    183                 double m = dxNext*(yCurrent0 - yPrev0) - dyNext*(xCurrent0 - xPrev0);
     186                double f = m / det;
     187                if (f < 0) {
     188                    ++idx;
     189                    prev = current;
     190                    xPrev0 = xCurrent0;
     191                    yPrev0 = yCurrent0;
     192                    return mapState.getForView(xCurrent0, yCurrent0);
     193                }
     194                // the position of the intersection or intermittent point
     195                double cx = xPrev0 + f * dxPrev;
     196                double cy = yPrev0 + f * dyPrev;
    184197
    185                 double cx = xPrev0 + m * dxPrev / det;
    186                 double cy = yPrev0 + m * dyPrev / det;
     198                if (f > 1) {
     199                    // check if the intersection point is too far away, this will happen for sharp angles
     200                    double dxI = cx - xCurrent;
     201                    double dyI = cy - yCurrent;
     202                    double lenISq = dxI * dxI + dyI * dyI;
     203
     204                    if (lenISq > Math.abs(2 * offset * offset)) {
     205                        // intersection point is too far away, calculate intermittent points for capping
     206                        double dxPrev0 = xCurrent0 - xPrev0;
     207                        double dyPrev0 = yCurrent0 - yPrev0;
     208                        double lenPrev0 = Math.sqrt(dxPrev0 * dxPrev0 + dyPrev0 * dyPrev0);
     209                        f = 1 + Math.abs(offset / lenPrev0);
     210                        double cxCap = xPrev0 + f * dxPrev;
     211                        double cyCap = yPrev0 + f * dyPrev;
     212                        xPrev0 = cxCap;
     213                        yPrev0 = cyCap;
     214                        // calculate a virtual prev point which lies on a line that goes through current and
     215                        // is perpendicular to the line that goes through current and the intersection
     216                        // so that the next capping point is calculated with it.
     217                        double lenI = Math.sqrt(lenISq);
     218                        double xv = xCurrent + dyI / lenI;
     219                        double yv = yCurrent - dxI / lenI;
     220
     221                        prev = mapState.getForView(xv, yv);
     222                        return mapState.getForView(cxCap, cyCap);
     223                    }
     224                }
    187225                ++idx;
    188226                prev = current;
    189227                xPrev0 = xCurrent0;