Каков наилучший способ удалить повторяющиеся точки из многоугольника geojson в ruby?

Я использую библиотеку rgeo ruby ​​для анализа полигонов geojson. Поведение заключается в возврате nil при вызове декодирования для многоугольника с повторяющимися точками, как в следующем примере:

geom = {:geom=>{"type"=>"Polygon", "coordinates"=>[[[-82.5721, 28.0245], [-82.5721, 28.0245] ... }
geo_factory = RGeo::Cartesian.factory(:srid => 4326)
rgeo_geom = RGeo::GeoJSON.decode(geom, json_parser: :json, geo_factory: geo_factory)

Из-за повторяющейся точки в начале rgeo_geom будет равен нулю после выполнения этого кода.

Как наиболее эффективно очистить этот многоугольник? Есть ли встроенная функция rgeo или мне нужно создать свою собственную?

Чтобы было ясно, я хотел бы удалить только последовательные повторяющиеся точки, так как это заставляет библиотеку возвращать nil для приведенного выше кода. Я также не ищу в БД решения, такие как postgis st_removerepeatedpoints, но по существу ищу такое поведение, выполненное в ruby.


person sakurashinken    schedule 11.01.2018    source источник
comment
Вы хотите удалить все повторяющиеся точки или только последовательные?   -  person Stefan    schedule 11.01.2018
comment
обновленный вопрос.   -  person sakurashinken    schedule 11.01.2018


Ответы (1)


Я не знаком с rgeo, но с точки зрения чистого Ruby я думаю, что вы могли бы сделать следующее.

h = { :geom=>{
        "type"=>"Polygon",
        "coordinates"=>[
          [-80.1234, 28.1234], [-82.5721, 28.0245], [-82.5721, 28.0245],
          [-83.1234, 29.1234], [-82.5721, 28.0245], [-83.1234, 29.1234],
          [-83.1234, 29.1234], [-83.1234, 29.1234]
        ]
      } 
    }

Вопрос показывает "coordinates"=>[[[-82.5721, 28.0245],... без правой скобки, соответствующей средней левой скобке. Я предположил, что должно быть только две левые скобки. Если это не так, мой ответ придется изменить.

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

hhash = h.hash
  #=> -4413716877847662410

h.merge({ :geom=>(h[:geom].merge("coordinates"=>
  h[:geom]["coordinates"].chunk_while(&:==).map(&:first))) })
  #=> { :geom=>{
  #       "type"=>"Polygon",
  #       "coordinates"=>[
  #         [-80.1234, 28.1234], [-82.5721, 28.0245], [-83.1234, 29.1234], 
  #         [-82.5721, 28.0245], [-83.1234, 29.1234]
  #       ]
  #     }
  #   }

h.hash == hhash
  #=> true

См. Hash#merge, Object#tap, Enumerable#chunk_while, Enumerable#flat_map и Enumerable#uniq.

person Cary Swoveland    schedule 12.01.2018
comment
Я думаю, вы можете использовать map(&:first) вместо flat_map(&:uniq) - person Stefan; 12.01.2018
comment
А chunk_while, будучи добропорядочным гражданином, позволяет обходные пути: chunk_while(&:==) - person Stefan; 12.01.2018
comment
@Стефан, я только что понял, что не понимаю твоего второго предложения. enum.chunk_while { |pair| pair.== } вызывает исключение, так как Array#== требует аргумента (другого массива). Почему enum.chunk_while(&:==) работает? Должно быть, я упускаю из виду что-то довольно простое. - person Cary Swoveland; 17.01.2018
comment
Symbol#to_proc возвращает proc { |obj, *args| obj.public_send(self, *args) } (немного упрощенно). При вызове этого процесса первый аргумент становится получателем, сам символ является именем метода, а остальные аргументы (если есть) передаются как аргументы методов. Итак, :==.to_proc вызывается через :==.to_proc.call(1, 2), что эквивалентно 1.public_send(:==, 2). Под добропорядочным гражданином я подразумеваю, что chunk_while дает несколько значений (yield *pair), поэтому вместо :==.to_proc.call(pair) вызывается :==.to_proc.call(*pair). - person Stefan; 17.01.2018
comment
Спасибо, Стефан. Отличное объяснение! - person Cary Swoveland; 17.01.2018