20. دوال إنشاء الأشكال الهندسية¶
جميع الدوال التي رأيناها حتى الآن تعمل على الأشكال الهندسية «كما هي» وتُعيد
تحليلات للكائنات ( ST_Length(geometry)، ST_Area(geometry) )،
تسلسلات (serializations) للكائنات ( ST_AsText(geometry)، ST_AsGML(geometry) )،
أجزاء من الكائن ( ST_RingN(geometry,n) ) أو
اختبارات صواب/خطأ ( ST_Contains(geometry,geometry)، ST_Intersects(geometry,geometry) ).
أما «دوال إنشاء الأشكال الهندسية» فتأخذ أشكالًا هندسية كمدخلات وتُخرج أشكالًا جديدة.
20.1. ST_Centroid / ST_PointOnSurface¶
من الاحتياجات الشائعة عند صياغة استعلام مكاني استبدال معلم مضلع بتمثيل نقطي له. وهذا مفيد في الربط المكاني (كما نوقش في الربط بين المضلعات ) لأن استخدام ST_Intersects(geometry,geometry) على طبقتين من المضلعات يؤدي غالبًا إلى العدّ المزدوج: فالمضلع الواقع على حدٍّ ما سيتقاطع مع كائن على كلا الجانبين، واستبداله بنقطة يجبره على أن يكون على جانب واحد فقط لا على الجانبين.
ST_Centroid(geometry) تُعيد نقطة تقع تقريبًا عند مركز كتلة الوسيط المُدخل. هذا الحساب البسيط سريع جدًا، لكنه أحيانًا غير مرغوب فيه، لأن النقطة المُعادة لا تقع بالضرورة داخل المعلم نفسه. فإذا كان للمعلم المُدخل تقعّر (تخيّل الحرف 'C') فقد لا يقع المركز المُعاد داخل المعلم.
ST_PointOnSurface(geometry) تُعيد نقطة مضمونًا وقوعها داخل الوسيط المُدخل. وهذا يجعلها أكثر فائدة لحساب «النقاط البديلة» في الربط المكاني.
-- Compare the location of centroid and point-on-surface for a concave geometry
SELECT ST_Intersects(geom, ST_Centroid(geom)) AS centroid_inside,
ST_Intersects(geom, ST_PointOnSurface(geom)) AS pos_inside
FROM (VALUES
('POLYGON ((30 0, 30 10, 10 10, 10 40, 30 40, 30 50, 0 50, 0 0, 0 0, 30 0))'::geometry)
) AS t(geom);
centroid_inside | pos_inside
-----------------+------------
f | t
20.2. ST_Buffer¶
عملية إنشاء النطاق العازل شائعة في سير عمل GIS، وهي متاحة أيضًا في PostGIS. تأخذ الدالة ST_Buffer(geometry,distance) مسافة النطاق العازل والشكل الهندسي، وتُخرج مضلعًا تبعد حدوده عن الشكل الهندسي المُدخل بمقدار مسافة النطاق العازل.
على سبيل المثال، إذا أرادت هيئة المتنزهات الأمريكية فرض منطقة حركة بحرية حول جزيرة Liberty Island، فقد تنشئ مضلع نطاق عازل بعرض 500 متر حول الجزيرة. جزيرة Liberty Island كتلة إحصائية واحدة في جدولنا nyc_census_blocks، لذا يمكننا بسهولة استخراجها وإنشاء نطاق عازل حولها.
-- Make a new table with a Liberty Island 500m buffer zone
CREATE TABLE liberty_island_zone AS
SELECT ST_Buffer(geom,500)::geometry(Polygon,26918) AS geom
FROM nyc_census_blocks
WHERE blkid = '360610001001001';
تقبل الدالة ST_Buffer أيضًا المسافات السالبة، وتنشئ مضلعات داخلية ضمن المدخلات المضلعة. أما للخطوط والنقاط فستحصل على نتيجة فارغة فقط.
20.3. ST_Intersection¶
عملية أخرى كلاسيكية في GIS، وهي «التراكب» (overlay)، تنشئ تغطية جديدة بحساب تقاطع مضلعين متراكبين. وتتميز النتيجة بأن أي مضلع في أيٍّ من الطبقتين الأصليتين يمكن بناؤه بدمج مضلعات من النتيجة.
تُعيد الدالة ST_Intersection(geometry A, geometry B) المساحة المكانية (أو الخط أو النقطة) المشتركة بين الوسيطين. فإذا كانا منفصلين، تُعيد الدالة شكلًا هندسيًا فارغًا.
-- What is the area these two circles have in common?
-- Using ST_Buffer to make the circles!
SELECT ST_AsText(ST_Intersection(
ST_Buffer('POINT(0 0)', 2),
ST_Buffer('POINT(3 0)', 2)
));
20.4. ST_Union¶
في المثال السابق أجرينا تقاطعًا بين أشكال هندسية، فأنشأنا شكلًا هندسيًا جديدًا يحتوي على خطوط من كلا المدخلين. أما الدالة ST_Union فتفعل العكس؛ إذ تأخذ المدخلات وتزيل الخطوط المشتركة. وللدالة ST_Union صيغتان:
ST_Union(geometry, geometry): صيغة ذات وسيطين تأخذ شكلين هندسيين وتُعيد اتحادهما المدموج. على سبيل المثال، يبدو مثال الدائرتين من القسم السابق هكذا عند استبدال التقاطع بالاتحاد.
-- What is the total area these two circles cover? -- Using ST_Buffer to make the circles! SELECT ST_AsText(ST_Union( ST_Buffer('POINT(0 0)', 2), ST_Buffer('POINT(3 0)', 2) ));
ST_Union([geometry]): صيغة تجميعية تأخذ مجموعة من الأشكال الهندسية وتُعيد الشكل الهندسي المدموج للمجموعة بأكملها. يمكن استخدام ST_Union التجميعية مع تعليمة SQL
GROUP BYلإنشاء مجموعات فرعية مدموجة بعناية من الأشكال الهندسية الأساسية. إنها قوية جدًا.
كمثال على تجميع ST_Union، لنأخذ جدولنا nyc_census_blocks. صُممت الوحدات الجغرافية للتعداد بعناية بحيث يمكن بناء الوحدات الأكبر من الوحدات الأصغر. لذلك يمكننا إنشاء خريطة للمناطق الإحصائية (census tracts) بدمج الكتل التي تشكّل كل منطقة (كما سنفعل لاحقًا في إنشاء جدول للمناطق الإحصائية (Census Tracts) ). أو يمكننا إنشاء خريطة للمقاطعات بدمج الكتل الواقعة ضمن كل مقاطعة.
لإجراء الدمج، لاحظ أن المفتاح الفريد blkid يتضمن في الواقع معلومات عن الوحدات الجغرافية ذات المستوى الأعلى. إليك أجزاء المفتاح لجزيرة Liberty Island التي استخدمناها سابقًا:
360610001001001 = 36 061 000100 1 001
36 = State of New York
061 = New York County (Manhattan)
000100 = Census Tract
1 = Census Block Group
001 = Census Block
إذن يمكننا إنشاء خريطة للمقاطعات بدمج جميع الأشكال الهندسية التي تشترك في أول 5 أرقام من blkid. تحلَّ بالصبر؛ فهذه العملية مكلفة حسابيًا وقد تستغرق دقيقة أو دقيقتين.
-- Create a nyc_census_counties table by merging census blocks
CREATE TABLE nyc_census_counties AS
SELECT
ST_Union(geom)::Geometry(MultiPolygon,26918) AS geom,
SubStr(blkid,1,5) AS countyid
FROM nyc_census_blocks
GROUP BY countyid;
يمكن لاختبار المساحة أن يؤكد أن عملية الاتحاد لم تفقد أي شكل هندسي. أولًا، نحسب مساحة كل كتلة إحصائية على حدة، ونجمع تلك المساحات مع التجميع حسب معرّف المقاطعة الإحصائي.
SELECT SubStr(blkid,1,5) AS countyid, Sum(ST_Area(geom)) AS area
FROM nyc_census_blocks
GROUP BY countyid
ORDER BY countyid;
countyid | area
----------+------------------
36005 | 110196022.906506
36047 | 181927497.678368
36061 | 59091860.6261323
36081 | 283194473.613692
36085 | 150758328.111199
ثم نحسب مساحة كل مضلع من مضلعات المقاطعات الجديدة من جدول المقاطعات:
SELECT countyid, ST_Area(geom) AS area
FROM nyc_census_counties
ORDER BY countyid;
countyid | area
----------+------------------
36005 | 110196022.906507
36047 | 181927497.678367
36061 | 59091860.6261324
36081 | 283194473.593646
36085 | 150758328.111199
الإجابة نفسها! لقد نجحنا في بناء جدول لمقاطعات نيويورك من بيانات الكتل الإحصائية.
20.5. قائمة الدوال¶
ST_Centroid(geometry): تُعيد شكلًا هندسيًا نقطيًا يمثل مركز كتلة الشكل الهندسي المُدخل.
ST_PointOnSurface(geometry): تُعيد شكلًا هندسيًا نقطيًا مضمونًا وقوعه داخل الشكل الهندسي المُدخل.
ST_Buffer(geometry, distance): بالنسبة لـ geometry: تُعيد شكلًا هندسيًا يمثل جميع النقاط التي تقل مسافتها عن هذا الشكل الهندسي أو تساوي المسافة المحددة. تُجرى الحسابات في النظام المرجعي المكاني لهذا الشكل الهندسي. بالنسبة لـ geography: تستخدم غلاف تحويل مستوٍ.
ST_Intersection(geometry A, geometry B): تُعيد شكلًا هندسيًا يمثل الجزء المشترك بين geomA و geomB. يُجري تنفيذ geography تحويلًا إلى geometry لإجراء التقاطع ثم يعيد التحويل إلى WGS84.
ST_Union(): تُعيد شكلًا هندسيًا يمثل اتحاد مجموعات النقاط للأشكال الهندسية.
ST_AsText(text): تُعيد تمثيل Well-Known Text (WKT) للشكل الهندسي geometry/geography دون البيانات الوصفية لـ SRID.
substring(string [from int] [for int]): دالة نصية في PostgreSQL لاستخراج سلسلة فرعية تطابق تعبيرًا نمطيًا في SQL.
sum(expression): دالة تجميعية في PostgreSQL تُعيد مجموع السجلات في مجموعة من السجلات.