Oluşturmak istediğiniz satırların algılanan her bir ucundan başlayarak her noktanın en yakın komşusunu keşfetmek için özyinelemeli bir sorgu kullanabilirsiniz .
Önkoşullar : Yollarınızı içeren tek bir Multi-linestring nesnesiyle noktalarınızla bir postgis katmanı hazırlayın. İki katmanın aynı CRS üzerinde olması gerekir. İşte oluşturduğum test veri kümesinin kodu, lütfen gerektiği gibi değiştirin. (Postgres 9.2 ve postgis 2.1 üzerinde test edilmiştir)
WITH RECURSIVE
points as (SELECT id, st_transform((st_dump(wkb_geometry)).geom,2154) as geom, my_comment as com FROM mypoints),
roads as (SELECT st_transform(ST_union(wkb_geometry),2154) as geom from highway),
İşte adımlar :
Her bir nokta için, bu üç kriteri karşılayan her komşu ve onların mesafe listesini oluşturun.
- Mesafe, kullanıcı tanımlı bir eşiği aşmamalıdır (bu, izole noktaya bağlantı yapılmasını önler)
graph_full as (
SELECT a.id, b.id as link_id, a.com, st_makeline(a.geom,b.geom) as geom, st_distance(a.geom,b.geom) as distance
FROM points a
LEFT JOIN points b ON a.id<>b.id
WHERE st_distance(a.geom,b.geom) <= 15
),
- Doğrudan yol bir yoldan geçmemelidir
graph as (
SELECt graph_full.*
FROM graph_full RIGHT JOIN
roads ON st_intersects(graph_full.geom,roads.geom) = false
),
Mesafe, en yakın komşudan uzaklığın kullanıcı tanımlı bir oranını aşmamalıdır (bu, sabit mesafeden daha düzensiz dijitalleşmeye daha iyi uyum sağlamalıdır) Bu parçanın uygulanması çok zordu, sabit arama yarıçapına yapıştı
Bu tabloya "grafik" diyelim
Grafiğe katılarak ve grafikte yalnızca bir girişi olan noktayı tutarak çizgi sonu noktasını seçin.
eol as (
SELECT points.* FROM
points JOIN
(SELECT id, count(*) FROM graph
GROUP BY id
HAVING count(*)= 1) sel
ON points.id = sel.id),
Bu tabloya "eol" (satır sonu) diyelim
kolay mı? harika bir grafik yapmanın ama bir şeyleri tutmanın ödülünün bir sonraki adımda çıldırması
Her bir eol'den başlayarak komşulardan komşulara geçiş yapacak bir özyinelemeli sorgu ayarlama
- Eol tablosunu kullanarak ve derinlik için bir sayaç, yol için bir toplayıcı ve çizgileri oluşturmak için bir geometri yapıcısı kullanarak özyinelemeli sorguyu başlatın
- Grafiği kullanarak en yakın komşuya geçip yolu kullanarak asla geriye gitmediğinizi kontrol ederek bir sonraki yinelemeye geçin
- Yineleme bittikten sonra, her başlangıç noktası için yalnızca en uzun yolu saklayın (veri kümeniz, parçanın daha fazla koşula ihtiyaç duyacağı beklenen çizgiler arasında potansiyel kavşak içeriyorsa)
recurse_eol (id, link_id, depth, path, start_id, geom) AS (--initialisation
SELECT id, link_id, depth, path, start_id, geom FROM (
SELECT eol.id, graph.link_id,1 as depth,
ARRAY[eol.id, graph.link_id] as path,
eol.id as start_id,
graph.geom as geom,
(row_number() OVER (PARTITION BY eol.id ORDER BY distance asc))=1 as test
FROM eol JOIn graph ON eol.id = graph.id
) foo
WHERE test = true
UNION ALL ---here start the recursive part
SELECT id, link_id, depth, path, start_id, geom FROM (
SELECT graph.id, graph.link_id, r.depth+1 as depth,
path || graph.link_id as path,
r.start_id,
ST_union(r.geom,graph.geom) as geom,
(row_number() OVER (PARTITION BY r.id ORDER BY distance asc))=1 as test
FROM recurse_eol r JOIN graph ON r.link_id = graph.id AND NOT graph.link_id = ANY(path)) foo
WHERE test = true AND depth < 1000), --this last line is a safe guard to stop recurring after 1000 run adapt it as needed
Bu tabloya "recurse_eol" diyelim
Her başlangıç noktası için yalnızca en uzun satırı tutun ve her yinelenen her yolu kaldırın Örnek: yollar 1,2,3,5 VE 5,3,2,1, iki farklı "satır sonu" tarafından keşfedilen aynı satırdır
result as (SELECT start_id, path, depth, geom FROM
(SELECT *,
row_number() OVER (PARTITION BY array(SELECT * FROM unnest(path) ORDER BY 1))=1 as test_duplicate,
(max(depth) OVER (PARTITION BY start_id))=depth as test_depth
FROM recurse_eol) foo
WHERE test_depth = true AND test_duplicate = true)
SELECT * FROM result
Kalan hataları manuel olarak kontrol eder (yalıtılmış noktalar, çakışan çizgiler, garip şekilli sokak)
Söz verildiği gibi güncellenmiş, yine de bazen yinelemeli sorgunun aynı satırın ters eolünden başlarken neden tam olarak aynı sonucu vermediğini anlayamıyorum, bu nedenle bazı yinelemeler şu anda sonuç katmanında kalabilir.
Tamamen bu kodun daha fazla yoruma ihtiyaç duyduğunu sormaktan çekinmeyin. İşte tam sorgu:
WITH RECURSIVE
points as (SELECT id, st_transform((st_dump(wkb_geometry)).geom,2154) as geom, my_comment as com FROM mypoints),
roads as (SELECT st_transform(ST_union(wkb_geometry),2154) as geom from highway),
graph_full as (
SELECT a.id, b.id as link_id, a.com, st_makeline(a.geom,b.geom) as geom, st_distance(a.geom,b.geom) as distance
FROM points a
LEFT JOIN points b ON a.id<>b.id
WHERE st_distance(a.geom,b.geom) <= 15
),
graph as (
SELECt graph_full.*
FROM graph_full RIGHT JOIN
roads ON st_intersects(graph_full.geom,roads.geom) = false
),
eol as (
SELECT points.* FROM
points JOIN
(SELECT id, count(*) FROM graph
GROUP BY id
HAVING count(*)= 1) sel
ON points.id = sel.id),
recurse_eol (id, link_id, depth, path, start_id, geom) AS (
SELECT id, link_id, depth, path, start_id, geom FROM (
SELECT eol.id, graph.link_id,1 as depth,
ARRAY[eol.id, graph.link_id] as path,
eol.id as start_id,
graph.geom as geom,
(row_number() OVER (PARTITION BY eol.id ORDER BY distance asc))=1 as test
FROM eol JOIn graph ON eol.id = graph.id
) foo
WHERE test = true
UNION ALL
SELECT id, link_id, depth, path, start_id, geom FROM (
SELECT graph.id, graph.link_id, r.depth+1 as depth,
path || graph.link_id as path,
r.start_id,
ST_union(r.geom,graph.geom) as geom,
(row_number() OVER (PARTITION BY r.id ORDER BY distance asc))=1 as test
FROM recurse_eol r JOIN graph ON r.link_id = graph.id AND NOT graph.link_id = ANY(path)) foo
WHERE test = true AND depth < 1000),
result as (SELECT start_id, path, depth, geom FROM
(SELECT *,
row_number() OVER (PARTITION BY array(SELECT * FROM unnest(path) ORDER BY 1))=1 as test_duplicate,
(max(depth) OVER (PARTITION BY start_id))=depth as test_depth
FROM recurse_eol) foo
WHERE test_depth = true AND test_duplicate = true)
SELECT * FROM result