1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Swift】平面座標系である点がある線分上にあるかを評価する方法

Last updated at Posted at 2021-09-02

解説

タイトルの通りです。
環境:Xcode12.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 {
    // A--P-B という関係なら AP + PB < AB は成り立たないことを用いる 
    // ※ ここで AP + PB = AB で評価すると Double の端数で等式が成り立たなくなるので .ulpOfOne を用いる
    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()でもよいがDouble型の指定があるため使いづらいため敬遠
    }
    
    func diffX(to target: RectangularCoordinateSystemPoint) -> Double {
        return self.x - target.x
    }
    
    func diffY(to target: RectangularCoordinateSystemPoint) -> Double {
        return self.y - target.y
    }
}

extension RectangularCoordinateSystemPoint {
    // 別の評価方法(問題があるかもしれません)
    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 {
                    // 点Pが線分AB上にある
                    return true
                }
            }
        }
        return false
    }
}

/// テスト
/// y = 2x + 1
/// 5点列挙:(0, 1), (1, 3), (2,5), (3,7), (4,8)
/// (1,3) と (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) // 直線上にないその他の点

/// 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

/// 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
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?