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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值