Skip to content

Commit

Permalink
feat: Add a Circle.fromPoints utility method (#2603)
Browse files Browse the repository at this point in the history
# Description

Add a `Circle.fromPoints` utility method to (maybe) create Circles that
intersect three given points.
  • Loading branch information
luanpotter authored Jul 16, 2023
1 parent 1f9f350 commit a83f281
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
21 changes: 21 additions & 0 deletions packages/flame/lib/src/experimental/geometry/shapes/circle.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:math';
import 'dart:ui';

import 'package:flame/geometry.dart';
Expand Down Expand Up @@ -98,4 +99,24 @@ class Circle extends Shape {

@override
String toString() => 'Circle([${_center.x}, ${_center.y}], $_radius)';

/// Tries to create a Circle that intersects the 3 points, if it exists.
///
/// As long as the points are not co-linear, there is always exactly one
/// circle intersecting all 3 points.
static Circle? fromPoints(Vector2 p1, Vector2 p2, Vector2 p3) {
final offset = p2.length2;
final bc = (p1.length2 - offset) / 2.0;
final cd = (offset - p3.length2) / 2.0;
final det = (p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p2.y);
if (det == 0) {
return null;
}

final centerX = (bc * (p2.y - p3.y) - cd * (p1.y - p2.y)) / det;
final centerY = (cd * (p1.x - p2.x) - bc * (p2.x - p3.x)) / det;
final radius = sqrt(pow(p2.x - centerX, 2) + pow(p2.y - centerY, 2));

return Circle(Vector2(centerX, centerY), radius);
}
}
14 changes: 14 additions & 0 deletions packages/flame/test/experimental/geometry/shapes/circle_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,19 @@ void main() {
expect(result1, isNotNull);
expect(result2, Vector2(0, 0));
});

test('fromPoints', () {
final p1 = Vector2.zero();
final p2 = Vector2(0, 1);
final p3 = Vector2(1, 0);

final circle = Circle.fromPoints(p1, p2, p3)!;
expect(circle.center, Vector2.all(0.5));
expectDouble(circle.radius, 1 / sqrt(2));

expect(circle.containsPoint(p1), true);
expect(circle.containsPoint(p2), true);
expect(circle.containsPoint(p3), true);
});
});
}

0 comments on commit a83f281

Please sign in to comment.