Skip to content

Commit

Permalink
Use radians when rotating matrix (#9)
Browse files Browse the repository at this point in the history
* Use radians when rotating matrix

* less precision in tests
  • Loading branch information
dnfield authored Aug 4, 2022
1 parent 94c7958 commit 74a10e9
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 34 deletions.
5 changes: 5 additions & 0 deletions third_party/packages/path_parsing/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## 1.0.1

- Fix [bug in arc decomposition](https://github.com/dnfield/flutter_svg/issues/742).
- Minor code cleanup for analysis warnings.

## 1.0.0

- Stable release.
Expand Down
52 changes: 25 additions & 27 deletions third_party/packages/path_parsing/lib/src/path_parsing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import 'dart:math' as math show sqrt, max, pi, tan, sin, cos, pow, atan2;

import 'package:meta/meta.dart';
import 'package:vector_math/vector_math.dart' show Matrix4;
import 'package:vector_math/vector_math.dart' show Matrix4, radians;

import './path_segment_type.dart';

Expand Down Expand Up @@ -178,10 +178,9 @@ class SvgPathStringSource {
}

bool _isValidRange(double x) =>
-double.maxFinite <= x && x <= double.maxFinite;
-double.maxFinite <= x && x <= double.maxFinite;

bool _isValidExponent(double x) =>
-37 <= x && x <= 38;
bool _isValidExponent(double x) => -37 <= x && x <= 38;

/// Reads a code unit and advances the index.
///
Expand Down Expand Up @@ -209,8 +208,8 @@ class SvgPathStringSource {
c = _readCodeUnit();
}

if ((c < AsciiConstants.number0 || c > AsciiConstants.number9)
&& c != AsciiConstants.period) {
if ((c < AsciiConstants.number0 || c > AsciiConstants.number9) &&
c != AsciiConstants.period) {
throw StateError('First character of a number must be one of [0-9+-.].');
}

Expand All @@ -232,8 +231,7 @@ class SvgPathStringSource {
c = _readCodeUnit();

// There must be a least one digit following the .
if (c < AsciiConstants.number0 ||
c > AsciiConstants.number9)
if (c < AsciiConstants.number0 || c > AsciiConstants.number9)
throw StateError('There must be at least one digit following the .');

double frac = 1.0;
Expand Down Expand Up @@ -264,8 +262,7 @@ class SvgPathStringSource {
}

// There must be an exponent
if (c < AsciiConstants.number0 ||
c > AsciiConstants.number9)
if (c < AsciiConstants.number0 || c > AsciiConstants.number9)
throw StateError('Missing exponent');

double exponent = 0.0;
Expand Down Expand Up @@ -408,20 +405,18 @@ class SvgPathStringSource {
}
}

class OffsetHelper {
static _PathOffset reflectedPoint(
_PathOffset reflectedIn, _PathOffset pointToReflect) {
return _PathOffset(2 * reflectedIn.dx - pointToReflect.dx,
2 * reflectedIn.dy - pointToReflect.dy);
}
_PathOffset reflectedPoint(
_PathOffset reflectedIn, _PathOffset pointToReflect) {
return _PathOffset(2 * reflectedIn.dx - pointToReflect.dx,
2 * reflectedIn.dy - pointToReflect.dy);
}

static const double _kOneOverThree = 1.0 / 3.0;
const double _kOneOverThree = 1.0 / 3.0;

/// Blend the points with a ratio (1/3):(2/3).
static _PathOffset blendPoints(_PathOffset p1, _PathOffset p2) {
return _PathOffset((p1.dx + 2 * p2.dx) * _kOneOverThree,
(p1.dy + 2 * p2.dy) * _kOneOverThree);
}
/// Blend the points with a ratio (1/3):(2/3).
_PathOffset blendPoints(_PathOffset p1, _PathOffset p2) {
return _PathOffset((p1.dx + 2 * p2.dx) * _kOneOverThree,
(p1.dy + 2 * p2.dy) * _kOneOverThree);
}

bool isCubicCommand(SvgPathSegType command) {
Expand All @@ -448,7 +443,10 @@ class PathSegmentData {

_PathOffset get arcRadii => point1;

/// Angle in degrees.
double get arcAngle => point2.dx;

/// In degrees.
set arcAngle(double angle) => point2 = _PathOffset(angle, point2.dy);

double get r1 => arcRadii.dx;
Expand Down Expand Up @@ -553,7 +551,7 @@ class SvgPathNormalizer {
if (!isCubicCommand(_lastCommand)) {
normSeg.point1 = _currentPoint;
} else {
normSeg.point1 = OffsetHelper.reflectedPoint(
normSeg.point1 = reflectedPoint(
_currentPoint,
_controlPoint,
);
Expand All @@ -578,7 +576,7 @@ class SvgPathNormalizer {
if (!isQuadraticCommand(_lastCommand)) {
normSeg.point1 = _currentPoint;
} else {
normSeg.point1 = OffsetHelper.reflectedPoint(
normSeg.point1 = reflectedPoint(
_currentPoint,
_controlPoint,
);
Expand All @@ -589,8 +587,8 @@ class SvgPathNormalizer {
case SvgPathSegType.quadToAbs:
// Save the unmodified control point.
_controlPoint = normSeg.point1;
normSeg.point1 = OffsetHelper.blendPoints(_currentPoint, _controlPoint);
normSeg.point2 = OffsetHelper.blendPoints(
normSeg.point1 = blendPoints(_currentPoint, _controlPoint);
normSeg.point2 = blendPoints(
normSeg.targetPoint,
_controlPoint,
);
Expand Down Expand Up @@ -655,7 +653,7 @@ class SvgPathNormalizer {
return false;
}

final double angle = arcSegment.arcAngle;
final double angle = radians(arcSegment.arcAngle);

final _PathOffset midPointDistance =
(currentPoint - arcSegment.targetPoint) * 0.5;
Expand Down
2 changes: 1 addition & 1 deletion third_party/packages/path_parsing/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: path_parsing
version: 1.0.0
version: 1.0.1
description: >
A Dart library to help with SVG Path parsing and code generation. Used by Flutter SVG.
homepage: https://github.com/dnfield/dart_path_parsing
Expand Down
27 changes: 21 additions & 6 deletions third_party/packages/path_parsing/test/parse_path_deep_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,20 @@ class DeepTestPathProxy extends PathProxy {
double x3,
double y3,
) {
actualCommands.add('cubicTo($x1, $y1, $x2, $y2, $x3, $y3)');
actualCommands.add(
'cubicTo(${x1.toStringAsFixed(4)}, ${y1.toStringAsFixed(4)}, ${x2.toStringAsFixed(4)}, ${y2.toStringAsFixed(4)}, ${x3.toStringAsFixed(4)}, ${y3.toStringAsFixed(4)})');
}

@override
void lineTo(double x, double y) {
actualCommands.add('lineTo($x, $y)');
actualCommands
.add('lineTo(${x.toStringAsFixed(4)}, ${y.toStringAsFixed(4)})');
}

@override
void moveTo(double x, double y) {
actualCommands.add('moveTo($x, $y)');
actualCommands
.add('moveTo(${x.toStringAsFixed(4)}, ${y.toStringAsFixed(4)})');
}

void validate() {
Expand All @@ -48,9 +51,21 @@ void main() {

test('Deep path validation', () {
assertValidPath('M20,30 Q40,5 60,30 T100,30', <String>[
'moveTo(20.0, 30.0)',
'cubicTo(33.33333333333333, 13.333333333333332, 46.666666666666664, 13.333333333333332, 60.0, 30.0)',
'cubicTo(73.33333333333333, 46.666666666666664, 86.66666666666666, 46.666666666666664, 100.0, 30.0)',
'moveTo(20.0000, 30.0000)',
'cubicTo(33.3333, 13.3333, 46.6667, 13.3333, 60.0000, 30.0000)',
'cubicTo(73.3333, 46.6667, 86.6667, 46.6667, 100.0000, 30.0000)'
]);

assertValidPath(
'M5.5 5.5a.5 1.5 30 1 1-.866-.5.5 1.5 30 1 1 .866.5z', <String>[
'moveTo(5.5000, 5.5000)',
'cubicTo(5.2319, 5.9667, 4.9001, 6.3513, 4.6307, 6.5077)',
'cubicTo(4.3612, 6.6640, 4.1953, 6.5683, 4.1960, 6.2567)',
'cubicTo(4.1967, 5.9451, 4.3638, 5.4655, 4.6340, 5.0000)',
'cubicTo(4.9021, 4.5333, 5.2339, 4.1487, 5.5033, 3.9923)',
'cubicTo(5.7728, 3.8360, 5.9387, 3.9317, 5.9380, 4.2433)',
'cubicTo(5.9373, 4.5549, 5.7702, 5.0345, 5.5000, 5.5000)',
'close()'
]);
});
}

0 comments on commit 74a10e9

Please sign in to comment.