Changeset 18183 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2021-08-30T18:44:20+02:00 (3 years ago)
Author:
Don-vip
Message:

fix #21254 - fix shoe lace formula implementation (patch by taylor.smock)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/imagery/vectortile/mapbox/Geometry.java

    r17994 r18183  
    4545            Area area = null;
    4646            // MVT uses delta encoding. Each feature starts at (0, 0).
    47             double x = 0;
    48             double y = 0;
     47            int x = 0;
     48            int y = 0;
    4949            // Area is used to determine the inner/outer of a polygon
    50             double areaAreaSq = 0;
     50            final int maxArraySize = commands.stream().filter(command -> command.getType() != Command.ClosePath).mapToInt(command -> command.getOperations().length).sum();
     51            final List<Integer> xArray = new ArrayList<>(maxArraySize);
     52            final List<Integer> yArray = new ArrayList<>(maxArraySize);
    5153            for (CommandInteger command : commands) {
    5254                final short[] operations = command.getOperations();
    5355                // Technically, there is no reason why there can be multiple MoveTo operations in one command, but that is undefined behavior
    5456                if (command.getType() == Command.MoveTo && operations.length == 2) {
    55                     areaAreaSq = 0;
    5657                    x += operations[0];
    5758                    y += operations[1];
    5859                    line = new Path2D.Float();
    5960                    line.moveTo(x, y);
     61                    xArray.add(x);
     62                    yArray.add(y);
    6063                    shapes.add(line);
    6164                } else if (command.getType() == Command.LineTo && operations.length % 2 == 0 && line != null) {
    6265                    for (int i = 0; i < operations.length / 2; i++) {
    63                         final double lx = x;
    64                         final double ly = y;
    6566                        x += operations[2 * i];
    6667                        y += operations[2 * i + 1];
    67                         areaAreaSq += lx * y - x * ly;
     68                        xArray.add(x);
     69                        yArray.add(y);
    6870                        line.lineTo(x, y);
    6971                    }
     
    7779                    }
    7880
     81                    final double areaAreaSq = calculateSurveyorsArea(xArray.stream().mapToInt(i -> i).toArray(), yArray.stream().mapToInt(i -> i).toArray());
    7982                    Area nArea = new Area(line);
    8083                    // SonarLint thinks that this is never > 0. It can be.
     
    9497
    9598    /**
     99     * This is also known as the "shoelace formula".
     100     * @param xArray The array of x coordinates
     101     * @param yArray The array of y coordinates
     102     * @return The area of the object
     103     * @throws IllegalArgumentException if the array lengths are not equal
     104     */
     105    static double calculateSurveyorsArea(int[] xArray, int[] yArray) {
     106        if (xArray.length != yArray.length) {
     107            throw new IllegalArgumentException("Cannot calculate areas when arrays are uneven");
     108        }
     109        // Lines have no area
     110        if (xArray.length < 3) {
     111            return 0;
     112        }
     113        int area = 0;
     114        // Do the non-special stuff first (x0 * y1 - x1 * y0)
     115        for (int i = 0; i < xArray.length - 1; i++) {
     116            area += xArray[i] * yArray[i + 1] - xArray[i + 1] * yArray[i];
     117        }
     118        // Now calculate the edges (xn * y0 - x0 * yn)
     119        area += xArray[xArray.length - 1] * yArray[0] - xArray[0] * yArray[yArray.length - 1];
     120        return area / 2d;
     121    }
     122
     123    /**
    96124     * Get the shapes to draw this geometry with
    97125     * @return A collection of shapes
Note: See TracChangeset for help on using the changeset viewer.