Я новичок в postgis и rgeo. Я подозреваю, что я, возможно, решусь не так, но я был немного удивлен, узнав несколько операций, в частности содержит & внутри, невозможно на сферических объектах.polygon 'contains' и другие операции с геометриями не поддерживаются
У меня есть куча географически распределенных объектов, которые я хотел бы объединить на основе таких вещей, как почтовый индекс. Для каждой из этих групп у меня есть граница, и я хотел бы проверить, находится ли объект внутри этой границы, а также проверить, находится ли одна граница внутри другой. Я использую рельсы и это миграция используется для настройки моей коллекции модели
class CreateGeoCollectionDefinition < ActiveRecord::Migration[5.0]
def change
create_table :geo_collection_definitions do |t|
t.string :name
t.string :geo_place_id
t.string :geo_place_types, array: true, default: []
t.st_polygon :boundary, geographic: true
t.jsonb :boundary_json
t.st_point :latlng, geographic: true
end
end
end
В настоящее время границы идет от Google обратного геокодирования поиска. В NorthEast и SouthWest ограничивающих координат коробков передаются в этот метод при создании объекта
GEO_FACTORY = RGeo::Geographic.spherical_factory(srid: 4326)
def self.createBoundary(pointOne, pointTwo)
point1 = GEO_FACTORY.point(pointOne['lat'], pointOne['lng'])
point2 = GEO_FACTORY.point(pointTwo['lat'], pointTwo['lng'])
boundingBox = RGeo::Cartesian::BoundingBox.create_from_points(point1, point2).to_geometry
boundingBox
end
Я написал несколько спецификаций, чтобы проверить, что все ведут себя так, как я ожидал. Простые тесты на основе расстояния проходят все, как ожидалось, но есть проблемы с теми, которые используются для проверки граничных функций. Я бегу в следующем
# ------------------
# --- Caused by: ---
# PG::UndefinedFunction:
# ERROR: function st_contains(geography, geography) does not exist
# LINE 1: ...COUNT(*) FROM "geo_collection_definitions" WHERE (ST_Contain...
# ^
# HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Когда я пытаюсь выполнить запрос, как (я знаю его немного глупый)
GeoCollectionDefinition.where("ST_Contains(boundary, boundary)")
или при попытке использования объекта RGEO непосредственно
it "should be possible to test is points belong in GeoCollection.boundary" do
factory = RGeo::Geographic.spherical_factory(srid: 4326)
externalPoint = factory.point(EmptyGeocodeLatLag['lng'], EmptyGeocodeLatLag['lat'])
expect(someplace_def.boundary.contains?(someplace_def.latlng)).to be_truthy
expect(someplace_def.boundary.contains?(externalPoint)).to be_falsy
end
я
RGeo::Error::UnsupportedOperation:
Method Geometry#contains? not defined.
Diggin g вокруг я нашел это rgeo issue и другие доказательства того, что эти операции просто не поддерживаются для сферических объектов на заводе
Мне просто интересно;
- Это определенно случай
- Моделирование границы и расположение объектов так, как описано в моей миграции, кажется, имеет смысл для меня, но я предполагаю, что я неправильно об этом?
- Как мне узнать, находится ли куча точек внутри многоугольника, используя postgis, rgeo и активный адаптер записи?
- Можно ли проверить, находится ли один полигон внутри другого?
EDIT:
Я последовал по предложению наклонить и побежал некоторые запросы непосредственно на моей дб. Во-первых, просто для проверки моей настройки
SELECT PostGIS_full_version();
NOTICE: Function postgis_topology_scripts_installed() not found. Is topology support enabled and topology.sql installed? postgis_full_version
POSTGIS="2.1.7 r13414" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel. 4.9.2, 08 September 2015" GDAL="GDAL 1.11.5, released 2016/07/01" LIBXML="2.9.2" LIBJSON="UNKNOWN" RASTER
Я также выполнил некоторые запросы;
SELECT name FROM geo_collection_definitions WHERE st_contains(latlng, boundary);
ERROR: function st_contains(geography, geography) does not exist
LINE 1: ...ELECT name FROM geo_collection_definitions WHERE st_contain...
Так что угадайте, что в географии не будет работать.Я порылся и нашел st_covers
SELECT name FROM geo_collection_definitions WHERE st_covers(boundary, latlng);
name
------
(0 rows)
SELECT name FROM geo_collection_definitions WHERE st_covers(boundary, ST_GeomFromText('POINT(12.9549709 55.5563043)', 4326));
name
------
(0 rows)
Это действительно удивительно, как LatLng является центральной точкой границы. Я довольно смущен и уверен, что делаю что-то довольно глупое. Любая помощь была бы принята с благодарностью
Поскольку проблема, по-видимому, является чистой почтой, возможно, было бы лучше, если бы вы перефразировали свой вопрос с помощью вместо SQL-релей. По моему опыту, всегда лучше тестировать свои запросы в чистом SQL, прежде чем подключать их к структуре, дает вам гораздо лучший контроль. – tilt
Привет наклон! Спасибо миллион за ваш ответ. Я уверен, что это просто глупо, что я делаю. Я собираюсь изучить, что у меня установлен proj4. Затем я попытаюсь запустить некоторые запросы непосредственно на postgis db, чтобы проверить что-то. – Conor
Можете ли вы дать вывод WKT этой границы? (ST_AsText (граница)). Кроме того, вы уверены, что хотите продолжать использовать географию? Это имеет смысл, если вы работаете с крупномасштабными (за пределами национальных границ) данными, но, как правило, лучше работать в локальной проекции. Я удивлен, что ваши почтовые индексы в любом случае находятся в географии, обычно они будут проецироваться. – tilt