الأحد، 29 مايو، 2011

البيانات الممتدة في أوتوكاد

البيانات الممتدة في أوتوكاد
سامر الجودي
http://www.cadmagazine.net/content.php?r=1798-Adding-XData-To-AutoCAD-Entities-Using-VB
تردد الحديث في المنتدى مؤخراً عن ربط كائنات أوتوكاد بالبيانات، ووصلت العديد من الأسئلة التي يطلب فيها أصحابها شرح كيفية القيام بذلك باستخدام لغات البرمجة، وبخاصة فيجوال بيسك للتطبيقات. ولما كان الحديث عن البيانات وقواعد البيانات وربطهما بكائنات أوتوكاد حديثاً ذا شجون، ويصعب على المرء إيجازه في مقالة واحدة، فقد رأيت أن أعمد إلى كتابة هذه المقالة - ولو سريعاً - لتكون عوناً للمبتدئين ومرشداً لهم في أول الطريق لاستخدام البيانات الممتدة، وهي أحد أسلوبين شهيرين لربط البيانات بكائنات أوتوكاد.مقدمة لابد منها:
البيانات التي نتحدث عنها في هذه المقالة معلومات لا رسومية (nongraphic) مرفقة بكائنات أوتوكاد، لا تمثل الخصائص الأولية لهذه الكائنات، ولكنها تمثل مجموعة من الخصائص الإضافية التي يرغب المستخدم في إضافتها، مثل اسم المادة في الرسوم التنفيذية، واسم صاحب العقار في خرائط المدن.والمقصود بعبارة "لا رسومية" أن هذه البيانات ليست ظاهرة في الرسم، لأن كائنات أوتوكاد مثل الخط والدائرة والقوس والتظليل هي بيانات أيضاً، ولكنها بيانات رسومية. وأما المقصود بعبارة "لا تمثل الخصائص الأولية" فأن تكون هذه البيانات زائدة عن البيانات الأساسية التي تعبّر عن ماهية الكائن الرسومي، فنصف القطر واسم الطبقة ولون الدائرة هي بيانات أيضاً، ولكنها أساسية لايمكن تمثيل الدائرة من دونها. ونقش التظليل (hatch) ومقياسه وزاويته بيانات أساسية ولا يمكن تمثيل التظليل إلا بوجودها.
عندما يقوم المستخدم - في القسم الهندسي - بتحضير الرسوم لمبنى ما، فإنه يقوم بإضافة مجموعة كبيرة من النصوص لتوضيح المعلومات المطلوبة لفهم التصميم بشكل جيد، وتأتي هذه النصوص على نوعين، أولهما التعليقات (annotations) أو النصوص التي في حكمها، وهي ملاحظات يتركز الهدف منها في توضيح طريقة الإنشاء أو علاقة المكونات في المبنى بعضها ببعض، كتلك الملاحظات التي نجدها عادة في الإطار المحيط بالرسم. وثانيهما المواصفات الفنية لهذه المكونات مثل الأبواب التي تقضي العادة بوضع نص مختصر مثل D1 وD2 على كل منها، للإحالة إلى رسم تفصيلي مستقل للأبواب توضح فيه المواصفات الفنية كاملة لكل صنف من الأبواب، بما فيها أبعاده والمواد الداخلة في تصنيعه.
وإذا ذهبنا ابعد من ذلك، إلى قسم المشتريات، فإن لكل باب من هذه الأبواب مواصفات أخرى مثل السعر واسم الشركة المزودة، وهكذا. وينطبق الحديث ذاته على العقارات في خريطة المدينة، التي يمكن أن تشتمل على رقم العقار ورقم وتاريخ ترخيص البناء واسم صاحب العقار واستخدام الأراضي (تجاري أم سكني... الخ) وقيمته التاريخية. وكل هذه المعلومات التي تحدثت عنها هي معلومات إضافية لا يمكن أن نطلب من أوتوكاد أو غيره من برمجيات التصميم بالحاسوب الاضطلاع بأعباء إدارتها مباشرة.
يقدم أوتوكاد العديد من الأساليب التي تسهل ربط الكائنات الرسومية بالبيانات الإضافية، بالإضافة إلى لغات البرمجة العديدة. ومن هذه الأساليب استخدام السمات (attributes) في الكتل، وهي طريقة غير مناسبة للتطبيقات الكبيرة، واستخدام البيانات الممتدة (XData) والربط مع قواعد البيانات الخارجية.
الفرق بين البيانات الممتدة والربط مع قواعد البيانات الخارجية:
ثمة العديد من الفروق الجوهرية بين استخدام البيانات الممتدة مع الكائن، وربط الكائن بقواعد البيانات الخارجية، فالبيانات الممتدة تخزن في الكائن مباشرة، بينما تبقى البيانات الخارجية المربوطة به خارجية، باستثناء فهرس يشير إلى موقع البيانات في قواعد البيانات الخارجية، وهو مؤشر إلى صف أي سجل في جدول أكسيس أو سيكويل سيرفر أو أوراكل. ويعني ذلك أن تخزين مجموعة كبيرة من البيانات الممتدة في الرسم يزيد بشكل واضح من حجم ذلك الملف، ناهيك عن حدود 16 كيلوبايت التي يخصصها أوتوكاد كحد أقصى لتخزين البيانات الممتدة مع كل كائن، على الرغم من أن معظم التطبيقات لن تصل إلى هذا الحجم، ولهذا لا أنصح باستخدام البيانات الممتدة في التطبيقات الفائقة، مثل إضافة معلومات العقارات إلى العقارات في خريطة مدينة كبيرة مثل دمشق أو القاهرة، لأن ذلك يبطئ بشكل ملحوظ من أداء أوتوكاد. كما أنه من المهم أن نعلم أن إدارة البيانات الممتدة لا يمكن تنفيذها يدوياً كما هو الحال مع الربط مع قواعد البيانات الخارجية، لأنها لا تتم إلا عبر البرمجة.
لكن للبيانات الممتدة حسنات أيضاً، فهي بيانات يمكن إدارتها بسهولة، والوصول إليها بسرعة، بكتابة شفرة أصغر بكثير مقارنة مع الأسلوب الآخر، وهي تنتقل مع ملف أوتوكاد أينما انتقلنا، لأنها مخزّنة مع الكائنات الرسومية، كما أنها أسلوب اقتصادي إذ لا تتطلب برنامجاً خاصاً لإدارة قاعدة البيانات مثل سيكويل سيرفر وأوراكل أو خبرات في استخدامها.
ومن الجدير بالذكر أن Autodesk Map - وهو نسخة خاصة من أوتوكاد موجهة لتطبيقات نظام المعلومات الجغرافية (GIS: تطبيقات تعتمد على فكرة ربط الكائنات الرسومية بالبيانات لتحليل الخرائط ومساعدة صناع القرار والمخططين على صناعة قراراتهم) يسمح باستخدام الأسلوبين معاً، ولذلك سيتركز الحديث في هذه المقالة عن البيانات الممتدة، بينما سنفرد مقالة أخرى في المستقبل للحديث عن قواعد البيانات الخارجية وربطها في أوتوكاد.
الفكرة الأساسية:
تخزن البيانات الممتدة في الكائن الرسومي باستخدام شفرات المجموعات (group codes) بشكل شبيه بالبيانات الأساسية التي نجدها مع الكائن الرسومي مثل نوع الكائن (الشفرة 0) ونمط الخط (الشفرة 6) والطبقة ( الشفرة 8 ). وتستخدم هذه الشفرة لكتابة البيانات الممتدة إلى الكائن الرسومي، ولقرائتها منه أيضاً.تحتل البيانات الأساسية (الخصائص) شفرات المجموعات من 0 إلى 299 تقريباً، بينما تحتل البيانات الممتدة شفرات المجموعة من 1000 إلى 1071. وسنتعلم أهمية هذه الشفرات في المثال اللاحق. فإذا كان البرنامج التي تنوي كتابته يقوم بتخزين واسترجاع خمسة قيم بهيئة أعداد حقيقية فستضطر إذاً إلى استخدام الشفرة 1040 خمس مرات، لتخزين البيانات الحقيقية، وهكذا. وفيما يلي بعض من أهم هذه الشفرات:

  • 1000: نص.
  • 1001: اسم التطبيق المسجّل.
  • 1003: اسم طبقة.
  • 1005: مقبض الكائن الرسومي.
  • 1010 و1020 و1030: إحداثيات X وY وZ لنقطة.
  • 1040: عدد حقيقي ذي دقة مضاعفة.
  • 1041: قيمة مسافة.
  • 1042: عامل قياس.
  • 1070: عدد صحيح.
  • 1071: عدد صحيح طويل.

