share connected arc impl (#2403)

This commit is contained in:
Belleve 2024-06-30 20:51:05 -10:00 committed by GitHub
parent 016c5494f9
commit 3bd1bfa454
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 866 additions and 731 deletions

View file

@ -41,12 +41,12 @@ function convertContourToArcs(contour) {
const zc = z;
let zf = contour[(j + 1) % contour.length];
const zfIsCorner = zf.type === Point.Type.contour;
if (!zfIsCorner) zf = Point.from(Point.Type.Corner, zc).mix(0.5, zf);
if (!zfIsCorner) zf = Point.from(Point.Type.Corner, zc).mix(zf, 0.5);
newContour.push(
new TypoGeom.Arcs.Bez3(
z0,
Point.from(Point.Type.CubicStart, z0).mix(2 / 3, zc),
Point.from(Point.Type.CubicEnd, zf).mix(2 / 3, zc),
Point.from(Point.Type.CubicStart, z0).mix(zc, 2 / 3),
Point.from(Point.Type.CubicEnd, zf).mix(zc, 2 / 3),
Point.from(Point.Type.Corner, zf),
),
);

View file

@ -33,12 +33,8 @@ export class Point {
addScale(scale, z2) {
return new Point(this.type, this.x + scale * z2.x, this.y + scale * z2.y);
}
mix(scale, z2) {
return new Point(
this.type,
this.x + scale * (z2.x - this.x),
this.y + scale * (z2.y - this.y),
);
mix(z2, t) {
return new Point(this.type, mix(this.x, z2.x, t), mix(this.y, z2.y, t));
}
scale(t) {
return new Point(this.type, t * this.x, t * this.y);

View file

@ -54,63 +54,21 @@ class SpiroSimplifier {
if (arc.arcLength > 1e-6) this.combinedArcs.push(arc);
} else {
const combined = new SpiroSequenceArc(this.m_ongoingArcs);
if (combined.totalLength > 1e-6) this.combinedArcs.push(combined);
if (!combined.isEmpty() && combined.totalLength > 1e-6) {
this.combinedArcs.push(combined);
}
}
this.m_ongoingArcs = [];
}
}
class SpiroSequenceArc {
const SpiroMeasurer = {
measureLength(a) {
return a.arcLength;
},
};
class SpiroSequenceArc extends TypoGeom.Arcs.CombinedArc {
constructor(segments) {
// Filter out zero-length segments
let rear = 0;
for (let j = 0; j < segments.length; j++) {
if (segments[j].arcLength > 1e-6) {
segments[rear++] = segments[j];
}
}
segments.length = rear;
// Compute total length and stops
let totalLength = 0;
let stops = [];
for (let j = 0; j < segments.length; j++) {
stops[j] = totalLength;
totalLength += segments[j].arcLength;
}
for (let j = 0; j < segments.length; j++) {
stops[j] = stops[j] / totalLength;
}
this.totalLength = totalLength;
this.m_segments = segments;
this.m_stops = stops;
}
eval(t) {
const j = segTSearch(this.m_stops, t);
const tBefore = this.m_stops[j];
const tNext = j < this.m_stops.length - 1 ? this.m_stops[j + 1] : 1;
const tRelative = (t - tBefore) / (tNext - tBefore);
return this.m_segments[j].eval(tRelative);
}
derivative(t) {
const j = segTSearch(this.m_stops, t);
const tBefore = this.m_stops[j];
const tNext = j < this.m_stops.length - 1 ? this.m_stops[j + 1] : 1;
const tRelative = (t - tBefore) / (tNext - tBefore);
return Vec2.scaleFrom(1 / (tNext - tBefore), this.m_segments[j].derivative(tRelative));
super(SpiroMeasurer, segments);
}
}
function segTSearch(stops, t) {
if (t < 0) return 0;
let l = 0,
r = stops.length;
while (l < r) {
let m = (l + r) >>> 1;
if (stops[m] > t) r = m;
else l = m + 1;
}
return r - 1;
}