iTranslated by AI
The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🕊
[Swift] How to determine if a point lies on a line segment in a 2D coordinate system
Explanation
As the title suggests.
Environment: Xcode 12.5.1
import Foundation
struct RectangularCoordinateSystemPoint {
let x: Double
let y: Double
init(_ x: Double, _ y: Double) {
self.x = x
self.y = y
}
}
extension RectangularCoordinateSystemPoint {
// Uses the principle that for a relation A--P--B, the inequality AP + PB < AB does not hold.
// * Note: Evaluating as AP + PB = AB may fail due to floating-point errors in Double, so .ulpOfOne is used instead.
func isIncludeLineSegment(consistingOf endPoint: (a: RectangularCoordinateSystemPoint, b: RectangularCoordinateSystemPoint)) -> Bool {
let distanceToA = self.distance(to: endPoint.a)
let distanceToB = self.distance(to: endPoint.b)
let distanceAB = endPoint.a.distance(to: endPoint.b)
return distanceToA + distanceToB - distanceAB < .ulpOfOne
}
func distance(to target: RectangularCoordinateSystemPoint) -> Double {
return sqrt(self.diffX(to: target) * self.diffX(to: target) + self.diffY(to: target) * self.diffY(to: target)) // pow() could be used for squaring, but it's avoided because it's cumbersome with specific Double type requirements.
}
func diffX(to target: RectangularCoordinateSystemPoint) -> Double {
return self.x - target.x
}
func diffY(to target: RectangularCoordinateSystemPoint) -> Double {
return self.y - target.y
}
}
extension RectangularCoordinateSystemPoint {
// Another evaluation method (might have issues)
func isIncludeLineSegmentOther(consistingOf endPoint: (a: RectangularCoordinateSystemPoint, b: RectangularCoordinateSystemPoint)) -> Bool {
if (endPoint.a.x <= self.x && self.x <= endPoint.b.x) || (endPoint.b.x <= self.x && self.x <= endPoint.a.x) {
if (endPoint.a.y <= self.y && self.y <= endPoint.b.y) || (endPoint.b.y <= self.y && self.y <= endPoint.a.y) {
if (self.y * (endPoint.a.x - endPoint.b.x)) + (endPoint.a.y * (endPoint.b.x - self.x)) + (endPoint.b.y * (self.x - endPoint.a.x)) == 0 {
// Point P is on the line segment AB
return true
}
}
}
return false
}
}
/// Test
/// y = 2x + 1
/// 5 listed points: (0, 1), (1, 3), (2,5), (3,7), (4,8)
/// Consider the line segment between (1,3) and (3, 7)
let point01 = RectangularCoordinateSystemPoint(0,1)
let point13 = RectangularCoordinateSystemPoint(1,3)
let point25 = RectangularCoordinateSystemPoint(2,5)
let point37 = RectangularCoordinateSystemPoint(3,7)
let point48 = RectangularCoordinateSystemPoint(4,8)
let point00 = RectangularCoordinateSystemPoint(0,0) // Another point not on the line
/// Test with isIncludeLineSegment
print(point01.isIncludeLineSegment(consistingOf: (point13, point37))) // false
print(point13.isIncludeLineSegment(consistingOf: (point13, point37))) // true
print(point25.isIncludeLineSegment(consistingOf: (point13, point37))) // true
print(point37.isIncludeLineSegment(consistingOf: (point13, point37))) // true
print(point48.isIncludeLineSegment(consistingOf: (point13, point37))) // false
print(point00.isIncludeLineSegment(consistingOf: (point13, point37))) // false
/// Test with isIncludeLineSegmentOther
print(point01.isIncludeLineSegmentOther(consistingOf: (point13, point37))) // false
print(point13.isIncludeLineSegmentOther(consistingOf: (point13, point37))) // true
print(point25.isIncludeLineSegmentOther(consistingOf: (point13, point37))) // true
print(point37.isIncludeLineSegmentOther(consistingOf: (point13, point37))) // true
print(point48.isIncludeLineSegmentOther(consistingOf: (point13, point37))) // false
print(point00.isIncludeLineSegmentOther(consistingOf: (point13, point37))) // false
Discussion