الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

[شبه مكتمل] : المرحلة الأولى: تطوير وحدة Core

رائج
بدأه فريق الأندلس في 27 سبتمبر 2009 · 177 رد · 11,907 مشاهدة · في قسم برمجة الألعاب و الرسوميات العام
مشاركة: واتساب X فيسبوك تيليجرام
#126

أنا حاليا مشغول (الدراسه بدأت عندنا في إمريكا)

ولكن أستطيع العمل على الكلاسات البسيطه مثل

Point2D

Circle

Rectangle

بستخدام c++

تم تعديل هذه المشاركة بواسطة hunterxhunter في 4 أكتوبر 2009 في 11:04

#127

جيد ، لنتقسامها اذن :) :

نظرا لأن عدد الأعضاء قليل حتى هذه اللحظة ،فسيزيد الحمل قليلاً ..

الأخ محمد علاء :

لغة السي بلس : Line2D- Vector2D - Triangle - Math

بالنسبة للـ Math هي مجرد تغليف لدوال السي بلس العادية ، حتى تعمل على جميع الأنظمة ، وسننظر لاحقاً بحول الله في تسريعها .

الاخ hunterxhunter بما أنك مشغول فلا نريد أن نثقل عليك .. فقط نريدك ان تشارك بفئتين :) .

لغة السي بلس : Point2D - Circle

الاخ ahmad_n3na3 :

لغة الجافا : Line2D - Point2D - Triangle - Circle

لاحظ أننا نستخدم Generic وليس نوع معين float ، لذلك لابد من الالتزام بالمواصفات التي اتفقنا عليها ، هل سبق لك استخدام Generic في الجافا ؟ اذا واجهت صعوبة مع Generic فاستخدم float وسأقوم بتحويلها الى Generic ان شاء الله .

الشمري :

لغة السي بلس : Random - Rectangle

لغة الجافا : Random - Rectangle

يبقى Matrix .. ;) .

عموما بعد أن انتهي مما لدي ، اذا لم يتطوّع أحد ليستلمها ، فسأقوم بها ان شاء الله ، هذا الكلاس مهم ، لذلك يجب كتابته بشكل جيد .

الاخ سلوان : يمكنك المساعدة بطريقة أخرى كما تقوم به الان من اضافة معلومات وتصحيح أخطائنا ، أعتقد هذا أسهل من كتابة كود قد يأخذ من الوقت ، لذلك لك الخيار باختيار الطريقة المناسبة في المساعدة ;) .

الاخ خلدون : نسخة الشي شارب يبدو أنه لايوجد أحد معك الان .. قد تستلم كل شيء :/ .. لذلك يمكننا تعليق هذه النسخة اذا كنت مشغول .

- بعض الكلاسات تعتمد على كلاسات أخرى فمثلا Line2D يعتمد على Point2D ، يمكنك بناء كلاس Point2D بسيط فقط لتستطيع تجربة وترجمة الكود .. مثال :

class Point2D<T>
{
 public :
T x;
T y;
}

- لنبدأ ... أي مبرمج يواجه مشكلة يضعها هنا ، لنناقشها .

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#128

سأقوم بعمل التعديلات التى اتفقنا عليها الأن و سأرفعها على الـ svn اليوم ان شاء الله

مدونتي: C++ Tips and Tricks

#129
اقتباس
يبقى Matrix ..

يمكننى اخذها او يمكن تعليقها حتى ننتهى مما لدينا .... كما تحب

مدونتي: C++ Tips and Tricks

#130
اقتباس
سأقوم بعمل التعديلات التى اتفقنا عليها الأن و سأرفعها على الـ svn اليوم ان شاء الله

لقد قممت ببعضها :D .. لاحظت أنك لم تحدثها فقلت يمكن أنك نسيتها ..

عموما بقي Point2D الدوال static لم أعدلها ..

اقتباس
يمكننى اخذها او يمكن تعليقها حتى ننتهى مما لدينا .... كما تحب

