php如何测量坐标周围,php – 如何检查经度/纬度点是否在坐标范围内?
這基本上是球體上的
Point in polygon問題.您可以修改光線投射算法,使其使用大圓弧而不是線段.
>對于構成多邊形的每對相鄰坐標,在它們之間繪制一個大的圓弧段.
>選擇不在多邊形區域內的參考點.
>繪制一個從參考點開始并在車輛終點結束的大圓段.計算此段跨越多邊形段的次數.如果總次數是奇數,則車輛在多邊形內.如果均勻,則車輛在多邊形之外.
或者,如果坐標和車輛足夠靠近,而不是靠近極點或國際日期線,您可以假裝地球是平坦的,并使用經度和緯度作為簡單的x和y坐標.這樣,您可以將光線投射算法與簡單的線段一起使用.如果您對非歐幾里德幾何體感到不舒服,這是更可取的,但是由于弧會扭曲,因此您的多邊形邊界周圍會有一些扭曲.
編輯:關于球體幾何的更多信息.
可以通過垂直于圓所在平面的矢量來識別大圓(AKA,normal vector)
class Vector{
double x;
double y;
double z;
};
class GreatCircle{
Vector normal;
}
不是antipodal的任何兩個緯度/經度坐標恰好共享一個大圓.要找到這個大圓,請將坐標轉換為穿過地球中心的線.這兩條線的cross product是坐標大圓的法線向量.
//arbitrarily defining the north pole as (0,1,0) and (0'N, 0'E) as (1,0,0)
//lattidues should be in [-90, 90] and longitudes in [-180, 180]
//You'll have to convert South lattitudes and East longitudes into their negative North and West counterparts.
Vector lineFromCoordinate(Coordinate c){
Vector ret = new Vector();
//given:
//tan(lat) == y/x
//tan(long) == z/x
//the Vector has magnitude 1, so sqrt(x^2 + y^2 + z^2) == 1
//rearrange some symbols, solving for x first...
ret.x = 1.0 / math.sqrt(tan(c.lattitude)^2 + tan(c.longitude)^2 + 1);
//then for y and z
ret.y = ret.x * tan(c.lattitude);
ret.z = ret.x * tan(c.longitude);
return ret;
}
Vector Vector::CrossProduct(Vector other){
Vector ret = new Vector();
ret.x = this.y * other.z - this.z * other.y;
ret.y = this.z * other.x - this.x * other.z;
ret.z = this.x * other.y - this.y * other.x;
return ret;
}
GreatCircle circleFromCoordinates(Coordinate a, Coordinate b){
Vector a = lineFromCoordinate(a);
Vector b = lineFromCoordinate(b);
GreatCircle ret = new GreatCircle();
ret.normal = a.CrossProdct(b);
return ret;
}
兩個大圓在球體上的兩個點相交.圓的叉積形成通過這些點之一的矢量.該向量的對映體通過另一個點.
Vector intersection(GreatCircle a, GreatCircle b){
return a.normal.CrossProduct(b.normal);
}
Vector antipode(Vector v){
Vector ret = new Vector();
ret.x = -v.x;
ret.y = -v.y;
ret.z = -v.z;
return ret;
}
大圓段可以通過段的起點和終點表示.
class GreatCircleSegment{
Vector start;
Vector end;
Vector getNormal(){return start.CrossProduct(end);}
GreatCircle getWhole(){return new GreatCircle(this.getNormal());}
};
GreatCircleSegment segmentFromCoordinates(Coordinate a, Coordinate b){
GreatCircleSegment ret = new GreatCircleSegment();
ret.start = lineFromCoordinate(a);
ret.end = lineFromCoordinate(b);
return ret;
}
您可以使用dot product測量大圓弧段的圓弧大小或任意兩個向量之間的角度.
double Vector::DotProduct(Vector other){
return this.x*other.x + this.y*other.y + this.z*other.z;
}
double Vector::Magnitude(){
return math.sqrt(pow(this.x, 2) + pow(this.y, 2) + pow(this.z, 2));
}
//for any two vectors `a` and `b`,
//a.DotProduct(b) = a.magnitude() * b.magnitude() * cos(theta)
//where theta is the angle between them.
double angleBetween(Vector a, Vector b){
return math.arccos(a.DotProduct(b) / (a.Magnitude() * b.Magnitude()));
}
您可以測試一個大圓段a是否與一個大圓b相交:
>找到向量c,一個整個大圓與b的交點.
>找到向量d,c的對映體.
>如果c位于a.start和a.end之間,或者d位于a.start和a.end之間,則a與b相交.
//returns true if Vector x lies between Vectors a and b.
//note that this function only gives sensical results if the three vectors are coplanar.
boolean liesBetween(Vector x, Vector a, Vector b){
return angleBetween(a,x) + angleBetween(x,b) == angleBetween(a,b);
}
bool GreatCircleSegment::Intersects(GreatCircle b){
Vector c = intersection(this.getWhole(), b);
Vector d = antipode(c);
return liesBetween(c, this.start, this.end) or liesBetween(d, this.start, this.end);
}
如果出現以下情況,兩個大圓段a和b相交:
> a與b的整個大圓相交
> b與整個大圓相交
bool GreatCircleSegment::Intersects(GreatCircleSegment b){
return this.Intersects(b.getWhole()) and b.Intersects(this.getWhole());
}
現在,您可以構造多邊形并計算參考線在其上經過的次數.
bool liesWithin(Array polygon, Coordinate pointNotLyingInsidePolygon, Coordinate vehiclePosition){
GreatCircleSegment referenceLine = segmentFromCoordinates(pointNotLyingInsidePolygon, vehiclePosition);
int intersections = 0;
//iterate through all adjacent polygon vertex pairs
//we iterate i one farther than the size of the array, because we need to test the segment formed by the first and last coordinates in the array
for(int i = 0; i < polygon.size + 1; i++){
int j = (i+1) % polygon.size;
GreatCircleSegment polygonEdge = segmentFromCoordinates(polygon[i], polygon[j]);
if (referenceLine.Intersects(polygonEdge)){
intersections++;
}
}
return intersections % 2 == 1;
}
總結
以上是生活随笔為你收集整理的php如何测量坐标周围,php – 如何检查经度/纬度点是否在坐标范围内?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle access manage
- 下一篇: c#怎么调用oracle存储过程,c#