Skip to content

Commit

Permalink
feat: lines tangent to ellipse arc and bezier curve
Browse files Browse the repository at this point in the history
  • Loading branch information
plantain-00 committed Oct 29, 2024
1 parent e09999b commit b8ee28f
Showing 1 changed file with 97 additions and 1 deletion.
98 changes: 97 additions & 1 deletion src/utils/tangent-line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ export function getLinesTangentTo2GeometryLines(line1: GeometryLine, line2: Geom
if (line2.type === 'quadratic curve') {
return getLinesTangentToEllipseArcAndQuadraticCurve(line1.curve, line2.curve)
}
return []
if (line2.type === 'bezier curve') {
return getLinesTangentToEllipseArcAndBezierCurve(line1.curve, line2.curve)
}
if (line2.type === 'hyperbola curve') {
return []
}
return getLinesTangentToEllipseArcAndNurbsCurve(line1.curve, line2.curve)
}
if (line2.type === 'ellipse arc') return getLinesTangentTo2GeometryLines(line2, line1)
if (line1.type === 'quadratic curve') {
Expand Down Expand Up @@ -158,6 +164,96 @@ export function getLinesTangentToEllipseArcAndQuadraticCurve(curve1: EllipseArc,
})
}

export function getLinesTangentToEllipseArcAndBezierCurve(curve1: EllipseArc, curve2: BezierCurve): Tuple2<Position>[] {
const [p1, d1, d2] = getEllipseDerivatives(curve1)
const [p2, e1, e2] = getBezierCurveDerivatives(curve2)
const f1 = (t: Vec2): Vec2 => {
// (y1 - y2)/(x1 - x2) = y1'/x1' = y2'/x2'
// z1 = (y1 - y2)x1' - (x1 - x2)y1'
// z2 = y1'x2' - x1'y2'
const { x: x1, y: y1 } = p1(t[0])
const { x: x11, y: y11 } = d1(t[0])
const { x: x2, y: y2 } = p2(t[1])
const { x: x21, y: y21 } = e1(t[1])
return [(y1 - y2) * x11 - (x1 - x2) * y11, y11 * x21 - x11 * y21]
}
const f2 = (t: Vec2): Matrix2 => {
const { x: x1, y: y1 } = p1(t[0])
const { x: x11, y: y11 } = d1(t[0])
const { x: x12, y: y12 } = d2(t[0])
const { x: x2, y: y2 } = p2(t[1])
const { x: x21, y: y21 } = e1(t[1])
const { x: x22, y: y22 } = e2(t[1])
// dz1/dt1 = y1'x1' + (y1 - y2)x1'' - (x1'y1' + (x1 - x2)y1'')
// dz1/dt2 = -y2'x1' + x2'y1'
// dz2/dt1 = y1''x2' - x1''y2'
// dz2/dt2 = y1'x2'' - x1'y2''
return [
y11 * x11 + (y1 - y2) * x12 - (x11 * y11 + (x1 - x2) * y12),
-y21 * x11 + x21 * y11,
y12 * x21 - x12 * y21,
y11 * x22 - x11 * y22,
]
}
let ts: Vec2[] = []
for (const t1 of [-Math.PI / 2, Math.PI / 2]) {
for (const t2 of [0, 0.5, 1]) {
const t = newtonIterate2([t1, t2], f1, f2, delta2)
if (t !== undefined) {
ts.push(t)
}
}
}
ts = deduplicate(ts, deepEquals)
return ts.filter(v => angleInRange(v[0], curve1) && isValidPercent(v[1])).map(t => {
return [p1(t[0]), p2(t[1])]
})
}

export function getLinesTangentToEllipseArcAndNurbsCurve(curve1: EllipseArc, curve2: NurbsCurve): Tuple2<Position>[] {
const [p1, d1, d2] = getEllipseDerivatives(curve1)
const nurbs2 = toVerbNurbsCurve(curve2)
const f1 = (t: Vec2): Vec2 => {
// (y1 - y2)/(x1 - x2) = y1'/x1' = y2'/x2'
// z1 = (y1 - y2)x1' - (x1 - x2)y1'
// z2 = y1'x2' - x1'y2'
const { x: x1, y: y1 } = p1(t[0])
const { x: x11, y: y11 } = d1(t[0])
const [[x2, y2], [x21, y21]] = nurbs2.derivatives(t[1])
return [(y1 - y2) * x11 - (x1 - x2) * y11, y11 * x21 - x11 * y21]
}
const f2 = (t: Vec2): Matrix2 => {
const { x: x1, y: y1 } = p1(t[0])
const { x: x11, y: y11 } = d1(t[0])
const { x: x12, y: y12 } = d2(t[0])
const [[x2, y2], [x21, y21], [x22, y22]] = nurbs2.derivatives(t[1], 2)
// dz1/dt1 = y1'x1' + (y1 - y2)x1'' - (x1'y1' + (x1 - x2)y1'')
// dz1/dt2 = -y2'x1' + x2'y1'
// dz2/dt1 = y1''x2' - x1''y2'
// dz2/dt2 = y1'x2'' - x1'y2''
return [
y11 * x11 + (y1 - y2) * x12 - (x11 * y11 + (x1 - x2) * y12),
-y21 * x11 + x21 * y11,
y12 * x21 - x12 * y21,
y11 * x22 - x11 * y22,
]
}
let ts: Vec2[] = []
const maxParam2 = getNurbsMaxParam(curve2)
for (const t1 of [-Math.PI / 2, Math.PI / 2]) {
for (let t2 = 0.5; t2 < maxParam2; t2++) {
const t = newtonIterate2([t1, t2], f1, f2, delta2)
if (t !== undefined) {
ts.push(t)
}
}
}
ts = deduplicate(ts, deepEquals)
return ts.filter(v => angleInRange(v[0], curve1) && isBetween(v[1], 0, maxParam2)).map(t => {
return [p1(t[0]), fromVerbPoint(nurbs2.point(t[1]))]
})
}

export function getLinesTangentTo2QuadraticCurves(curve1: QuadraticCurve, curve2: QuadraticCurve): Tuple2<Position>[] {
const { from: { x: a1, y: b1 }, cp: { x: a2, y: b2 }, to: { x: a3, y: b3 } } = curve1
const c1 = a2 - a1, c2 = a3 - a2 - c1, c3 = b2 - b1, c4 = b3 - b2 - c3
Expand Down

0 comments on commit b8ee28f

Please sign in to comment.