reducePathForText method

LineSegmentPath reducePathForText(
  1. double textWidth,
  2. double repeatStart,
  3. double repeatGap
)

Implementation

LineSegmentPath reducePathForText(double textWidth, double repeatStart, double repeatGap) {
  LineSegmentPath result = LineSegmentPath();
  LineSegmentPath path = LineSegmentPath();
  LineSegmentPath longestPath = LineSegmentPath();
  double preLength = repeatStart;
  for (LineSegment segment in segments) {
    if (path.length() > preLength + textWidth && path.segments.first.start != path.segments.last.end) {
      // the length of all previous tiny paths is in sum long enough to fit the text
      result.segments.add(LineSegment(path.segments.first.start, path.segments.last.end));
      path = LineSegmentPath();
    }
    while (segment.length() >= preLength + textWidth) {
      // we found a segment which is long enough
      result.segments.add(segment.subSegment(preLength, textWidth));
      segment = segment.subSegment(preLength + textWidth);
      preLength = repeatGap;
      // ignore the tiny paths from previous iterations
      path.segments.clear();
    }
    if (segment.length() > 10) {
      if (path.segments.isEmpty || path.segments.last.angleTo(segment).abs() < MAX_LABEL_CORNER_ANGLE) {
        // the angle to the last segment is small enough to be part of the same path
        path.segments.add(segment);
      } else {
        path.segments.clear();
        if (longestPath.length() < path.length()) longestPath = path;
      }
    }
  }
  if (result.segments.isEmpty && longestPath.segments.isNotEmpty && longestPath.length() > textWidth * 2 / 3) {
    // we do not have a sufficient length for the text but the remaining path is 2/3 of what we need so use it
    if (longestPath.segments.first.start != longestPath.segments.last.end) {
      result.segments.add(LineSegment(longestPath.segments.first.start, longestPath.segments.last.end));
    }
  }
  return result;
}