share connected arc impl (#2403)
This commit is contained in:
parent
016c5494f9
commit
3bd1bfa454
9 changed files with 866 additions and 731 deletions
|
@ -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),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue