private void calculateTimeSpeedAndAttachRoadSegments(
      RoutingContext ctx, List<RouteSegmentResult> result) throws IOException {
    for (int i = 0; i < result.size(); i++) {
      if (ctx.checkIfMemoryLimitCritical(ctx.config.memoryLimitation)) {
        ctx.unloadUnusedTiles(ctx.config.memoryLimitation);
      }
      RouteSegmentResult rr = result.get(i);
      RouteDataObject road = rr.getObject();
      checkAndInitRouteRegion(ctx, road);
      double distOnRoadToPass = 0;
      double speed = ctx.getRouter().defineSpeed(road);
      if (speed == 0) {
        speed = ctx.getRouter().getMinDefaultSpeed();
      }
      boolean plus = rr.getStartPointIndex() < rr.getEndPointIndex();
      int next;
      double distance = 0;
      for (int j = rr.getStartPointIndex(); j != rr.getEndPointIndex(); j = next) {
        next = plus ? j + 1 : j - 1;
        if (j == rr.getStartPointIndex()) {
          attachRoadSegments(ctx, result, i, j, plus);
        }
        if (next != rr.getEndPointIndex()) {
          attachRoadSegments(ctx, result, i, next, plus);
        }

        double d =
            measuredDist(
                road.getPoint31XTile(j),
                road.getPoint31YTile(j),
                road.getPoint31XTile(next),
                road.getPoint31YTile(next));
        distance += d;
        double obstacle = ctx.getRouter().defineObstacle(road, j);
        if (obstacle < 0) {
          obstacle = 0;
        }
        distOnRoadToPass += d / speed + obstacle;

        List<RouteSegmentResult> attachedRoutes = rr.getAttachedRoutes(next);
        if (next != rr.getEndPointIndex()
            && !rr.getObject().roundabout()
            && attachedRoutes != null) {
          float before = rr.getBearing(next, !plus);
          float after = rr.getBearing(next, plus);
          boolean straight = Math.abs(MapUtils.degreesDiff(before + 180, after)) < TURN_DEGREE_MIN;
          boolean isSplit = false;
          // split if needed
          for (RouteSegmentResult rs : attachedRoutes) {
            double diff = MapUtils.degreesDiff(before + 180, rs.getBearingBegin());
            if (Math.abs(diff) <= TURN_DEGREE_MIN) {
              isSplit = true;
            } else if (!straight && Math.abs(diff) < 100) {
              isSplit = true;
            }
          }
          if (isSplit) {
            int endPointIndex = rr.getEndPointIndex();
            RouteSegmentResult split = new RouteSegmentResult(rr.getObject(), next, endPointIndex);
            split.copyPreattachedRoutes(rr, Math.abs(next - rr.getStartPointIndex()));
            rr.setSegmentTime((float) distOnRoadToPass);
            rr.setSegmentSpeed((float) speed);
            rr.setDistance((float) distance);
            rr.setEndPointIndex(next);
            result.add(i + 1, split);
            i++;
            // switch current segment to the splitted
            rr = split;
            distOnRoadToPass = 0;
            distance = 0;
          }
        }
      }
      // last point turn time can be added
      // if(i + 1 < result.size()) { distOnRoadToPass += ctx.getRouter().calculateTurnTime(); }
      rr.setSegmentTime((float) distOnRoadToPass);
      rr.setSegmentSpeed((float) speed);
      rr.setDistance((float) distance);
    }
  }