Найдите полигоны, содержащиеся внутри полигона, используя RGeo, PostGIS и ST_Contains.

У меня есть две модели: Search (геометрия сохранена в атрибуте area) и Land (геометрия сохранена в атрибуте geom).

Land импортируется из внешней службы и сохраняется в БД с определенным SRID. НАПРИМЕР:

SRID=28992;POLYGON((84078.122 444751.117,84076.78 444756.486,84074.578 444765.296,84073.017 444771.6,84072.863 444771.565,83990.385 444752.587,83983.081 444741.282,83973.47 444727.641,83977.639 444696.765,83977.795 444696.272,83978.017 444695.806,83978.303 444695.376,83978.645 444694.989,83979.038 444694.654,83979.474 444694.376,83979.944 444694.162,83980.439 444694.015,83980.849 444687.415,83980.059 444680.175,83981.009 444674.015,83990.579 444630.535,83991.039 444628.175,83992.959 444622.795,83993.499 444619.895,83996.899 444602.515,84008.879 444549.116,84012.229 444550.167,84008.676 444568.23,84006.244 444579.55,83996.923 444617.582,83994.764 444631.493,83990.631 444646.408,83982.258 444684.123,83981.276 444694.907,83977.284 444727.724,83982.965 444736.217,83992.091 444749.86,84017.353 444756.019,84019.237 444745.384,84019.439 444745.432,84064.525 444756.091,84065.019 444756.24,84065.528 444756.322,84066.044 444756.336,84066.557 444756.28,84067.058 444756.157,84067.539 444755.967,84067.989 444755.716,84068.402 444755.406,84068.77 444755.044,84069.086 444754.636,84069.345 444754.19,84069.542 444753.713,84069.674 444753.214,84070.354 444750.339,84070.689 444749.934,84071.073 444749.575,84071.5 444749.269,84071.963 444749.02,84072.455 444748.834,84072.966 444748.712,84073.489 444748.657,84074.014 444748.67,84074.533 444748.751,84075.038 444748.898,84083.199 444750.826,84082.865 444752.243,84078.122 444751.117))

Геометрия, сохраненная в экземпляре Search, исходит из координат на OpenStreetMap, который, как я полагаю, использует SRID=4326. В БД я вижу, что эти значения сохраняются без части SRID=. НАПРИМЕР:

POLYGON((4.270822 52.088838,4.271509 52.088324,4.271214 52.088232,4.270533 52.088235,4.270248 52.088637,4.270527 52.088822,4.270822 52.088838))

class Land < ActiveRecord::Base
  def self.in_area(area)
    sql = "SELECT * FROM #{self.table_name} WHERE ST_Contains(ST_Transform(ST_SetSRID(#{area},4326),4326), ST_Transform(geom,4326))"
    result = Land.connection.execute(sql)
  end
end

И я называю это так:

Land.in_area(Search.last.area)

Что дает ошибку: ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "52.19414")

Search.last.area.factory возвращает RGeo::Geos::CAPIFactory с неправильным SRID. Поэтому я подумал сделать это правильной фабрикой:

factory = RGeo::Geos.factory(srid: 4326).parse_wkt(Search.last.area)
Land.in_area(factory) # however, this still returns the same error

Я также пробовал несколько других вариантов и комбинаций, таких как:

"SELECT * FROM #{self.table_name} WHERE ST_Contains(ST_Geomfromtext(#{area.to_s}), geom)"

Которые все возвращают одну и ту же ошибку. Должно быть, я упускаю что-то очень очевидное. Что мне не хватает?


person Glenn    schedule 13.09.2019    source источник
comment
Можете ли вы опубликовать трассировку SQL того, что происходит, когда вы запускаете Land.in_area(Search.last.area)? Также вы перечитали всю документацию на github.com/rgeo/activerecord-postgis-adapter.   -  person sevensidedmarble    schedule 14.09.2019
comment
Да, все эти настройки в acticerecord-postgis-adapter присутствуют, и я искал подобный пример (пока безрезультатно). След: gist.github.com/glennpjones/7b44ad7ece0f3026d97bdb2508fb7dfa   -  person Glenn    schedule 14.09.2019
comment
Итак, интерполяция строки SQL не удалась. Если я вставлю буквальную строку POLYGON в запрос, синтаксической ошибки больше не будет.   -  person Glenn    schedule 14.09.2019
comment
Я до сих пор не понимаю, почему: SELECT * FROM lands WHERE ST_Contains(ST_Transform(ST_SetSRID(ST_GeomFromText('POLYGON ((4.405174 52.046156, 4.461823 51.973884, 4.267502 51.962885, 4.267845 52.037287, 4.385948 52.054179, 4.405174 52.046156))'),4326),4326), ST_Transform(geom, 4326)) в порядке, но при интерполяции строк выдает синтаксическую ошибку. Есть идеи, почему?   -  person Glenn    schedule 14.09.2019
comment
Приятно рад, что у вас получилось!   -  person sevensidedmarble    schedule 14.09.2019


Ответы (1)


Решено с областью действия:

scope :in_area, -> (area_4326) { where("ST_Contains(ST_Transform(ST_SetSRID(ST_GeomFromText(?),4326),4326), ST_Transform(geom, 4326))", area_4326) }

Где area_4326 — строковое представление геометрии.

person Glenn    schedule 14.09.2019