英文:
How to determine the point on the perimeter of a square by adding length?
问题
给定代表正方形四个角的四个向量(v1、v2、v3 和 v4)、正方形周边上的任意一点(p)以及一个长度(n),如何确定正方形周边上的点(r),该点是将长度添加到点 p 上的结果?
例如:
let v1 = CGPoint(x: 0.0, y: 0.0)
let v2 = CGPoint(x: 10.0, y: 0.0)
let v3 = CGPoint(x: 10.0, y: 10.0)
let v4 = CGPoint(x: 0.0, y: 10.0)
let corners = [v1, v2, v3, v4]
let p = CGPoint(x: 5.0, y: 0.0)
func add(length n: CGFloat, to p: CGPoint, constrainedTo corners: [CGPoint]) -> CGPoint {
// …魔法!🔮;
return r
}
var n: CGFloat = 17.0
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 8.0, 10.0)
n: CGFloat = -17.0
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 2.0, 10.0)
n: CGFloat = -32.8
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 10.0, y: 2.2)
最有效的方法是否只是循环遍历“边”,根据需要添加和减少,直到 n = 0
?还是实际上有一个等式可以用来解决这个问题,可能是我在学校学过但已经忘记的?
英文:
Given four vectors that represent the corners of a square (v1, v2, v3, and v4), any point along the perimeter of the square (p), and a length (n), how can I determine the point on the perimeter of the square (r) that is the result of adding the length?
For example:
let v1 = CGPoint(x: 0.0, y: 0.0)
let v2 = CGPoint(x: 10.0, y: 0.0)
let v3 = CGPoint(x: 10.0, y: 10.0)
let v4 = CGPoint(x: 0.0, y: 10.0)
let corners = [v1, v2, v3, v4]
let p = CGPoint(x: 5.0, y: 0.0)
func add(length n: CGFloat, to p: CGPoint, constrainedTo corners: [CGPoint]) -> CGPoint {
// …magic!🪄
return r
}
var n: CGFloat = 17.0
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 8.0, 10.0)
n: CGFloat = -17.0
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 2.0, 10.0)
n: CGFloat = -32.8
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 10.0, y: 2.2)
Is the most efficient way to just loop through the “sides”, adding and subtracting as necessary until n = 0
? Or is there an actual equation for this that I was probably taught in school and forgot?
答案1
得分: 1
你可以通过考虑每一边的长度,并使用数学方法来确定正方形周长上的点,从而创建一个更有效的解决方案。在给定的情况下,你有一个正方形,因此所有边的长度将相等。以下是如何执行此操作的步骤:
- 使用两个相邻的顶点计算正方形的边长。
- 使用该长度来计算结果点将位于哪一边以及该边内的剩余长度。
- 使用线性插值确定精确的点。
以下是一个代码片段,可完成此操作:
import CoreGraphics
import Foundation
func add(length n: CGFloat, to p: CGPoint, constrainedTo corners: [CGPoint]) -> CGPoint {
let sideLength = hypot(corners[0].x - corners[1].x, corners[0].y - corners[1].y)
let perimeterLength = 4 * sideLength
// Normalize the length to within the range of the perimeter
var normalizedLength = n.truncatingRemainder(dividingBy: perimeterLength)
if normalizedLength < 0 {
normalizedLength += perimeterLength
}
// Determine which side the starting point is on and calculate total distance traveled
var totalLength: CGFloat = 0
var sideIndex: Int = 0
for i in 0..<4 {
let nextI = (i + 1) % 4
let sideVector = CGPoint(x: corners[nextI].x - corners[i].x, y: corners[nextI].y - corners[i].y)
let toPointVector = CGPoint(x: p.x - corners[i].x, y: p.y - corners[i].y)
let dotProduct = sideVector.x * toPointVector.x + sideVector.y * toPointVector.y
let sideLengthToPoint = dotProduct / sideLength
if sideLengthToPoint >= 0 && sideLengthToPoint <= sideLength {
totalLength = CGFloat(i) * sideLength + sideLengthToPoint + normalizedLength
break
}
}
// Determine which side the result is on and calculate the final point
sideIndex = Int(totalLength / sideLength)
let remainingLength = totalLength.truncatingRemainder(dividingBy: sideLength)
let ratio = remainingLength / sideLength
let startCorner = corners[sideIndex]
let endCorner = corners[(sideIndex + 1) % 4]
let r = CGPoint(x: startCorner.x + ratio * (endCorner.x - startCorner.x),
y: startCorner.y + ratio * (endCorner.y - startCorner.y))
return r
}
// Usage example:
let v1 = CGPoint(x: 0.0, y: 0.0)
let v2 = CGPoint(x: 10.0, y: 0.0)
let v3 = CGPoint(x: 10.0, y: 10.0)
let v4 = CGPoint(x: 0.0, y: 10.0)
let corners = [v1, v2, v3, v4]
let p = CGPoint(x: 5.0, y: 0.0)
var n: CGFloat = 17.0
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 8.0, y: 10.0)
英文:
You can create a more efficient solution by considering the length of each side and using a mathematical approach to determine the point on the perimeter of the square. In the given scenario, you have a square, so all the sides will have the same length. Here's how you can do it:
- Calculate the side length of the square using two adjacent vertices.
- Use that length to calculate which side the resulting point will fall on, and the remaining length within that side.
- Use linear interpolation to determine the exact point.
Below is a code snippet to accomplish this:
import CoreGraphics
import Foundation
func add(length n: CGFloat, to p: CGPoint, constrainedTo corners: [CGPoint]) -> CGPoint {
let sideLength = hypot(corners[0].x - corners[1].x, corners[0].y - corners[1].y)
let perimeterLength = 4 * sideLength
// Normalize the length to within the range of the perimeter
var normalizedLength = n.truncatingRemainder(dividingBy: perimeterLength)
if normalizedLength < 0 {
normalizedLength += perimeterLength
}
// Determine which side the starting point is on and calculate total distance traveled
var totalLength: CGFloat = 0
var sideIndex: Int = 0
for i in 0..<4 {
let nextI = (i + 1) % 4
let sideVector = CGPoint(x: corners[nextI].x - corners[i].x, y: corners[nextI].y - corners[i].y)
let toPointVector = CGPoint(x: p.x - corners[i].x, y: p.y - corners[i].y)
let dotProduct = sideVector.x * toPointVector.x + sideVector.y * toPointVector.y
let sideLengthToPoint = dotProduct / sideLength
if sideLengthToPoint >= 0 && sideLengthToPoint <= sideLength {
totalLength = CGFloat(i) * sideLength + sideLengthToPoint + normalizedLength
break
}
}
// Determine which side the result is on and calculate the final point
sideIndex = Int(totalLength / sideLength)
let remainingLength = totalLength.truncatingRemainder(dividingBy: sideLength)
let ratio = remainingLength / sideLength
let startCorner = corners[sideIndex]
let endCorner = corners[(sideIndex + 1) % 4]
let r = CGPoint(x: startCorner.x + ratio * (endCorner.x - startCorner.x),
y: startCorner.y + ratio * (endCorner.y - startCorner.y))
return r
}
// Usage example:
let v1 = CGPoint(x: 0.0, y: 0.0)
let v2 = CGPoint(x: 10.0, y: 0.0)
let v3 = CGPoint(x: 10.0, y: 10.0)
let v4 = CGPoint(x: 0.0, y: 10.0)
let corners = [v1, v2, v3, v4]
let p = CGPoint(x: 5.0, y: 0.0)
var n: CGFloat = 17.0
let r = add(length: n, to: p, constrainedTo: corners) // CGPoint(x: 8.0, y: 10.0)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论