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

كيف ترسم دائرة في OpenGL (خاص)

مغلق
بدأه Abdullah.Alshammeri في 9 أكتوبر 2006 · 15 رد · 19,281 مشاهدة · في OpenGL
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم .

هو طبعا مو خاص او حاجة فريدة .. ولكن انجزت هذا الكود دون أن انظر الى مثال جاهز .. لهذا هو انجاز و Exclusive :D .

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

نبدأ :

.. opengl لاتوفر طريقة مباشرة لرسم دائرة . .

لذلك سنستفيد من الدوال المثلثية لانجاز الكود .

" سأتكلم عن الدوال المثلثية ... في موضوع قادم ان شاء الله . "

باختصار :

باستخدام طريقة الرسم GL_POLYGON .. والتي تقوم بوصل النقطة بالنقطة التي تليها ثم يتم اغلاق الشكل ..

فمثلا شاهد الصورة .. ستجد اننا رسمنا نقاط .. وسيتم تحويل هذه النقاط الى شكل.. حسب الطريقة GL_POLYGON .

a.JPG

اذا أمامنا مشكلة .. وهي رسم دائرة .

عرفنا جزء من الحل وهو رسم نقاط بشكل دائري وفق احداثيات معينة ..

واخيرا نحول طريقة الرسم الى GL_POLYGON .

كل شيء سهل الا رسم النقاط بشكل دائري ..

هنا يبرز دور الدوال المثلثية .

الحل :

نخزن 360 نقطة ( دورة كاملة ) . . هكذا :

void Init()
{
	 int degree =0;
	 for(;degree<=360;degree++)
	 {

		 double d=(degree*(3.14/180));
		 cp[degree].x=sin(d);
		 cp[degree].y=cos(d);

	 }
}

بالنسبة للدوال المثلثية وكيفية استخدامها هذا سنتكلم عنه في موضوع منفصل ان شاء الله

كما قلت قبل قليل .

لكن باختصار : قمنا بتحويل الزاوية ثم بحساب قيم الدوال المثلثية

------------------------------

الان تستدعي الدالة قبل عملية الloop في برنامجك .. وذلك لان استدعاء الدالة السابقة اثناء البرنامج يتعب المعالج ومن هالكلام . . لهذا السبب قمنا بتخزين قيم الدوال المثلثية في مصفوفة لاستخدامها مباشرة وهذا يسرع من عملية التصيير ويريح المعالج.

الان الى الاستخدام في داخل الloop

void Render()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 	glLoadIdentity();
	glTranslatef(0,0,-12);

		 glBegin(GL_POLYGON);
		 for(int i=0;i<360;i+=10)
			 glVertex2f(cp.x * 3,cp.y*3);
		 glEnd();
}

النتيجة هي رسم نقاط حسب قيم المصفوفة التي جاءت من الدوال المثلثية

ثم توصيل هذه النقاط حسب طريقة GL_POLYGON

لمزيد من الفهم :

قم بتغيير الرقم 10 في السطر السابق

for(int i=0;i<360;i+=10)

الى الرقم 40 ثم الى الرقم 1 مثلا ...

ماذا تلاحظ؟

نلاحظ انه كلما زادت قيمته قل عدد النقاط المرسومة وبالتالي تقل نعومة الدائرة ,

--

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

struct CPOINT {
	float x,y;
};

CPOINT cp[360];

//--------------- Draw Circle -----------------
	void glCircle(int radian,unsigned int softness,CPOINT cp[])
	{
 		glBegin(GL_POLYGON);
		 for(int i=0;i<360;i+=softness)
			 glVertex2f(cp.x * radian,cp.y*radian);
		 glEnd();

	 }
//--------------- Init Points---------------

void Init()
{
	 for( int degree =0;degree<360;degree++)
	 {

		 double d=(degree*(3.14/180));
		 cp[degree].x=sin(d);
		 cp[degree].y=cos(d);

	 }
}


/**************** Important *********************/ 

void Render()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
////2
	glLoadIdentity();
	glTranslatef(0,0,-12);
	glCircle(1,10,cp);
////1
 	glLoadIdentity();
	glTranslatef(3,0,-12);
	glCircle(2,40,cp);


}

وتستطيع استخدام الDisplay Lists لتزيد من سرعة الرندر .

ولو أردت ان ترسم دائرة بدوت تعبئتها بالالوان استخدم

 	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

المرفقات :

التطبيق - وهو باستخدام OPENGL+ WINAPI + CPP .

glCircle.zip

تم تعديل هذه المشاركة بواسطة الشمري في 10 أكتوبر 2006 في 06:00

