1 module math.geometry.line;
2 
3 import math.linear.vector;
4 import math.linear.point;
5 import vec_ = math.linear.vector;
6 import point_ = math.linear.point;
7 
8 alias PointLine = PointPointLine;
9 alias PPLine = PointPointLine;
10 struct PointPointLine(T) {
11 	PVec2!T pointA; alias a=pointA;
12 	PVec2!T pointB; alias b=pointB;
13 
14 	PointVecLine!T opCast(_:PointVecLine!T)() {
15 		return VecLine!T(pointA,pointB-pointA);
16 	}
17 }
18 alias VecLine = PointVecLine;
19 alias PVLine = PointVecLine;
20 struct PointVecLine(T) {
21 	PVec2!T pos; alias point=pos; alias p=pos;
22 	Vec2!T vector; alias vec=vector; alias v=vector; alias offset=vector;
23 	
24 	PointPointLine!T opCast(_:PointPointLine!T)() {
25 		return PointLine!T(pos,pos+vec);
26 	}
27 }
28 
29 
30 T distance(T)(Point!(Vec!(T,2)) p, VecLine!T l) {
31 	import std.algorithm.comparison;
32 	import std.math;
33 	auto ms = l.vec.magnitudeSquared;
34 	if (ms == 0)
35 		return (cast(T) sqrt(cast(real) ms)).abs;
36 	auto t = max(0, min(1, dot(p - l.pos, l.vec) / ms));
37 	auto projection = l.pos + t*l.vec;
38 	return vec_.distance(p.v, projection.v);
39 }
40 T distance(T)(VecLine!T l, Point!(Vec!(T,2)) p) {
41 	return distance(p,l);
42 }
43 T distance(T)(Point!(Vec!(T,2)) p, PointLine!T l) {
44 	return distance!T(p, cast(VecLine!T) l);
45 }
46 T distance(T)(PointLine!T l, Point!(Vec!(T,2)) p) {
47 	return distance(p, cast(VecLine!T) l);
48 }
49 
50 /// This does not work when two lines cross.
51 /// TODO: Make this work for when two lines cross.
52 /// TODO: This needs optimized.
53 T distance(T)(VecLine!T l, VecLine!T m) {
54 	import std.algorithm.comparison;
55 	return min(
56 		distance(l.pos	,m),
57 		distance(l.pos+l.vec	,m),
58 		distance(m.pos	,l),
59 		distance(m.pos+m.vec	,l),
60 	);
61 }
62 /// Ditto
63 T distance(T)(PointLine!T l, PointLine!T m) {
64 	import std.algorithm.comparison;
65 	return min(
66 		distance(l.a	,m),
67 		distance(l.b	,m),
68 		distance(m.a	,l),
69 		distance(m.b	,l),
70 	);
71 }
72 
73 
74 @("Point Line Distance")
75 unittest {
76 	assert(distance(pvec(1f,0f), PPLine!float(pvec(0f,1f),pvec(0f,-1f)))==1f);
77 	assert(distance(pvec(-1f,0f), PPLine!float(pvec(0f,1f),pvec(0f,-1f)))==1f);
78 	assert(distance(pvec(1f,0f), PPLine!float(pvec(0f,-1f),pvec(0f,1f)))==1f);
79 	assert(distance(pvec(1f,2f), PPLine!float(pvec(0f,1f),pvec(0f,-1f)))==vec_.distance(vec(1f,2f), vec(0f,1f)));
80 }
81 @("Line Line Distance")
82 unittest {
83 	assert(distance(PPLine!float(pvec(1f,0f), pvec(2f,0f)), PPLine!float(pvec(0f,1f),pvec(0f,-1f)))==1f);
84 }
85