لا مشكلة ..

لكن لاتضغط على نفسك كثيراً .. الأولوية هي للموجود لديك الان .

( تم تحديث المرفق في المشاركة #110 )

تم تعديل هذه المشاركة بواسطة الشمري في 4 أكتوبر 2009 في 20:32

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#131

كيف يمكن رفع الملفات المنتهى منها على SVN؟

اقتباس
هل سبق لك استخدام Generic في الجافا ؟

لا تقلق تعاملت معها سابقا في مشروع رسام بسيط و بعض المشاريع الأخرى المتعلقة بقواعد البيانات

الايميل غير صحيح

يرجى تصحيح الايميل برسالة لأحد مدراء المنتدى

#132

قمت بتعديل طفيف على Vector2D :

أضفت dotProduct .

وعدلت على multiply ..

أظن هذا أفضل .. ( قمت أيضا بالنظر الى محركات أخرى ووجدتها تتبع نفس الطريقة مثل irrlicht ) .

اقتباس
كيف يمكن رفع الملفات المنتهى منها على SVN؟

لاتملك الصلاحيات الان / لذلك أضفها كمرفق ، ويوجد الان ثلاث أعضاء يملكون الصلاحيات لتحديث svn .

الصلاحيات ستمنح بشكل تدريجي :) .. تبعاً لحجم العمل المحدد للمبرمج ،

تم تعديل هذه المشاركة بواسطة الشمري في 4 أكتوبر 2009 في 20:45

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#133
اقتباس
الاخ خلدون : نسخة الشي شارب يبدو أنه لايوجد أحد معك الان .. قد تستلم كل شيء :/ .. لذلك يمكننا تعليق هذه النسخة اذا كنت مشغول .

حسنا سوف أحاول أن أعمل على حسب فراغي لأنني مشغول بعض الشيئ في هذه الفتره، سأعمل بدون رفع أي ملفات على ال SVN إذا أنجزت كمية جيدة من العمل سوف أقوم بالرفع إن شاء الله،..

بكل الأحوال أنا متابع معكم هنا لكي أستفيد مما تطرحون..

#134

العمليات الحسابية في غير معرفة للـ generics في لغة الجافا

أرجو النصيحة

الايميل غير صحيح

يرجى تصحيح الايميل برسالة لأحد مدراء المنتدى

#135
اقتباس
العمليات الحسابية في غير معرفة للـ generics في لغة الجافا

عفواً لم أفكر في هذه النقطة .

أظن أفضل الحلول هو ما تفضلت به أخ أحمد ، استخدم float .

بحثت عن حل ولم أجد حل مناسب ، وكل محركات الألعاب المبنية على الجافا تستخدم float .. لذلك لنقوم بما قاموا به :-) .

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#136

قمت بتحويل ملفات المواصفات لفئات خاصه بالـ C++ و موجوده بالمرفقات لذا كل ما عليك فعله هو ان تقوم بتحميل الملف و مراجعة ملف الـ Header الخاص بالفئه التى ستعمل عليها و بعدها قم بفتح الملف الذى اسمه على اسم الفئه التى ستبرمجها و الذى ينتهى بالإمتداد inl و ابدء فى كتابة الكود مباشرة داخله.

قم بتضمين الملف AndalusEngine.h داخل ملف الـ Header الخاص بفئتك إن لم يكن تم اضافته بها و ذلك لإنه يحتوى على انواع البيانات التى سيتم استخدامها بالإضافه إلى اى فئات مشتركه داخل المشروع.

سيتم تحديث مرفقات هذه المشاركه بإستمرار بكل التعديلات الجديده منى و من كل الأعضاء و بالطبع توجد نسخه اخرى بالـ svn للأخوه من لديهم الصلاحيات

تم تحديث المرفق بتاريخ 7-10-2009 الساعه 2:57 صباحا

0.1.rar

بالنسبه لمن يعمل على نسخة الـ C++ الموجوده بـ svn تم وضع هذه الملفات فى المسار التالى

