Динамическое упрощение с проекцией в D3

Я рисую карту SVG с D3, используя проекцию d3.geo.mercator().

Я также использую поведение масштабирования с картой, которое применяет transform к объекту <g>, содержащему все пути карты.

После изучения примеров динамического упрощения Майка Бостока (http://bl.ocks.org/mbostock/6252418) Интересно, могу ли я применить такой алгоритм в моем случае, чтобы перерисовать геометрию с меньшим количеством точек при уменьшении масштаба?

Во всех примерах, которые я видел, есть функция simplify, которая пропускает незначительные точки и отображает остальное как есть, и эта функция используется в var path = d3.geo.path().projection(simplify). Я не могу использовать его таким образом, так как мне нужно, чтобы он применялся поверх уже существующего projection = d3.geo.mercator().scale(*).translate([*,*]).

Как мне использовать динамическое упрощение с существующей проекцией?


person BartoNaz    schedule 31.05.2014    source источник


Ответы (1)


Согласно приведенному вами примеру, Динамическое упрощение II

Функция simplify будет выглядеть примерно так

var simplify = d3.geo.transform({
  point: function(x, y, z) {
    if (z >= area) {
        this.stream.point(x, y);
    }
  }
});

Где area — это пороговая переменная, которую вы можете установить заранее или изменить динамически в соответствии с увеличением.

Затем вы использовали бы его в методе projection d3.geo.path(), например

var path = d3.geo.path()
    .projection(simplify);

Это более или менее ситуация, которую вы описали в своем ответе. Теперь, в соответствии с Dynamic Simplification IV, метод прогнозирования также может быть определен как

var path = d3.geo.path()
    .projection({
        stream: function(s) { 
            return simplify.stream(s); 
        }
     });

Это точно так же, как и раньше. Это просто «расширение» методов по умолчанию. d3.geo.path всегда вызывает метод проекции stream, поэтому вы можете объявить свой собственный поток и перенаправить его на simplify.stream.

Теперь вы говорите, что вам нужно перепроецировать свой путь, используя d3.geo.mercator().

var mercatorProjection = d3.geo.mercator().scale(*).translate([*,*]);

Нет проблем: потоки объединяются в цепочки. Ты можешь сделать:

var path = d3.geo.path()
    .projection({
        stream: function(s) { 
            return simplify.stream(mercatorProjection.stream(s)); 
        }
     });

Также как и:

var path = d3.geo.path()
    .projection({
        stream: function(s) { 
            return mercatorProjection.stream(simplify.stream(s)); 
        }
     });

Единственная разница в том, что площадь порога должна быть рассчитана по-другому, если вы имеете дело с WGS84, пикселями или другой системой координат.

Важное предостережение: параметр z в функции simplify не является высотой. Это площадь треугольника, определяемая каждой точкой, предварительно рассчитанное значение, являющееся частью привлекательности TopoJSON. .

Боюсь, это означает, что вы не можете полагаться на этот пример для упрощения обычного geoJSON. Вам придется добавить свою собственную логику для расчета соответствующей площади каждой точки (если вы хотите применить алгоритм Висвалингама) или расстояние до ближайшей точки (если вы хотите применить алгоритм Дугласа-Пекера) или реализуйте свой собственный алгоритм.

Удачи.

person ffflabs    schedule 02.04.2015