getStrokeOutlineTracks function
Map<String, List<Vec> >
getStrokeOutlineTracks(
- List<
StrokePoint> strokePoints, [ - StrokeOptions? options
Implementation
Map<String, List<Vec>> getStrokeOutlineTracks(
List<StrokePoint> strokePoints, [
StrokeOptions? options,
]) {
options ??= StrokeOptions();
final double size = options.size;
final double smoothing = options.smoothing;
if (strokePoints.isEmpty || size <= 0) {
return {'left': [], 'right': []};
}
final StrokePoint firstStrokePoint = strokePoints[0];
final StrokePoint lastStrokePoint = strokePoints[strokePoints.length - 1];
final double totalLength = lastStrokePoint.runningLength;
final double minDistance = pow(size * smoothing, 2).toDouble();
final List<Vec> leftPts = [];
final List<Vec> rightPts = [];
Vec prevVector = strokePoints[0].vector;
Vec pl = strokePoints[0].point;
Vec pr = pl;
Vec tl = pl;
Vec tr = pr;
bool isPrevPointSharpCorner = false;
for (int i = 0; i < strokePoints.length; i++) {
final StrokePoint strokePoint = strokePoints[i];
final Vec point = strokePoint.point;
final Vec vector = strokePoint.vector;
final double prevDpr = vector.dpr(prevVector);
final Vec nextVector =
(i < strokePoints.length - 1)
? strokePoints[i + 1].vector
: strokePoints[i].vector;
final double nextDpr =
i < strokePoints.length - 1 ? nextVector.dpr(vector) : 1;
final bool isPointSharpCorner = prevDpr < 0 && !isPrevPointSharpCorner;
final bool isNextPointSharpCorner = nextDpr < 0.2;
if (isPointSharpCorner || isNextPointSharpCorner) {
if (nextDpr > -0.62 &&
totalLength - strokePoint.runningLength > strokePoint.radius) {
// Draw a "soft" corner
final Vec offset = prevVector.clone().mul(strokePoint.radius);
final double cpr = prevVector.clone().cpr(nextVector);
if (cpr < 0) {
tl = Vec.addVec(point, offset);
tr = Vec.subVec(point, offset);
} else {
tl = Vec.subVec(point, offset);
tr = Vec.addVec(point, offset);
}
leftPts.add(tl);
rightPts.add(tr);
} else {
// Draw a "sharp" corner
final Vec offset = prevVector.clone().mul(strokePoint.radius).per();
final Vec start = Vec.subVec(strokePoint.input, offset);
for (double step = 1 / 13, t = 0; t < 1; t += step) {
tl = Vec.rotWithVec(start, strokePoint.input, fixedPi * t);
leftPts.add(tl);
tr = Vec.rotWithVec(start, strokePoint.input, fixedPi + fixedPi * -t);
rightPts.add(tr);
}
}
pl = tl;
pr = tr;
if (isNextPointSharpCorner) {
isPrevPointSharpCorner = true;
}
continue;
}
isPrevPointSharpCorner = false;
if (strokePoint == firstStrokePoint || strokePoint == lastStrokePoint) {
final Vec offset = vector.per().mul(strokePoint.radius);
leftPts.add(Vec.subVec(point, offset));
rightPts.add(Vec.addVec(point, offset));
continue;
}
final Vec nextVectorLerped = Vec.lerpVec(nextVector, vector, nextDpr);
final Vec offset = nextVectorLerped.per().mul(strokePoint.radius);
tl = Vec.subVec(point, offset);
if (i <= 1 || Vec.dist2Between(pl, tl) > minDistance) {
leftPts.add(tl);
pl = tl;
}
tr = Vec.addVec(point, offset);
if (i <= 1 || Vec.dist2Between(pr, tr) > minDistance) {
rightPts.add(tr);
pr = tr;
}
prevVector = vector;
}
return {'left': leftPts, 'right': rightPts};
}