تصور البيانات ثلاثية الأبعاد باستخدام أدوات مفتوحة المصدر: برنامج تعليمي باستخدام VTK
نشرت: 2022-03-11في مقالته الأخيرة على مدونة Toptal ، كتب عالم البيانات الماهر تشارلز كوك عن الحوسبة العلمية باستخدام أدوات مفتوحة المصدر. يوضح البرنامج التعليمي الخاص به نقطة مهمة حول أدوات المصدر المفتوح والدور الذي يمكن أن تلعبه في معالجة البيانات بسهولة والحصول على النتائج.
ولكن بمجرد حل كل هذه المعادلات التفاضلية المعقدة تظهر مشاكل أخرى. كيف نفهم ونفسر الكميات الهائلة من البيانات الناتجة عن هذه المحاكاة؟ كيف يمكننا تصور وحدات الجيجابايت المحتملة من البيانات ، مثل البيانات التي تحتوي على ملايين من نقاط الشبكة ضمن محاكاة كبيرة؟
أثناء عملي على مشكلات مماثلة لرسالة الماجستير الخاصة بي ، اتصلت بمجموعة أدوات التصور ، أو VTK - وهي مكتبة رسومات قوية متخصصة في تصور البيانات.
في هذا البرنامج التعليمي ، سأقدم مقدمة سريعة عن VTK وبنية خطوط الأنابيب الخاصة بها ، وسأواصل مناقشة مثال تصور ثلاثي الأبعاد واقعي باستخدام بيانات من سائل محاكى في مضخة دافعة. أخيرًا ، سأدرج نقاط القوة في المكتبة ، بالإضافة إلى نقاط الضعف التي واجهتها.
تصور البيانات وخط أنابيب VTK
تحتوي مكتبة VTK مفتوحة المصدر على معالجة قوية وخط أنابيب مع العديد من خوارزميات التصور المعقدة. ومع ذلك ، لا تتوقف قدراتها عند هذا الحد ، حيث تمت إضافة خوارزميات معالجة الصور والشبكات بمرور الوقت أيضًا. في مشروعي الحالي مع شركة أبحاث طب الأسنان ، أستخدم VTK لمهام المعالجة القائمة على الشبكة ضمن تطبيق يشبه CAD يعتمد على Qt. تُظهر دراسات حالة VTK مجموعة واسعة من التطبيقات المناسبة.
تدور بنية VTK حول مفهوم خط الأنابيب القوي. يظهر المخطط الأساسي لهذا المفهوم هنا:
- المصادر في بداية خط الأنابيب وتخلق "شيئًا من لا شيء". على سبيل المثال ، ينشئ
vtkConeSource
مخروطًا ثلاثي الأبعاد ، ويقرأvtkSTLReader
ملفات*.stl
الهندسية ثلاثية الأبعاد. - تقوم المرشحات بتحويل ناتج أي من المصادر أو عوامل التصفية الأخرى إلى شيء جديد. على سبيل المثال ، يقطع
vtkCutter
إخراج الكائن السابق في الخوارزميات باستخدام وظيفة ضمنية ، على سبيل المثال ، المستوى. يتم تنفيذ جميع خوارزميات المعالجة التي تأتي مع VTK كمرشحات ويمكن ربطها معًا بحرية. - يقوم رسامو الخرائط بتحويل البيانات إلى رسوم أولية. على سبيل المثال ، يمكن استخدامها لتحديد جدول بحث لتلوين البيانات العلمية. إنها طريقة مجردة لتحديد ما سيتم عرضه.
- تمثل الجهات الفاعلة كائنًا (هندسة بالإضافة إلى خصائص العرض) داخل المشهد. يتم هنا تحديد أشياء مثل اللون أو التعتيم أو التظليل أو الاتجاه.
- يصف Renderers & Windows أخيرًا العرض على الشاشة بطريقة مستقلة عن النظام الأساسي.
يبدأ خط أنابيب عرض VTK النموذجي بمصدر واحد أو أكثر ، ويعالجها باستخدام مرشحات مختلفة في العديد من كائنات الإخراج ، والتي يتم عرضها بعد ذلك بشكل منفصل باستخدام المخططات والممثلين. القوة الكامنة وراء هذا المفهوم هي آلية التحديث. إذا تم تغيير إعدادات عوامل التصفية أو المصادر ، فسيتم تلقائيًا تحديث جميع عوامل التصفية ورسمي الخرائط والممثلين ونوافذ العرض التابعة. من ناحية أخرى ، إذا احتاج كائن ما أسفل خط الأنابيب إلى معلومات من أجل أداء مهامه ، فيمكنه الحصول عليها بسهولة.
بالإضافة إلى ذلك ، ليست هناك حاجة للتعامل مباشرة مع أنظمة العرض مثل OpenGL. تقوم VTK بتغليف جميع المهام منخفضة المستوى في نظام أساسي و (جزئيًا) بطريقة مستقلة عن النظام ؛ المطور يعمل على مستوى أعلى بكثير.
مثال رمز مع مجموعة بيانات مضخة الدوار
دعونا نلقي نظرة على مثال تصور البيانات باستخدام مجموعة بيانات لتدفق السوائل في مضخة دافعة دوارة من مسابقة التصور IEEE 2011. البيانات نفسها هي نتيجة لمحاكاة ديناميكيات السوائل الحسابية ، مثل تلك الموضحة في مقالة تشارلز كوك.
يزيد حجم بيانات المحاكاة المضغوطة للمضخة المميزة عن 30 جيجابايت. يحتوي على أجزاء متعددة وخطوات زمنية متعددة ، ومن ثم الحجم الكبير. في هذا الدليل ، سنتلاعب بالجزء الدوار لإحدى هذه الخطوات الزمنية ، والتي يبلغ حجمها المضغوط حوالي 150 ميجابايت.
لغتي المفضلة لاستخدام VTK هي C ++ ، ولكن هناك تعيينات لعدة لغات أخرى مثل Tcl / Tk و Java و Python. إذا كان الهدف هو مجرد تصور لمجموعة بيانات واحدة ، فلن يحتاج المرء إلى كتابة رمز على الإطلاق ويمكنه بدلاً من ذلك استخدام Paraview ، واجهة أمامية رسومية لمعظم وظائف VTK.
مجموعة البيانات ولماذا يعد 64 بت ضروريًا
لقد استخرجت مجموعة البيانات الدوارة من مجموعة بيانات 30 جيجا بايت المتوفرة أعلاه ، عن طريق فتح خطوة زمنية واحدة في Paraview واستخراج جزء الدوار في ملف منفصل. إنه ملف شبكة غير منظم ، أي حجم ثلاثي الأبعاد يتكون من نقاط وخلايا ثلاثية الأبعاد ، مثل سداسي الوجوه ورباعي الأسطح وما إلى ذلك. كل نقطة من النقاط الثلاثية الأبعاد لها قيم مرتبطة. أحيانًا يكون للخلايا قيم مرتبطة أيضًا ، ولكن ليس في هذه الحالة. سيركز هذا التدريب على الضغط والسرعة عند النقاط ومحاولة تصورها في سياقها ثلاثي الأبعاد.
يبلغ حجم الملف المضغوط حوالي 150 ميجابايت وحجم الذاكرة الداخلية حوالي 280 ميجابايت عند تحميله باستخدام VTK. ومع ذلك ، من خلال معالجتها في VTK ، يتم تخزين مجموعة البيانات مؤقتًا عدة مرات داخل خط أنابيب VTK ونصل بسرعة إلى حد ذاكرة 2 جيجا بايت لبرامج 32 بت. توجد طرق لحفظ الذاكرة عند استخدام VTK ، ولكن لتبسيط الأمر سنقوم فقط بتجميع وتشغيل المثال في 64 بت.
شكر وتقدير : تم توفير مجموعة البيانات بإذن من معهد الميكانيكا التطبيقية ، جامعة كلاوستال ، ألمانيا (دبلوم Wirtsch.-Ing. Andreas Lucius).
الهدف
ما سنحققه باستخدام VTK كأداة هو التصور الموضح في الصورة أدناه. كسياق ثلاثي الأبعاد ، يتم عرض مخطط مجموعة البيانات باستخدام عرض إطار سلكي شفاف جزئيًا. ثم يتم استخدام الجزء الأيسر من مجموعة البيانات لعرض الضغط باستخدام ترميز لوني بسيط للأسطح. (سنتخطى عرض الحجم الأكثر تعقيدًا لهذا المثال). من أجل تصور مجال السرعة ، يتم ملء الجزء الأيمن من مجموعة البيانات بخطوط انسيابية ، والتي تم ترميزها بالألوان حسب حجم سرعتها. خيار التصور هذا ليس مثاليًا من الناحية الفنية ، لكنني أردت أن أبقي رمز VTK بسيطًا قدر الإمكان. بالإضافة إلى ذلك ، هناك سبب لكون هذا المثال جزءًا من تحدي التصور ، أي الكثير من الاضطرابات في التدفق.
خطوة بخطوة
سأناقش رمز VTK خطوة بخطوة ، موضحًا كيف سيبدو إخراج العرض في كل مرحلة. يمكن تنزيل كود المصدر الكامل في نهاية التدريب.
لنبدأ بتضمين كل ما نحتاجه من VTK ونفتح الوظيفة الرئيسية.
#include <vtkActor.h> #include <vtkArrayCalculator.h> #include <vtkCamera.h> #include <vtkClipDataSet.h> #include <vtkCutter.h> #include <vtkDataSetMapper.h> #include <vtkInteractorStyleTrackballCamera.h> #include <vtkLookupTable.h> #include <vtkNew.h> #include <vtkPlane.h> #include <vtkPointData.h> #include <vtkPointSource.h> #include <vtkPolyDataMapper.h> #include <vtkProperty.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkRibbonFilter.h> #include <vtkStreamTracer.h> #include <vtkSmartPointer.h> #include <vtkUnstructuredGrid.h> #include <vtkXMLUnstructuredGridReader.h> int main(int argc, char** argv) {
بعد ذلك ، نقوم بإعداد العارض ونافذة التقديم لعرض نتائجنا. قمنا بتعيين لون الخلفية وحجم نافذة العرض.
// Setup the renderer vtkNew<vtkRenderer> renderer; renderer->SetBackground(0.9, 0.9, 0.9); // Setup the render window vtkNew<vtkRenderWindow> renWin; renWin->AddRenderer(renderer.Get()); renWin->SetSize(500, 500);
باستخدام هذا الرمز ، يمكننا بالفعل عرض نافذة عرض ثابتة. بدلاً من ذلك ، نختار إضافة vtkRenderWindowInteractor
من أجل التدوير والتكبير والتصغير بشكل تفاعلي للمشهد.
// Setup the render window interactor vtkNew<vtkRenderWindowInteractor> interact; vtkNew<vtkInteractorStyleTrackballCamera> style; interact->SetRenderWindow(renWin.Get()); interact->SetInteractorStyle(style.Get());
الآن لدينا مثال قيد التشغيل يظهر نافذة عرض رمادية فارغة.
بعد ذلك ، نقوم بتحميل مجموعة البيانات باستخدام أحد أجهزة القراءة العديدة التي تأتي مع VTK.
// Read the file vtkSmartPointer<vtkXMLUnstructuredGridReader> pumpReader = vtkSmartPointer<vtkXMLUnstructuredGridReader>::New(); pumpReader->SetFileName("rotor.vtu");
رحلة قصيرة إلى إدارة ذاكرة VTK: تستخدم VTK مفهومًا ملائمًا لإدارة الذاكرة التلقائية يدور حول حساب المرجع. ومع ذلك ، يختلف عن معظم التطبيقات الأخرى ، يتم الاحتفاظ بعدد المرجع داخل كائنات VTK نفسها ، بدلاً من فئة المؤشر الذكي. هذا له ميزة أنه يمكن زيادة عدد المرجع ، حتى إذا تم تمرير كائن VTK كمؤشر خام. هناك طريقتان رئيسيتان لإنشاء كائنات VTK مُدارة. vtkNew<T>
و vtkSmartPointer<T>::New()
، مع الاختلاف الرئيسي في أن vtkSmartPointer<T>
هو ضمني قابل للإرسال إلى المؤشر الخام T*
، ويمكن إرجاعه من دالة. بالنسبة لمثيلات vtkNew<T>
علينا استدعاء .Get()
للحصول على مؤشر خام ويمكننا فقط إعادته عن طريق لفه في vtkSmartPointer
. في مثالنا ، لا نعود أبدًا من الدوال وكل الكائنات تعيش طوال الوقت ، لذلك سنستخدم vtkNew
، مع الاستثناء أعلاه فقط لأغراض العرض.
في هذه المرحلة ، لم تتم قراءة أي شيء من الملف حتى الآن. سيتعين علينا نحن أو مرشح آخر أسفل السلسلة استدعاء Update()
حتى تحدث قراءة الملف بالفعل. عادةً ما يكون هذا هو أفضل نهج للسماح لفئات VTK بمعالجة التحديثات بأنفسهم. ومع ذلك ، في بعض الأحيان نريد الوصول إلى نتيجة عامل التصفية مباشرة ، على سبيل المثال للحصول على نطاق الضغوط في مجموعة البيانات هذه. ثم نحتاج إلى استدعاء Update()
يدويًا. (لا نفقد الأداء من خلال استدعاء Update()
عدة مرات ، حيث يتم تخزين النتائج مؤقتًا.)
// Get the pressure range pumpReader->Update(); double pressureRange[2]; pumpReader->GetOutput()->GetPointData()->GetArray("Pressure")->GetRange(pressureRange);
بعد ذلك ، نحتاج إلى استخراج النصف الأيسر من مجموعة البيانات باستخدام vtkClipDataSet
. لتحقيق ذلك ، نحدد أولاً vtkPlane
الذي يحدد الانقسام. بعد ذلك ، سنرى لأول مرة كيف يتم توصيل خط أنابيب VTK معًا: successor->SetInputConnection(predecessor->GetOutputPort())
. عندما نطلب تحديثًا من clipperLeft
، سيضمن هذا الاتصال الآن أن جميع عوامل التصفية السابقة محدثة أيضًا.
// Clip the left part from the input vtkNew<vtkPlane> planeLeft; planeLeft->SetOrigin(0.0, 0.0, 0.0); planeLeft->SetNormal(-1.0, 0.0, 0.0); vtkNew<vtkClipDataSet> clipperLeft; clipperLeft->SetInputConnection(pumpReader->GetOutputPort()); clipperLeft->SetClipFunction(planeLeft.Get());
أخيرًا ، أنشأنا الممثلين ومصممي الخرائط الأوائل لعرض تمثيل الإطار السلكي للنصف الأيسر. لاحظ أن مصمم الخرائط متصل بالفلتر الخاص به بنفس طريقة توصيل المرشحات ببعضها البعض. في معظم الأوقات ، يقوم العارض نفسه بتشغيل تحديثات جميع الممثلين ومصممي الخرائط وسلاسل التصفية الأساسية!
السطر الوحيد الذي لا يحتاج إلى شرح هو على الأرجح leftWireMapper->ScalarVisibilityOff();
- يحظر تلوين الإطار السلكي بقيم الضغط ، والتي يتم تعيينها على أنها المصفوفة النشطة حاليًا.
// Create the wireframe representation for the left part vtkNew<vtkDataSetMapper> leftWireMapper; leftWireMapper->SetInputConnection(clipperLeft->GetOutputPort()); leftWireMapper->ScalarVisibilityOff(); vtkNew<vtkActor> leftWireActor; leftWireActor->SetMapper(leftWireMapper.Get()); leftWireActor->GetProperty()->SetRepresentationToWireframe(); leftWireActor->GetProperty()->SetColor(0.8, 0.8, 0.8); leftWireActor->GetProperty()->SetLineWidth(0.5); leftWireActor->GetProperty()->SetOpacity(0.8); renderer->AddActor(leftWireActor.Get());
في هذه المرحلة ، تظهر نافذة العرض أخيرًا شيئًا ما ، أي الإطار السلكي للجزء الأيسر.

