public static PointList simplify(ResponsePath responsePath, RamerDouglasPeucker ramerDouglasPeucker, boolean enableInstructions) {
        final PointList pointList = responsePath.getPoints();
        List<Partition> partitions = new ArrayList<>();

        // make sure all waypoints are retained in the simplified point list
        // we copy the waypoint indices into temporary intervals where they will be mutated by the simplification,
        // afterwards we need to update the way point indices accordingly.
        List<Interval> intervals = new ArrayList<>();
        for (int i = 0; i < responsePath.getWaypointIndices().size() - 1; i++)
            intervals.add(new Interval(responsePath.getWaypointIndices().get(i), responsePath.getWaypointIndices().get(i + 1)));
        partitions.add(new Partition() {
            @Override
            public int size() {
                return intervals.size();
            }

            @Override
            public int getIntervalLength(int index) {
                return intervals.get(index).end - intervals.get(index).start;
            }

            @Override
            public void setInterval(int index, int start, int end) {
                intervals.get(index).start = start;
                intervals.get(index).end = end;
            }
        });

        // todo: maybe this code can be simplified if path details and instructions would be merged, see #1121
        if (enableInstructions) {
            final InstructionList instructions = responsePath.getInstructions();
            partitions.add(new Partition() {
                @Override
                public int size() {
                    return instructions.size();
                }

                @Override
                public int getIntervalLength(int index) {
                    return instructions.get(index).getLength();
                }

                @Override
                public void setInterval(int index, int start, int end) {
                    Instruction instruction = instructions.get(index);
                    if (instruction instanceof ViaInstruction || instruction instanceof FinishInstruction) {
                        if (start != end) {
                            throw new IllegalStateException("via- and finish-instructions are expected to have zero length");
                        }
                        // have to make sure that via instructions and finish instructions contain a single point
                        // even though their 'instruction length' is zero.
                        end++;
                    }
                    instruction.setPoints(pointList.shallowCopy(start, end, false));
                }
            });
        }

        for (final Map.Entry<String, List<PathDetail>> entry : responsePath.getPathDetails().entrySet()) {
            // If the pointList only contains one point, PathDetails have to be empty because 1 point => 0 edges
            final List<PathDetail> detail = entry.getValue();
            if (detail.isEmpty() && pointList.size() > 1)
                throw new IllegalStateException("PathDetails " + entry.getKey() + " must not be empty");

            partitions.add(new Partition() {
                @Override
                public int size() {
                    return detail.size();
                }

                @Override
                public int getIntervalLength(int index) {
                    return detail.get(index).getLength();
                }

                @Override
                public void setInterval(int index, int start, int end) {
                    PathDetail pd = detail.get(index);
                    pd.setFirst(start);
                    pd.setLast(end);
                }
            });
        }

        simplify(responsePath.getPoints(), partitions, ramerDouglasPeucker);

        List<Integer> simplifiedWaypointIndices = new ArrayList<>();
        simplifiedWaypointIndices.add(intervals.get(0).start);
        for (Interval interval : intervals)
            simplifiedWaypointIndices.add(interval.end);
        responsePath.setWaypointIndices(simplifiedWaypointIndices);

        assertConsistencyOfPathDetails(responsePath.getPathDetails());
        if (enableInstructions)
            assertConsistencyOfInstructions(responsePath.getInstructions(), responsePath.getPoints().size());
        return pointList;
    }
@Test
    public void testSinglePartition() {
        // points are chosen such that DP will remove those marked with an x
        // todo: we could go further and replace Ramer-Douglas-Peucker with some abstract thing that makes this easier to test
        PointList points = new PointList();
        points.add(48.89107, 9.33161); // 0   -> 0
        points.add(48.89104, 9.33102); // 1 x
        points.add(48.89100, 9.33024); // 2 x
        points.add(48.89099, 9.33002); // 3   -> 1
        points.add(48.89092, 9.32853); // 4   -> 2
        points.add(48.89101, 9.32854); // 5 x
        points.add(48.89242, 9.32865); // 6   -> 3
        points.add(48.89343, 9.32878); // 7   -> 4
        PointList origPoints = points.clone(false);
        TestPartition partition = TestPartition.start()
                .add(0, 3)
                .add(3, 3) // via
                .add(3, 3) // via (just added this to make the test harder)
                .add(3, 4)
                .add(4, 4) // via
                .add(4, 7)
                .add(7, 7); // end
        List<PathSimplification.Partition> partitions = new ArrayList<>();
        partitions.add(partition);
        PathSimplification.simplify(points, partitions, new RamerDouglasPeucker());

        // check points were modified correctly
        assertEquals(5, points.size());
        origPoints.set(1, Double.NaN, Double.NaN, Double.NaN);
        origPoints.set(2, Double.NaN, Double.NaN, Double.NaN);
        origPoints.set(5, Double.NaN, Double.NaN, Double.NaN);
        RamerDouglasPeucker.removeNaN(origPoints);
        assertEquals(origPoints, points);

        // check partition was modified correctly
        TestPartition expected = TestPartition.start()
                .add(0, 1)
                .add(1, 1)
                .add(1, 1)
                .add(1, 2)
                .add(2, 2)
                .add(2, 4)
                .add(4, 4);
        assertEquals(expected.intervals, partition.intervals);
    }