andalus\trunk\0.1

و الله ولى التوفيق

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 7 أكتوبر 2009 في 03:58

مدونتي: C++ Tips and Tricks

#137

المعذرة كنت مشغولا خلال الفترة الماضية

هل الكلاسات التي يتم تقاسمها للعمل عليها على مستوى المحرك ام الكلاسات في الوحده core ؟

بالنسبة لي اجيد العمل على ++C و #C و لكني هجرت ويندوز و استخدم حاليا لينوكس و Code::Block

تحياتي

#138
اقتباس
هل الكلاسات التي يتم تقاسمها للعمل عليها على مستوى المحرك ام الكلاسات في الوحده core ؟

على مستوى جزئية الرياضيات الموجوده بالوحده core.

مدونتي: C++ Tips and Tricks

#139

تم تحديث مرفق المشاركه رقم 163 ليحتوى على الأتى:

1 - تم اضافة الملف Datatypes.h و الذى يحتوى على انواع البيانات التى سيتم استخدامها.

2 - تم انشاء الملف AndalusEngine.h ليحتوى فيما بعد على كل ملفات الـ Header المشتركه داخل المشروع بأكمله لذا لابد من استيراد هذا الملف داخل كل ملفات الـ Header الجديده (قمت بإضافتهم فى كل الملفات الموجوده بالمرفق بالأعلى).

3 - تم تعديل اسماء انواع البيانات مثل int و char لتصبح int32 و achar كما هو موجود داخل ملف Datatypes.h

للأخوه الذين لا صلاحيات لديهم قم بإضافة ملف الـ Header و ملف inl الخاص بالفئات التى تعمل عليها هنا كمرفق و سيتم تحديثها داخل الـ svn ان شاء الله.

جارى العمل على الجزء الخاص بى من المشروع

و الله ولى التوفيق

مدونتي: C++ Tips and Tricks

#140

شكرا أخي محمد على المجهود الرائع

سأبدأ العمل عليهم يوم الجمعه إن شاء الله

إلا إذا كنتم مستعجلين سأحاول أن أنهيهم في مده أقل

#141

اعمل الأن فى الفئه Line2D.

داخل الداله getIntersectPoint اقوم بإرجاع Point2D تمثل نقطة التقاطع بين الخط الحالى و خط يتم تمريره.

هذه الداله تأخذ الشكل التالى

 

Point2D[color= #000000;]<T[color= #000000;]> getIntersectPoint [color= #000000;]( Line2D[color= #000000;]<T[color= #000000;]> l [color= #000000;]);

السؤال الأن فى حال عدم وجود قيمه مشتركه ماذا اعيد ؟؟؟ :angry:

الأخ hunterxhunter حيث انى اعمل على الفئه Line2D و هى تستخدم تقريبا كل دوال الفئه Point2D لذا فقد قمت ببرمجتها حيث اضطرتنى الحاجه لذلك.

اعتذر عن هذا الأمر و لكنى اريد الإنتهاء من الفئات التى لدى قريبا حتى يتسنى لباقى الأخوه استخدامهم داخل فئاتهم.

و الله ولى التوفيق

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 6 أكتوبر 2009 في 04:56

مدونتي: C++ Tips and Tricks

#142
اقتباس
السؤال الأن فى حال عدم وجود قيمه مشتركه ماذا اعيد ؟؟؟

:D .

هذه من المشاكل التي واجهتني أيضا .. ما أفكر فيه هو أن نضيف بارمتر ثاني نعيد من خلاله الناتج ، وتعيد الدالة true او false اذا وجدت تقاطع أو لم تجد ! المشكلة من السهل حلها بالجافا .. نعيد null .. لكن المشكلة في السي بلس ..

هناك حل اخر .. وهو أن نعلن عن ثوابت مثل أن نكتب :

return NO_POINT2D

حيث :

#define NO_POINT2D Point2D(9999,-9999)

اقتباس
اعتذر عن هذا الأمر و لكنى اريد الإنتهاء من الفئات التى لدى قريبا حتى يتسنى لباقى الأخوه استخدامهم داخل فئاتهم.

تم توضيح هذه النقطة ، وهي أنه يمكن انشاء كلاس مؤقت مثل Point2D يحوي على متغيرين x و y .. فقط حتى تستطيع اكمال المطلوب منك ثم تزيل الكلاسات المؤقتة ..

@ الاخ :hunterxhunter ، يمكن لأي عضو أن يقوم بالمهمة ، لاتضغط على نفسك .. فقط أحببنا أن تشاركنا بشيء :) ، لذلك يمكنك المشاركة بأي وقت في المشروع ، أو حتى تأجيل المشاركة لنسخة مقبلة 0.2 .

