How to divide the world map into equal parts (squares)?

  • 0
    It is necessary to split the world map into equal parts (hereinafter squares). The task is to find out which of these squares a point with a certain latitude and longitude falls into. Due to the fact that the length of the longitude is not fixed, it is not possible to split the map into equal parts.
    Let's say you need to find out which square the point with coordinates falls into:
    Latitude 30.95 degrees
    Longitude 40.80 degrees
    The height and length of the square into which the map is divided is 200x200 meters.

    My solution was to find out the distance (in meters) from zero degree (latitude and longitude 0; 0) to the longitude of the point (0; 40.80) and divide the found distance by 200, then removing the remainder to find the point. Then find the distance from the obtained point to the point with the longitude coordinates that we received and the latitude 30.95 and divide the result by 200 and then remove the remainder. But the solution doesn't work, because the length of longitude is different at all points. I've been trying to find a solution for 10 days, but my knowledge is not enough. I ask for any help! Thanks in advance!

    The solution can be written in any language, well, or just a formula)
    JavaScript Harper Simpson, Aug 8, 2020

  • 1 Answers
  • 0
    Right now I rummaged through one of my own projects ... I was solving a slightly different problem, but I think I can improve it ...

    I had this task:

    1. There is a point on the map;

    2. There are polygons (polygons) on the map;

    3. There is a point inside each polygon in case the point from item 1 did not fall into any polygon, then you need to find the closest point from item 3 for the point from item 1 ...



    Below is an example of how to check the occurrence of a point from item 1 in polygons (polygons) from item 2 ...



    class Polygon {
    /**
    * @var array
    */
    var $polygon = [];
    /**
    * Polygon itself, with basic vector-based structure
    * Array: [ [1,1], [2,1], [3,0], [2,-1] ]
    *
    * @var $polygon array
    */
    function setPolygon($polygon) {
    if (count($polygon) < 3) {
    return false;
    }

    if (!isset($polygon[0]['x'])) {
    foreach ($polygon as &$point) {
    //$point = ['x' => round($point[0] + 300, 4), 'y' => round($point[1] + 300, 4)];
    //$point = ['x' => round($point[0], 4), 'y' => round($point[1], 4)];

    if($point[0] < 0)
    $point[0] = 90 + 90 - abs($point[0]);
    if($point[1] < 0)
    $point[1] = 180 + 180 - abs($point[1]);

    $point = ['x' => round($point[0], 4), 'y' => round($point[1], 4)];
    }
    }
    $this->polygon = $polygon;
    }
    /**
    * Check if $polygon contains $test value
    *
    * @var $test array(x=>decimal, y=>decimal)
    */
    function calc($test) {

    if($test['x'] < 0)
    $test['x'] = 90 + 90 - abs($test['x']);
    if($test['y'] < 0)
    $test['y'] = 180 + 180 - abs($test['y']);

    $q_patt= [[0, 1], [3, 2]];
    $end = end($this->polygon);

    $pred_pt = end($this->polygon);
    $pred_pt['x'] -= $test['x'];
    $pred_pt['y'] -= $test['y'];
    $pred_q = $q_patt[$pred_pt['y'] < 0][$pred_pt['x'] < 0];
    $w = 0;

    for ($iter = reset($this->polygon); $iter !== false; $iter = next($this->polygon)) {
    $cur_pt = $iter;
    $cur_pt['x'] -= $test['x'];
    $cur_pt['y'] -= $test['y'];
    $q = $q_patt[$cur_pt['y'] < 0][$cur_pt['x'] < 0];

    switch ($q - $pred_q) {
    case -3:
    ++$w;
    break;
    case 3:
    --$w;
    break;
    case -2:
    if ($pred_pt['x'] * $cur_pt['y'] >= $pred_pt['y'] * $cur_pt['x']) {
    ++$w;
    }
    break;
    case 2:
    if (!($pred_pt['x'] * $cur_pt['y'] >= $pred_pt['y'] * $cur_pt['x'])) {
    --$w;
    }
    break;
    }
    $pred_pt = $cur_pt;
    $pred_q = $q;
    }

    return $w != 0;
    }

    public static function distance($lat1, $lng1, $lat2, $lng2) {

    $lat1=deg2rad($lat1);
    $lng1=deg2rad($lng1);
    $lat2=deg2rad($lat2);
    $lng2=deg2rad($lng2);

    $delta_lat=($lat2 - $lat1);
    $delta_lng=($lng2 - $lng1);

    return round( 6378137 * acos( cos( $lat1 ) * cos( $lat2 ) * cos( $lng1 - $lng2 ) + sin( $lat1 ) * sin( $lat2 ) ) );
    }

    public static function closestPoint($x, $y, $arPoints) {

    $RESULT = false;

    $x = floatval($x);
    $y = floatval($y);

    if(!empty($arPoints) && is_array($arPoints) && count($arPoints) > 0) {

    $arRes = array();

    foreach ($arPoints as $KEY => $VAL) {

    $x2 = floatval($VAL[0]);
    $y2 = floatval($VAL[1]);

    $distance = self::distance($x, $y, $x2, $y2);

    $arRes[$KEY] = $distance;

    }

    if(count($arRes) > 0) {

    natsort($arRes);
    reset($arRes);

    //$RESULT[key($arRes)] = current($arRes);

    $RESULT = array(
    'ID' => key($arRes),
    'DISTANCE' => current($arRes)
    );

    }

    }

    return $RESULT;
    }
    }

    /* Ипользование */

    // Координаты точки, которую проверяем на вхождение в "полигон"
    $X = 33.45;
    $Y = 44.25;

    // "Полигоны"
    $arCheckPoints = [
    'КЛЮЧ_МНОГОУГОЛЬНИКА' => [22.45, 44.55, 11.22, 55.66], // Координаты вершин
    'КЛЮЧ_МНОГОУГОЛЬНИКА_2' => [33.45, 66.55, 77.22, 99.66], // Координаты вершин
    'КЛЮЧ_МНОГОУГОЛЬНИКА_3' => [12.45, 15.55, 17.22, 54.66], // Координаты вершин
    ];

    $arResults = [];

    $p = new \App\Helpers\Polygon();

    foreach ($arCheckPoints as $KEY_POLYGON => $arPolygon) {

    $p->setPolygon($arPolygon);

    if($p->calc(array('x' => $X, 'y' => $Y)))
    $arResults[$KEY_POLYGON] = $arPolygon;

    }




    To solve clause 3, the distance function is used ... if this logic suits your tasks ... then I will show you another example further ...



    I just have to rewrite the code before putting it out ...))



    P.S .: All coordinates are stupid from my head ... it's better to test on real data ...
    Anonymous

Your Answer
To place the code, please use CodePen or similar tool. Thanks you!