আপনি যে লাইনগুলি তৈরি করতে চান তার প্রতিটি সনাক্ত করা প্রান্ত থেকে শুরু করে প্রতিটি পয়েন্টের নিকটতম প্রতিবেশীর অন্বেষণ করতে আপনি পুনরাবৃত্ত ক্যোয়ারী ব্যবহার করতে পারেন ।
পূর্বশর্ত : আপনার পয়েন্ট সহ একটি পোস্টগিজ স্তর এবং অন্য একটিতে আপনার রাস্তাগুলি সহ একক মাল্টি-লাস্টারিং বস্তু প্রস্তুত করুন। দুটি স্তর অবশ্যই একই সিআরএসে থাকা উচিত। আমি তৈরি করা টেস্ট ডেটা-সেটটির কোড এখানে, দয়া করে এটি প্রয়োজনীয় হিসাবে সংশোধন করুন। (পোস্টগ্রিস ৯.২ এবং পোস্টগ্রিস ২.১ এ পরীক্ষিত)
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
),
- সরাসরি পথ অবশ্যই কোনও রাস্তা অতিক্রম করবে না cross
graph as (
SELECt graph_full.*
FROM graph_full RIGHT JOIN
roads ON st_intersects(graph_full.geom,roads.geom) = false
),
দূরত্বটি অবশ্যই নিকটবর্তী প্রতিবেশী থেকে দূরত্বের ব্যবহারকারীর সংজ্ঞায়িত অনুপাতের বেশি হওয়া উচিত নয় (এটি নির্ধারিত দূরত্বের তুলনায় অনিয়মিত ডিজিটালাইজেশনের সাথে আরও ভালভাবে সংযোজন করা উচিত) এই অংশটি বাস্তবায়নের পক্ষে আসলে খুব কঠিন ছিল, স্থির অনুসন্ধানের ব্যাসার্ধের সাথে সংযুক্ত
এই টেবিলটিকে "গ্রাফ" বলি
গ্রাফটিতে যোগদান করে এবং গ্রাফের ঠিক একটি প্রবেশ রয়েছে এমন পয়েন্ট রেখে লাইনের পয়েন্টের শেষটি নির্বাচন করুন Select
eol as (
SELECT points.* FROM
points JOIN
(SELECT id, count(*) FROM graph
GROUP BY id
HAVING count(*)= 1) sel
ON points.id = sel.id),
আসুন এই টেবিলটিকে "ইওল" (লাইনের শেষ) বলি
? যে দুর্দান্ত গ্রাফ করার জন্য পুরষ্কার পাবে কিন্তু পরের ধাপে জিনিসগুলি হোল্ড-অন করবে crazy
একটি পুনরাবৃত্তি ক্যোয়ারী সেট আপ করুন যা প্রতি ইওল থেকে প্রতিবেশী থেকে প্রতিবেশীদের কাছাকাছি চলে
- ইওল টেবিল ব্যবহার করে এবং পুনর্গঠন ক্যোয়ারি প্রারম্ভিক করুন গভীরতার জন্য একটি কাউন্টার, পথের জন্য একগ্রিগেটর এবং লাইনগুলি তৈরি করতে জ্যামিতি নির্মাণকারী
- গ্রাফটি ব্যবহার করে নিকটতম প্রতিবেশী স্যুইচ করে এবং পথটি ব্যবহার করে আপনি কখনই পিছিয়ে যাবেন না তা পরীক্ষা করে পরবর্তী পুনরাবৃত্তিতে যান
- পুনরাবৃত্তি সমাপ্ত হওয়ার পরে প্রতিটি প্রারম্ভিক পয়েন্টের জন্য কেবল দীর্ঘতম পথ রাখুন (যদি আপনার ডেটাসেটে প্রত্যাশিত লাইনের মধ্যে সম্ভাব্য ছেদ অন্তর্ভুক্ত থাকে তবে অংশটির আরও শর্ত প্রয়োজন হবে)
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
আসুন এই টেবিলটিকে "recurse_eol" বলি
প্রতিটি শুরুর পয়েন্টের জন্য কেবল দীর্ঘতম লাইন রাখুন এবং প্রতিটি সঠিক সদৃশ পথ সরান উদাহরণস্বরূপ: 1,2,3,5 এবং 5,3,2,1 পথ দুটি পৃথক "লাইনের শেষ" দ্বারা আবিষ্কার করা একই লাইন
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
ম্যানুয়ালি অবশিষ্ট ত্রুটিগুলি পরীক্ষা করে (বিচ্ছিন্ন পয়েন্টগুলি, ওভারল্যাপিং লাইনগুলি, অদ্ভুত আকারের রাস্তায়)
প্রতিশ্রুতি অনুসারে আপডেট হয়েছে, আমি এখনও বুঝতে পারি না যে কখনও কখনও পুনরাবৃত্ত হওয়া ক্যোয়ারী একই লাইনের বিপরীত ইওল থেকে শুরু করার সময় কেন একই ফলাফল দেয় না যাতে কিছু সদৃশ এখনকার ফলাফলের স্তরে থাকতে পারে।
বিনা দ্বিধায় আমি সম্পূর্ণরূপে এই কোডটি আরও মন্তব্য প্রয়োজন যে পেতে। এখানে পূর্ণ জিজ্ঞাসা:
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