Создание произвольной, изогнутой строки Well Known Text LineString для отображения в OpenLayers

Я динамически генерирую строку WKT LineString между точками в слое карты, создаваемом для отображения в OpenLayers. Я хотел бы, чтобы линии между точками были изогнутыми, и я хотел бы иметь возможность динамически изменять кривизну на основе различных входных переменных.

Это для приложения мониторинга сети, и мы хотели бы, чтобы кривизна основывалась на временах задержки между точками (не на самой необработанной задержке, а на отклонении от «нормальных» значений в течение заданного периода времени).

Хотя некоторые ГИС-приложения и базы данных поддерживают расширение CircularString для WKT, OpenLayers ничего об этом не знает.

Поэтому мне нужно создать изогнутую линию из сегментов линии:

Прямо сейчас строки строки просто:

LINESTRING(hop1_long hop1_lat, hop2_long hop2_lat)

Единственный способ, которым я могу определить, чтобы сделать линейный сегмент «изогнутым», - это вставить промежуточные точки:

LINESTRING(hop1_long hop1_lat, long1 lat1, long2 lat2, ..., hop2_long hop2_lat)

Этого должно быть вполне достаточно для нашего приложения, но я не знаю, как генерировать промежуточные точки!

Я предполагаю, что существуют хорошо известные методы/алгоритмы для создания «изогнутой» линии из сегментов линии в 2d-плоскости. Есть ли у кого-нибудь идеи о том, как это сделать, или книги/статьи/интернет-ресурсы, которые могут быть полезны?

ОБНОВЛЕНИЕ (13 августа 2010 г.):

Кривые Безье были билетом, и реализовать базовый алгоритм Безье было довольно легко после прочтения о нем. Но мне пришлось написать код для генерации контрольных точек. Вот код PHP, который я придумал. Это предполагает класс "Vector2d" с элементами x и y.

function get_control_points($to, $from, $mag_scale, $angle) {
  $dirX = $to->x - $from->x;
  $dirY = $to->y - $from->y;

  $mag = sqrt(($dirX * $dirX) + ($dirY * $dirY));
  if (!$mag) {
    return array($to, $from);
  }

  $length = $mag * $mag_scale;

  $dirX = $dirX / $mag;
  $dirY = $dirY / $mag;

  $sin = sin($angle);
  $cos = cos($angle);

  $rotX = $cos * $dirX - $sin * $dirY;
  $rotY = $sin * $dirX + $cos * $dirY;
  $rotNegX = $cos * -$dirX - $sin * $dirY;
  $rotNegY = $sin * $dirX - $cos * $dirY;

  // Flip control points for "backwards" curves
  if ($dirX x;
    $y1 = -$rotNegY * $length + $from->y;
    $x2 = -$rotX * $length + $to->x;
    $y2 = -$rotY * $length + $to->y;
  }
  // Or generate "normal" control points
  else {
    $x1 = $rotX * $length + $from->x;
    $y1 = $rotY * $length + $from->y;
    $x2 = $rotNegX * $length + $to->x;
    $y2 = $rotNegY * $length + $to->y;
  }

  return array(new Vector2d($x2, $y2), new Vector2d($x1, $y1));
}

person David Eads    schedule 09.08.2010    source источник


Ответы (1)


Если вы хотите сгенерировать серию отрезков, образующих кривую, начните с кривых, которые легко параметризуются одной переменной. Например, окружность с центром в (cx,cy) и радиусом r параметризуется следующим выражением:

(x,y) = (cx,cy)+r*(cos(t), sin(t)),

где t изменяется от 0 до 2.

Таким образом, вы можете создать полукруглую форму, скажем, оценив окружность со значениями tk=k/30, где k варьируется от 0 до 30. Это даст вам полукруглую дугу, сделанную из 30 сегментов линии.

Если вам нужны более общие кривые, посмотрите кривые Безье. Они параметризуются значением t, которое может оцениваться с одинаковыми интервалами от 0 до 1.

person brainjam    schedule 09.08.2010
comment
Удобно! Моя геометрия действительно слаба, если я забыл параметрические уравнения. Другой вопрос для меня заключается в определении (cx, cy) на основе начальной/конечной точек на плоскости. - person David Eads; 10.08.2010