// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.turnlanes.gui; import java.awt.geom.PathIterator; import java.util.Arrays; /** * Path iterator which reverses the path of a given iterator. * * <p> * The given (unreversed) iterator must start with a {@code PathIterator.SEG_MOVETO} and must not * contain any {@code PathIterator.SEG_CLOSE}. This class is intended for use with iterators * returned by {@code Path.getIterator} which has exactly those properties. * </p> * * @author Ben Schulz */ final class ReversePathIterator implements PathIterator { private static final int[] COUNTS = { 2, // SEG_MOVETO = 0 2, // SEG_LINETO = 1 4, // SEG_QUADTO = 2 6, // SEG_CUBICTO = 3 0, // SEG_CLOSE = 4 }; public static ReversePathIterator reverse(PathIterator it) { return new ReversePathIterator(it); } private static int[] reverseTypes(int[] types, int length) { if (length > 0 && types[0] != SEG_MOVETO) { // the last segment of the reversed path is not defined throw new IllegalArgumentException("Can not reverse path without initial SEG_MOVETO."); } final int[] result = new int[length]; result[0] = SEG_MOVETO; int lower = 1; int upper = length - 1; while (lower <= upper) { result[lower] = types[upper]; result[upper] = types[lower]; ++lower; --upper; } return result; } private static double[] reverseCoords(double[] coords, int length) { final double[] result = new double[length]; int lower = 0; int upper = length - 2; while (lower <= upper) { result[lower] = coords[upper]; result[lower + 1] = coords[upper + 1]; result[upper] = coords[lower]; result[upper + 1] = coords[lower + 1]; lower += 2; upper -= 2; } return result; } private final int winding; private final int[] types; private int typesIndex = 0; private final double[] coords; private int coordsIndex = 0; private ReversePathIterator(PathIterator it) { this.winding = it.getWindingRule(); double[] tmpCoords = new double[62]; int[] tmpTypes = new int[11]; int tmpCoordsI = 0; int tmpTypesI = 0; while (!it.isDone()) { if (tmpTypesI >= tmpTypes.length) { tmpTypes = Arrays.copyOf(tmpTypes, 2 * tmpTypes.length); } final double[] cs = new double[6]; final int t = it.currentSegment(cs); tmpTypes[tmpTypesI++] = t; final int count = COUNTS[t]; if (tmpCoordsI + count > tmpCoords.length) { tmpCoords = Arrays.copyOf(tmpCoords, 2 * tmpCoords.length); } System.arraycopy(cs, 0, tmpCoords, tmpCoordsI, count); tmpCoordsI += count; it.next(); } this.types = reverseTypes(tmpTypes, tmpTypesI); this.coords = reverseCoords(tmpCoords, tmpCoordsI); } @Override public int getWindingRule() { return winding; } @Override public boolean isDone() { return typesIndex >= types.length; } @Override public void next() { coordsIndex += COUNTS[types[typesIndex]]; ++typesIndex; } @Override public int currentSegment(float[] coords) { final double[] tmp = new double[6]; final int type = currentSegment(tmp); coords[0] = (float) tmp[0]; coords[1] = (float) tmp[1]; coords[2] = (float) tmp[2]; coords[3] = (float) tmp[3]; coords[4] = (float) tmp[4]; coords[5] = (float) tmp[5]; return type; } @Override public int currentSegment(double[] coords) { final int type = types[typesIndex]; System.arraycopy(this.coords, coordsIndex, coords, 0, COUNTS[type]); return type; } }