يتم إنشاء عرض الإطار السلكي للجزء الأيمن بطريقة مماثلة ، عن طريق تبديل المستوى الطبيعي لـ vtkClipDataSet
(الذي تم إنشاؤه حديثًا) إلى الاتجاه المعاكس وتغيير اللون وشفافية (تم إنشاؤه حديثًا) والممثل بشكل طفيف. لاحظ أنه هنا ينقسم خط أنابيب VTK إلى اتجاهين (يمين ويسار) من نفس مجموعة بيانات الإدخال.
// Clip the right part from the input vtkNew<vtkPlane> planeRight; planeRight->SetOrigin(0.0, 0.0, 0.0); planeRight->SetNormal(1.0, 0.0, 0.0); vtkNew<vtkClipDataSet> clipperRight; clipperRight->SetInputConnection(pumpReader->GetOutputPort()); clipperRight->SetClipFunction(planeRight.Get()); // Create the wireframe representation for the right part vtkNew<vtkDataSetMapper> rightWireMapper; rightWireMapper->SetInputConnection(clipperRight->GetOutputPort()); rightWireMapper->ScalarVisibilityOff(); vtkNew<vtkActor> rightWireActor; rightWireActor->SetMapper(rightWireMapper.Get()); rightWireActor->GetProperty()->SetRepresentationToWireframe(); rightWireActor->GetProperty()->SetColor(0.2, 0.2, 0.2); rightWireActor->GetProperty()->SetLineWidth(0.5); rightWireActor->GetProperty()->SetOpacity(0.1); renderer->AddActor(rightWireActor.Get());
تعرض نافذة الإخراج الآن كلا الجزأين السلكي ، كما هو متوقع.
الآن نحن جاهزون لتصور بعض البيانات المفيدة! لإضافة تصور الضغط إلى الجزء الأيسر ، لا نحتاج إلى فعل الكثير. نقوم بإنشاء مخطط جديد وربطه بـ clipperLeft
أيضًا ، لكن هذه المرة نقوم بالتلوين بواسطة مجموعة الضغط. ومن هنا أيضًا ، نستخدم أخيرًا نطاق pressureRange
الذي اشتقناه أعلاه.
// Create the pressure representation for the left part vtkNew<vtkDataSetMapper> pressureColorMapper; pressureColorMapper->SetInputConnection(clipperLeft->GetOutputPort()); pressureColorMapper->SelectColorArray("Pressure"); pressureColorMapper->SetScalarRange(pressureRange); vtkNew<vtkActor> pressureColorActor; pressureColorActor->SetMapper(pressureColorMapper.Get()); pressureColorActor->GetProperty()->SetOpacity(0.5); renderer->AddActor(pressureColorActor.Get());
الإخراج يبدو الآن مثل الصورة الموضحة أدناه. الضغط في المنتصف منخفض جدًا ، مما يؤدي إلى امتصاص المواد في المضخة. بعد ذلك ، يتم نقل هذه المادة إلى الخارج ، مما يؤدي إلى زيادة الضغط بسرعة. (بالطبع يجب أن يكون هناك وسيلة إيضاح لونية مع القيم الفعلية ، لكنني تركتها لإبقاء المثال أقصر.)
الآن يبدأ الجزء الأصعب. نريد رسم خطوط انسيابية السرعة في الجزء الأيمن. يتم إنشاء التبسيط عن طريق التكامل داخل حقل متجه من نقاط المصدر. حقل المتجه هو بالفعل جزء من مجموعة البيانات في شكل مجموعة المتجهات "Velocities". لذلك نحتاج فقط إلى إنشاء نقاط المصدر. ينشئ vtkPointSource
مجالًا من النقاط العشوائية. سننشئ 1500 نقطة مصدر ، لأن معظمها لن يقع ضمن مجموعة البيانات على أي حال وسيتم تجاهلها بواسطة متتبع التدفق.
// Create the source points for the streamlines vtkNew<vtkPointSource> pointSource; pointSource->SetCenter(0.0, 0.0, 0.015); pointSource->SetRadius(0.2); pointSource->SetDistributionToUniform(); pointSource->SetNumberOfPoints(1500);
بعد ذلك ، نقوم بإنشاء Streamtracer وتعيين اتصالات الإدخال الخاصة به. قد تقول "انتظر ، اتصالات متعددة ؟" نعم - هذا هو أول مرشح VTK بمدخلات متعددة نواجهها. يتم استخدام اتصال الإدخال العادي لحقل المتجه ، ويتم استخدام اتصال المصدر للنقاط الأولية. نظرًا لأن "Velocities" هي مجموعة المتجهات "النشطة" في clipperRight
، فنحن لا نحتاج إلى تحديدها هنا بشكل صريح. أخيرًا نحدد أن التكامل يجب أن يتم في كلا الاتجاهين من النقاط الأولية ، وقمنا بتعيين طريقة التكامل على Runge-Kutta-4.5.
vtkNew<vtkStreamTracer> tracer; tracer->SetInputConnection(clipperRight->GetOutputPort()); tracer->SetSourceConnection(pointSource->GetOutputPort()); tracer->SetIntegrationDirectionToBoth(); tracer->SetIntegratorTypeToRungeKutta45();
مشكلتنا التالية هي تلوين الخطوط الانسيابية بحجم السرعة. نظرًا لعدم وجود مصفوفة لأحجام المتجهات ، فسنحسب المقادير ببساطة في مصفوفة عددية جديدة. كما خمنت ، هناك مرشح VTK لهذه المهمة أيضًا: vtkArrayCalculator
. يأخذ مجموعة بيانات ويخرجها دون تغيير ، لكنه يضيف صفيفًا واحدًا يتم حسابه من واحد أو أكثر من المجموعات الموجودة. نقوم بتكوين آلة حاسبة المصفوفة هذه لأخذ حجم متجه "السرعة" وإخراجها كـ "MagVelocity". أخيرًا ، نقوم باستدعاء Update()
يدويًا مرة أخرى ، من أجل اشتقاق نطاق المصفوفة الجديدة.
// Compute the velocity magnitudes and create the ribbons vtkNew<vtkArrayCalculator> magCalc; magCalc->SetInputConnection(tracer->GetOutputPort()); magCalc->AddVectorArrayName("Velocity"); magCalc->SetResultArrayName("MagVelocity"); magCalc->SetFunction("mag(Velocity)"); magCalc->Update(); double magVelocityRange[2]; magCalc->GetOutput()->GetPointData()->GetArray("MagVelocity")->GetRange(magVelocityRange);
vtkStreamTracer
بإخراج الخطوط المتعددة مباشرة vtkArrayCalculator
دون تغيير. لذلك يمكننا فقط عرض إخراج magCalc
مباشرة باستخدام مخطط وممثل جديد.
بدلاً من ذلك ، في هذا التدريب ، نختار جعل الإخراج أجمل قليلاً ، من خلال عرض الأشرطة بدلاً من ذلك. ينشئ vtkRibbonFilter
خلايا ثنائية الأبعاد لعرض شرائط لجميع الخطوط المتعددة لمدخلاته.
// Create and render the ribbons vtkNew<vtkRibbonFilter> ribbonFilter; ribbonFilter->SetInputConnection(magCalc->GetOutputPort()); ribbonFilter->SetWidth(0.0005); vtkNew<vtkPolyDataMapper> streamlineMapper; streamlineMapper->SetInputConnection(ribbonFilter->GetOutputPort()); streamlineMapper->SelectColorArray("MagVelocity"); streamlineMapper->SetScalarRange(magVelocityRange); vtkNew<vtkActor> streamlineActor; streamlineActor->SetMapper(streamlineMapper.Get()); renderer->AddActor(streamlineActor.Get());
ما لا يزال مفقودًا الآن ، والمطلوب بالفعل لإنتاج التصييرات الوسيطة أيضًا ، هي الأسطر الخمسة الأخيرة لتقديم المشهد وتهيئة المتفاعل.
// Render and show interactive window renWin->Render(); interact->Initialize(); interact->Start(); return 0; }
أخيرًا ، نصل إلى التصور النهائي ، والذي سأقدمه مرة أخرى هنا:
يمكن العثور على شفرة المصدر الكاملة للتصور أعلاه هنا.
الجيد، السيء والقبيح
سأغلق هذه المقالة بقائمة من إيجابيات وسلبيات إطار عمل VTK.
المؤيد : التطوير النشط : VTK قيد التطوير النشط من قبل العديد من المساهمين ، بشكل رئيسي من داخل مجتمع البحث. هذا يعني أن بعض الخوارزميات المتطورة متوفرة ، ويمكن استيراد العديد من التنسيقات ثلاثية الأبعاد وتصديرها ، ويتم إصلاح الأخطاء بشكل نشط ، وعادة ما يكون للمشكلات حل جاهز في لوحات المناقشة.
السلبيات : الموثوقية : اقتران العديد من الخوارزميات من مساهمين مختلفين بتصميم خط الأنابيب المفتوح لـ VTK ، ومع ذلك ، يمكن أن يؤدي إلى مشاكل مع مجموعات المرشحات غير العادية. لقد اضطررت إلى الدخول في الكود المصدري لـ VTK عدة مرات لمعرفة سبب عدم قيام سلسلة التصفية المعقدة الخاصة بي بإنتاج النتائج المرجوة. أوصي بشدة بإعداد VTK بطريقة تسمح بتصحيح الأخطاء.
المؤيد : هندسة البرمجيات : يبدو أن تصميم خط الأنابيب والهندسة العامة لـ VTK مدروسة جيدًا ويسعدني العمل معها. يمكن أن ينتج عن بعض أسطر الكود نتائج مذهلة. هياكل البيانات المدمجة سهلة الفهم والاستخدام.
Con : Micro Architecture : بعض قرارات التصميم المعماري المصغر تفلت من فهمي. يكاد يكون تصحيح العناصر غير موجود ، ويتم تمرير المصفوفات كمدخلات ومخرجات بدون تمييز واضح. لقد خففت هذا من أجل الخوارزميات الخاصة بي عن طريق التخلي عن بعض الأداء واستخدام برنامج التضمين الخاص بي لـ
vtkMath
الذي يستخدم أنواعًا ثلاثية الأبعاد مخصصة مثلtypedef std::array<double, 3> Pnt3d;
.Pro : Micro Documentation : وثائق Doxygen لجميع الفئات والمرشحات واسعة النطاق وقابلة للاستخدام ، والأمثلة وحالات الاختبار على wiki هي أيضًا مساعدة كبيرة لفهم كيفية استخدام المرشحات.
Con : Macro Documentation : هناك العديد من البرامج التعليمية الجيدة والمقدمات لـ VTK على الويب. ومع ذلك ، وبقدر ما أعرف ، لا توجد وثائق مرجعية كبيرة تشرح كيفية إنجاز أشياء محددة. إذا كنت تريد أن تفعل شيئًا جديدًا ، فتوقع البحث عن كيفية القيام بذلك لبعض الوقت. بالإضافة إلى أنه من الصعب العثور على عامل تصفية معين لمهمة ما. بمجرد العثور عليه ، ستكفي وثائق Doxygen عادةً. من الطرق الجيدة لاستكشاف إطار عمل VTK تنزيل Paraview وتجربته.
المؤيد : دعم التوازي الضمني : إذا كان من الممكن تقسيم مصادرك إلى عدة أجزاء يمكن معالجتها بشكل مستقل ، فإن الموازاة بسيطة مثل إنشاء سلسلة تصفية منفصلة داخل كل مؤشر ترابط يعالج جزءًا واحدًا. تقع معظم مشكلات التصور الكبيرة عادةً في هذه الفئة.
Con : لا يوجد دعم موازٍ صريح : إذا لم تنعم بمشاكل كبيرة وقابلة للتقسيم ، لكنك تريد استخدام نوى متعددة ، فأنت وحدك. سيتعين عليك معرفة الفئات الآمنة ، أو حتى إعادة المشاركة عن طريق التجربة والخطأ أو عن طريق قراءة المصدر. لقد تعقبت ذات مرة مشكلة موازاة لمرشح VTK الذي استخدم متغيرًا عالميًا ثابتًا لاستدعاء بعض مكتبات C.
Pro : Buildsystem CMake : تم تطوير CMake لنظام بناء meta متعدد المنصات بواسطة Kitware (صانعي VTK) ويستخدم في العديد من المشاريع خارج Kitware. إنه يتكامل بشكل جيد للغاية مع VTK ويجعل إنشاء نظام بناء لمنصات متعددة أقل إيلامًا.
المؤيد : استقلالية النظام الأساسي ، والترخيص ، وطول العمر : VTK عبارة عن منصة مستقلة خارج الصندوق ، ومرخصة بموجب ترخيص متساهل للغاية على غرار BSD. بالإضافة إلى ذلك ، يتوفر الدعم المهني للمشاريع المهمة التي تتطلب ذلك. Kitware مدعوم من قبل العديد من الكيانات البحثية والشركات الأخرى وسيكون موجودًا لبعض الوقت.
الكلمة الأخيرة
بشكل عام ، تعد VTK أفضل أداة لتصور البيانات لأنواع المشاكل التي أحبها. إذا صادفت مشروعًا يتطلب التصور أو معالجة الشبكة أو معالجة الصور أو مهام مماثلة ، فحاول إطلاق Paraview بمثال إدخال وتقييم ما إذا كانت VTK هي الأداة المناسبة لك.