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) تُعيد نقطة مضمونًا وقوعها داخل الوسيط المُدخل. وهذا يجعلها أكثر فائدة لحساب «النقاط البديلة» في الربط المكاني.

_images/centroid.jpg
-- 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) مسافة النطاق العازل والشكل الهندسي، وتُخرج مضلعًا تبعد حدوده عن الشكل الهندسي المُدخل بمقدار مسافة النطاق العازل.

_images/st_buffer.png

على سبيل المثال، إذا أرادت هيئة المتنزهات الأمريكية فرض منطقة حركة بحرية حول جزيرة 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';
_images/liberty_positive.jpg

تقبل الدالة ST_Buffer أيضًا المسافات السالبة، وتنشئ مضلعات داخلية ضمن المدخلات المضلعة. أما للخطوط والنقاط فستحصل على نتيجة فارغة فقط.

_images/liberty_negative.jpg

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)
));
_images/intersection.jpg

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)
    ));
    
    _images/union.jpg
  • 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;
_images/union_counties.png

يمكن لاختبار المساحة أن يؤكد أن عملية الاتحاد لم تفقد أي شكل هندسي. أولًا، نحسب مساحة كل كتلة إحصائية على حدة، ونجمع تلك المساحات مع التجميع حسب معرّف المقاطعة الإحصائي.

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 تُعيد مجموع السجلات في مجموعة من السجلات.