تستخدم لغة فيجوال بيسك للتطبيقات مصفوفتين مستقلتين متساويتين للتعبير عن البيانات الممتدة، تمثل المصفوفة الأولى أنواع البيانات (شفرات المجموعات المناسبة) بينما تمثل المصفوفة الثانية البيانات الفعلية. وهذا شبيه بفكرة الحقول والسجل في الجدول.
تكون شفرة المجوعة الأولى في المصفوفة الأولى هي الشفرة 1001، التي تمثل اسم التطبيق الذي يمتلك هذه البيانات، بينما يكون البيان الأول في المصفوفة الثانية اسم التطبيق الفعلي، لأنه من الممكن إضافة أكثر من مجموعة واحدة من البيانات الممتدة إلى الكائن الرسومي، بحيث تتبع كل مجموعة من البيانات تطبيقاً مستقلاً، ولذلك لا بد من تخزين اسم التطبيق ليتسنى لنا تمييز البيانات الممتدة المختلفة.
توفر هذه اللغة طريقتين (أي methods أو أوامر) للتعامل مع البيانات الممتدة في الكائن الرسومي، أولاهما الطريقة SetXData لتخزين البيانات في الكائن أو تعديلها، وثانيتهما الطريقة GetXadat لاسترجاع البيانات الممتدة في ذلك الكائن.
عندما نقوم بكتابة البيانات إلى الكائن الرسومي، علينا أولاً إنشاء المصفوفتين، وتعبئة عناصرهما بالقيم المطلوبة، وعندما نستخدم الطريقة SetXData نمرر هاتين المصفوفتين إلى الطريقة SetXData فتقوم بتخزينها في الكائن الرسومي. تكون هذه الطريقة بالنحو التالي:
شفرة:
object.SetXData XDataType, XData
حيث object الكائن الرسومي (في الحقيقة يمكن إضافة البيانات الممتدة إلى الكائنات غير الرسومية أيضاً، مثل الطبقة والمشهد ونمط النص ونمط البعد...الخ) ، وXDataType مصفوفة شفرات المجموعة، وXData مصفوفة القيم المراد كتابتها.
وعندما نستخدم الطريقة GetXData لاسترجاع البيانات الممتدة، فإننا ننشئ هاتين المصفوفتين (في الحقيقة نحن نصرح فقط عن متحولين من النوع Variant)، ونمررهما إلى الطريقة GetXData فتقوم بتخزين البيانات الممتدة في هاتين المصفوفتين، لقرائتها فيما بعد. وتكون هذه الطريقة بالنحو التالي:
شفرة:
object.GetXData [AppName,] XDataType, XDataValue
حيث AppName سلسلة (أي نص) اسم التطبيق، ويؤدي تجاهل كتابة اسم التطبيق إلى استعادة جميع البيانات الممتدة لكافة التطبيقات، بينما يؤدي كتابة اسم التطبيق إلى استرجاع البيانات الممتدة الخاصة بذلك التطبيق فقط.
المشروع المثال:
نرغب بكتابة تطبيق للبيانات الممتدة في أوتوكاد للاستفادة منه في إدارة المعلومات الخاصة بالعقارات في المدينة، وستكون هذه المعلومات هي اسم صاحب العقار (Owner) وهي بيانات نصية (string)، وسعر العقار (Price) وهي بيانات حقيقية (real)، وسنقتصر على هذين البيانين تجنباً للتعقيد.
يتكون المشروع من صندوقي الحوار frmxData وهو صندوق الحوار الأساسي في المشروع وفيه كافة الوظائف المستخدمة في التطبيق، بينما تقتصر وظيفة صندوق الحوار frmAbout على إظهار المعلومات المتعلقة بالتطبيق واسم مؤلفه، ويجب إضافة إجراء فرعي عمومي (الإجراء myXData) في الكائن ThisDrawing، وذلك لتمكين المستخدم من تشغيل البرنامج من القائمة Tools > Macro > Macros في أوتوكاد:
الشكل (1): مكونات المشروع Plot Application

