如何检查,如果经/纬度点是坐标范围之内?(How do I check if a longitude

2019-06-26 07:51发布

我公司拥有一批经度和纬度坐标,使一个多边形区域。 我也有一个经度和纬度坐标来定义车辆的位置。 如何检查车辆位于多边形区域内?

Answer 1:

这实质上是在多边形点上的球的问题。 所以它使用大圆,而不是线段的弧可以修改光线投射算法。

  1. 对于每一对,使您的多边形相邻的坐标,画出它们之间的大圆段。
  2. 选择一个参照点,是不是多边形区内。
  3. 绘制开始于参考点和在车辆点结束的大圆线段。 算上这部分有多少次跨越的多边形的部分。 如果总次数为奇数,则车辆处于多边形内。 如果连,车辆是多边形的外面。

另外,如果坐标和车辆的距离足够近,而不是极或国际日期变更线附近的任何地方,你可以假装地球是平的,并使用经度和lattitude简单的X和Y坐标。 这样一来,你可以使用简单的线段的光线投射算法。 这是最好,如果你是与非欧几里得几何不舒服,但你必须在你的多边形的边界有些失真,因为弧线将被扭曲。

编辑:更小几何球体上。

大圆可以由位于垂直于圆位于(AKA,所述平面中的矢量来识别正常矢量 )

class Vector{
    double x;
    double y;
    double z;
};

class GreatCircle{
    Vector normal;
}

任何两个lattitude /经度坐标不在对映份额只有一个大圆。 为了找到这个大圆,转换的坐标,通过地球的中心线上。 所述叉积这两行的是坐标的大圆的法线矢量。

//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;
}

可以测量大圆段的弧形尺寸,或者任何两个矢量之间的角度,使用点积 。

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 ,的交点a的整个大圆和b
  • 找到矢量d ,的对映体c
  • 如果c介于a.starta.end ,或d介于a.starta.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);
}

两个大圆段ab相交,如果:

  • a与相交b的整个大圆
  • b与相交a的整个大圆

 

bool GreatCircleSegment::Intersects(GreatCircleSegment b){
    return this.Intersects(b.getWhole()) and b.Intersects(this.getWhole());
}

现在,您可以构建您的多边形数一数你参考线多少次越过它。

bool liesWithin(Array<Coordinate> 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;
}


文章来源: How do I check if a longitude/latitude point is within a range of coordinates?