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 testScenario() {
        DecimalEncodedValue speedEnc = new DecimalEncodedValueImpl("speed", 5, 5, false);
        EncodingManager carManager = EncodingManager.start().add(speedEnc)
                .add(Roundabout.create()).add(RoadClass.create()).add(RoadClassLink.create()).add(MaxSpeed.create()).build();
        BaseGraph g = new BaseGraph.Builder(carManager).create();
        // 0-1-2
        // | | |
        // 3-4-5  9-10
        // | | |  |
        // 6-7-8--*
        NodeAccess na = g.getNodeAccess();
        na.setNode(0, 1.2, 1.0);
        na.setNode(1, 1.2, 1.1);
        na.setNode(2, 1.2, 1.2);
        na.setNode(3, 1.1, 1.0);
        na.setNode(4, 1.1, 1.1);
        na.setNode(5, 1.1, 1.2);
        na.setNode(9, 1.1, 1.3);
        na.setNode(10, 1.1, 1.4);

        na.setNode(6, 1.0, 1.0);
        na.setNode(7, 1.0, 1.1);
        na.setNode(8, 1.0, 1.2);

        g.edge(0, 1).set(speedEnc, 9).setDistance(10000).setKeyValues(Map.of(STREET_NAME, new KValue("0-1")));
        g.edge(1, 2).set(speedEnc, 9).setDistance(11000).setKeyValues(Map.of(STREET_NAME, new KValue("1-2")));

        g.edge(0, 3).set(speedEnc, 18).setDistance(11000);
        g.edge(1, 4).set(speedEnc, 18).setDistance(10000).setKeyValues(Map.of(STREET_NAME, new KValue("1-4")));
        g.edge(2, 5).set(speedEnc, 18).setDistance(11000).setKeyValues(Map.of(STREET_NAME, new KValue("5-2")));

        g.edge(3, 6).set(speedEnc, 27).setDistance(11000).setKeyValues(Map.of(STREET_NAME, new KValue("3-6")));
        g.edge(4, 7).set(speedEnc, 27).setDistance(10000).setKeyValues(Map.of(STREET_NAME, new KValue("4-7")));
        g.edge(5, 8).set(speedEnc, 27).setDistance(10000).setKeyValues(Map.of(STREET_NAME, new KValue("5-8")));

        g.edge(6, 7).setDistance(11000).set(speedEnc, 36).setKeyValues(Map.of(STREET_NAME, new KValue("6-7")));
        EdgeIteratorState tmpEdge = g.edge(7, 8).set(speedEnc, 36).setDistance(10000);
        PointList list = new PointList();
        list.add(1.0, 1.15);
        list.add(1.0, 1.16);
        tmpEdge.setWayGeometry(list);
        tmpEdge.setKeyValues(Map.of(STREET_NAME, new KValue("7-8")));

        // missing edge name
        g.edge(9, 10).set(speedEnc, 45).setDistance(10000);
        tmpEdge = g.edge(8, 9).set(speedEnc, 45).setDistance(20000);
        list.clear();
        list.add(1.0, 1.3);
        list.add(1.0, 1.3001);
        list.add(1.0, 1.3002);
        list.add(1.0, 1.3003);
        tmpEdge.setKeyValues(Map.of(STREET_NAME, new KValue("8-9")));
        tmpEdge.setWayGeometry(list);

        // Path is: [0 0-1, 3 1-4, 6 4-7, 9 7-8, 11 8-9, 10 9-10]
        Weighting weighting = new SpeedWeighting(speedEnc);
        Path p = new Dijkstra(g, weighting, tMode).calcPath(0, 10);
        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
        Map<String, List<PathDetail>> details = PathDetailsFromEdges.calcDetails(p, carManager, weighting,
                List.of(AVERAGE_SPEED), new PathDetailsBuilderFactory(), 0, g);

        PointList points = p.calcPoints();
        PointList waypoints = new PointList(2, g.getNodeAccess().is3D());
        waypoints.add(g.getNodeAccess(), 0);
        waypoints.add(g.getNodeAccess(), 10);
        List<Integer> waypointIndices = Arrays.asList(0, points.size() - 1);

        ResponsePath responsePath = new ResponsePath();
        responsePath.setInstructions(wayList);
        responsePath.addPathDetails(details);
        responsePath.setPoints(points);
        responsePath.setWaypoints(waypoints);
        responsePath.setWaypointIndices(waypointIndices);

        int numberOfPoints = points.size();

        RamerDouglasPeucker ramerDouglasPeucker = new RamerDouglasPeucker();
        // Do not simplify anything
        ramerDouglasPeucker.setMaxDistance(0);

        PathSimplification.simplify(responsePath, ramerDouglasPeucker, true);

        assertEquals(numberOfPoints, responsePath.getPoints().size());

        responsePath = new ResponsePath();
        responsePath.setInstructions(wayList);
        responsePath.addPathDetails(details);
        responsePath.setPoints(p.calcPoints());
        responsePath.setWaypoints(waypoints);
        responsePath.setWaypointIndices(waypointIndices);

        ramerDouglasPeucker.setMaxDistance(100000000);
        PathSimplification.simplify(responsePath, ramerDouglasPeucker, true);

        assertTrue(numberOfPoints > responsePath.getPoints().size());
    }