查找线段截取有角度的椭圆的点(在JavaScript / TypeScript中)

I ran into this question while working on perfect-arrows, a TypeScript library for drawing arrows between points, rectangles, and other shapes. While the question didn’t seem to obscure, I found it very hard to find an answer. The math itself is beyond me, but I was able to adapt some earlier work from another language.

我在处理Perfect-arrows (一个用于在点,矩形和其他形状之间绘制箭头)的TypeScript库时遇到了这个问题。 虽然这个问题似乎并没有模糊,但我发现很难找到答案。 数学本身超出了我的范围,但是我能够从另一种语言改编一些早期的作品

For the sake of paying it forward (and saving the next sucker—maybe you!—some headaches), here’s the code I came up with:

为了提前付款(并节省下一个傻瓜-也许您!-有点头疼),这是我想出的代码:

/**
 * Find the point(s) where a line segment intersects an ellipse.
 * @param x0 The x-axis coordinate of the line's start point.
 * @param y0 The y-axis coordinate of the line's start point.
 * @param x1 The x-axis coordinate of the line's end point.
 * @param y1 The y-axis coordinate of the line's end point.
 * @param cx The x-axis (horizontal) coordinate of the ellipse's center.
 * @param cy The y-axis (vertical) coordinate of the ellipse's center.
 * @param rx The ellipse's major-axis radius. Must be non-negative.
 * @param ry The ellipse's minor-axis radius. Must be non-negative.
 * @param rotation The rotation of the ellipse, expressed in radians.
 * @param segment_only When true, will test the segment as a line (of infinite length).
 */
export function getEllipseSegmentIntersections(
	x0: number,
	y0: number,
	x1: number,
	y1: number,
	cx: number,
	cy: number,
	rx: number,
	ry: number,
	rotation = 0,
	segment_only = true
) {
	// If the ellipse or line segment are empty, return no tValues.
	if (rx === 0 || ry === 0 || (x0 === x1 && y0 === y1)) {
		return []
	}


	// Get the semimajor and semiminor axes.
	rx = rx < 0 ? rx : -rx
	ry = ry < 0 ? ry : -ry


	// Rotate points.
	if (rotation !== 0) {
		;[x0, y0] = rotatePoint(x0, y0, cx, cy, -rotation)
		;[x1, y1] = rotatePoint(x1, y1, cx, cy, -rotation)
	}


	// Translate so the ellipse is centered at the origin.
	x0 -= cx
	y0 -= cy
	x1 -= cx
	y1 -= cy


	// Calculate the quadratic parameters.
	var A = ((x1 - x0) * (x1 - x0)) / rx / rx + ((y1 - y0) * (y1 - y0)) / ry / ry
	var B = (2 * x0 * (x1 - x0)) / rx / rx + (2 * y0 * (y1 - y0)) / ry / ry
	var C = (x0 * x0) / rx / rx + (y0 * y0) / ry / ry - 1


	// Make a list of t values (normalized points on the line where intersections occur).
	var tValues: number[] = []


	// Calculate the discriminant.
	var discriminant = B * B - 4 * A * C


	if (discriminant === 0) {
		// One real solution.
		tValues.push(-B / 2 / A)
	} else if (discriminant > 0) {
		// Two real solutions.
		tValues.push((-B + Math.sqrt(discriminant)) / 2 / A)
		tValues.push((-B - Math.sqrt(discriminant)) / 2 / A)
	}
	return (
		tValues
			// Filter to only points that are on the segment.
			.filter(t => !segment_only || (t >= 0 && t <= 1))
			// Solve for points.
			.map(t => [x0 + (x1 - x0) * t + cx, y0 + (y1 - y0) * t + cy])
			// Counter-rotate points
			.map(p =>
				rotation === 0 ? p : rotatePoint(p[0], p[1], cx, cy, rotation)
			)
	)
}




/**
 * Rotate a point around a center.
 * @param x0 The x-axis coordinate of the point.
 * @param y0 The y-axis coordinate of the point.
 * @param cx The x-axis coordinate of rotation point.
 * @param cy The y-axis coordinate of rotation point.
 * @param rotation The rotation, expressed in radians.
 */
export function rotatePoint(
	x: number,
	y: number,
	cx: number,
	cy: number,
	rotation: number
) {
	const s = Math.sin(rotation)
	const c = Math.cos(rotation)


	const px = x - cx
	const py = y - cy


	const nx = px * c - py * s
	const ny = px * s + py * c


	return [nx + cx, ny + cy]
}

The important function there is getEllipseSegmentIntersections . It’s written in TypeScript, but feel free to pull those types out if you’d like to use it in a JavaScript project.

其中的重要功能是getEllipseSegmentIntersections 。 它是用TypeScript编写的,但是如果您想在JavaScript项目中使用这些类型,可以随时将其提取出来。

Depending on your project, you may need to sort the returned points in clockwise or counterclockwise order, relative to a center. You can use the points’ cross product for this, and I’ve included a test (pointsAreClockwise) as somewhere to start with that.

根据您的项目,您可能需要按相对于中心的顺时针或逆时针顺序对返回的点进行排序。 您可以为此使用点的叉积,并且我已经在其中开始了一个测试( pointsAreClockwise )。

Good luck!

祝好运!

翻译自: https://medium.com/@steveruiz/find-the-points-where-a-line-segment-intercepts-an-angled-ellipse-in-javascript-typescript-e451524beece

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值