Option<Vec2> Intersection::get(const Ray& a, const LineSegment& b) {
	auto bdir = b.pointB() - b.pointA();
	auto blen = bdir.length();
	bdir /= blen;

	const auto dt = a.m_direction.x * bdir.y - bdir.x * a.m_direction.y;
	if (aeq(dt, 0.0f))
		return nullptr;
	const auto dx = a.m_point.x - b.pointA().x;
	const auto dy = a.m_point.y - b.pointA().y;
	auto u = (a.m_direction.x * dy - a.m_direction.y * dx) / dt;
	auto t = (bdir.x * dy - bdir.y * dx) / dt;

	auto pt = a.sampleAlongRay(t);
	if (aeq(pt, a.m_point)) {
		pt = a.m_point;
		t = 0;
	}
	if (aeq(pt, b.pointA())) {
		pt = b.pointA();
		u = 0;
	}
	if (aeq(pt, b.pointB())) {
		pt = b.pointB();
		u = blen;
	}
	assert(aeq(pt, b.pointA() + bdir * u));
	return t < 0 || u < 0 || u > blen ? nullptr : (Option<Vec2>)pt;
}
Option<Vec2> Intersection::get(const LineSegment& a, const LineSegment& b) {
	auto Intersection = get(a.containingLine(), b.containingLine());
	if (!Intersection)
		return nullptr;
	if (aeq(Intersection.value(), a.pointA()))
		Intersection = a.pointA();
	if (aeq(Intersection.value(), a.pointB()))
		Intersection = a.pointB();
	if (aeq(Intersection.value(), b.pointA()))
		Intersection = b.pointA();
	if (aeq(Intersection.value(), b.pointB()))
		Intersection = b.pointB();

	auto dirA = a.pointB() - a.pointA();
	const auto dirALen = dirA.length();
	dirA /= dirALen;
	auto dirB = b.pointB() - b.pointA();
	const auto dirBLen = dirB.length();
	dirB /= dirBLen;
	const auto t = dot(Intersection.value() - a.pointA(), dirA);
	const auto u = dot(Intersection.value() - b.pointA(), dirB);
	if (t >= 0 && u >= 0 && t <= dirALen && u <= dirBLen)
		return Intersection;
	else
		return nullptr;
}