kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

CGL_2_D: Distance (続き3)

交わらない場合に進む

まずは場合分け
線分の幅の範囲にあるかその外にあるかどうか

内積を取れば始点から終点の幅にいるかどうかは判定できる
んだけど関数名が思いつかない

class Point:

    def in_side_of(self, seg: 'Segment') -> bool:
        return seg.vector().dot(
            Segment(seg.p1, self).vector()) >= 0

    def in_width_of(self, seg: 'Segment') -> bool:
        return \
            self.in_side_of(seg) and \
            self.in_side_of(seg.reverse())

class Segment:
    def reverse(self) -> 'Segment':
        return Segment(self.p2, self.p1)

おっと2点間の距離がまだなかった

class Point:
    def distance(self, other: 'Point') -> float:
        return Segment(self, other).vector().abs()

えーとこれで点と線分の距離が出せるようになったかな
名前が苦しい
オーバーロードしたい

class Point:
    def distance_to_segment(self, seg: 'Segment') -> float:
        if self.in_width_of(seg):
            return self.distance(seg.projection(self))
        else:
            return min(self.distance(seg.p1),
                       self.distance(seg.p2))

ここまでくれば晴れて線分と線分の間の距離が出るはず

class Segment:
    def distance_with_segment(self, other: 'Segment') -> float:
        if not self.is_parallel(other) and \
                self.intersects(other):
            return 0
        else:
            return min(
                self.p1.distance_to_segment(other),
                self.p2.distance_to_segment(other),
                other.p1.distance_to_segment(self),
                other.p2.distance_to_segment(self))

あとは呼ぶだけ

def main() -> None:
    n = int(input())

    for _ in range(n):
        x1, y1, x2, y2, x3, y3, x4, y4 = [int(x) for x in input().split()]
        s1 = Segment(Point(x1, y1), Point(x2, y2))
        s2 = Segment(Point(x3, y3), Point(x4, y4))
        print(s1.distance_with_segment(s2))

if __name__ == "__main__":
    main()

AC