Рубрики
Без рубрики

Общий эллипс на карте

Автор оригинала: Dalya Gartzman.

Или, как выбрать лучший способ ходить на пляж после работы

Это был прохладный осенний вечер, когда Хила Клопер, и я думал поехать на пляж после работы. Пляж находится примерно в 2,5 км от офиса.

Мы даже рассматривали рассмотрение по улицам Тель-Авива, готовы растянуть наш путь к 3 км, и думать о себе «ммм, нам интересно, как далеко это растягивает нас?»

Ну, длинная история короткая, мы не ходили на пляж. Вместо этого мы написали скрипт, который рисует эллипс вокруг офиса и пляж. Эллипс охватывает городскую область, которую мы Май Пройдите, если мы когда-нибудь решили пойти на пляж после работы.

Это эллипс жизни

Или – почему мы должны заботиться о эллипсах?

Круг каким-то образом находится «натуральный» область вокруг одной точки. Эллипс – это «естественная» область около двух точек или линии. Назвать несколько примеров, Тела массового движения в эллиптических орбитах Эллипсы представляют собой Искажение, вызванные проецированием 3D-карты на 2D И эллипсы также являются точным способом сюжета Уверенность взорных данных GPSУверенность в 2D данных в целом).

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

Итак, если вы здесь, потому что вы ищете простого копирования код, который рисует эллипс на карте – вы можете пойти в Этот репозиторий мы сделали. Если вы также заинтересованы в изучении Как Мы нашли полное решение нашей проблемы, вы можете присоединиться к нам для поездки. Мы заново открываем элементарную геометрию, узнаем о системах координат и играем с некоторым математическим кодом.

Девочки просто хотят иметь эллипсы

Выяснение, какой эллипс на самом деле является первой проблемой. Wolfram Alpha Сказал нам, что эллипс – это набор очков, которые имеют ту же сумму расстояний от двух взаимных центров. Или что-то типа того. Вольфрам Альфа иногда может быть довольно загадочным. Но у них есть гиф, так что это приятно.

Так что все, что нам нужно сделать, это убедиться, что у нас есть эти входы:

  • P1, P2 – GPS координаты.
  • R – радиус, который на самом деле является суммой расстояний от точки на эллипсе до двух центров.

Затем следуйте по этому плану:

  1. Найти А и B оси эллипса.
  2. Нарисуйте эллипс вокруг происхождения (0,0) измеряется в метрах.
  3. Переместите эллипс в центр между входными классами GPS.
  4. Вращайтесь в соответствии с углом между входным GPS-локациями.

Вот и все.

Звучит достаточно просто, верно?

Длинная и извилистая дорога (которая приводит к эллипсе)

Шаг 1. Найдите оси.

Здесь нам нужно было сделать базовую пифагореельную алгебру. Это изображение из Википедия был несколько полезным:

Вычисляя C Из GPS координаты было легко благодаря Haversine упаковка.