- حاليا أعمل على الكلاس Random .. كنت في السابق أنوي أن أستخدم خوارزميات موحدة في لغة الجافا و السي بلس ( أي لا أعتمد على الدوال الجاهزة ) ، لكن وجدت الأمر معقد قليلاً .. وصعب الفهم .. فقمت بتغليف الدوال القياسية في اللغتين .. هذا للعلم فقط :( .

- بالنسبة للكلاس Rectangle ما أفكر أن أقوم به هو أن أجعل نقطة الأصل هي top left ، حيث أنها القياسية في الرسوميات .. لكن قد نحتاج لتعديلات بسيطة هنا وهناك في الأمور الرياضية ... لكن لو واجهنا أي مشكلة يمكن بسهولة أن نتلافاها .

أعتقد أن نقطة الأصل في الرسوميات من الافضل أن تكون الركن الأيسر العلوي .. فهذا المستخدم في جميع المكتبات الرسومية ..

تم تعديل هذه المشاركة بواسطة الشمري في 6 أكتوبر 2009 في 07:14

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#143
اقتباس
بالنسبة للكلاس Rectangle ما أفكر أن أقوم به هو أن أجعل نقطة الأصل هي top left

ارجح ان تأجل العمل فيها لبعض الظهر حيث انى على اوشكت على الإنتهاء من الفئه Line و كذلك انتهيت من الفئه Math و Point و بما يحتووا من دوال سيساعدك على انجاز عملك بشكل سريع بدلا من ان تقوم كل فتره بالدخول على احدهم لكتابة كود ستحتاجه فئتك حتى تستطيع تجربتها.

اقتباس
هذه من المشاكل التي واجهتني أيضا .. ما أفكر فيه هو أن نضيف بارمتر ثاني نعيد من خلاله الناتج ، وتعيد الدالة true او false اذا وجدت تقاطع أو لم تجد ! المشكلة من السهل حلها بالجافا .. نعيد null .. لكن المشكلة في السي بلس ..

او ان نستخدم المؤشرات هنا و نعود بـ null :unsure:

اقتباس
أعتقد أن نقطة الأصل في الرسوميات من الافضل أن تكون الركن الأيسر العلوي .. فهذا المستخدم في جميع المكتبات الرسومية ..

تذكر اننا الأن فى مكتبة الرياضيات و ليس الرسم الأمور تفرق هنا حيث لا نستخدم الركن العلوى الأيسر كنقطة اصل و لكن مركز الشاشه كنقطة اصل

مدونتي: C++ Tips and Tricks

#144
اقتباس
ارجح ان تأجل العمل فيها لبعض الظهر حيث انى على اوشكت على الإنتهاء من الفئه Line و كذلك انتهيت من الفئه Math و Point و بما يحتووا من دوال سيساعدك على انجاز عملك بشكل سريع بدلا من ان تقوم كل فتره بالدخول على احدهم لكتابة كود ستحتاجه فئتك حتى تستطيع تجربتها.

جزاك الله خير .. اذاّ سأنام الان :) .

اقتباس
او ان نستخدم المؤشرات هنا و نعود بـ null