يقوم الإجراء الفرعي myXData في الكائن ThisDrawing بإظهار صندوق الحوار frmxData:
شفرة:
Public Sub myXData()
frmxData.Show
End Sub
أما صندوق الحوار frmxData فهو يشتمل على صندوقي النص txtOwner (اسم مالك العقار) وtxtPrice (سعر العقار)، والزر cmdSelect وقد أضيفت إليه الصورة التقليدية لأزرار انتقاء الكائنات في برنامج أوتوكاد، وعنصر التحكم lblStatus وهو تسمية (lable) الغرض منها إظهار رسائل الخطأ والرسائل الأخرى، والزر cmdSave لكتابة وتعديل البيانات الممتدة، والزرين cmdExit وcmdAbout:
الشكل (1): صندوق حوار2المشروع

بعد تصميم صندوق الحوار frmxData سنقوم أولاً بالتصريح عن المتحولات التالية في القسم العام، وذلك للسماح لكافة الإجراءات الفرعية والوظائف بالوصول إلى هذه المتحولات، وهي المتحول myObject من النوع AcadObject ويمثل الكائن الرسومي الذي سنقوم بإدارة بياناته الممتدة، والمتحول xDataType وهي المصفوفة التي سنخزن فيها شفرات المجموعات (أي أنواع المتحولات) في المصفوفة الثانية xData، وهذه المصفوفة مكونة من ثلاثة عناصر الأول لاسم التطبيق والثاني لاسم مالك العقار والثالث لسعر العقار:
شفرة:
Dim myObject As AcadObject
Dim xDataType(0 To 2) As Integer
Dim xData(0 To 2) As Variant
عند تشغيل البرنامج، نقوم بضبط العناصر الثلاثة في المصفوفة الأولى على القيم 1001 و1000 و1040 وهي شفرات المجموعات المبينة في الجدول السابق، الأولى مناسبة لتمثيل اسم التطبيق والثانية لتمثيل النصوص (اسم المالك) والثالثة لتمثيل الأعداد الحقيقية (السعر).
ولأن اسم التطبيق ثابت (وليكن [size=2] Plot_Application مثلاً) فإننا نقوم بتعيينه إلى العنصر الأول من المصفوفة الثانية.
شفرة:
Private Sub UserForm_Initialize()
xDataType(0)=1001
xDataType(1)=1000
xDataType(2)=1040
xData(0)="Plot_Application"
[size=2]سنقوم أيضاً بتعطيل الزر Save، وسنسمح للمستخدم باستخدامه بعد أن ينتقي كائناً رسومياً، حتى يتمكن من إضافة وتعديل البيانات الممتدة فيه.
شفرة:
Me.cmdSave.Enabled=False
End Sub
قراءة البيانات الممتدة:
عندما يقوم المستخدم بالنقر على زر Select Object فإن أوتوكاد سيطلب منه انتقاء كائن رسومي، وسنستخدم ههنا الطريقة GetEntity في VBA، ولكن علينا أولاً التخلص من النصوص التي قد تظهر في صندوق الحوار، وتعطيل زر Save، بعد العمل مع كائنات سابقة:
شفرة:
Private Sub cmdSelect_Click()
Me.Hide
Me.txtOwner.Text="
Me.txtPrice.Text="
Me.cmdSave.Enabled=False
نمرر إلى الوظيفة GetEntity المتحول myObject الذي تم التصريح عنه في القسم العام، والمتحول pt وهو متحول من النوع Variant لتخزين إحداثيات الموقع حيث ينقر المستخدم فوق الكائن أثناء انتقائه، وإذا لم تفشل الوظيفة GetEntity فإنها تعيد الكائن الذي انتقاه المستخدم في المتحول myObject، وتفشل هذه الوظيفة عادة في حالتين: إذا نقر المستخدم في موقع فارغ، أو ألغى عملية الانتقاء بالضغط على زر ESC مثلاً. ولذلك يمكننا التأكد من نجاح عملية الانتقاء بعبارة If Err.Number 0:
شفرة:
Dim pt As Variant
On Error Resume Next
ThisDrawing.Utility.GetEntity myObject, pt
If Err.Number 0 Then
إذا كان رقم الخطأ لا يساوي الصفر، فهذا يعني أن المستخدم لم يقم بانتقاء كائن رسومي بعد، إما لأنه نقر فوق موقع فارغ أو لأنه ألغى عملية الانتقاء، وفي هذه الحالة ننبه المستخدم بعبارة (0 objects found)، بإظهاره في عنصر التحكم lblStatus، وسنبقي الزر Save معطلاً.
شفرة:
Me.lblStatus.Caption=0 objects found."
Me.Show
Exit Sub
وإذا كان رقم الخطأ صفراً ، فهذا يعني أن المستخدم نجح في انتقاء كائن رسومي، وبطبيعة الحال لن يتمكن المستخدم من انتقاء أكثر من كائن واحد باستخدام GetEntity.
Else
نستخدم عنصر التحكم lblStatus لإخبار المستخدم بأن هذا الكائن الذي انتقاه إن كان له بيانات ممتدة (تابعة للتطبيق Plot_Application) فإن هذه البيانات تظهر في صندوق الحوار، كما نقوم أيضاً بتمكين الزر Save وذلك حتى يتسنى للمستخدم إضافة البيانات التي يرغب بإضافتها:
شفرة:
Me.lblStatus.Caption=If selected object has extended data, these data will be shown in the text boxes above. To write new or modify existing data type it then press Savebutton."
Me.cmdSave.Enabled= True
نصرح هنا عن المتحولين XDataTypeOut وXDataOut لتمريرها إلى الوظيفة GetXData، وهما متحولان من النوع Variant، تقوم الطريقة GetXData بتعبئتهما بالبيانات الممتدة، إذا كان ثمة بيانات ممتدة:
شفرة:
Dim xDataTypeOut As Variant
Dim xDataOut As Variant
عند استدعاء الطريقة GetXData لابد من تحديد أي التطبيقات نرغب باسترجاع البيانات الممتدة الخاصة بها، وإلا أعادت الوظيفة كل البيانات الممتدة في الكائن، ولذلك لن نهمل اسم التطبيق وهو Plot_Application:
شفرة:
myObject.GetXData "Plot_Application", xDataTypeOut, xDataOut
توجد طريقة واحدة للتأكد من وجود بيانات ممتدة في الكائن، فإذا كان البيانات في المتحول xDataTypeOut من النوع vbEmpty فهذا يعني أنه لا توجد بيانات ممتدة مع الكائن، وأما إذا لم يكن كذلك، فإننا نسترجع البيانات من المتحول xDataOut، ونستطيع معرفة نوع البيانات في عناصر المصفوفة xData بقراءة شفرات المجموعة في عناصر المصفوفة xDataTypeOut. ولكن في حالتنا هذه نحن نعلم بنية البيانات الممتدة Plot_Application ونعلم أنها من ثلاثة بيانات هي اسم التطبيق واسم صاحب العقار وسعر العقار، ولذلك نظهر هذه القيم في صندوق الحوار مباشرة:
شفرة:
If VarType(xDataTypeOut) vbEmpty Then
txtOwner.Text=xDataOut(1)
txtPrice.Text=xDataOut(2)
End If
الشكل (2): إظهار البيانات الممتدة في صندو3 الحوار