1

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

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

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#2

السلام عليكم

مثال جيد.

هل المتغير radian هو نصف قطر الدائرة المراد رسمها ؟

لو تضع smoothness = 45 ستحصل على مربع.

#3

السلام عليكم

فعلاً المثال رائع ولو أني ما أفهم شئ في OpenGL

وإلى الأمام

حـــــــيـــــــدر

1042922905_iai_killua.jpg
#4
اقتباس
هل المتغير radian هو نصف قطر الدائرة المراد رسمها

نعم صحيح .. ولكن لا اعرف لماذا كتبت radian .. كنت اريد ان اكتب radius .. معلش غلطة .

اقتباس
تضع smoothness = 45 ستحصل على مربع.

نعم صحيح .لانه ستقل عدد النقاط المخزنة .

360/45= 8 نقاط ..

تم تعديل هذه المشاركة بواسطة الشمري في 10 أكتوبر 2006 في 06:01

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

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

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#5

شكراً الك ... اليوم كان عندي أول مختبر لماده الـ Computer Graphic

و استخدم الدكتور Java - OpenGL

Success Is A Journey Not A Destination

#6

السلام عليكم

بارك الله فيك اخر الشمري والطريقة سليمة 100% ولكن هناك طريقة اسرع بنسبة 8 مرات ساشرح الطريقة وعليك التطبيق...

افرض معي انك قمت بقسم الدائرة من النصف بحيث اصبح لديك النسف اليمين والنصف اليسار..

فى هذه الحالة نقطة sin 0 و cos 90 فى النصف اليمين يصبح المقابل لها من الجهة الثانية sin 0 و cos 90- ..

وهكذا لن تحتاج لحساب sin و cos اكثر من ½ عدد المرات..

والان افرض ايضاً انك قمت بتقسيم الدائرة لاربع اجزاء ..

فى هذه الحالة يصبح sin 0 و cos 90 الاتجاه المعاكس له يصبح sin 0 و cos 90-

وهكذا وبنفس الطريقة يمكنك تقسيم الدائرة لثمانية اقسام وتصبح العملية الحسابية اقل 8 مرات وعملية الرسم ايضاً تستطيع ان تدرجها فى نفس الحلقة فتختصر 8 مرات الوقت المستهلك..

إذا لم تكن الصورة واضحة إن شاء الله اوضح اكثر ولكن الان معذرة لضيق الوقت ..

والسلام عليكم

لا إله إلا الله محمد رسول الله

busbar : يجب ان تدرك انه هناك حد ادنى للمعرفة المطلوبة قبل البدء في عمل أي شئ.

#7

السلام عليكم

إن عملية الرسم لا تعتمد على حساب قيم sin, cos في كل مرة يراد فيها رسم الدائرة. لأنه مخزنة في مصفوفة.

لذلك لا أعتقد أن طريقة التقسيم ستوفر الكثير من الوقت.

أعتقد أن هذه الطريقة فعالة في حالة الإستغناء عن المصفوفة و حساب القيم في كل مرة عند رسم الدائرة.

#8

السلام عليكم

لاحظ ان عملية الرسم تحدث فى حلقة من 360 مرة تكرار.

إذا استطعت ان ترسم 8 خطوط فى كل حلقة فلن تحتاج لاكثر من 45 مرة تكرار.

وبذلك فانت توفر فى حساب الالمصفوفة وتوفر ايضاً فى عملية الرسم لانك ترسم بسرعة 8 مرات اكبر...

والسلام عليكم

لا إله إلا الله محمد رسول الله

busbar : يجب ان تدرك انه هناك حد ادنى للمعرفة المطلوبة قبل البدء في عمل أي شئ.

#9

سوف اوضح ما قصده اخي احمد غريب بالصوره المرفقه ، فهي ما تتبع في

Midpoint Circle Algorithm و Bresenham’s Circle Algorithm

طريقه midpint و Bresenham من التقنيات المشهوره لرسم الاشكال الهندسيه الاساسيه للكمبيوتر ،

post-49616-1160543929_thumb.jpg

تم تعديل هذه المشاركة بواسطة da-crystal في 11 أكتوبر 2006 في 08:41

لا مستحيل غير الوقت

#10

حاولت تطبيق ما قاله الاخ احمد .. لكن لم افهم مقصده بالظبط.

لكن من الصورة التي ادرجها الاخ da-crystal .. واضح ان الفكره هي :

أن اعين نقطة في الربع الاول وأقوم بايجاد نقاط التناظر لها ,,, حول محور السينات والصادات والقطع المنصفة ...

سأحاول مرة ثانية ,

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

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

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#11

لم أنجح كثيرا ..

لا ادري هل الفكرة بايجاد نقاط التناظر !!

عموما حاولت فقط من خلال نقطة واحدة موجودة على محيط الدائرة .

struct CPOINT {
	float x,y;
};

CPOINT cp[360];

void Init()
{

		 double d=(33*(3.14/180));
		 cp[0].x=cos(d);
		 cp[0].y=sin(d);
}

ثم أوجدت نقاط التناظر لهذه النقطة

//--------------- Draw Circle -----------------
	void glCircle(int radian,CPOINT cp[])
	{
		glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
 		glBegin(GL_POLYGON	);
			 {
			 glVertex2f(cp[0].x * radian,cp[0].y*radian);//A
			 glVertex2f(cp[0].y * radian,cp[0].x*radian);//B
			 glVertex2f(-cp[0].y * radian,cp[0].x*radian);//C
			 glVertex2f(-cp[0].x * radian,cp[0].y*radian);//D
			 glVertex2f(-cp[0].x * radian,-cp[0].y*radian);//E	
			 glVertex2f(-cp[0].y * radian,-cp[0].x*radian);//F	
			 glVertex2f(cp[0].y * radian,-cp[0].x*radian);//G
			 glVertex2f(cp[0].x * radian,-cp[0].y*radian);//H
			}
		 glEnd();
	 }

ثم الرسم

void Render()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
////1
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	glLoadIdentity();
	glTranslatef(0,0,-12);
	glCircle(1,cp);
////2
	glPolygonMode(GL_FRONT_AND_BACK,GL_POINT);
 	glLoadIdentity();
	glTranslatef(3,0,-12);
	glCircle(2,cp);


}

والنتيجة بالمرفقات..

الفكرة حلوة.. وهي بايجاد 45 نقطة عن طريق الجا والجتا .. ثم بايجاد نقاط التناظر لتلك 45 نقطة.

المشكلة التي واجهتني .. هي أن تلك النقاط لاتكون مرتبة باتجاه معين .. وبالتالي فشلت اكثر من مرة في تنفيذ الفكرة ..

ممكن مساعدة

post-42837-1160581373_thumb.jpg

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

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

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#12

السلام عليكم

طريقتك سليمة اخى الشمري كل ما عليك القيام به هو عمل قائمة تتكون من 45 نقطة .. نسميها على النحو التالي

x1,y1
x2,y2
x3,y3
...

عند القيام برسم الدائرة ما عليك سوى ان تصل بين النقاط على النحو التالي

(x1,y1)->(x2,y2)
(x2,y2)->(x3,y3)
...

(y1,x1)->(y2,x2)
(y2,x2)->(y3,x3)
....

(y1,-x1)->(y2,-x2)
(y2,-x2)->(y3,-x3)
....

اتمني تكون الصورة واضحة ...

إذا وضعتها فى حلقة ثم وضعت تايمر يبطئ الرسم ستلاحظ انها ترسم من ثماني جهات فى ان واحد...

للاسف انا ضعيف فى الOpenGL ولن استطيع ان اسعفك بكود ولكن الخوارزمية مشهورة جداً, ابحث فى جوجل عن Bresenham's Circle Algorithm وستجد الكثير من المراجع..

والسلام عليكم

لا إله إلا الله محمد رسول الله

busbar : يجب ان تدرك انه هناك حد ادنى للمعرفة المطلوبة قبل البدء في عمل أي شئ.

#13

السلام عليكم

كما ذكر الاخ احمد غريب ،

الافضل ايجاد نقاط ربع واحد ثم ايجاد نقاط التناظر لكل نقطة ،

،،

بالنسبة لأستخدام ال sin و cos

تعتبر هذه الطريقة معقدة نوعا نسبة لعمليات حساب ال sin و cos

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

واذا اردنا ان نحصل على نتيجة ادق نقوم بتصغير الزاوية ..

خوارزمية ال midpoint التي تعتمد على ايجاد نقطة وسطية تكون افضل ,,

(ممكن اعطيك الكود لها اذا بتحب فهي سهلة .. لكن بلغة سي العادية)

اخي الشمري اذا كنت لم تطلع عليها وعلى هذه الامور

عليك بكتاب Computer Graphics

فهو يشرح اساسيات وخوارزميات رسم الاشكال وغيرها ,,

اظنه مصدر ممتاز

،

،

تحياتي لك

تم تعديل هذه المشاركة بواسطة الاخير زمانه في 12 أكتوبر 2006 في 13:28

/index.php/topic/264448-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A9-%D9%85%D8%B9-%D8%A7%D9%84%D8%A7%D9%86%D8%AF%D8%B1%D9%88%D9%8A%D8%AF/

 

