Skip to content

ui Path length doesn't align with standard formula #108130

@JKris95

Description

@JKris95

The length of a circle as reported by the length property of dart:ui's PathMetric class deviates from the circle length calculated by the standard circle circumference formula c = 2 * pi * r

Steps to Reproduce

  1. Create a new Flutter dartpad
  2. Copy the code sample below and paste it into the dartpad
  3. Run the example.

Expected results:
I expected that the two lengths would (almost) equal each other.

Actual results:
As printed by the example code, there is a deviation between the two length calculations. From length calculations with 1000 different radii ranging from 1 to 1000, I find the mean deviation to be ~0.56 and the max deviation to be ~1.25.

I am not sure if this is a bug or not. If it is expected I am hoping that the reason can be explained and possibly added to the documentation. The documentation for path metric length currently reads:

Return the total length of the current contour.

Code sample
import 'dart:ui';
import 'dart:math';

void main() {
  double maxCircleLengthDeviation = 0.0;
  double maxDeviationRadius = 1.0;
  double deviationSum = 0.0;
  const int iterations = 1000;
  for (int i = 1; i <= iterations; i++) {
    final double radius = i.toDouble();

    final Path circle = Path()
      ..addArc(Rect.fromCircle(center: const Offset(10, 10), radius: radius),
          0.0, 2 * pi);

    final double circlePathLength = getSingleContourPathLength(circle);
    final double standardCircleLength = pi * 2 * radius;

    final deviation = (circlePathLength - standardCircleLength).abs();
    deviationSum += deviation;
    
    if (deviation > maxCircleLengthDeviation) {
      maxCircleLengthDeviation = deviation;
      maxDeviationRadius = radius;
    }
  }
  
  print('max circle length deviation: $maxCircleLengthDeviation at radius $maxDeviationRadius');
  
  final double circleLengthMeanDeviation = deviationSum / iterations;
  print('mean deviation: $circleLengthMeanDeviation');
}

double getSingleContourPathLength(Path path) {
  final metrics = path.computeMetrics().toList();
  if (metrics.length != 1) {
    throw ArgumentError('path must have exactly one contour');
  }
  return metrics.fold(0.0,
      (double tmpLength, PathMetric contour) => tmpLength + contour.length);
}

I have run the example on all channels available for dartpad. The output was consistent across all channels.

  • Stable channel: Flutter 3.0.5 Dart SDK 2.17.6
  • Beta channel: Flutter 3.1.0 Dart SDK 2.18.0-44.1.beta
  • Old channel: Flutter 2.10.5 Dart SDK 2.16.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    engineflutter/engine related. See also e: labels.frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions