treewide: dart format + analyze + some other fixes
This commit is contained in:
@@ -8,10 +8,11 @@ class Point {
|
|||||||
const Point.from({this.x = 0, this.y = 0});
|
const Point.from({this.x = 0, this.y = 0});
|
||||||
static const zero = Point(0, 0);
|
static const zero = Point(0, 0);
|
||||||
|
|
||||||
operator +(covariant Point p) => Point(x + p.x, y + p.y);
|
Point operator +(covariant Point p) => Point(x + p.x, y + p.y);
|
||||||
operator -(covariant Point p) => Point(x - p.x, y - p.y);
|
Point operator -(covariant Point p) => Point(x - p.x, y - p.y);
|
||||||
operator *(covariant Point p) => Point(x * p.x, y * p.y);
|
Point operator *(covariant Point p) => Point(x * p.x, y * p.y);
|
||||||
operator /(covariant Point p) => Point(x / p.x, y / p.y);
|
Point operator /(covariant Point p) => Point(x / p.x, y / p.y);
|
||||||
|
Point operator -() => Point(-x, -y);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
library kanimaji;
|
library;
|
||||||
|
|
||||||
/// A Calculator.
|
/// A Calculator.
|
||||||
class Calculator {
|
class Calculator {
|
||||||
|
@@ -6,21 +6,19 @@ import '../common/point.dart';
|
|||||||
|
|
||||||
import 'bezier_cubic.dart' as bezier_cubic;
|
import 'bezier_cubic.dart' as bezier_cubic;
|
||||||
import 'package:xml/xml.dart';
|
import 'package:xml/xml.dart';
|
||||||
import 'package:path/path.dart';
|
|
||||||
|
|
||||||
double _computePathLength(String path) =>
|
double _computePathLength(String path) =>
|
||||||
parsePath(path).size(error: 1e-8).toDouble();
|
parsePath(path).size(error: 1e-8).toDouble();
|
||||||
|
|
||||||
String _shescape(String path) =>
|
// String _shescape(String path) =>
|
||||||
"'${path.replaceAll(RegExp(r"(?=['\\\\])"), "\\\\")}'";
|
// "'${path.replaceAll(RegExp(r"(?=['\\\\])"), "\\\\")}'";
|
||||||
|
|
||||||
extension _Dedent on String {
|
extension _Dedent on String {
|
||||||
String get dedented {
|
String get dedented {
|
||||||
final withoutEmptyLines =
|
final withoutEmptyLines = split('\n').where((l) => l.isNotEmpty).toList();
|
||||||
this.split('\n').where((l) => l.isNotEmpty).toList();
|
|
||||||
final whitespaceAmounts = [
|
final whitespaceAmounts = [
|
||||||
for (final line in withoutEmptyLines)
|
for (final line in withoutEmptyLines)
|
||||||
line.split('').takeWhile((c) => c == ' ').length
|
line.split('').takeWhile((c) => c == ' ').length,
|
||||||
];
|
];
|
||||||
final whitespaceToRemove = whitespaceAmounts.reduce(min);
|
final whitespaceToRemove = whitespaceAmounts.reduce(min);
|
||||||
return withoutEmptyLines
|
return withoutEmptyLines
|
||||||
@@ -63,40 +61,34 @@ const pt2 = Point(1, 1);
|
|||||||
// class {
|
// class {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
enum TimingFunction {
|
enum TimingFunction { linear, ease, easeIn, easeInOut, easeOut }
|
||||||
linear,
|
|
||||||
ease,
|
|
||||||
easeIn,
|
|
||||||
easeInOut,
|
|
||||||
easeOut,
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Funcs on TimingFunction {
|
extension Funcs on TimingFunction {
|
||||||
double Function(double) get func => {
|
double Function(double) get func => {
|
||||||
TimingFunction.linear: (double x) => x,
|
TimingFunction.linear: (double x) => x,
|
||||||
TimingFunction.ease: (double x) =>
|
TimingFunction.ease: (double x) =>
|
||||||
bezier_cubic.value(pt1, easeCt1, easeCt2, pt2, x),
|
bezier_cubic.value(pt1, easeCt1, easeCt2, pt2, x),
|
||||||
TimingFunction.easeIn: (double x) =>
|
TimingFunction.easeIn: (double x) =>
|
||||||
bezier_cubic.value(pt1, easeInCt1, easeInCt2, pt2, x),
|
bezier_cubic.value(pt1, easeInCt1, easeInCt2, pt2, x),
|
||||||
TimingFunction.easeInOut: (double x) =>
|
TimingFunction.easeInOut: (double x) =>
|
||||||
bezier_cubic.value(pt1, easeInOutCt1, easeInOutCt2, pt2, x),
|
bezier_cubic.value(pt1, easeInOutCt1, easeInOutCt2, pt2, x),
|
||||||
TimingFunction.easeOut: (double x) =>
|
TimingFunction.easeOut: (double x) =>
|
||||||
bezier_cubic.value(pt1, easeOutCt1, easeOutCt2, pt2, x),
|
bezier_cubic.value(pt1, easeOutCt1, easeOutCt2, pt2, x),
|
||||||
}[this]!;
|
}[this]!;
|
||||||
|
|
||||||
String get name => {
|
String get name => {
|
||||||
TimingFunction.linear: 'linear',
|
TimingFunction.linear: 'linear',
|
||||||
TimingFunction.ease: 'ease',
|
TimingFunction.ease: 'ease',
|
||||||
TimingFunction.easeIn: 'ease-in',
|
TimingFunction.easeIn: 'ease-in',
|
||||||
TimingFunction.easeInOut: 'ease-in-out',
|
TimingFunction.easeInOut: 'ease-in-out',
|
||||||
TimingFunction.easeOut: 'ease-out',
|
TimingFunction.easeOut: 'ease-out',
|
||||||
}[this]!;
|
}[this]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we will need this to deal with svg
|
// we will need this to deal with svg
|
||||||
const namespaces = {
|
const namespaces = {
|
||||||
'n': 'http://www.w3.org/2000/svg',
|
'n': 'http://www.w3.org/2000/svg',
|
||||||
'xlink': 'http://www.w3.org/1999/xlink'
|
'xlink': 'http://www.w3.org/1999/xlink',
|
||||||
};
|
};
|
||||||
// etree.register_namespace("xlink","http://www.w3.org/1999/xlink")
|
// etree.register_namespace("xlink","http://www.w3.org/1999/xlink")
|
||||||
// final parser = etree.XMLParser(remove_blank_text=true);
|
// final parser = etree.XMLParser(remove_blank_text=true);
|
||||||
@@ -124,26 +116,36 @@ double timeRescale(interval) => pow(2 * interval, 2.0 / 3).toDouble();
|
|||||||
|
|
||||||
/// clear all extra elements this program may have previously added
|
/// clear all extra elements this program may have previously added
|
||||||
void clearPreviousElements(XmlDocument doc) {
|
void clearPreviousElements(XmlDocument doc) {
|
||||||
for (final XmlNode el in doc
|
for (final XmlNode el
|
||||||
.getElement('svg', namespace: namespaces['n'])
|
in doc
|
||||||
?.getElement('style', namespace: namespaces['n'])
|
.getElement('svg', namespace: namespaces['n'])
|
||||||
?.children ??
|
?.getElement('style', namespace: namespaces['n'])
|
||||||
[]) {
|
?.children ??
|
||||||
|
[]) {
|
||||||
if (RegExp(r'-Kanimaji$').hasMatch(el.getAttribute('id') ?? '')) {
|
if (RegExp(r'-Kanimaji$').hasMatch(el.getAttribute('id') ?? '')) {
|
||||||
el.parent!.children.remove(el);
|
el.parent!.children.remove(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final XmlNode g in doc
|
for (final XmlNode g
|
||||||
.getElement('svg', namespace: namespaces['n'])
|
in doc
|
||||||
?.getElement('g', namespace: namespaces['n'])
|
.getElement('svg', namespace: namespaces['n'])
|
||||||
?.children ??
|
?.getElement('g', namespace: namespaces['n'])
|
||||||
[]) {
|
?.children ??
|
||||||
|
[]) {
|
||||||
if (RegExp(r'-Kanimaji$').hasMatch(g.getAttribute('id') ?? '')) {
|
if (RegExp(r'-Kanimaji$').hasMatch(g.getAttribute('id') ?? '')) {
|
||||||
g.parent!.children.remove(g);
|
g.parent!.children.remove(g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String basename(String path) {
|
||||||
|
final int lastSlash = path.lastIndexOf(Platform.pathSeparator);
|
||||||
|
if (lastSlash == -1) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return path.substring(lastSlash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/// Note: setting any color to transparent will result in a much bigger
|
/// Note: setting any color to transparent will result in a much bigger
|
||||||
/// filesize for GIFs.
|
/// filesize for GIFs.
|
||||||
void createAnimation({
|
void createAnimation({
|
||||||
@@ -190,7 +192,8 @@ void createAnimation({
|
|||||||
'g',
|
'g',
|
||||||
attributes: {
|
attributes: {
|
||||||
'id': 'kvg:$baseid-$id-Kanimaji',
|
'id': 'kvg:$baseid-$id-Kanimaji',
|
||||||
'style': 'fill:none;'
|
'style':
|
||||||
|
'fill:none;'
|
||||||
'stroke:$color;'
|
'stroke:$color;'
|
||||||
'stroke-width:$width;'
|
'stroke-width:$width;'
|
||||||
'stroke-linecap:round;'
|
'stroke-linecap:round;'
|
||||||
@@ -232,11 +235,12 @@ void createAnimation({
|
|||||||
double tottime = 0;
|
double tottime = 0;
|
||||||
|
|
||||||
// for (final g in doc.xpath("/n:svg/n:g", namespaces=namespaces) {
|
// for (final g in doc.xpath("/n:svg/n:g", namespaces=namespaces) {
|
||||||
for (final XmlNode g in doc
|
for (final XmlNode g
|
||||||
.getElement('svg', namespace: namespaces['n'])
|
in doc
|
||||||
?.getElement('g', namespace: namespaces['n'])
|
.getElement('svg', namespace: namespaces['n'])
|
||||||
?.children ??
|
?.getElement('g', namespace: namespaces['n'])
|
||||||
[]) {
|
?.children ??
|
||||||
|
[]) {
|
||||||
if (RegExp(r'^kvg:StrokeNumbers_').hasMatch(g.getAttribute('id') ?? '')) {
|
if (RegExp(r'^kvg:StrokeNumbers_').hasMatch(g.getAttribute('id') ?? '')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -266,9 +270,7 @@ void createAnimation({
|
|||||||
'\n/* CSS automatically generated by kanimaji.py, do not edit! */\n';
|
'\n/* CSS automatically generated by kanimaji.py, do not edit! */\n';
|
||||||
if (GENERATE_SVG) animatedCss = cssHeader;
|
if (GENERATE_SVG) animatedCss = cssHeader;
|
||||||
if (GENERATE_JS_SVG) {
|
if (GENERATE_JS_SVG) {
|
||||||
jsAnimatedCss += cssHeader +
|
jsAnimatedCss += '''$cssHeader .backward {\n
|
||||||
'''
|
|
||||||
.backward {\n
|
|
||||||
animation-direction: reverse !important;\n
|
animation-direction: reverse !important;\n
|
||||||
}
|
}
|
||||||
''';
|
''';
|
||||||
@@ -287,18 +289,20 @@ void createAnimation({
|
|||||||
double elapsedtime = 0;
|
double elapsedtime = 0;
|
||||||
|
|
||||||
// add css elements for all strokes
|
// add css elements for all strokes
|
||||||
for (final XmlNode g in doc
|
for (final XmlNode g
|
||||||
.getElement('svg', namespace: namespaces['n'])!
|
in doc
|
||||||
.findElements('g', namespace: namespaces['n'])) {
|
.getElement('svg', namespace: namespaces['n'])!
|
||||||
|
.findElements('g', namespace: namespaces['n'])) {
|
||||||
// for (final g in doc.xpath("/n:svg/n:g", namespaces=namespaces)){
|
// for (final g in doc.xpath("/n:svg/n:g", namespaces=namespaces)){
|
||||||
final groupid = g.getAttribute('id') ?? '';
|
final groupid = g.getAttribute('id') ?? '';
|
||||||
if (RegExp(r'^kvg:StrokeNumbers_').hasMatch(groupid)) {
|
if (RegExp(r'^kvg:StrokeNumbers_').hasMatch(groupid)) {
|
||||||
final String rule = '''
|
final String rule =
|
||||||
|
'''
|
||||||
#${groupid.replaceAll(':', '\\3a ')} {
|
#${groupid.replaceAll(':', '\\3a ')} {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
if (GENERATE_SVG) animatedCss += rule;
|
if (GENERATE_SVG) animatedCss += rule;
|
||||||
if (GENERATE_JS_SVG) jsAnimatedCss += rule;
|
if (GENERATE_JS_SVG) jsAnimatedCss += rule;
|
||||||
if (GENERATE_GIF) {
|
if (GENERATE_GIF) {
|
||||||
@@ -310,13 +314,14 @@ void createAnimation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
final gidcss = groupid.replaceAll(':', '\\3a ');
|
final gidcss = groupid.replaceAll(':', '\\3a ');
|
||||||
final rule = '''
|
final rule =
|
||||||
|
'''
|
||||||
#$gidcss {
|
#$gidcss {
|
||||||
stroke-width: ${strokeBorderWidth.toStringAsFixed(1)}px !important;
|
stroke-width: ${strokeBorderWidth.toStringAsFixed(1)}px !important;
|
||||||
stroke: $strokeBorderColor !important;
|
stroke: $strokeBorderColor !important;
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
|
|
||||||
if (GENERATE_SVG) animatedCss += rule;
|
if (GENERATE_SVG) animatedCss += rule;
|
||||||
if (GENERATE_JS_SVG) jsAnimatedCss += rule;
|
if (GENERATE_JS_SVG) jsAnimatedCss += rule;
|
||||||
@@ -380,7 +385,8 @@ void createAnimation({
|
|||||||
|
|
||||||
if (GENERATE_SVG) {
|
if (GENERATE_SVG) {
|
||||||
// animation stroke progression
|
// animation stroke progression
|
||||||
animatedCss += '''
|
animatedCss +=
|
||||||
|
'''
|
||||||
@keyframes strike-$pathname {
|
@keyframes strike-$pathname {
|
||||||
0% { stroke-dashoffset: ${pathlen.toStringAsFixed(3)}; }
|
0% { stroke-dashoffset: ${pathlen.toStringAsFixed(3)}; }
|
||||||
${animStart.toStringAsFixed(3)}% { stroke-dashoffset: ${pathlen.toStringAsFixed(3)}; }
|
${animStart.toStringAsFixed(3)}% { stroke-dashoffset: ${pathlen.toStringAsFixed(3)}; }
|
||||||
@@ -398,11 +404,12 @@ void createAnimation({
|
|||||||
showhide-$pathname ${animationTime.toStringAsFixed(3)}s step-start infinite;
|
showhide-$pathname ${animationTime.toStringAsFixed(3)}s step-start infinite;
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
|
|
||||||
if (showBrush) {
|
if (showBrush) {
|
||||||
// brush element visibility
|
// brush element visibility
|
||||||
animatedCss += '''
|
animatedCss +=
|
||||||
|
'''
|
||||||
@keyframes showhide-brush-$pathname {
|
@keyframes showhide-brush-$pathname {
|
||||||
${animStart.toStringAsFixed(3)}% { visibility: hidden; }
|
${animStart.toStringAsFixed(3)}% { visibility: hidden; }
|
||||||
${animEnd.toStringAsFixed(3)}% { visibility: visible; }
|
${animEnd.toStringAsFixed(3)}% { visibility: visible; }
|
||||||
@@ -414,7 +421,7 @@ void createAnimation({
|
|||||||
showhide-brush-$pathname ${animationTime.toStringAsFixed(3)}s step-start infinite;
|
showhide-brush-$pathname ${animationTime.toStringAsFixed(3)}s step-start infinite;
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,17 +430,19 @@ void createAnimation({
|
|||||||
|
|
||||||
// brush and background hidden by default
|
// brush and background hidden by default
|
||||||
if (showBrush) {
|
if (showBrush) {
|
||||||
jsAnimatedCss += '''
|
jsAnimatedCss +=
|
||||||
|
'''
|
||||||
#$brushPathidcss, #$brushBorderPathidcss, #$bgPathidcss {
|
#$brushPathidcss, #$brushBorderPathidcss, #$bgPathidcss {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
}
|
}
|
||||||
|
|
||||||
// hide stroke after current element
|
// hide stroke after current element
|
||||||
const afterCurrent = '[class *= "current"]';
|
const afterCurrent = '[class *= "current"]';
|
||||||
jsAnimatedCss += '''
|
jsAnimatedCss +=
|
||||||
|
'''
|
||||||
$afterCurrent ~ #$animPathidcss {
|
$afterCurrent ~ #$animPathidcss {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
@@ -451,9 +460,10 @@ void createAnimation({
|
|||||||
animation: strike-$pathname ${relativeDuration.toStringAsFixed(3)}s ${timingFunction.name} forwards 1;
|
animation: strike-$pathname ${relativeDuration.toStringAsFixed(3)}s ${timingFunction.name} forwards 1;
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
if (showBrush) {
|
if (showBrush) {
|
||||||
jsAnimatedCss += '''
|
jsAnimatedCss +=
|
||||||
|
'''
|
||||||
@keyframes strike-brush-$pathname {
|
@keyframes strike-brush-$pathname {
|
||||||
0% { stroke-dashoffset: ${pathlen.toStringAsFixed(3)}; }
|
0% { stroke-dashoffset: ${pathlen.toStringAsFixed(3)}; }
|
||||||
100% { stroke-dashoffset: 0.4; }
|
100% { stroke-dashoffset: 0.4; }
|
||||||
@@ -464,7 +474,7 @@ void createAnimation({
|
|||||||
animation: strike-brush-$pathname ${relativeDuration.toStringAsFixed(3)}s ${timingFunction.name} forwards 1;
|
animation: strike-brush-$pathname ${relativeDuration.toStringAsFixed(3)}s ${timingFunction.name} forwards 1;
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +483,7 @@ void createAnimation({
|
|||||||
final time = k * GIF_FRAME_DURATION;
|
final time = k * GIF_FRAME_DURATION;
|
||||||
final reltime = time * tottime / animationTime; // unscaled time
|
final reltime = time * tottime / animationTime; // unscaled time
|
||||||
|
|
||||||
staticCss[k] = staticCss[k]! + '\n/* stroke $pathid */\n';
|
staticCss[k] = '${staticCss[k]!}\n/* stroke $pathid */\n';
|
||||||
|
|
||||||
String rule = '';
|
String rule = '';
|
||||||
|
|
||||||
@@ -486,7 +496,8 @@ void createAnimation({
|
|||||||
rule += ", #$brushPathidcss, #$brushBorderPathidcss";
|
rule += ", #$brushPathidcss, #$brushBorderPathidcss";
|
||||||
}
|
}
|
||||||
|
|
||||||
staticCss[k] = staticCss[k]! +
|
staticCss[k] =
|
||||||
|
staticCss[k]! +
|
||||||
'''
|
'''
|
||||||
%$rule {
|
%$rule {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@@ -501,7 +512,8 @@ void createAnimation({
|
|||||||
rule += ", #$brushPathidcss, #$brushBorderPathidcss";
|
rule += ", #$brushPathidcss, #$brushBorderPathidcss";
|
||||||
}
|
}
|
||||||
|
|
||||||
staticCss[k] = staticCss[k]! +
|
staticCss[k] =
|
||||||
|
staticCss[k]! +
|
||||||
'''
|
'''
|
||||||
$rule {
|
$rule {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@@ -513,7 +525,8 @@ void createAnimation({
|
|||||||
((reltime - elapsedtime) / (newelapsedtime - elapsedtime));
|
((reltime - elapsedtime) / (newelapsedtime - elapsedtime));
|
||||||
final progression = timingFunction.func(intervalprop);
|
final progression = timingFunction.func(intervalprop);
|
||||||
|
|
||||||
staticCss[k] = staticCss[k]! +
|
staticCss[k] =
|
||||||
|
staticCss[k]! +
|
||||||
'''
|
'''
|
||||||
#$animPathidcss {
|
#$animPathidcss {
|
||||||
stroke-dasharray: ${pathlen.toStringAsFixed(3)} ${(pathlen + 0.002).toStringAsFixed(3)};
|
stroke-dasharray: ${pathlen.toStringAsFixed(3)} ${(pathlen + 0.002).toStringAsFixed(3)};
|
||||||
@@ -523,7 +536,8 @@ void createAnimation({
|
|||||||
'''
|
'''
|
||||||
.dedented;
|
.dedented;
|
||||||
if (showBrush) {
|
if (showBrush) {
|
||||||
staticCss[k] = staticCss[k]! +
|
staticCss[k] =
|
||||||
|
staticCss[k]! +
|
||||||
'''
|
'''
|
||||||
#$brushPathidcss, #$brushBorderPathidcss {
|
#$brushPathidcss, #$brushBorderPathidcss {
|
||||||
stroke-dasharray: 0.001 ${(pathlen + 0.002).toStringAsFixed(3)};
|
stroke-dasharray: 0.001 ${(pathlen + 0.002).toStringAsFixed(3)};
|
||||||
@@ -554,13 +568,13 @@ void createAnimation({
|
|||||||
if (GENERATE_SVG) {
|
if (GENERATE_SVG) {
|
||||||
print(animatedCss);
|
print(animatedCss);
|
||||||
final builder = XmlBuilder();
|
final builder = XmlBuilder();
|
||||||
final style = (builder
|
final style =
|
||||||
..element(
|
(builder..element(
|
||||||
'style',
|
'style',
|
||||||
attributes: {'id': "style-Kanimaji", 'type': 'text/css'},
|
attributes: {'id': "style-Kanimaji", 'type': 'text/css'},
|
||||||
nest: animatedCss,
|
nest: animatedCss,
|
||||||
))
|
))
|
||||||
.buildFragment();
|
.buildFragment();
|
||||||
doc.root.firstElementChild!.children.insert(0, style);
|
doc.root.firstElementChild!.children.insert(0, style);
|
||||||
File(outputFile).writeAsStringSync(doc.toXmlString(pretty: true));
|
File(outputFile).writeAsStringSync(doc.toXmlString(pretty: true));
|
||||||
doc.root.children.removeAt(0);
|
doc.root.children.removeAt(0);
|
||||||
@@ -684,16 +698,15 @@ void main(List<String> args) {
|
|||||||
final fileList = [];
|
final fileList = [];
|
||||||
for (int k = 0; k < kanji.length; k++) {
|
for (int k = 0; k < kanji.length; k++) {
|
||||||
createAnimation(
|
createAnimation(
|
||||||
inputFile: 'assets/kanjivg/kanji/${kanji.codeUnits[k].toRadixString(16).padLeft(5, '0')}.svg',
|
inputFile:
|
||||||
outputFile: '${k+1}.svg',
|
'assets/kanjivg/kanji/${kanji.codeUnits[k].toRadixString(16).padLeft(5, '0')}.svg',
|
||||||
|
outputFile: '${k + 1}.svg',
|
||||||
);
|
);
|
||||||
fileList.add('${k+1}.svg');
|
fileList.add('${k + 1}.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
File('index.html').writeAsStringSync(
|
File('index.html').writeAsStringSync(
|
||||||
'<html>' +
|
'<html>${fileList.map((e) => File(e).readAsStringSync().replaceAll(']>', '')).join('\n')}</html>',
|
||||||
fileList.map((e) => File(e).readAsStringSync().replaceAll(']>', '')).join('\n') +
|
|
||||||
'</html>'
|
|
||||||
);
|
);
|
||||||
// createAnimation(
|
// createAnimation(
|
||||||
// inputFile: 'assets/kanjivg/kanji/060c5.svg',
|
// inputFile: 'assets/kanjivg/kanji/060c5.svg',
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
|
||||||
import '../common/point.dart';
|
import '../common/point.dart';
|
||||||
|
|
||||||
// class Point {
|
// class Point {
|
||||||
@@ -31,7 +29,8 @@ double time(Point pt1, Point ct1, Point ct2, Point pt2, double x) {
|
|||||||
final num c = 3 * ct2.x - 3 * pt2.x;
|
final num c = 3 * ct2.x - 3 * pt2.x;
|
||||||
final num d = pt2.x - x;
|
final num d = pt2.x - x;
|
||||||
|
|
||||||
if (a.abs() < 0.000000001) { // quadratic
|
if (a.abs() < 0.000000001) {
|
||||||
|
// quadratic
|
||||||
if (b.abs() < 0.000000001) return -d / c; // linear
|
if (b.abs() < 0.000000001) return -d / c; // linear
|
||||||
|
|
||||||
final qb = c / b;
|
final qb = c / b;
|
||||||
@@ -45,7 +44,8 @@ double time(Point pt1, Point ct1, Point ct2, Point pt2, double x) {
|
|||||||
final addcoef = -b / (3 * a);
|
final addcoef = -b / (3 * a);
|
||||||
|
|
||||||
final lmbd = sq(q) / 4 + cb(p) / 27;
|
final lmbd = sq(q) / 4 + cb(p) / 27;
|
||||||
if (lmbd >= 0) { // real
|
if (lmbd >= 0) {
|
||||||
|
// real
|
||||||
final sqlambda = sqrt(lmbd);
|
final sqlambda = sqrt(lmbd);
|
||||||
final tmp = thrt(-q / 2 + (q < 0 ? sqlambda : -sqlambda));
|
final tmp = thrt(-q / 2 + (q < 0 ? sqlambda : -sqlambda));
|
||||||
return tmp - p / (3 * tmp) + addcoef;
|
return tmp - p / (3 * tmp) + addcoef;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/// SVG Path specification parser
|
/// SVG Path specification parser
|
||||||
///
|
///
|
||||||
/// See https://pypi.org/project/svg.path/ for the original implementation.
|
/// See https://pypi.org/project/svg.path/ for the original implementation.
|
||||||
|
library;
|
||||||
|
|
||||||
import '../common/point.dart';
|
import '../common/point.dart';
|
||||||
import 'path.dart';
|
import 'path.dart';
|
||||||
@@ -25,7 +26,7 @@ const _commands = {
|
|||||||
'T',
|
'T',
|
||||||
't',
|
't',
|
||||||
'A',
|
'A',
|
||||||
'a'
|
'a',
|
||||||
};
|
};
|
||||||
|
|
||||||
// const _uppercaseCommands = {'M', 'Z', 'L', 'H', 'V', 'C', 'S', 'Q', 'T', 'A'};
|
// const _uppercaseCommands = {'M', 'Z', 'L', 'H', 'V', 'C', 'S', 'Q', 'T', 'A'};
|
||||||
@@ -181,8 +182,9 @@ class Token {
|
|||||||
other is Token &&
|
other is Token &&
|
||||||
command == other.command &&
|
command == other.command &&
|
||||||
args.length == other.args.length &&
|
args.length == other.args.length &&
|
||||||
![for (int i = 0; i < args.length; i++) args[i] == other.args[i]]
|
![
|
||||||
.any((b) => !b);
|
for (int i = 0; i < args.length; i++) args[i] == other.args[i],
|
||||||
|
].any((b) => !b);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => command.hashCode ^ args.hashCode;
|
int get hashCode => command.hashCode ^ args.hashCode;
|
||||||
@@ -358,7 +360,8 @@ Path parsePath(String pathdef) {
|
|||||||
// The control point is assumed to be the reflection of
|
// The control point is assumed to be the reflection of
|
||||||
// the control point on the previous command relative
|
// the control point on the previous command relative
|
||||||
// to the current point.
|
// to the current point.
|
||||||
control = currentPos +
|
control =
|
||||||
|
currentPos +
|
||||||
currentPos -
|
currentPos -
|
||||||
(segments.last as QuadraticBezier).control;
|
(segments.last as QuadraticBezier).control;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
/// This file contains classes for the different types of SVG path segments as
|
/// This file contains classes for the different types of SVG path segments as
|
||||||
/// well as a Path object that contains a sequence of path segments.
|
/// well as a Path object that contains a sequence of path segments.
|
||||||
|
library;
|
||||||
|
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
@@ -69,10 +70,7 @@ abstract class SvgPath {
|
|||||||
final Point start;
|
final Point start;
|
||||||
final Point end;
|
final Point end;
|
||||||
|
|
||||||
const SvgPath({
|
const SvgPath({required this.start, required this.end});
|
||||||
required this.start,
|
|
||||||
required this.end,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
@@ -89,10 +87,7 @@ abstract class SvgPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class Bezier extends SvgPath {
|
abstract class Bezier extends SvgPath {
|
||||||
const Bezier({
|
const Bezier({required super.start, required super.end});
|
||||||
required Point start,
|
|
||||||
required Point end,
|
|
||||||
}) : super(start: start, end: end);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => other is Bezier && super == other;
|
bool operator ==(Object other) => other is Bezier && super == other;
|
||||||
@@ -107,10 +102,7 @@ abstract class Bezier extends SvgPath {
|
|||||||
/// A straight line
|
/// A straight line
|
||||||
/// The base for Line() and Close().
|
/// The base for Line() and Close().
|
||||||
class Linear extends SvgPath {
|
class Linear extends SvgPath {
|
||||||
const Linear({
|
const Linear({required super.start, required super.end});
|
||||||
required Point start,
|
|
||||||
required Point end,
|
|
||||||
}) : super(start: start, end: end);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => other is Linear && super == other;
|
bool operator ==(Object other) => other is Linear && super == other;
|
||||||
@@ -129,10 +121,7 @@ class Linear extends SvgPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Line extends Linear {
|
class Line extends Linear {
|
||||||
const Line({
|
const Line({required super.start, required super.end});
|
||||||
required Point start,
|
|
||||||
required Point end,
|
|
||||||
}) : super(start: start, end: end);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => other is Line && super == other;
|
bool operator ==(Object other) => other is Line && super == other;
|
||||||
@@ -151,11 +140,11 @@ class CubicBezier extends Bezier {
|
|||||||
final Point control2;
|
final Point control2;
|
||||||
|
|
||||||
const CubicBezier({
|
const CubicBezier({
|
||||||
required Point start,
|
required super.start,
|
||||||
required this.control1,
|
required this.control1,
|
||||||
required this.control2,
|
required this.control2,
|
||||||
required Point end,
|
required super.end,
|
||||||
}) : super(start: start, end: end);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
@@ -168,13 +157,14 @@ class CubicBezier extends Bezier {
|
|||||||
int get hashCode => super.hashCode ^ control1.hashCode ^ control2.hashCode;
|
int get hashCode => super.hashCode ^ control1.hashCode ^ control2.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => "CubicBezier(start=$start, control1=$control1, "
|
String toString() =>
|
||||||
|
"CubicBezier(start=$start, control1=$control1, "
|
||||||
"control2=$control2, end=$end)";
|
"control2=$control2, end=$end)";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isSmoothFrom(Object? previous) => previous is CubicBezier
|
bool isSmoothFrom(Object? previous) => previous is CubicBezier
|
||||||
? start == previous.end &&
|
? start == previous.end &&
|
||||||
control1 - start == previous.end - previous.control2
|
control1 - start == previous.end - previous.control2
|
||||||
: control1 == start;
|
: control1 == start;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -205,10 +195,10 @@ class QuadraticBezier extends Bezier {
|
|||||||
final Point control;
|
final Point control;
|
||||||
|
|
||||||
const QuadraticBezier({
|
const QuadraticBezier({
|
||||||
required Point start,
|
required super.start,
|
||||||
required Point end,
|
required super.end,
|
||||||
required this.control,
|
required this.control,
|
||||||
}) : super(start: start, end: end);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
@@ -224,7 +214,7 @@ class QuadraticBezier extends Bezier {
|
|||||||
@override
|
@override
|
||||||
bool isSmoothFrom(Object? previous) => previous is QuadraticBezier
|
bool isSmoothFrom(Object? previous) => previous is QuadraticBezier
|
||||||
? start == previous.end &&
|
? start == previous.end &&
|
||||||
(control - start) == (previous.end - previous.control)
|
(control - start) == (previous.end - previous.control)
|
||||||
: control == start;
|
: control == start;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -258,7 +248,8 @@ class QuadraticBezier extends Bezier {
|
|||||||
final num c2 = 2 * sqrt(C);
|
final num c2 = 2 * sqrt(C);
|
||||||
final num bA = B / a2;
|
final num bA = B / a2;
|
||||||
|
|
||||||
s = (a32 * sabc +
|
s =
|
||||||
|
(a32 * sabc +
|
||||||
a2 * B * (sabc - c2) +
|
a2 * B * (sabc - c2) +
|
||||||
(4 * C * A - (B * B)) * log((2 * a2 + bA + sabc) / (bA + c2))) /
|
(4 * C * A - (B * B)) * log((2 * a2 + bA + sabc) / (bA + c2))) /
|
||||||
(4 * a32);
|
(4 * a32);
|
||||||
@@ -280,13 +271,13 @@ class Arc extends SvgPath {
|
|||||||
// late num delta;
|
// late num delta;
|
||||||
|
|
||||||
const Arc({
|
const Arc({
|
||||||
required Point start,
|
required super.start,
|
||||||
required Point end,
|
required super.end,
|
||||||
required this.radius,
|
required this.radius,
|
||||||
required this.rotation,
|
required this.rotation,
|
||||||
required this.arc,
|
required this.arc,
|
||||||
required this.sweep,
|
required this.sweep,
|
||||||
}) : super(start: start, end: end);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
@@ -306,10 +297,10 @@ class Arc extends SvgPath {
|
|||||||
sweep.hashCode;
|
sweep.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'Arc(start=$start, radius=$radius, rotation=$rotation, '
|
String toString() =>
|
||||||
|
'Arc(start=$start, radius=$radius, rotation=$rotation, '
|
||||||
'arc=$arc, sweep=$sweep, end=$end)';
|
'arc=$arc, sweep=$sweep, end=$end)';
|
||||||
|
|
||||||
|
|
||||||
// Conversion from endpoint to center parameterization
|
// Conversion from endpoint to center parameterization
|
||||||
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||||
num get _cosr => cos(radians(rotation));
|
num get _cosr => cos(radians(rotation));
|
||||||
@@ -337,15 +328,16 @@ class Arc extends SvgPath {
|
|||||||
num get _cyprim => -c * _ry * _x1prim / _rx;
|
num get _cyprim => -c * _ry * _x1prim / _rx;
|
||||||
|
|
||||||
num get radiusScale {
|
num get radiusScale {
|
||||||
final rs = (_x1primSq / (radius.x * radius.x)) +
|
final rs =
|
||||||
|
(_x1primSq / (radius.x * radius.x)) +
|
||||||
(_y1primSq / (radius.y * radius.y));
|
(_y1primSq / (radius.y * radius.y));
|
||||||
return rs > 1 ? sqrt(rs) : 1;
|
return rs > 1 ? sqrt(rs) : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point get center => Point(
|
Point get center => Point(
|
||||||
(_cosr * _cxprim - _sinr * _cyprim) + ((start.x + end.x) / 2),
|
(_cosr * _cxprim - _sinr * _cyprim) + ((start.x + end.x) / 2),
|
||||||
(_sinr * _cxprim + _cosr * _cyprim) + ((start.y + end.y) / 2),
|
(_sinr * _cxprim + _cosr * _cyprim) + ((start.y + end.y) / 2),
|
||||||
);
|
);
|
||||||
|
|
||||||
num get theta {
|
num get theta {
|
||||||
final num n = sqrt(_ux * _ux + _uy * _uy);
|
final num n = sqrt(_ux * _ux + _uy * _uy);
|
||||||
@@ -365,7 +357,8 @@ class Arc extends SvgPath {
|
|||||||
d = -1.0;
|
d = -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((((_ux * _vy - _uy * _vx) < 0) ? -1 : 1) * degrees(acos(d))) % 360 - (!sweep ? 360 : 0);
|
return ((((_ux * _vy - _uy * _vx) < 0) ? -1 : 1) * degrees(acos(d))) % 360 -
|
||||||
|
(!sweep ? 360 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -375,7 +368,7 @@ class Arc extends SvgPath {
|
|||||||
|
|
||||||
// This should be treated as a straight line
|
// This should be treated as a straight line
|
||||||
if (this.radius.x == 0 || this.radius.y == 0) {
|
if (this.radius.x == 0 || this.radius.y == 0) {
|
||||||
return start + (end - start) * pos;
|
return start + (end - start).times(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
final angle = radians(theta + pos * delta);
|
final angle = radians(theta + pos * delta);
|
||||||
@@ -415,14 +408,15 @@ class Arc extends SvgPath {
|
|||||||
final startPoint = point(0);
|
final startPoint = point(0);
|
||||||
final endPoint = point(1);
|
final endPoint = point(1);
|
||||||
return segmentLength(
|
return segmentLength(
|
||||||
curve: this,
|
curve: this,
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
startPoint: startPoint,
|
startPoint: startPoint,
|
||||||
endPoint: endPoint,
|
endPoint: endPoint,
|
||||||
error: error,
|
error: error,
|
||||||
minDepth: minDepth,
|
minDepth: minDepth,
|
||||||
depth: 0);
|
depth: 0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,10 +443,7 @@ class Move extends SvgPath {
|
|||||||
|
|
||||||
/// Represents the closepath command
|
/// Represents the closepath command
|
||||||
class Close extends Linear {
|
class Close extends Linear {
|
||||||
const Close({
|
const Close({required super.start, required super.end});
|
||||||
required Point start,
|
|
||||||
required Point end,
|
|
||||||
}) : super(start: start, end: end);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => other is Close && super == other;
|
bool operator ==(Object other) => other is Close && super == other;
|
||||||
@@ -502,12 +493,14 @@ class Path extends ListBase<SvgPath> {
|
|||||||
String toString() =>
|
String toString() =>
|
||||||
'Path(${[for (final s in segments) s.toString()].join(", ")})';
|
'Path(${[for (final s in segments) s.toString()].join(", ")})';
|
||||||
|
|
||||||
void _calcLengths(
|
void _calcLengths({
|
||||||
{num error = defaultError, int minDepth = defaultMinDepth}) {
|
num error = defaultError,
|
||||||
|
int minDepth = defaultMinDepth,
|
||||||
|
}) {
|
||||||
if (_memoizedLength != null) return;
|
if (_memoizedLength != null) return;
|
||||||
|
|
||||||
final lengths = [
|
final lengths = [
|
||||||
for (final s in segments) s!.size(error: error, minDepth: minDepth)
|
for (final s in segments) s!.size(error: error, minDepth: minDepth),
|
||||||
];
|
];
|
||||||
_memoizedLength = lengths.reduce((a, b) => a + b);
|
_memoizedLength = lengths.reduce((a, b) => a + b);
|
||||||
if (_memoizedLength == 0) {
|
if (_memoizedLength == 0) {
|
||||||
@@ -552,7 +545,7 @@ class Path extends ListBase<SvgPath> {
|
|||||||
return segments[i]!.point(segmentPos);
|
return segments[i]!.point(segmentPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
num size({error = defaultError, minDepth = defaultMinDepth}) {
|
num size({double error = defaultError, int minDepth = defaultMinDepth}) {
|
||||||
_calcLengths(error: error, minDepth: minDepth);
|
_calcLengths(error: error, minDepth: minDepth);
|
||||||
return _memoizedLength!;
|
return _memoizedLength!;
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
extension _Hexcode on Color {
|
|
||||||
String get hexcode => '#${value.toRadixString(16).padLeft(8, '0')}';
|
|
||||||
}
|
|
||||||
|
|
||||||
class Kanimaji extends StatelessWidget {
|
class Kanimaji extends StatelessWidget {
|
||||||
final String kanji;
|
final String kanji;
|
||||||
const Kanimaji({
|
const Kanimaji({super.key, required this.kanji});
|
||||||
Key? key,
|
|
||||||
required this.kanji,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@@ -6,16 +6,17 @@ import 'package:kanimaji/svg/path.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
group("Examples from the SVG spec", () {
|
group("Examples from the SVG spec", () {
|
||||||
test(
|
test(
|
||||||
"[Path 1]: MLLz",
|
"[Path 1]: MLLz",
|
||||||
() => expect(
|
() => expect(
|
||||||
parsePath("M 100 100 L 300 100 L 200 300 z"),
|
parsePath("M 100 100 L 300 100 L 200 300 z"),
|
||||||
Path.fromSegments(const [
|
Path.fromSegments(const [
|
||||||
Move(to: Point(100, 100)),
|
Move(to: Point(100, 100)),
|
||||||
Line(start: Point(100, 100), end: Point(300, 100)),
|
Line(start: Point(100, 100), end: Point(300, 100)),
|
||||||
Line(start: Point(300, 100), end: Point(200, 300)),
|
Line(start: Point(300, 100), end: Point(200, 300)),
|
||||||
Close(start: Point(200, 300), end: Point(100, 100)),
|
Close(start: Point(200, 300), end: Point(100, 100)),
|
||||||
]),
|
]),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
test(
|
test(
|
||||||
@@ -160,10 +161,11 @@ void main() {
|
|||||||
Path.fromSegments(const [
|
Path.fromSegments(const [
|
||||||
Move(to: Point(600, 800)),
|
Move(to: Point(600, 800)),
|
||||||
CubicBezier(
|
CubicBezier(
|
||||||
start: Point(600, 800),
|
start: Point(600, 800),
|
||||||
control1: Point(625, 700),
|
control1: Point(625, 700),
|
||||||
control2: Point(725, 700),
|
control2: Point(725, 700),
|
||||||
end: Point(750, 800)),
|
end: Point(750, 800),
|
||||||
|
),
|
||||||
CubicBezier(
|
CubicBezier(
|
||||||
start: Point(750, 800),
|
start: Point(750, 800),
|
||||||
control1: Point(775, 900),
|
control1: Point(775, 900),
|
||||||
@@ -347,9 +349,10 @@ void main() {
|
|||||||
Path.fromSegments(const [
|
Path.fromSegments(const [
|
||||||
Move(to: Point(100, 200)),
|
Move(to: Point(100, 200)),
|
||||||
QuadraticBezier(
|
QuadraticBezier(
|
||||||
start: Point(100, 200),
|
start: Point(100, 200),
|
||||||
control: Point(100, 200),
|
control: Point(100, 200),
|
||||||
end: Point(250, 200)),
|
end: Point(250, 200),
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -361,9 +364,10 @@ void main() {
|
|||||||
Path.fromSegments(const [
|
Path.fromSegments(const [
|
||||||
Move(to: Point(100, 200)),
|
Move(to: Point(100, 200)),
|
||||||
QuadraticBezier(
|
QuadraticBezier(
|
||||||
start: Point(100, 200),
|
start: Point(100, 200),
|
||||||
control: Point(100, 200),
|
control: Point(100, 200),
|
||||||
end: Point(250, 200)),
|
end: Point(250, 200),
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -382,12 +386,12 @@ void main() {
|
|||||||
() =>
|
() =>
|
||||||
// It can be e or E, the plus is optional, and a minimum of +/-3.4e38 must be supported.
|
// It can be e or E, the plus is optional, and a minimum of +/-3.4e38 must be supported.
|
||||||
expect(
|
expect(
|
||||||
parsePath("M-3.4e38 3.4E+38L-3.4E-38,3.4e-38"),
|
parsePath("M-3.4e38 3.4E+38L-3.4E-38,3.4e-38"),
|
||||||
Path.fromSegments(const [
|
Path.fromSegments(const [
|
||||||
Move(to: Point(-3.4e38, 3.4e38)),
|
Move(to: Point(-3.4e38, 3.4e38)),
|
||||||
Line(start: Point(-3.4e38, 3.4e38), end: Point(-3.4e-38, 3.4e-38))
|
Line(start: Point(-3.4e38, 3.4e38), end: Point(-3.4e-38, 3.4e-38)),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -405,15 +409,17 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
test('svg.path library, issue 45', () {
|
test('svg.path library, issue 45', () {
|
||||||
final path = parsePath("m 1672.2372,-54.8161 "
|
final path = parsePath(
|
||||||
"a 14.5445,14.5445 0 0 0 -11.3152,23.6652 "
|
"m 1672.2372,-54.8161 "
|
||||||
"l 27.2573,27.2572 27.2572,-27.2572 "
|
"a 14.5445,14.5445 0 0 0 -11.3152,23.6652 "
|
||||||
"a 14.5445,14.5445 0 0 0 -11.3012,-23.634 "
|
"l 27.2573,27.2572 27.2572,-27.2572 "
|
||||||
"a 14.5445,14.5445 0 0 0 -11.414,5.4625 "
|
"a 14.5445,14.5445 0 0 0 -11.3012,-23.634 "
|
||||||
"l -4.542,4.5420 "
|
"a 14.5445,14.5445 0 0 0 -11.414,5.4625 "
|
||||||
"l -4.5437,-4.5420 "
|
"l -4.542,4.5420 "
|
||||||
"a 14.5445,14.5445 0 0 0 -11.3984,-5.4937 "
|
"l -4.5437,-4.5420 "
|
||||||
"z");
|
"a 14.5445,14.5445 0 0 0 -11.3984,-5.4937 "
|
||||||
|
"z",
|
||||||
|
);
|
||||||
expect(path.d(), contains("A 14.5445,14.5445 0 0,0 1672.2372,-54.8161 Z"));
|
expect(path.d(), contains("A 14.5445,14.5445 0 0,0 1672.2372,-54.8161 Z"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:kanimaji/common/point.dart';
|
import 'package:kanimaji/common/point.dart';
|
||||||
import 'package:kanimaji/svg/parser.dart' show Command, Token, commandifyPath, parsePath, tokenizePath;
|
import 'package:kanimaji/svg/parser.dart'
|
||||||
|
show Command, Token, commandifyPath, parsePath, tokenizePath;
|
||||||
|
|
||||||
class TokenizerTest {
|
class TokenizerTest {
|
||||||
final String pathdef;
|
final String pathdef;
|
||||||
@@ -30,7 +31,7 @@ final List<TokenizerTest> tokenizerTests = [
|
|||||||
Token(command: "M", args: [Point(100, 100)]),
|
Token(command: "M", args: [Point(100, 100)]),
|
||||||
Token(command: "L", args: [Point(300, 100)]),
|
Token(command: "L", args: [Point(300, 100)]),
|
||||||
Token(command: "L", args: [Point(200, 300)]),
|
Token(command: "L", args: [Point(200, 300)]),
|
||||||
Token(command: "z", args: [])
|
Token(command: "z", args: []),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const TokenizerTest(
|
const TokenizerTest(
|
||||||
@@ -42,17 +43,22 @@ final List<TokenizerTest> tokenizerTests = [
|
|||||||
Command(command: "M", args: "5 1"),
|
Command(command: "M", args: "5 1"),
|
||||||
Command(command: "v", args: "7.344"),
|
Command(command: "v", args: "7.344"),
|
||||||
Command(
|
Command(
|
||||||
command: "A", args: "3.574 3.574 0 003.5 8 3.515 3.515 0 000 11.5"),
|
command: "A",
|
||||||
|
args: "3.574 3.574 0 003.5 8 3.515 3.515 0 000 11.5",
|
||||||
|
),
|
||||||
Command(command: "C", args: "0 13.421 1.579 15 3.5 15"),
|
Command(command: "C", args: "0 13.421 1.579 15 3.5 15"),
|
||||||
Command(command: "A", args: "3.517 3.517 0 007 11.531"),
|
Command(command: "A", args: "3.517 3.517 0 007 11.531"),
|
||||||
Command(command: "v", args: "-7.53"),
|
Command(command: "v", args: "-7.53"),
|
||||||
Command(command: "h", args: "6"),
|
Command(command: "h", args: "6"),
|
||||||
Command(command: "v", args: "4.343"),
|
Command(command: "v", args: "4.343"),
|
||||||
Command(
|
Command(
|
||||||
command: "A", args: "3.574 3.574 0 0011.5 8 3.515 3.515 0 008 11.5"),
|
command: "A",
|
||||||
|
args: "3.574 3.574 0 0011.5 8 3.515 3.515 0 008 11.5",
|
||||||
|
),
|
||||||
Command(
|
Command(
|
||||||
command: "c",
|
command: "c",
|
||||||
args: "0 1.921 1.579 3.5 3.5 3.5 1.9 0 3.465 -1.546 3.5 -3.437"),
|
args: "0 1.921 1.579 3.5 3.5 3.5 1.9 0 3.465 -1.546 3.5 -3.437",
|
||||||
|
),
|
||||||
Command(command: "V", args: "1"),
|
Command(command: "V", args: "1"),
|
||||||
Command(command: "z", args: ""),
|
Command(command: "z", args: ""),
|
||||||
],
|
],
|
||||||
@@ -61,26 +67,36 @@ final List<TokenizerTest> tokenizerTests = [
|
|||||||
Token(command: "v", args: [7.344]),
|
Token(command: "v", args: [7.344]),
|
||||||
Token(command: "A", args: [3.574, 3.574, 0, false, false, Point(3.5, 8)]),
|
Token(command: "A", args: [3.574, 3.574, 0, false, false, Point(3.5, 8)]),
|
||||||
Token(
|
Token(
|
||||||
command: "A", args: [3.515, 3.515, 0, false, false, Point(0, 11.5)]),
|
command: "A",
|
||||||
|
args: [3.515, 3.515, 0, false, false, Point(0, 11.5)],
|
||||||
|
),
|
||||||
Token(
|
Token(
|
||||||
command: "C",
|
command: "C",
|
||||||
args: [Point(0, 13.421), Point(1.579, 15), Point(3.5, 15)]),
|
args: [Point(0, 13.421), Point(1.579, 15), Point(3.5, 15)],
|
||||||
|
),
|
||||||
Token(
|
Token(
|
||||||
command: "A",
|
command: "A",
|
||||||
args: [3.517, 3.517, 0, false, false, Point(7, 11.531)]),
|
args: [3.517, 3.517, 0, false, false, Point(7, 11.531)],
|
||||||
|
),
|
||||||
Token(command: "v", args: [-7.53]),
|
Token(command: "v", args: [-7.53]),
|
||||||
Token(command: "h", args: [6]),
|
Token(command: "h", args: [6]),
|
||||||
Token(command: "v", args: [4.343]),
|
Token(command: "v", args: [4.343]),
|
||||||
Token(
|
Token(
|
||||||
command: "A", args: [3.574, 3.574, 0, false, false, Point(11.5, 8)]),
|
command: "A",
|
||||||
|
args: [3.574, 3.574, 0, false, false, Point(11.5, 8)],
|
||||||
|
),
|
||||||
Token(
|
Token(
|
||||||
command: "A", args: [3.515, 3.515, 0, false, false, Point(8, 11.5)]),
|
command: "A",
|
||||||
|
args: [3.515, 3.515, 0, false, false, Point(8, 11.5)],
|
||||||
|
),
|
||||||
Token(
|
Token(
|
||||||
command: "c",
|
command: "c",
|
||||||
args: [Point(0, 1.921), Point(1.579, 3.5), Point(3.5, 3.5)]),
|
args: [Point(0, 1.921), Point(1.579, 3.5), Point(3.5, 3.5)],
|
||||||
|
),
|
||||||
Token(
|
Token(
|
||||||
command: "c",
|
command: "c",
|
||||||
args: [Point(1.9, 0), Point(3.465, -1.546), Point(3.5, -3.437)]),
|
args: [Point(1.9, 0), Point(3.465, -1.546), Point(3.5, -3.437)],
|
||||||
|
),
|
||||||
Token(command: "V", args: [1]),
|
Token(command: "V", args: [1]),
|
||||||
Token(command: "z", args: []),
|
Token(command: "z", args: []),
|
||||||
],
|
],
|
||||||
|
Reference in New Issue
Block a user