اني وان كنت الاخير زمانه ---- لأتِ بما لم تستطعه الاوائلُ

#14

هذا pdf لدرس في ماده ICS-434 و تتحدث عن Computer Graphics

من اعداد البروفسور محمد سيرفراز وهو مدرس للماده

وهو يشرح رسم الاشكال الاساسيه في الكمبيوتر ،

Computer Graphics with OpenGL كتاب شامل

03_1_2D_Primitives.zip

لا مستحيل غير الوقت

#15

انا بحثت مساء البارحة عن مثل هالخوارزميات ووجدت مثال يعمل على الماكنتوش .. قمت بتحويله الى opengl (فقط غيرت دالة الرسم glPoint ) ..

void circlePlotPoints(int xCenter, int yCenter, int x, int y);
void glPoint(int x,int y)
{
	glBegin(GL_POINTS);
		 glVertex2f(x,y);//A
	glEnd();
}
void circleMidpoint(int xCenter, int yCenter, int radius)
{
	int x = 0;
	int y = radius;
	int p = 1 - radius;
	void circlePlotPoints(int xCenter, int yCenter, int x, int y);

	/* Plot first set of points */
	circlePlotPoints(xCenter, yCenter, x, y);

	while (x < y) {
		x++;
		if (p < 0)
			p += 2*x + 1;
		else {
			y--;
			p += 2 * (x-y) + 1;
		}
		circlePlotPoints(xCenter, yCenter, x, y);
	}
}
void circlePlotPoints(int xCenter, int yCenter, int x, int y)
{
	glPoint(xCenter + x, yCenter + y);
	glPoint(xCenter - x, yCenter + y);
	glPoint( xCenter + x, yCenter - y);
	glPoint(xCenter - x, yCenter - y);
	glPoint(xCenter + y, yCenter + x);
	glPoint(xCenter - y, yCenter + x);
	glPoint(xCenter + y, yCenter - x);
	glPoint(xCenter - y, yCenter - x);
}
void Render()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glLoadIdentity();
	glTranslatef(0,0,0);
	circleMidpoint(200,200,100);
}

اعتقد الخوارزمية هي التي ذكرتموها لنا ...

لكن المشكلة اني لم استطع تعبئة الدائرة ..

سأبحث وأقرأ عن المصادر الموجودة في الردود .

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

http://www.epanorama.net/links/pc_compgraphics.html

تم تعديل هذه المشاركة بواسطة الشمري في 12 أكتوبر 2006 في 23:46

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

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

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#16

السلام عليكم ،،

اقتباس
اعتقد الخوارزمية هي التي ذكرتموها لنا ...

رغم اني لا اذكر الخوارزمية مية مية ،،

لكن اظنها هي midpoint

اقتباس
لكن المشكلة اني لم استطع تعبئة الدائرة ..

هل تقصد ملء الدائرة ؟؟

اذا نعم ،،

فقط غير هنا

void circlePlotPoints(int xCenter, int yCenter, int x, int y)
{
	glPoint(xCenter + x, yCenter + y);
	glPoint(xCenter - x, yCenter + y);
	glPoint( xCenter + x, yCenter - y);
	glPoint(xCenter - x, yCenter - y);
	glPoint(xCenter + y, yCenter + x);
	glPoint(xCenter - y, yCenter + x);
	glPoint(xCenter + y, yCenter - x);
	glPoint(xCenter - y, yCenter - x);
}

هذه الدالة تقوع بطباعة ثمان نقاط

تمام ؟؟

لم اعد اذكر ايعازات ال GL

بدل ذلك فقط قم برسم خط بين كل نقطتين متقابلتين ،

يعني ستحتاج الى 4 من

	glPoint(xCenter - y, yCenter - x);

بدل ثمان

ما طولها عليك

داخل هذه الدالة

void circlePlotPoints(int xCenter, int yCenter, int x, int y)

قم برسم اربع خطوط بين كل نقطتين متقابلتين (واحذف هذه الدالة glPoint)،، وستظهر الدائرة مملوءة ،

فقط عليك من ان تتأكد من انك تصل بين النقاط الصحيحة ..

اتمنى ان يكون هذا قصدك ;)

/index.php/topic/264448-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A9-%D9%85%D8%B9-%D8%A7%D9%84%D8%A7%D9%86%D8%AF%D8%B1%D9%88%D9%8A%D8%AF/

 

اني وان كنت الاخير زمانه ---- لأتِ بما لم تستطعه الاوائلُ

هذا الموضوع مغلق.

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