如何通过增加长度来确定正方形周长上的点?

huangapple go评论82阅读模式
英文:

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

你可以通过考虑每一边的长度,并使用数学方法来确定正方形周长上的点,从而创建一个更有效的解决方案。在给定的情况下,你有一个正方形,因此所有边的长度将相等。以下是如何执行此操作的步骤:

  1. 使用两个相邻的顶点计算正方形的边长。
  2. 使用该长度来计算结果点将位于哪一边以及该边内的剩余长度。
  3. 使用线性插值确定精确的点。

以下是一个代码片段,可完成此操作:

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:

  1. Calculate the side length of the square using two adjacent vertices.
  2. Use that length to calculate which side the resulting point will fall on, and the remaining length within that side.
  3. 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]) -&gt; 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 &lt; 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..&lt;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 &gt;= 0 &amp;&amp; sideLengthToPoint &lt;= 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)

huangapple
  • 本文由 发表于 2023年8月10日 14:03:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76872993.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定