def GetEllipseAxisLengths(p1_lat, p1_lng, p2_lat, p2_lng,
                          radius_in_meters):
    c2 = haversine((p1_lat, p1_lng), (p2_lat, p2_lng)) * 1000.0
    if radius_in_meters < c2:
        raise ValueError("Please specify radius larger than the               
                          distance between the two input points.")
    a = radius_in_meters / 2.0
    b = sqrt(pow(a, 2) - pow(c2 / 2.0, 2))
    return a, b

Шаг 2. Нарисуйте эллипс вокруг происхождения.

Что мы сделали вот то, что мы взяли равномерно расположенные очки на х Ось и для каждого нашли две точки на эллипсе, который проект к нему:

def GetEllipsePointInMeters(a, b, num_points):
    """
    :param a: length of "horizontal" axis in meters
    :param b: length of "vertical" axis in meters
    :param num_points: (half the) number of points to draw
    :return: List of tuples of perimeter points on the ellipse, 
             centered around (0,0), in m.
    """
    x_points = list(np.linspace(-a, a, num_points))[1:-1]
    y_points_pos = [sqrt(pow(a, 2) - pow(x, 2)) * 
                    (float(b) / float(a))
                    for x in x_points]
    y_points_neg = [-y for y in y_points_pos]

    perimeter_points_in_meters = 
        [tuple([-a, 0])] + \
        [tuple([x, y]) for x, y in zip(x_points, y_points_pos)] + \
        [tuple([a, 0])] + \
        list(reversed([tuple([x, y]) 
                       for x, y in zip(x_points, y_points_neg)]))
    return perimeter_points_in_meters

Шаг 3. Как вы даже добавляете счетчики GPS?

Ну это было сложно, и ответ заключается в понимании того, что

def AddMetersToPoint(center_lng, center_lat, dx, dy):
    """
    :param center_lng, center_lat: GPS coordinates of the center  
           between the two input points.
    :param dx: distance to add to x-axis (lng) in meters
    :param dy: distance to add to y-axis (lat) in meters
    """
    new_x = (center_lng + (dx / R_EARTH) * (180 / pi) /   
             np.cos(center_lat * pi/180))
    new_y = center_lat + (dy / R_EARTH) * (180 / pi)
    return tuple([new_x, new_y])

Шаг 4. Поверните.

На этот раз чудеса Интернета не потерпели неудачу. Мы нашли Сделай Пакет, чтобы сделать вращение для нас. Один трюк, который нужно помнить здесь, так это то, что вы не можете повернуть точки один за другим. Скорее вы должны Сформируйте форму первой , а потом Поверните всю форму Отказ

def GetEllipsePoints(p1_lat, p1_lng, p2_lat, p2_lng, 
                     perimeter_points_in_meters):
    """
    Enter ellipse centers in lat-lng and ellipse perimeter points    
    around the origin (0,0), and get points on the perimeter of the 
    ellipse around the centers in lat-lng.
    :param p1_lat: lat coordinates of center point 1
    :param p1_lng: lng coordinates of center point 1
    :param p2_lat: lat coordinates of center point 2
    :param p2_lng: lng coordinates of center point 2
    :param perimeter_points_in_meters: List of tuples of perimeter 
           points on the ellipse, centered around (0,0), in m.
    :return: List of the points we really want, tuples of (lat,lng)
    """
    center_lng = (p1_lng + p2_lng) / 2.0
    center_lat = (p1_lat + p2_lat) / 2.0
    perimeter_points_in_lng_lat = \
        [AddMetersToPoint(center_lng, center_lat, p[0], p[1])
         for p in perimeter_points_in_meters]
    ellipse = LineString(perimeter_points_in_lng_lat)

    angle = degrees(atan2(p2_lat - p1_lat, p2_lng - p1_lng))
    ellipse_rotated = affinity.rotate(ellipse, angle)

    ellipse_points_lng_lat = list(ellipse_rotated.coords)
    ellipse_points = [tuple([p[1], p[0]]) 
                      for p in ellipse_points_lng_lat]
    return ellipse_points

Сюрприз! Шаг 5. Нарисуйте на карте S2!

Мы хотели представить эллипс красиво на S2map Отказ По-видимому, вы можете сделать это, открывая URL изнутри вашего сценария. Мы использовали подпрокат сделать это.

def OpenS2Map(points):
    url = \
      "http://s2map.com/#order=latlng&mode=polygon&s2=false" \
      "&points={}".format(str(points).replace(" ", ","))
    cmd = ["python", "-m", "webbrowser", "-t", url]
    subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                     stderr=subprocess.STDOUT).communicate()

Эллипс соседа круглый

Вы можете заметить наш эллипс не идеален. Точки равномерно расположены на оси между центрами, но они не разнесены по периметру эллипса. GPS-> метры-> GPS Преобразование может привести к потере метров здесь и там. Но эй, сделано лучше, чем идеально, и мы должны оставить что-то, чтобы сделать в следующий раз, мы хотим пойти на пляж, верно?