treewide: dart format + analyze + some other fixes

This commit is contained in:
2025-08-04 21:11:37 +02:00
parent 9f9757d710
commit c83821fa38
10 changed files with 863 additions and 844 deletions

View File

@@ -6,21 +6,19 @@ import '../common/point.dart';
import 'bezier_cubic.dart' as bezier_cubic;
import 'package:xml/xml.dart';
import 'package:path/path.dart';
double _computePathLength(String path) =>
parsePath(path).size(error: 1e-8).toDouble();
String _shescape(String path) =>
"'${path.replaceAll(RegExp(r"(?=['\\\\])"), "\\\\")}'";
// String _shescape(String path) =>
// "'${path.replaceAll(RegExp(r"(?=['\\\\])"), "\\\\")}'";
extension _Dedent on String {
String get dedented {
final withoutEmptyLines =
this.split('\n').where((l) => l.isNotEmpty).toList();
final withoutEmptyLines = split('\n').where((l) => l.isNotEmpty).toList();
final whitespaceAmounts = [
for (final line in withoutEmptyLines)
line.split('').takeWhile((c) => c == ' ').length
line.split('').takeWhile((c) => c == ' ').length,
];
final whitespaceToRemove = whitespaceAmounts.reduce(min);
return withoutEmptyLines
@@ -63,40 +61,34 @@ const pt2 = Point(1, 1);
// class {
// }
enum TimingFunction {
linear,
ease,
easeIn,
easeInOut,
easeOut,
}
enum TimingFunction { linear, ease, easeIn, easeInOut, easeOut }
extension Funcs on TimingFunction {
double Function(double) get func => {
TimingFunction.linear: (double x) => x,
TimingFunction.ease: (double x) =>
bezier_cubic.value(pt1, easeCt1, easeCt2, pt2, x),
TimingFunction.easeIn: (double x) =>
bezier_cubic.value(pt1, easeInCt1, easeInCt2, pt2, x),
TimingFunction.easeInOut: (double x) =>
bezier_cubic.value(pt1, easeInOutCt1, easeInOutCt2, pt2, x),
TimingFunction.easeOut: (double x) =>
bezier_cubic.value(pt1, easeOutCt1, easeOutCt2, pt2, x),
}[this]!;
TimingFunction.linear: (double x) => x,
TimingFunction.ease: (double x) =>
bezier_cubic.value(pt1, easeCt1, easeCt2, pt2, x),
TimingFunction.easeIn: (double x) =>
bezier_cubic.value(pt1, easeInCt1, easeInCt2, pt2, x),
TimingFunction.easeInOut: (double x) =>
bezier_cubic.value(pt1, easeInOutCt1, easeInOutCt2, pt2, x),
TimingFunction.easeOut: (double x) =>
bezier_cubic.value(pt1, easeOutCt1, easeOutCt2, pt2, x),
}[this]!;
String get name => {
TimingFunction.linear: 'linear',
TimingFunction.ease: 'ease',
TimingFunction.easeIn: 'ease-in',
TimingFunction.easeInOut: 'ease-in-out',
TimingFunction.easeOut: 'ease-out',
}[this]!;
TimingFunction.linear: 'linear',
TimingFunction.ease: 'ease',
TimingFunction.easeIn: 'ease-in',
TimingFunction.easeInOut: 'ease-in-out',
TimingFunction.easeOut: 'ease-out',
}[this]!;
}
// we will need this to deal with svg
const namespaces = {
'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")
// 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
void clearPreviousElements(XmlDocument doc) {
for (final XmlNode el in doc
.getElement('svg', namespace: namespaces['n'])
?.getElement('style', namespace: namespaces['n'])
?.children ??
[]) {
for (final XmlNode el
in doc
.getElement('svg', namespace: namespaces['n'])
?.getElement('style', namespace: namespaces['n'])
?.children ??
[]) {
if (RegExp(r'-Kanimaji$').hasMatch(el.getAttribute('id') ?? '')) {
el.parent!.children.remove(el);
}
}
for (final XmlNode g in doc
.getElement('svg', namespace: namespaces['n'])
?.getElement('g', namespace: namespaces['n'])
?.children ??
[]) {
for (final XmlNode g
in doc
.getElement('svg', namespace: namespaces['n'])
?.getElement('g', namespace: namespaces['n'])
?.children ??
[]) {
if (RegExp(r'-Kanimaji$').hasMatch(g.getAttribute('id') ?? '')) {
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
/// filesize for GIFs.
void createAnimation({
@@ -190,7 +192,8 @@ void createAnimation({
'g',
attributes: {
'id': 'kvg:$baseid-$id-Kanimaji',
'style': 'fill:none;'
'style':
'fill:none;'
'stroke:$color;'
'stroke-width:$width;'
'stroke-linecap:round;'
@@ -232,11 +235,12 @@ void createAnimation({
double tottime = 0;
// for (final g in doc.xpath("/n:svg/n:g", namespaces=namespaces) {
for (final XmlNode g in doc
.getElement('svg', namespace: namespaces['n'])
?.getElement('g', namespace: namespaces['n'])
?.children ??
[]) {
for (final XmlNode g
in doc
.getElement('svg', namespace: namespaces['n'])
?.getElement('g', namespace: namespaces['n'])
?.children ??
[]) {
if (RegExp(r'^kvg:StrokeNumbers_').hasMatch(g.getAttribute('id') ?? '')) {
continue;
}
@@ -266,9 +270,7 @@ void createAnimation({
'\n/* CSS automatically generated by kanimaji.py, do not edit! */\n';
if (GENERATE_SVG) animatedCss = cssHeader;
if (GENERATE_JS_SVG) {
jsAnimatedCss += cssHeader +
'''
.backward {\n
jsAnimatedCss += '''$cssHeader .backward {\n
animation-direction: reverse !important;\n
}
''';
@@ -287,18 +289,20 @@ void createAnimation({
double elapsedtime = 0;
// add css elements for all strokes
for (final XmlNode g in doc
.getElement('svg', namespace: namespaces['n'])!
.findElements('g', namespace: namespaces['n'])) {
for (final XmlNode g
in doc
.getElement('svg', namespace: namespaces['n'])!
.findElements('g', namespace: namespaces['n'])) {
// for (final g in doc.xpath("/n:svg/n:g", namespaces=namespaces)){
final groupid = g.getAttribute('id') ?? '';
if (RegExp(r'^kvg:StrokeNumbers_').hasMatch(groupid)) {
final String rule = '''
final String rule =
'''
#${groupid.replaceAll(':', '\\3a ')} {
display: none;
}
'''
.dedented;
.dedented;
if (GENERATE_SVG) animatedCss += rule;
if (GENERATE_JS_SVG) jsAnimatedCss += rule;
if (GENERATE_GIF) {
@@ -310,13 +314,14 @@ void createAnimation({
}
final gidcss = groupid.replaceAll(':', '\\3a ');
final rule = '''
final rule =
'''
#$gidcss {
stroke-width: ${strokeBorderWidth.toStringAsFixed(1)}px !important;
stroke: $strokeBorderColor !important;
}
'''
.dedented;
.dedented;
if (GENERATE_SVG) animatedCss += rule;
if (GENERATE_JS_SVG) jsAnimatedCss += rule;
@@ -380,7 +385,8 @@ void createAnimation({
if (GENERATE_SVG) {
// animation stroke progression
animatedCss += '''
animatedCss +=
'''
@keyframes strike-$pathname {
0% { 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;
}
'''
.dedented;
.dedented;
if (showBrush) {
// brush element visibility
animatedCss += '''
animatedCss +=
'''
@keyframes showhide-brush-$pathname {
${animStart.toStringAsFixed(3)}% { visibility: hidden; }
${animEnd.toStringAsFixed(3)}% { visibility: visible; }
@@ -414,7 +421,7 @@ void createAnimation({
showhide-brush-$pathname ${animationTime.toStringAsFixed(3)}s step-start infinite;
}
'''
.dedented;
.dedented;
}
}
@@ -423,17 +430,19 @@ void createAnimation({
// brush and background hidden by default
if (showBrush) {
jsAnimatedCss += '''
jsAnimatedCss +=
'''
#$brushPathidcss, #$brushBorderPathidcss, #$bgPathidcss {
visibility: hidden;
}
'''
.dedented;
.dedented;
}
// hide stroke after current element
const afterCurrent = '[class *= "current"]';
jsAnimatedCss += '''
jsAnimatedCss +=
'''
$afterCurrent ~ #$animPathidcss {
visibility: hidden;
}
@@ -451,9 +460,10 @@ void createAnimation({
animation: strike-$pathname ${relativeDuration.toStringAsFixed(3)}s ${timingFunction.name} forwards 1;
}
'''
.dedented;
.dedented;
if (showBrush) {
jsAnimatedCss += '''
jsAnimatedCss +=
'''
@keyframes strike-brush-$pathname {
0% { stroke-dashoffset: ${pathlen.toStringAsFixed(3)}; }
100% { stroke-dashoffset: 0.4; }
@@ -464,7 +474,7 @@ void createAnimation({
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 reltime = time * tottime / animationTime; // unscaled time
staticCss[k] = staticCss[k]! + '\n/* stroke $pathid */\n';
staticCss[k] = '${staticCss[k]!}\n/* stroke $pathid */\n';
String rule = '';
@@ -486,7 +496,8 @@ void createAnimation({
rule += ", #$brushPathidcss, #$brushBorderPathidcss";
}
staticCss[k] = staticCss[k]! +
staticCss[k] =
staticCss[k]! +
'''
%$rule {
visibility: hidden;
@@ -501,7 +512,8 @@ void createAnimation({
rule += ", #$brushPathidcss, #$brushBorderPathidcss";
}
staticCss[k] = staticCss[k]! +
staticCss[k] =
staticCss[k]! +
'''
$rule {
visibility: hidden;
@@ -513,7 +525,8 @@ void createAnimation({
((reltime - elapsedtime) / (newelapsedtime - elapsedtime));
final progression = timingFunction.func(intervalprop);
staticCss[k] = staticCss[k]! +
staticCss[k] =
staticCss[k]! +
'''
#$animPathidcss {
stroke-dasharray: ${pathlen.toStringAsFixed(3)} ${(pathlen + 0.002).toStringAsFixed(3)};
@@ -523,7 +536,8 @@ void createAnimation({
'''
.dedented;
if (showBrush) {
staticCss[k] = staticCss[k]! +
staticCss[k] =
staticCss[k]! +
'''
#$brushPathidcss, #$brushBorderPathidcss {
stroke-dasharray: 0.001 ${(pathlen + 0.002).toStringAsFixed(3)};
@@ -554,13 +568,13 @@ void createAnimation({
if (GENERATE_SVG) {
print(animatedCss);
final builder = XmlBuilder();
final style = (builder
..element(
'style',
attributes: {'id': "style-Kanimaji", 'type': 'text/css'},
nest: animatedCss,
))
.buildFragment();
final style =
(builder..element(
'style',
attributes: {'id': "style-Kanimaji", 'type': 'text/css'},
nest: animatedCss,
))
.buildFragment();
doc.root.firstElementChild!.children.insert(0, style);
File(outputFile).writeAsStringSync(doc.toXmlString(pretty: true));
doc.root.children.removeAt(0);
@@ -684,16 +698,15 @@ void main(List<String> args) {
final fileList = [];
for (int k = 0; k < kanji.length; k++) {
createAnimation(
inputFile: 'assets/kanjivg/kanji/${kanji.codeUnits[k].toRadixString(16).padLeft(5, '0')}.svg',
outputFile: '${k+1}.svg',
);
fileList.add('${k+1}.svg');
inputFile:
'assets/kanjivg/kanji/${kanji.codeUnits[k].toRadixString(16).padLeft(5, '0')}.svg',
outputFile: '${k + 1}.svg',
);
fileList.add('${k + 1}.svg');
}
File('index.html').writeAsStringSync(
'<html>' +
fileList.map((e) => File(e).readAsStringSync().replaceAll(']>', '')).join('\n') +
'</html>'
'<html>${fileList.map((e) => File(e).readAsStringSync().replaceAll(']>', '')).join('\n')}</html>',
);
// createAnimation(
// inputFile: 'assets/kanjivg/kanji/060c5.svg',

View File

@@ -1,7 +1,5 @@
import 'dart:math' as math;
import '../common/point.dart';
// 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 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
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 lmbd = sq(q) / 4 + cb(p) / 27;
if (lmbd >= 0) { // real
if (lmbd >= 0) {
// real
final sqlambda = sqrt(lmbd);
final tmp = thrt(-q / 2 + (q < 0 ? sqlambda : -sqlambda));
return tmp - p / (3 * tmp) + addcoef;
@@ -84,4 +84,4 @@ double value(Point pt1, Point ct1, Point ct2, Point pt2, double x) {
// for i in range(0,part+1,1):
// x = float(i) / part
// y = value(pt1, ct1, ct2, pt2, x)
// f.write("%f %f\n" % (x,y))
// f.write("%f %f\n" % (x,y))