تعرف أخ محمد أن هذا له ضريبة عالية في السي بلس .. مشاكل الذاكرة وحجزها ..

لذلك ارى أن نضيف بارمتر اضافي لاستقبال كائن من نوع Point2D ، ونعيد true أو false .

هذا رأيي ، لذلك يمكنك أن تعمل ما تشاء الان .. الى أن نسمع رأي عضو اخر قد يكون قد مر بتجربة سابقة .. قد يحسم المسألة .

اقتباس
تذكر اننا الأن فى مكتبة الرياضيات و ليس الرسم الأمور تفرق هنا حيث لا نستخدم الركن العلوى الأيسر كنقطة اصل و لكن مركز الشاشه كنقطة اصل

أنا كنت أقصد أنني أعتبرbottom أكبر من top ،

بينما في الرياضيات ، العكس .. حيث bottom أصغر من top .

عموماً ساتبع الرياضيات كما تريد .. وسنراجع هذا الموضوع عندما نصل لمرحلة الرسم .

تم تعديل هذه المشاركة بواسطة الشمري في 6 أكتوبر 2009 في 08:22

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#145

السلام عليكم

الحمد لله أنهيت الفئة Point2D وجاري العمل على الفئة Line2D

أريد أن أعرف كيف استنتج نقطة التقاطع بين خطين متعامدين؟

الايميل غير صحيح

يرجى تصحيح الايميل برسالة لأحد مدراء المنتدى

#146

تم تحديث مرفقات المشاركه رقم 136

يحتوى المرفق الأن بالإضافه للسابق على الأتى:

1 - تم الإنتهاء من الفئه Math

2 - تم الإنتهاء من فئة Point2D

3 - تم الإنتهاء من الفئه Line2D

داخل فولدر الإصدار الحالى 0.1 تم اضافة الفولدر tests و الذى يحتوى على ملفات الإختبار لكل فئه من الفئات بالأعلى ماعدا Point2D سأضعه اليوم بعد العشاء ان شاء الله.

ملفات الـ test اسمائها تأخذ الشكل التالى:

tests_className

حيث className التى تم صنع لها هذا الـ testUnit.

لتشغيل ملف الـ test_xxx.cpp قم بعمل include له جاخل المشروع و لكن تذكر انه موجود الداله main داخل هذا الملف لذا قم بعمل exclude لأى ملف يحتوى على الداله main داخل مشروعك حتى لا يحدث تضارب.

و الله ولى التوفيق

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 6 أكتوبر 2009 في 11:19

مدونتي: C++ Tips and Tricks

#147

اخى احمد كنت اريد ان انام اليوم صباحا فلم انتبه لسؤالك جيدا

عموما ها هى الإجابه

اقتباس
أريد أن أعرف كيف استنتج نقطة التقاطع بين خطين متعامدين؟

الخطوط المستقيمه إذا كانت غير متوازيه فهى ستتقاطع إن عاجلا او اجلا و لكن هذا الكلام ينطبق على الأشعه او المتجهات و فى حالة القطعه المستقيمه فهى لها بدايه و نهايه و قد يكون الخطان يتقاطعا فى نقطة ما على المدى الطويل و لكن احدى القطع المستقيمه التى تنتمى لهما لا تتقاطع.

الهدف من الكلام السابق هو ان الفئه Line2D تمثل قطعه مستقيمه و ليس شعاع او متجه و بالتالى قد يكون الخطان المستقيمان لتلك القطع يتقاطعان فى نقطه معينه و لكن القطعتان نفسهما لا يتقطعان ابدا.

لنفهم اولا كيف نوجد نقطة التقاطع و بعدها لنتكلم عن حالة القطعه المستقيمه

لكل خط مستقيم معادلة تأخذ الشكل التالى

p><p>

حيث m هى الـ slope لهذا الخط و b هى y-intercept اى انها قيمة الزياده الثابته التى تضاف على x لتعطينا y.

لذا معادلة الخط المستقيم لكلا الخطان هى

