Как найти все многоугольники, которые включают в себя специальную точку долготы

Я использую rgeo и гем activerecord-postgis-adapter. Я хочу найти все записи, в которых особая точка включена в многоугольник. Я отметил прямоугольник на карте Google и ожидаю, что sql вернет строку, если точка находится внутри, и не вернет строку, когда точка находится снаружи. К сожалению, point_outside_2 также возвращает результат. Что я делаю неправильно? Должен ли я использовать проекции вместо реальной широты и долготы?

введите здесь описание изображения

describe 'polygon' do
  let(:factory) { RGeo::Geographic.simple_mercator_factory }

  let(:left_up_corner) { factory.point(50.095073, 19.852121) }
  let(:right_up_corner) { factory.point(50.092230, 20.057740) }
  let(:left_bottom_corner) { factory.point(50.021297, 19.857577) }
  let(:right_bottom_corner) { factory.point(50.015820, 20.051943) }

  let(:point_inside_1) { factory.point(50.059631, 19.939323) }
  let(:point_inside_2) { factory.point(50.029995, 19.941997) }
  let(:point_outside_1) { factory.point(50.153008, 19.990906) }
  let(:point_outside_2) { factory.point(50.118037, 19.970446) }


  let(:line) { factory.line_string([left_up_corner, right_up_corner, right_bottom_corner, left_bottom_corner]) }
  let(:area) { factory.polygon(line) }

  it 'finds nurses with polygon include point' do
    Nurse.create(area: area)
    expect(count_nurses(point_inside_1)).to be 1
    expect(count_nurses(point_inside_2)).to be 1
    expect(count_nurses(point_outside_1)).to be 0
    expect(count_nurses(point_outside_2)).to be 0 # it return 1
  end

  def count_nurses(point)
    Nurse.where("ST_DWithin(area, ST_Point(#{point.coordinates.join(',')}), 4326)").count
  end
end

миграция:

class AddPolygonToNurse < ActiveRecord::Migration[5.1]
  def change
    add_column :nurses, :area, :st_polygon, :geographic => true
    add_column :nurses, :latlong, :st_point, :geographic => true
  end
end

person Piotr Galas    schedule 18.07.2017    source источник
comment
в ST_Dwithin вы запрашиваете точку в пределах 4326 метров от полигона. Должно быть 0, если вы ищете точку внутри полигона. Также вы используете географические координаты (широта/долгота) с simple_mercator_factory, которая является проекционной системой координат (одна из двух неверна, либо ваши координаты, либо ваша фабрика)   -  person JGH    schedule 18.07.2017
comment
Да, я считаю, что он ищет ST_Contains, а не ST_Dwithin. 4326 — это идентификатор системы географической проекции WGS86. Точка 2, вероятно, находится в пределах 4,326 км от ящика.   -  person Aaron Breckenridge    schedule 18.07.2017
comment
@JGH Это правильный ответ. Большое спасибо. Меняю 4326 на 0 и теперь работает.   -  person Piotr Galas    schedule 19.07.2017
comment
@AaronBreckenridge, у тебя тоже есть право, я хотел указать там идентификатор. Я также пытался использовать ST_contains, но у меня все еще есть синтаксическая ошибка.   -  person Piotr Galas    schedule 19.07.2017


Ответы (1)


Попробуйте это, я делаю что-то подобное в приложении с RGeo, чтобы найти точки внутри многоугольника. Надеюсь, что это работает для вас

describe 'polygon' do
  let(:factory) { RGeo::Geographic.simple_mercator_factory }
  let(:ewkb_generator) do
    RGeo::WKRep::WKBGenerator.new(
      type_format:    :ewkb,
      emit_ewkb_srid: true,
      hex_format:     true
    )
  end

  let(:left_up_corner) { factory.point(50.095073, 19.852121) }
  let(:right_up_corner) { factory.point(50.092230, 20.057740) }
  let(:left_bottom_corner) { factory.point(50.021297, 19.857577) }
  let(:right_bottom_corner) { factory.point(50.015820, 20.051943) }

  let(:point_inside_1) { factory.point(50.059631, 19.939323) }
  let(:point_inside_2) { factory.point(50.029995, 19.941997) }
  let(:point_outside_1) { factory.point(50.153008, 19.990906) }
  let(:point_outside_2) { factory.point(50.118037, 19.970446) }


  let(:line) { factory.line_string([left_up_corner, right_up_corner, right_bottom_corner, left_bottom_corner]) }
  let(:area) { factory.polygon(line) }

  it 'finds nurses with polygon include point' do
    Nurse.create(area: area)
    expect(count_nurses(point_inside_1)).to be 1
    expect(count_nurses(point_inside_2)).to be 1
    expect(count_nurses(point_outside_1)).to be 0
    expect(count_nurses(point_outside_2)).to be 0 # it return 1
  end

  def count_nurses(point)
    ewkb = ewkb_generator.generate(point.projection)
    Nurse.where('ST_Intersects(area, ST_GeomFromEWKB(E?))', "\\\\x#{ewkb}").count
  end
end
person m. simon borg    schedule 18.07.2017
comment
Это полезно, но это не прямой ответ. @JGH решит мою проблему. Ваше решение основано на другом формате точки. Даже правильно, я думаю, что это немного сложнее - person Piotr Galas; 19.07.2017