33. الطوبولوجيا وتمثيل الأشكال الهندسية¶
قبل قراءة هذا المستند، يُرجى مراجعة واحد على الأقل من هذه المصادر:
من المفيد أن تكون لدينا طوبولوجيا بكل عناصرها الأولية (Primitives)، لكن لجعلها أكثر عملية نحتاج إلى طريقة لتمثيل هذه العناصر في جدول. وكما أن لدينا جداول مكانية، يمكن أن تكون لدينا جداول طوبولوجية.
33.1. مقدمة في تمثيل الأشكال الهندسية¶
إذا كنت قد اتبعت أي مثال على استخدام الطوبولوجيا لتمثيل الأشكال الهندسية، فقد تتذكر هذا: عندما نملأ جدولًا طوبولوجيًا من جدول أشكال هندسية فإننا نستخدم TopoGeometry بدلًا من Geometry، وبطريقة ما يستطيع كل TopoGeometry أن يمثّل عنصرًا أوليًا واحدًا أو أكثر من العناصر الموجودة في الطوبولوجيا.
السؤال هو كيف نصل إلى العناصر الأولية الفعلية انطلاقًا من TopoGeometry، وكيف تُنظَّم البيانات، لذا لنرَ أولًا التعريفات الأعم:
يمكن أن يمثّل TopoGeometry مجموعة من العناصر الأولية أو من كائنات TopoGeometry أخرى، ولإنشاء TopoGeometry تحتاج إلى طبقة (Layer).
الطبقات هي الصندوق الأكبر، فهي تخزّن كائنات TopoGeometry التي تخزّن بدورها كائنات TopoElement، وهذه الأخيرة تمثّل عناصر أولية أو كائنات TopoGeometry أخرى.
لنكتب ذلك بطريقتين:
تحتوي الطبقة على كائنات TopoGeometry، ويحتوي كل TopoGeometry على كائنات TopoElement من نوع TopoElement نفسه.
يمكن أن يمثّل كل TopoElement:
TopoGeometry من طبقة أخرى
مجموعة أشكال هندسية (Geometry Collection)
عنصرًا أوليًا من الطوبولوجيا: عقدًا أو حوافًا أو أوجهًا
تُعرَض كائنات TopoGeometry على هيئة مفاتيح، فلكل منها مفتاح فريد داخل الطبقة، لكنها تخزّن أيضًا مفتاح طبقتها، وهذا يتيح لـ PostGIS تخزينها في أي عمود مع القدرة دائمًا على إيجاد كائنات TopoElement الخاصة بها، ومن خلالها ما تمثّله.
تحتاج إلى طبقة يُبنى فيها TopoGeometry، وبعد ذلك لا تحتاج إلى تذكّر الطبقة التي ينتمي إليها.
هذا هو المفهوم الذي يستخدمه المستخدم، ومن هذه النقطة سنشرح تفاصيل عميقة وتقنية.
وكملاحظة جانبية، يستخدم PostGIS Topology داخليًا بعض الحيل المتعلقة بالمفاتيح للمساعدة في تحسين أجزاء كثيرة، لكن في الوقت نفسه هناك الكثير من المعلومات المكررة، فلا تتفاجأ إذا وجدت المعلومات نفسها في مكانين أو أكثر.
33.2. المعالم (Features)¶
يمكن أن تمثّل كائنات TopoElement كائن TopoGeometry أو عنصرًا أوليًا؛ فكّر في TopoGeometry: إذا خزّناه في TopoElement فإنه لا يزال يحتوي على كائنات TopoElement أخرى، وإذا تتبعنا مساره فسننتهي دائمًا إلى عناصر أولية من الطوبولوجيا.
تمثّل المعالم نوع مجموعة الأشكال الهندسية، ولا يهم إن كنت تستخدم كائنات TopoGeometry أو عناصر أولية، ففي النهاية يمكن أن تحتوي الطبقة بشكل مباشر أو غير مباشر على أيٍّ من هذه المجموعات:
العقد
الحواف
الأوجه
مجموعات الأشكال الهندسية (Geometry Collections)
الأرقام مهمة، ففي أي دالة تطلب نوع المعلم (Feature Type) يمكنك تحديده باستخدام الرقم أو الاسم كسلسلة نصية.
33.3. الطبقات الهرمية، الأبناء والآباء¶
كنت أود تقديم هذا المفهوم لاحقًا، لكنك ستجد أنه ضروري لشرح المفهوم بشكل أفضل وأعمق.
أول ما يظهر في الصورة جدول مبني باستخدام العناصر الأولية؛ فالطبقة 1 ستحتوي على كائنات TopoGeometry لا تشير كائنات TopoElement فيها إلا إلى عناصر أولية من الطوبولوجيا.
نعرّف العلاقة بين الطبقة 1 والعناصر الأولية كما يلي:
الطبقة 1 هي الأب (Parent) للعناصر الأولية
العناصر الأولية هي أبناء (Childs) الطبقة 1
تتعلق العلاقة بين الأب والابن بالحجم؛ فالأبناء صغار، وعندما تكون لدينا مجموعة منهم نبني أبًا، أي مجموعة أكبر.
أبناء الطبقة 2 هم الطبقة 1، وهذا يعني أن كل TopoGeometry من هذه الطبقة يمكن أن يشير إلى TopoGeometry واحد أو أكثر من الطبقة 1.
ويعني هذا أيضًا أنك لا تستطيع اختيار نصف TopoGeometry من الطبقة 1، فاختيار نصفه يعني أنك تحتاج إلى الإشارة إلى أحد كائنات TopoElement الخاصة بـ TopoGeometry، وهي في هذه الحالة تنتمي إلى العناصر الأولية (أبنائه)؛ وإذا كنت تحتاج إلى ذلك فعلًا فابنِ الطبقة 2 باستخدام أبناء الطبقة 1 (العناصر الأولية).
لا يمكن أن يكون لكل طبقة إلا طبقة ابن واحدة، وهذا يعني أن الابن والأب يتشاركان مخطط (schema) الطوبولوجيا نفسه.
ستلاحظ أن بعض جوانب الهرمية قد تتغير ربما لدعم أمور مثل نصف TopoGeometry أو مزج الطبقات، لكن ذلك غير منفّذ حاليًا.
33.4. الطبقات¶
لتخزين كائنات TopoGeometry نحتاج إلى طبقة، ولهذا عندما ننشئ عمود TopoGeometry فإننا ننشئ أيضًا طبقة، ولهذا السبب نستخدم دالة خاصة لإنشاء هذا العمود.
بين الطبقات وأعمدة TopoGeometry علاقة خاصة؛ فهي مرتبطة ببعضها، لكنها ليست الشيء نفسه.
للطبقات الكثير من المعلومات التي يجب أن نوفرها لتحديد نوع الطبقة التي نريدها.
للطبقات معرّف فريد في كل طوبولوجيا، ويُسمّى هذا المعرّف layer_id.
مفتاح الطبقات (Layers Key): مفتاح مركّب من [topology_id, layer_id]
مسار الجدول: اسم المخطط واسم الجدول واسم العمود لمعرفة المكان المرتبطة به.
نوع المعلم (Feature Type): نوع المعالم التي ستحتويها الطبقة.
المستوى (Level): تبدأ هذه القيمة من 0، وإذا بنينا هذه الطبقة باستخدام طبقة أخرى تُضاف إليها 1، وبذلك نعرف كم طبقة تفصلنا عن العناصر الأولية؛ وإذا كانت القيمة 0 فهذا يعني أن الطبقة مبنية باستخدام عناصر أولية بدلًا من كائنات TopoGeometry.
child_id: إذا لم تُبنَ الطبقة باستخدام العناصر الأولية بل باستخدام طبقة أخرى أساسًا، فنحتاج إلى معرّف تلك الطبقة (layer_id)، ولا نحتاج إلى topology_id لأننا نعرفه مسبقًا من الأب.
33.5. جدول العلاقات (Relation's Table)¶
وأخيرًا القسم الذي ربما تبحث عنه: كيف ينتقل PostGIS Topology من TopoGeometry إلى ما يحتويه.
وظيفة جدول العلاقات هي أن يكون الجسر بين الأب والأبناء.
يمكن العثور على هذا الجدول في: my_topology.relation.
33.5.1. المفاتيح والمعرّفات التي نعرفها الآن¶
سأستخدم كلمة "معرّف" (Identifier) بمعنى مفتاح فريد في سياق معين. فمثلًا لكل طبقة رقم معرّف (layer_id)، وهو فريد في سياق طوبولوجيتها، لكنه لا يكفي لإيجاد طبقة في قاعدة بيانات.
بينما تعمل المعرّفات ضمن سياق ما، فإن المفتاح (Key) هو الطريقة الكاملة للوصول إلى عنصر؛ فمثلًا مفتاح أي طبقة هو قيمتان [topology_id, layer_id].
تقدّم الصورة ملخصًا جيدًا لكيفية تركيب المفاتيح لكل منها.
33.5.1.1. المعرّفات الضمنية في المفاتيح¶
يستخدم PostGIS إلى حد ما منطقًا ضمنيًا عند العمل مع الطبقات وكائنات TopoGeometry، وذلك لأن لها سياقًا لا تحتاج فيه إلى تخزين المفتاح الكامل لمعرفتها.
لنعرض مثالًا:
يتكون TopoGeometry من:
topology_id
layer_id
topogeometry_id
كما قلنا سابقًا، يُخزَّن جدول العلاقات داخل مخطط الطوبولوجيا. سيحتوي هذا الجدول على علاقة TopoGeometry بكائنات TopoElement، فهل نحتاج إلى topology_id للإشارة إليه في هذا السياق؟
يمكننا الاستغناء عنه! فعندما نكون خارج مخطط الطوبولوجيا نحتاج إلى المعرّف لإيجاده، أما عندما نكون داخله فيمكننا النظر إلى اسم المخطط وإيجاد معرّفه في الجدول topology.topology الذي يضم معرّفات جميع الطوبولوجيات وأسماءها.
33.5.2. TopoGeometry¶
TopoGeometry مفتاح مركّب من العناصر التالية:
topology_id: قيمة topology_id في مفتاح TopoGeometry
layer_id: قيمة layer_id في مفتاح TopoGeometry
id: قيمة topogeometry_id في مفتاح TopoGeometry
type: نوع المعلم على هيئة رقم
33.5.3. البنية الأساسية لجدول العلاقات¶
يمكن أن يكون لكل مخطط طوبولوجيا جدول علاقات خاص به، يُنشأ عندما تنشئ أول TopoGeometry، ويُخزَّن الجدول داخل الطوبولوجيا باسم custom_topology.relation.
يُسمّى كل صف في الجدول "مكوّنًا" (Component)، أي مكوّنًا من مكوّنات العلاقات.
يحفظ المكوّن أزواجًا من شيئين: مفتاح TopoGeometry و TopoElement. تذكّر أن كل TopoElement لا يمكنه أن يمثّل إلا عنصرًا أوليًا واحدًا أو TopoGeometry واحدًا، لذا لكي يتمكن TopoGeometry من تمثيل عدة عناصر يخزّن الجدول صفوفًا متعددة بمفتاح TopoGeometry نفسه وكائنات TopoElement مختلفة، وبهذه الطريقة يمكننا بمجرد التصفية في الجدول الحصول على جميع كائنات TopoElement لأي TopoGeometry.
33.5.4. إيجاد مكوّنات TopoGeometry¶
إيجاد المكوّنات التي تنتمي إلى TopoGeometry معقّد بعض الشيء، لأن المفاتيح الضمنية تعمل هنا.
يتكون المكوّن من العناصر التالية:
مفتاح TopoGeometry
topogeom_id: قيمة topogeometry_id من مفتاح TopoGeometry
layer_id: قيمة layer_id من مفتاح TopoGeometry
TopoElement
element_id
element_type
نلاحظ أن مفتاح TopoGeometry غير مكتمل، وذلك لأن جدول العلاقات ينتمي أصلًا إلى طوبولوجيا، فلا حاجة إلى تخزين معرّف الطوبولوجيا مرة أخرى.
للوصول من TopoGeometry إلى مكوّن نحتاج إلى النظر إلى TopoGeometry.topology_id والبحث في topology.topology.id واسترجاع اسم الطوبولوجيا، وبه يمكننا العثور على جدول العلاقات في المخطط الخاص بها.
33.5.5. قراءة كائنات TopoElement¶
الجزء الأخير في تفكيك TopoGeometry هو القدرة على تفسير كائنات TopoElement، وهو أعقد من المفاتيح الأخرى لأن معناه قد يتغير بحسب الطبقة المحفوظ فيها.
كما ذكرنا، يمكن أن يكون للطبقة أحد خيارين من الأبناء: عناصر أولية أو كائنات TopoGeometry.
أول ما نحتاج إلى معرفته هو نوع الأبناء الذي تستخدمه، ولهذا نحتاج إلى البحث في topology.layer.id باستخدام TopoGeometry Key.layer_id والحصول على `topology.layer.child_id`.
لذا تعتمد الحالات على قيمة child_id:
إذا كانت NULL:
element_id: معرّف العنصر الأولي
element_type: رقم المعلم، راجع قسم المعالم لمعرفة جدول العناصر الأولية الذي يجب البحث فيه.
إذا لم تكن NULL:
element_id: قيمة topogeometry_id من مفتاح TopoGeometry
element_type: قيمة layer_id من مفتاح TopoGeometry
الحالة الأولى بسيطة؛ ما عليك إلا النظر في جدول العناصر الأولية المعني واستخدام المعرّف لمعرفة العنصر الأولي.
أما في الحالة الثانية فيُستخدم TopoElement لبناء مفتاح TopoGeometry جديد، و topology_id ضمني كما ذكرنا، فيكتمل المفتاح؛ ولإيجاد العناصر الجديدة ابحث مجددًا في جدول العلاقات لكن باستخدام المفاتيح الجديدة.