p><p>

p><p>

حيث ان الخطان يتقاطعان لذا فإن المعادلتان السابقتان يتساويان عند نقطه معينه لذا تصبح المعادلتان كالتالى

p><p>

و لكن كما قلنا النقطه متساويه للإثنان بالتالى x ستكون متساويه للإثنان ولكن m و b هما ما يختلف لكل خط لذا ستصبح المعادله الجديده هى

p><p>

حيث m1 هى الـ slope للخط الأول و b1 هى y-intercept للخط الأول , m2 هى الـ slope للخط الثانى , b2 هى الـ y-intercept للخط الثانى.

لذا نقوم بإرسال m2x للجانب الأخر و ارسال b1 للجانب الأخر لتصبح المعادله

p><p>

بأخذ x عامل مشترك فى الجانب الأيسر للمعادله تصبح

p><p>

بالقسمه على m1 - m2 تصبح المعادله النهائيه للحصول على x المشتركه للخطين هى

p><p>

ثم بالتعويض بـ x داخل اى من معادلتين الخط المستقيم تصبح لدينا y المشتركه و بهذا فقد حصلنا على النقطه المشتركه

بالنسبه للـ slope لأى خط يتم الحصول عليها عن طريق المعادله التاليه

p><p>

حيث ان x و y هما نقاط معروفه على هذا الخط.

بالنسبه للـ y-intercept يتم احضارها من التعويض المباشر فى معادلة الخط المستقيم لهذا الخط حيث انك لديك نقطه معروفه على هذا الخط فبالتالى x و y معروفين و كذلك الـ slope لهذا الخط معروف لذا المجهول فقط من المعادله b لذا بعمليه بسيطه نحصل على b و للتسهيل المعادله هى

p><p>

نأتى الأن لموضوع نقطه تقاطع القطع المستقيمه و كيفية اكتشافها.

بعد إحضارك لنقطة تقاطع الخطين قم بالتأكد فقط ان هذه النقطه تقع ما بين نقطة البدء و النهايه للقطعه المستقيمه و ذلك عن طريق ان تحضر قيمة المحور x (او y) لنقطة البدء و نقطة النهايه ثم تصنع متغيرين احداهما يحتوى على القيمه الكبرى لـ x و الأخر يحتوى على القيمه الصغرى لـ x و قم بالتاكد ان قيمة x للنقطه تقع ما بين x الكبيره و x الصغيره.

ايضا يمكنك مراجعة الفئه Line2D الموجوده بمرفقات المشاركه 136 فى حالة انك احتجت معادلة معينه.

و الله ولى التوفيق

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 7 أكتوبر 2009 في 02:15

مدونتي: C++ Tips and Tricks

#148

داخل الفئه Vector2D توجد الداله

 

T[color= #000000;][[color= #000000;]] toArray[color= #000000;]([color= #000000;]);

و التى تعود بعناصر المتجه على شكل مصفوفه، هذه الداله ستكون كالتالى داخل الـ C++

 

operator T[color= #000000;]*[color= #000000;]([color= #000000;])

و الله ولى التوفيق

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 7 أكتوبر 2009 في 03:12

مدونتي: C++ Tips and Tricks

#149

داخل الفئه Vector2D توجد الداله

 

T length();

و طول المتجه يتم حسابه عن طريق هذه المعادله :mad:

تم تعديل هذه المشاركة بواسطة Muhammad alaa في 7 أكتوبر 2009 في 03:27

مدونتي: C++ Tips and Tricks

#150

أعمل لها Cast .. مثل ما اقترحت .. لأنه من المفروض أن المستخدم النهائي رح يستخدم امّا int أو float في الغالب .. لذلك تكتب شيء مثل كذا

value = (T) sqrt( (float) v );

لا أعرف ان كانت sqrt تستقبل float أو double ؟

تم تعديل هذه المشاركة بواسطة الشمري في 7 أكتوبر 2009 في 03:46

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

مواضيع مشابهة