نكمل الإجراء الفرعي cmdSelect_Click:
شفرة:
End If
Me.Show
End Sub
كتابة البيانات الممتدة:
بعد انتقاء المستخدم كائناً رسومياً، يستطيع المستخدم كتابة البيانات الممتدة في ذلك الكائن، بعد أن مكّنا الزر Save، فإن كان له بيانات ممتدة يعمل الزر Save على تعديل هذه البيانات، وأما إذا لم يكن لذلك الكائن بيانات ممتدة يعمل الزر Save على إضافة بيانات ممتدة (تابعة للتطبيق Plot Application). وعلينا في كلا الحالتين التأكد من صحة البيانات، إلا أننا سنقبل أي قيمة لاسم صاحب العقار بما في ذلك ترك اسمه فارغاً.
شفرة:
Private Sub cmdSave_Click()
xData(1)=txtOwner.Text
سنعمل على التحقق من صحة البيانات في صندوق النص Price فقط، ولن نسمح للمستخدم بكتابة السعر إلا بعد تحقق شرطين: أولهما أن لا يكون صندوق نص السعر فارغاً:
شفرة:
If txtPrice.Text "" Then
والشرط الثاني أن يمكن تحويل النص في صندوق نص السعر إلى رقم:
شفرة:
If IsNumeric(txtPrice.Text) Then
xData(2)=CDbl(txtPrice.Text)
myObject.SetXData xDataType, xData
Me.lblStatus.Caption=Extended data saved."
فإذا لم يتحقق الشرط الثاني، فإننا ننقل التركيز إلى صندوق نص السعر، ونحدد محتوياته للفت انتباه المستخدم، ونعرض رسالة الخطأ في عنصر التحكم lblStatus:
شفرة:
Else
txtPrice.SetFocus
txtPrice.SelStart=0
txtPrice.SelLength=Len(txtPrice.Text)
Me.lblStatus.Caption="Invalid input."
End If
أما إذا لم يتحقق الشرط الأول، فإننا ننقل التركيز إلى صندوق نص السعر، ونعرض رسالة الخطأ:
شفرة:
Else
txtPrice.SetFocus
Me.lblStatus.Caption="Invalid input."
End If
End Sub
بقي لنا فقط كتابة الشفرة الخاصة بإظهار صندوق حوار "حول البرنامج" وزر Exit.
شفرة:
Private Sub cmdAbout_Click()
frmAbout.Show [color=#008000]'[color=#008000]لعرض صندوق حوار عن البرنامج
End Sub
Private Sub cmdExit_Click()
Set myObject= Nothing
Unload Me
End Sub

كلمة أخيرة:
ليس المقصود من هذا المثال تعليم برمجة فيجوال بيسك للتطبيقات، وإنما شرح تعليمتي GetXData وSetXData. وسيجد كل خبراء فيجوال بيسك للتطبيقات أن المشروع مكتوبة بطريقة مبسطة وسهلة، بعيداً عن التقنيات المتقدمة في VBA. لأن الهدف من هذا المثال هو تعليم القارئ كيفية استخدام ميزة البيانات الممتدة لكتابة برامج خاصة به، وفي الحقيقة يستطيع القارئ المتمرس تطوير هذا البرنامج بأسلوبه الخاص، وبحيث يضيف العديد من البيانات الأخرى مثل رقم العقار ورقم رخصة البناء وتاريخه. أو كتابة تطبيق آخر لأغراض مختلفة تماماً.
تكمن في استخدام البيانات الممتدة والربط مع قواعد البيانات الخارجية فوائد عظيمة، فهي الفكرة الأساس التي تقوم عليها تطبيقات نظام المعلومات الجغرافية (GIS)، ويمكن استخدام البيانات الممتدة لترميز الرسم برموز وألوان خاصة للحصول على خرائط موضوعية (thematic maps)، كأن نقوم مثلاً بتطوير وظيفة خاصة تبحث عن كل العقارات التي يزيد سعرها عن مبلغ معين، ثم تقوم بتلوين كل عقار (الكائن myObject) بلون خاص بتغيير خاصية Color التابعة له. وفي الحقيقة لا يمكننا حصر التطبيقات التي يمكن استخدام البيانات الممتدة فيها، لكنها مفيدة في تخطيط المدن والعمارة والإنشاء وإدارة الموارد الطبيعية والغابات والنقل والمواصلات.
أرجو أن أكون وفقت في شرح البيانات الممتدة في أوتوكاد للقارئ الكريم. فإذا كان لي ذلك، أعتبر هذه المقالة جواباً على كل الأسئلة التي وصلت إلي ولم أتمكن من الإجابة عليها في المنتدى أو صفحة الأسئلة، لصعوبة ذلك.
والله من وراء القصد.
الملفات المرفقة



 

Dr. EMAD H. ISMAEEL

                  Dept. of Architecture
                  University of Mosul
                  Mosul - Iraq
E-mail:        emadhanee@yahoo.com
                  emadhanee@gmail.com
                  http://emadhani.blogspot.com/
Tel :           +964 (0)770 164 93 74
                 



ليست هناك تعليقات:

إرسال تعليق