Всем привет))
Кто нибудь работал с гемом 'activerecord-postgis-adapter'?
У меня есть модель RoutePoint с колонками longitude latitude и User с колонкой work_area, type=>"st_polygon"
Хочу написать скоуп, чтобы найти все route_points которые содержаться в work_area (т.е. polygon-а)
(
create_table "users", force: :cascade do |t|
t.geometry "work_area", limit: {:srid=>0, :type=>"st_polygon"}
end
create_table "route_points", force: :cascade do |t|
t.string "address_title"
t.float "longitude"
t.float "latitude"
t.bigint "order_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["order_id"], name: "index_route_points_on_order_id"
end
)
#<RoutePoint:0x00007ff888f8bbe0
id: 30,
address_title: "Магнитогорск, Челябинская обл., Россия",
longitude: 59.0623067,
latitude: 53.3927214,
order_id: 38,
created_at: Wed, 13 Jan 2021 12:23:55 UTC +00:00,
updated_at: Wed, 13 Jan 2021 12:23:55 UTC +00:00>
User.last.work_area
User Load (171.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<RGeo::Geographic::SphericalPolygonImpl:0x4ba0 "POLYGON ((-84.39731626974567 33.75570358345219, -84.33139830099567 33.86524376001825, -84.25243406759724 33.770545357734925, -84.39731626974567 33.75570358345219))">
Не могу понять как написать запрос для получения поинтов, которые внтури полигона, может кто то сталкивался и знает?
в общем за ночь разобрался. нужно обязательно геометрическим данным для postgis в запросах указывать SRID ( я так понимаю это параметр отправной точки для расчетов координат). Документация конечно для гема RGeo и вытекающий ну мягко говоря "не очень".
Чтобы спасти некоторым жизнь, и уделить больше времени на близких вам людей и впечатления в жизни, вот запрос:
class RoutePoint < ApplicationRecord
belongs_to :order
def self.g_within_polygon
# polygon = Geo.polygon(points)
polygon = User.last.work_area
self.where("ST_Contains(:polygon, ST_SetSRID(ST_MakePoint(longitude, latitude), #{Geo::SRID}))", polygon: Geo.to_wkt(polygon))
end
# points = [
# [-84.39731626974567, 33.75570358345219],
# [-84.33139830099567, 33.86524376001825],
# [-84.25243406759724, 33.770545357734925],
# [-84.39731626974567, 33.75570358345219]
# ]
# coords = Geo.pairs_to_points(points)
# User.last.update(work_area: Geo.polygon(coords))
end
Geo это класс, который я взял в статье у человека, ссылка:
https://pganalyze.com/blog/postgis-rails-geocoder#installing-postgisКстати засунул я этот класс в папку config/initializers, может вы как думаете стоит в другое место вынести его?
Из postgis использую функцию ST_Contains для ограничения области поиска, но также есть функция ST_Covers, советую изучить и ту и ту.
Вот результат выполнения в консоли:
RoutePoint.g_within_polygon.first
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
RoutePoint Load (0.6ms) SELECT "route_points".* FROM "route_points" WHERE (ST_Contains('srid=4326;POLYGON ((-84.39731626974567 33.75570358345219, -84.33139830099567 33.86524376001825, -84.25243406759724 33.770545357734925, -84.39731626974567 33.75570358345219))', ST_SetSRID(ST_MakePoint(longitude, latitude), 4326))) ORDER BY "route_points"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<RoutePoint:0x00007ff8950f1d20
id: 31,
address_title: "1798 Haygood Dr NE, Atlanta, GA 30307, США",
longitude: -84.3167664,
latitude: 33.7936176,
order_id: 39,
created_at: Wed, 20 Jan 2021 23:55:38 UTC +00:00,
updated_at: Wed, 20 Jan 2021 23:55:38 UTC +00:00>