Skip to content

Instantly share code, notes, and snippets.

@Pooh3Mobi
Last active March 26, 2019 01:05
Show Gist options
  • Save Pooh3Mobi/f0905fd70db12b99a9f3c0bd29045b87 to your computer and use it in GitHub Desktop.
Save Pooh3Mobi/f0905fd70db12b99a9f3c0bd29045b87 to your computer and use it in GitHub Desktop.
the intersection of two lines
import java.lang.AssertionError
data class Point(val x: Float, val y: Float)
fun pointAt(x: Float, y: Float) = Point(x, y)
data class Line(val p1: Point, val p2: Point)
infix fun Point.to(other: Point) = Line(this, other)
// 傾き
fun Line.slope() = (p2.y - p1.y) / (p2.x - p1.x)
// Y軸切片
fun Line.interceptYAxis() = p1.y - slope() * p1.x
// y = f(x)
fun Line.getY(x: Float): Float = slope() * x + interceptYAxis()
// 交点
fun Line.getIntercept(other: Line): Point? {
val slopeA = this.slope()
val slopeB = other.slope()
return if (slopeA == slopeB) {
// parallel
null
} else {
val interceptX = (other.interceptYAxis() - this.interceptYAxis()) / (slopeA - slopeB)
val interceptY = this.getY(interceptX)
pointAt(interceptX, interceptY)
}
}
// 線上に存在するかどうか
fun Line.contains(point: Point): Boolean {
val x = point.x
val y = point.y
val containsX = (x in p1.x..p2.x) || (x in p2.x..p1.x)
val containsY = (y in p1.y..p2.y) || (y in p2.y..p1.y)
return containsX && containsY
}
// 交差しているかどうか
fun Line.isIntersect(other: Line): Boolean {
if (this.slope() == other.slope()) return false
val intercept = this.getIntercept(other) ?: return false
return this.contains(intercept) && other.contains(intercept)
}
fun Point.move(point: Point) = copy(x = x + point.x, y = y + point.y)
fun Line.parallelTransport(point: Point) = copy(p1 = p1.move(point), p2 = p2.move(point))
fun main() {
run {
val lineA = pointAt(1f, 1f) to pointAt(-1f, -1f)
val lineB = pointAt(-1f, 1f) to pointAt(1f, -1f)
// 交点を持つ
val interceptPoint = lineA.getIntercept(lineB)
if (interceptPoint != pointAt(0f, 0f)) throw AssertionError("$interceptPoint")
val isIntersect = lineA.isIntersect(lineB)
if (!isIntersect) throw AssertionError("$lineA : $lineB")
}
run {
val lineA = pointAt(1f, 1f) to pointAt(0f, 0f)
val lineB = pointAt(0f, 0f) to pointAt(1f, -1f)
// 交点を持つ
val interceptPoint = lineA.getIntercept(lineB)
if (interceptPoint != pointAt(0f, 0f)) throw AssertionError("$interceptPoint")
val isIntersect = lineA.isIntersect(lineB)
if (!isIntersect) throw AssertionError("$lineA : $lineB")
}
run {
val dist = pointAt(3f, -3f)
val lineA = pointAt(1f, 1f) to pointAt(-1f, -1f)
val lineB = pointAt(-1f, 1f).move(dist) to pointAt(1f, -1f).move(dist)
// 直線上の延長線上に交点を持つが、範囲内では交差しない
val interceptPoint = lineA.getIntercept(lineB)
if (interceptPoint != pointAt(0f, 0f)) throw AssertionError("$interceptPoint")
val isIntersect = lineA.isIntersect(lineB)
if (isIntersect) throw AssertionError("$lineA : $lineB")
}
run {
val dist = pointAt(-3f, 3f)
val lineA = pointAt(1f, 1f) to pointAt(-1f, -1f)
val lineB = pointAt(-1f, 1f).move(dist) to pointAt(1f, -1f).move(dist)
// 直線上の延長線上に交点を持つが、範囲内では交差しない
val interceptPoint = lineA.getIntercept(lineB)
if (interceptPoint != pointAt(0f, 0f)) throw AssertionError("$interceptPoint")
val isIntersect = lineA.isIntersect(lineB)
if (isIntersect) throw AssertionError("$lineA : $lineB")
}
run {
val dist = pointAt(-5f, -5f)
val lineA = pointAt(1f, 1f) to pointAt(-1f, -1f)
val lineB = pointAt(-1f, 1f).move(dist) to pointAt(1f, -1f).move(dist)
// 直線上の延長線上に交点を持つが、範囲内では交差しない
val interceptPoint = lineA.getIntercept(lineB)
if (interceptPoint != pointAt(-5f, -5f)) throw AssertionError("$interceptPoint")
val isIntersect = lineA.isIntersect(lineB)
if (isIntersect) throw AssertionError("$lineA : $lineB")
}
run {
val dist = pointAt(5f, 5f)
val lineA = pointAt(1f, 1f) to pointAt(-1f, -1f)
val lineB = pointAt(-1f, 1f).move(dist) to pointAt(1f, -1f).move(dist)
// 直線上の延長線上に交点を持つが、範囲内では交差しない
val interceptPoint = lineA.getIntercept(lineB)
if (interceptPoint != pointAt(5f, 5f)) throw AssertionError("$interceptPoint")
val isIntersect = lineA.isIntersect(lineB)
if (isIntersect) throw AssertionError("$lineA : $lineB")
}
run {
val dist = pointAt(5f, 5f)
val lineA = pointAt(1f, 1f) to pointAt(1f, -1f)
val lineB = lineA.parallelTransport(dist)
// 直線上の延長線上に持たず、範囲内では交差しない
val interceptPoint = lineA.getIntercept(lineB)
if (interceptPoint != null) throw AssertionError("$interceptPoint")
val isIntersect = lineA.isIntersect(lineB)
if (isIntersect) throw AssertionError("$lineA : $lineB")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment