Intereting Posts
Итерация цикла в игре Php Как авто Войти и перенаправление после регистрации в yii? Загрузите пользователя facebook, если вы только зарегистрировались в facebook php sdk Найти перекрывающиеся диапазоны дат в PostgreSQL FOSUser Bundle – запрет входа пользователей в систему как вызвать функцию класса php непосредственно с помощью ajax? Как выполнить WP_Query с несколькими аргументами? Прямое уведомление RealTime JQuery PHP Преобразование ajax относительных путей к абсолютным путям с помощью codeigniter Доступ к сеансу в командной строке PHP? Чтение большого файла по строкам или сохранение его строк в массиве php require_once не работает так, как я хочу. Относительный путь openssl_verify (): указанный ключевой параметр не может быть принудительно введен в открытый ключ для файла .pem Codeigniter – передача нескольких значений для просмотра Как обновить базу данных osCommerce с v2.2 до v2.3

Как проверить, находится ли точка долготы / широты в пределах диапазона координат?

У меня есть несколько координат долготы и широты, которые составляют многоугольную зону. У меня также есть координата долготы и широты, чтобы определить положение транспортного средства. Как проверить, что транспортное средство находится внутри полигональной зоны?

Это по существу проблема Точки в многоугольнике на сфере. Вы можете изменить алгоритм преобразования лучей так, чтобы он использовал дуги больших кругов вместо сегментов линии.

  1. для каждой пары соседних координат, составляющих ваш многоугольник, нарисуйте между ними большой круг.
  2. Выберите опорную точку, которая не находится внутри полигональной зоны.
  3. нарисуйте сегмент большого круга, который начинается в контрольной точке и заканчивается в точке транспортного средства. Подсчитайте, сколько раз этот сегмент пересекает сегмент вашего многоугольника. Если общее количество раз нечетно, транспортное средство находится внутри полигона. Если даже, автомобиль находится вне полигона.

В качестве альтернативы, если координаты и транспортное средство находятся достаточно близко друг к другу, а не где-нибудь рядом с полюсами или международной линией даты, вы можете притворяться, что земля плоская, и использовать долготу и ширину как простые координаты x и y. Таким образом, вы можете использовать алгоритм литья лучей с простыми сегментами линии. Это предпочтительнее, если вам не нравится геометрия без евклидова, но у вас будут некоторые искажения вокруг границ ваших полигонов, поскольку дуги будут искажены.

EDIT: Немного больше о геометрии на сфере.

Большой круг может быть идентифицирован вектором, лежащим перпендикулярно плоскости, на которой лежит круг (AKA, нормальный вектор )

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

Любые две координаты долготы и долготы, которые не являются антиподами, разделяют ровно один большой круг. Чтобы найти этот большой круг, преобразуйте координаты в линии, проходящие через центр земли. Перекрестное произведение этих двух линий является нормальным вектором большого круга координат.

 //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 = -vx; ret.y = -vy; ret.z = -vz; 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 , пересечение целого большого круга и 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<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; }