//(注)
//dist,isIntersectは擬似的に二項関係の演算子として扱う
//intersectionはPのコンストラクタとして扱う
class L extends AL{
L(P _p1, P _p2) {super(_p1, _p2);}
//直線と点の距離
double dist(P p){
return abs(P.S(p2,p,p1))/p1.sub(p2).norm();
}
boolean isIntersect(P p){
return abs(P.S(p2,p,p1))<EPS;
}
boolean isIntersect(L l){
if(isPoint() && l.isPoint())return p1.equals(l.p1);
if(isPoint())return l.isIntersect(p1);
if(l.isPoint())return isIntersect(l.p1);
return !isParallel(l) || isIntersect(l.p1);
}
//垂線の足
static P FootOfLP(L l,P p){
return l.p1.add(P.proj(p.sub(l.p1),l.p2.sub(l.p1)));
}
//線対称な点
static P LineSymmetricLP(L l,P p){
return FootOfLP(l,p).mul(new P(2.0,0)).sub(p);
}
public boolean equals(Object obj) {
if(obj instanceof L){
L l=(L)obj;
return isParallel(l) && isIntersect(l.p1);
}
return false;
}
}
//線分
class S extends AL{
S(P _p1, P _p2) {super(_p1, _p2);}
boolean isIntersect(P p){//|a-p|+|p-b|<=|a-b|
return p1.sub(p).norm()+p2.sub(p).norm()<=p1.sub(p2).norm()+EPS;
}
boolean isIntersect(L l){//l2の端点がl1の上か下か
return P.cross(l.p2.sub(l.p1),p1.sub(l.p1))*
P.cross(l.p2.sub(l.p1),p2.sub(l.p1))<EPS;
}
boolean isIntersect(S l){
return P.ccw(p1,p2,l.p1)*P.ccw(p1,p2,l.p2)<=0
&& P.ccw(l.p1,l.p2,p1)*P.ccw(l.p1,l.p2,p2)<=0;
}
//線分と点
double dist(P p){
if(P.dot(p2.sub(p1),p.sub(p1))<EPS)return p.sub(p1).norm();
if(P.dot(p1.sub(p2),p.sub(p2))<EPS)return p.sub(p2).norm();
return abs(P.S(p2,p,p1))/p1.sub(p2).norm();
}
//直線との距離
double dist(L l){
if(isIntersect(l))return 0;
return min(l.dist(p1),l.dist(p2));
}
//線分と線分
double dist(S l){
if(isIntersect(l))return 0;
return min(min(dist(l.p1),dist(l.p2)),min(l.dist(p1),l.dist(p2)));
}
}
abstract class AL{
//geo
static final double EPS=1e-10;
static int signum(double x){
return x<-EPS?-1:x>EPS?1:0;
}
public P p1,p2;
AL(P _p1,P _p2){
p1=_p1;
p2=_p2;
}
boolean isPoint(){
return p1.equals(p2);
}
// public double a(){
// P dir= p2.sub(p1);
// return dir.y/dir.x;
// }
// public double b(){
// return P.cross(p1,p2)/(p1.x-p2.x);
// }
//平行
boolean isParallel(AL l){
return abs(P.cross(p2.sub(p1),l.p2.sub(l.p1)))<EPS;
}
//直交
boolean isOrthogonal(AL l){
return abs(P.dot(p2.sub(p1),l.p2.sub(l.p1)))<EPS;
}
//交点 (交差判定なし)
static P intersection(AL l1,AL l2){
P dl1=l1.p2.sub(l1.p1),dl2=l2.p2.sub(l2.p1);
double a=P.cross(dl2,l2.p1.sub(l1.p1));
double b=P.cross(dl2,dl1);
if(abs(a)<EPS && abs(b) <EPS)return l1.p1;//same
return l1.p1.add(dl1.mul(new P(a/b,0.0)));
}
public boolean equals(Object obj) {
if(obj instanceof L){
L l=(L)obj;
return this.p1.equals(l.p1) && this.p2.equals(l.p2);
}
return false;
}
public String toString(){
return p1+"-"+p2;
}
}