package storm.applications.model.gis;
import java.util.ArrayList;
public class Polygon {
private static final int EARTH_RADIUS = 6378137;
private ArrayList<Point> points;
private double xmin;
private double xmax;
private double ymin;
private double ymax;
private int count;
private double distance_min = 10/111.2*1000;
public Polygon(ArrayList<Point> points) {
this.points = points;
this.count = points.size();
this.xmin = Double.MAX_VALUE;
this.xmax = Double.MIN_VALUE;
this.ymin = Double.MAX_VALUE;
this.ymax = Double.MIN_VALUE;
for (Point p : points) {
if (p.getX() > this.xmax)
this.xmax = p.getX();
if (p.getX() < this.xmin)
this.xmin = p.getX();
if (p.getY() > this.ymax)
this.ymax = p.getY();
if (p.getY() < this.ymin)
this.ymin = p.getY();
}
}
public Boolean contains(Point p) {
if(p.getX() >= xmax || p.getX() < xmin || p.getY() >= ymax || p.getY() < ymin)
return false;
int cn = 0;
int n = points.size();
for (int i = 0; i < n - 1; i++) {
if (points.get(i).getY() != points.get(i+1).getY() && !((p.getY() < points.get(i).getY())
&& (p.getY() < points.get(i+1).getY())) && !((p.getY() > points.get(i).getY())
&& (p.getY() > points.get(i+1).getY()))) {
double uy = 0;
double by = 0;
double ux = 0;
double bx = 0;
int dir = 0;
if (points.get(i).getY() > points.get(i+1).getY()) {
uy = points.get(i).getY();
by = points.get(i+1).getY();
ux = points.get(i).getX();
bx = points.get(i+1).getX();
dir = 0;//downward
} else {
uy = points.get(i+1).getY();
by = points.get(i).getY();
ux = points.get(i+1).getX();
bx = points.get(i).getX();
dir = 1;//upward
}
double tx = 0;
if (ux != bx){
double k = (uy-by)/(ux-bx);
double b = ((uy-k*ux)+(by-k*bx))/2;
tx = (p.getY()-b)/k;
} else {
tx = ux;
}
if (tx > p.getX()) {
if(dir == 1 && p.getY() != points.get(i+1).getY())
cn++;
else if(p.getY() != points.get(i).getY())
cn++;
}
}
}
return cn%2 != 0;
}
public boolean matchToRoad(Point p, int roadWidth) {
int n = points.size();
for (int i = 0; i < n - 1; i++) {
double distance = Math.sqrt(Math.pow(points.get(i).getY() - p.getY(), 2) + Math.pow(points.get(i).getX() - p.getX(), 2));
if (distance < roadWidth/2.0 * Math.sqrt(2.0))
return true;
}
return false;
}
public boolean matchToRoad(Point p, int roadWidth, ArrayList<Point> ps) {
double minD=Double.MAX_VALUE;
int n = ps.size();
for (int i = 0; i < n - 2; i++) {
double distance = Polygon.pointToLine(ps.get(i).getX(), ps.get(i).getY(), ps.get(i+1).getX(), ps.get(i+1).getY(), p.getX(), p.getY())*111.2*1000 ;
if (distance < minD)
minD = distance;
//System.out.println("distance="+distance);
if (distance < roadWidth/2.0 * Math.sqrt(2.0))
return true;
}
return false;
}
public static double pointToLine(double x1, double y1, double x2, double y2, double x0, double y0) {
double space = 0;
double a, b, c;
a = Polygon.lineSpace(x1, y1, x2, y2);
b = lineSpace(x1, y1, x0, y0);
c = lineSpace(x2, y2, x0, y0);
if (c <= 0.000001 || b <= 0.000001) {
space = 0;
return space;
}
if (a <= 0.000001) {
space = b;
return space;
}
if (c * c >= a * a + b * b) {
space = b;
return space;
}
if (b * b >= a * a + c * c) {
space = c;
return space;
}
double p = (a + b + c) / 2;
double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));
space = 2 * s / a;
return space;
}
public static double lineSpace(double x1, double y1, double x2, double y2) {
double lineLength = 0;
lineLength = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2)
* (y1 - y2));
return lineLength;
}
public static double DistancePointToLine(double x1, double y1, double x2, double y2,double x, double y) {
if (y1 == y2) {
if (Math.min(x1, x2) < x && Math.max(x1, x2) > x) {
return Math.abs(ComputeD(y1, x, y, x));
} else {
return Math.min(ComputeD(y, x, y1, x1), ComputeD(y, x, y2, x2));
}
}
if (x1 == x2) {
if (Math.min(y1, y2) < y && Math.max(y1, y2) > y) {
return ComputeD(y, x1, y, x);
} else {
return Math.min(ComputeD(y, x, y1, x1), ComputeD(y, x, y2, x2));
}
} else {
double k = (y2 - y1) / (x2 - x1);
double tempX = (Math.pow(k, 2.0) * x1 + k * (y - y1) + x) / (Math.pow(k, 2.0) + 1.0);
double tempY = k * (tempX - x1) + y1;
if (tempX < -180 || tempX > 180 || tempY < -90 || tempY > 90) {
return Math.min(ComputeD(y, x, y1, x1), ComputeD(y, x, y2, x2));
}
double tempDis1 = (ComputeD(tempY, tempX, y1, x1) + ComputeD(tempY, tempX, y2, x2));
double tempDis2 = ComputeD(y1, x1, y2, x2);
if ((tempDis1 - tempDis2) < 0.001) {
return (ComputeD(tempY, tempX, y, x));
} else {
return Math.min(ComputeD(y, x, y1, x1), ComputeD(y, x, y2, x2));
}
}
}
public static double ComputeD(double lat_a, double lng_a, double lat_b, double lng_b) {
double radLat1 = (lat_a * Math.PI / 180.0);
double radLat2 = (lat_b * Math.PI / 180.0);
double a = radLat1 - radLat2;
double b = (lng_a - lng_b) * Math.PI / 180.0;
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
+ Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * EARTH_RADIUS;
return s;
}
}