برای روشن کردن ترمینال، کلیک کن یا هر کلیدی را بزن

پرش به محتوای اصلی
>_
درس ۲۴پیشرفته

رسم اشکال و چندضلعی‌ها

دایره محاطی، تقسیم مثلث، چندضلعی منتظم، دایره‌های تصادفی و هم‌مرکز

معمولی
گرافیک و ماتریس•صفحات ۳۷-۳۸•۴۰ دقیقه•۱٬۷۳۳ کلمهزمان مطالعه: ۰ دقیقه
فهرست این درس
// اهداف۵
  • رسم دایره محاطی در مربع و مستطیل
  • تقسیم مثلث به n قسمت با خطوطی از رأس
  • رسم چندضلعی منتظم n-ضلعی از روی نقاط راسی
  • تولید دایره‌های تصادفی رنگی با rand و delay
  • رسم شبکه‌ای از دسته‌های دایره هم‌مرکز

مرور توابع گرافیکی پایه

در درس قبل با initwindow, putpixel, line, circle, rectangle و setcolor آشنا شدیم. در این درس از چند تابع جدید نیز استفاده می‌کنیم:

  • bar(x1, y1, x2, y2) — مستطیل توپر با رنگ فعلی.
  • fillellipse(x, y, rx, ry) — بیضی توپر با شعاع‌های افقی rx و عمودی ry.
  • setfillstyle(pattern, color) — تنظیم الگو و رنگ توپر. الگوی SOLID_FILL (مقدار ۱) ساده‌ترین حالت است.
  • delay(ms) — توقف به‌مدت ms میلی‌ثانیه (برای انیمیشن).
  • kbhit() — بررسی اینکه آیا کلیدی فشرده شده (مقدار غیرصفر) یا خیر. در حلقه while(!kbhit()) برنامه تا فشردن کلید منتظر می‌ماند.

دایره محاطی در مربع و مستطیل

اگر یک مربع با مرکز (x, y) و نیم‌ضلع r داشته باشیم، دایره محاطی در آن، دایره‌ای است که به تمام چهار ضلع مربع مماس باشد. شعاع این دایره برابر r و مرکز آن (x, y) است.

main.cppcpp

برای مستطیل محاطی (با ابعاد متفاوت)، باید از شعاع کوچک‌تر استفاده کنیم. اگر ضلع‌های مستطیل 2a و 2b باشند، شعاع دایره محاطی برابر است با min(a, b).

دایره محاطی در مربع

رسم مربع و دایره محاطی در آنcpp

اصلاح سینتکس rectangle در جزوه

در کد اصلی جزوه برای رسم مستطیل با ضلع کوچک‌تر (r/d که در آن d = √2)، دستوری به‌صورت rectangle(x-r/d, y-r/d, x+r(d), y+r(d)) نوشته شده بود که دارای دو خطای نگارشی است: نبود عملگر * بین r و (d)، و پرانتزگذاری اشتباه.

نسخه اشتباه جزوه
کد دارای باگcpp
نسخه اصلاح‌شده و استاندارد
کد صحیحcpp

تقسیم مثلث به n قسمت

فرض کنید مثلثی با دو رأس پایین (x1, y) و (x2, y) و یک رأس بالا (x, Y) داریم. می‌خواهیم با خطوطی که از رأس بالا به نقاط روی ضلع پایین کشیده می‌شوند، مثلث را به n قسمت تقسیم کنیم.

روش:

  1. طول ضلع پایین: L = x2 - x1
  2. نقطه میانی پایین: x = (x1 + x2) / 2
  3. در حلقه از i = 1 تا n، نقاط تقسیم روی ضلع پایین را محاسبه می‌کنیم و خطوطی از رأس بالا به آن‌ها می‌کشیم.

در نسخه جزوه از فرمول Y = y - i * L / 2 برای محاسبه ارتفاع رأس بالا استفاده شده بود که در این پیاده‌سازی آن را به شکل استانداردتر بازنویسی می‌کنیم.

تقسیم مثلث به n قسمت

رسم مثلث و تقسیم آن با خطوط از رأس بالاcpp

فلوچارت تقسیم مثلث

flow.svg

تولید اعداد تصادفی: rand و srand

برای تولید اعداد تصادفی در ⁦C++⁩ از تابع rand() در هدر <cstdlib> استفاده می‌شود. این تابع عدد صحیحی بین 0 تا RAND_MAX (معمولاً ۳۲۷۶۷) برمی‌گرداند.

محدود کردن بازه: برای تولید عدد در بازه [a, b] از فرمول زیر استفاده می‌کنیم:

main.cppcpp

مثال: عدد بین ۱۰ تا ۱۵:

main.cppcpp

مشکل تکرار: بدون srand، در هر بار اجرا دنباله یکسانی تولید می‌شود. برای تولید واقعاً تصادفی در هر اجرا، باید با زمان سیستم seed کنیم:

main.cppcpp

تابع time(NULL) تعداد ثانیه‌های گذشته از سال ۱۹۷۰ را برمی‌گرداند و در هر اجرا متفاوت است.

رسم دایره‌های تصادفی رنگی

رسم دایره‌های با موقعیت و رنگ تصادفیcpp

چندضلعی منتظم (n-ضلعی)

برای رسم چندضلعی، کافی است n رأس را به ترتیب با خطوط به‌هم وصل کنیم و در پایان رأس آخر را به رأس اول وصل کنیم تا شکل بسته شود.

اگر مختصات رئوس از قبل داده شده باشد، الگوریتم ساده است:

  1. آرایه‌های x[] و y[] از ورودی بگیر.
  2. برای i از ۰ تا n-2: line(x[i], y[i], x[i+1], y[i+1]).
  3. در پایان: line(x[n-1], y[n-1], x[0], y[0]).

نکته آرایه‌ها: در این مثال از آرایه‌های پویا استفاده می‌کنیم. در ⁦C++⁩ مدرن از std::vector استفاده می‌شود که در تمرین‌ها نشان داده شده است.

رسم چندضلعی از روی نقاط

رسم چندضلعی n-ضلعی با مختصات ورودیcpp

دایره‌های هم‌مرکز

برای رسم چند دایره هم‌مرکز، در یک حلقه شعاع را افزایش می‌دهیم و circle را با همان مرکز اما شعاع متفاوت فراخوانی می‌کنیم.

برای رسم یک شبکه از دسته‌های دایره هم‌مرکز (مثلاً m ردیف و k ستون، هر دسته شامل n دایره)، از سه حلقه تودرتو استفاده می‌کنیم:

  • حلقه بیرونی: ردیف‌ها (m)
  • حلقه میانی: ستون‌ها (k)
  • حلقه درونی: دایره‌های هر دسته (n)

بعد از رسم هر دسته، مرکز را به اندازه قطر کل دسته به‌علاوه یک فاصله به سمت راست جابجا می‌کنیم. در پایان هر ردیف، مرکز به نقطه شروع برمی‌گردد و به سمت پایین جابجا می‌شود.

شبکه دایره‌های هم‌مرکز

رسم m×k دسته از n دایره هم‌مرکزcpp

اصلاح کد شبکه دایره‌ها در جزوه

کد اصلی جزوه دارای چند اشکال بود: استفاده از حرف بزرگ I به‌عنوان شمارنده (که با عدد ۱ اشتباه گرفته می‌شود)، جابجایی نادرست x و نبود مدیریت ردیف‌ها. در نسخه اصلاح‌شده از نام‌های معنادارتر row, col, i استفاده شده و مدیریت افقی و عمودی به‌درستی تفکیک شده است.

نسخه اشتباه جزوه
کد دارای باگcpp
نسخه اصلاح‌شده و استاندارد
کد صحیحcpp

استفاده از kbhit برای انیمیشن

تابع kbhit() (از <conio.h>) بررسی می‌کند آیا کلیدی فشرده شده است. این تابع در ساخت انیمیشن‌های گرافیکی مفید است:

main.cppcpp

به این ترتیب تا فشردن کلید، انیمیشن اجرا می‌شود.

یادآوری: graphics.h قدیمی است

تمام کدهای این درس به کتابخانه graphics.h وابسته‌اند که روی کامپایلر‌های استاندارد مدرن موجود نیست. اگر کد بالا را اجرا نمی‌کند، دلایل احتمالی:

  1. کامپایلر شما graphics.h را ندارد → باید WinBGIm را نصب کنید یا از Dev-⁦C++⁩ قدیمی استفاده کنید.
  2. روی لینوکس/مک → عملاً اجرا نمی‌شود مگر با Wine یا کتابخانه‌های شبیه‌ساز.
  3. در کدبلاک‌ها (Code::Blocks) → باید مسیر کتابخانه را به‌صورت دستی اضافه کنید.

پیشنهاد: برای یادگیری واقعی گرافیک، همان کدها را با raylib یا SFML بازنویسی کنید (درس قبلی به‌عنوان جایگزین معرفی شدند). منطق الگوریتم‌ها یکسان است، فقط API فرق می‌کند.

مرور سریع مطالب

۱۶ بخش در این درس

تمرین‌ها

01
تمرین•حل کامل دارد

برنامه‌ای بنویسید که یک مربع با ضلع `2r` حول مرکز `(x, y)` و دایره محاطی در آن رسم کند. سپس مربعی کوچک‌تر با ضلع `2r/√2` (دایره محاطی کوچک‌تر) هم رسم کند.

نمایش راهنما
برای √2 از `sqrt(2.0)` استفاده کنید و شعاع کوچک‌تر `r/sqrt(2)` را برای دایره داخلی به‌کار ببرید.
02
تمرین•حل کامل دارد

برنامه‌ای بنویسید که n دایره تصادفی با موقعیت، شعاع و رنگ تصادفی رسم کند. شعاع بین ۱۰ تا ۵۰ و رنگ بین ۱ تا ۱۵ باشد. بین هر دایره ۲۰۰ میلی‌ثانیه مکث کنید.

نمایش راهنما
از `srand(time(NULL))`، `rand() % range + min` و `delay(200)` استفاده کنید.
03
تمرین•حل کامل دارد

برنامه‌ای بنویسید که یک چندضلعی منتظم n-ضلعی را با محاسبه مختصات رئوس روی یک دایره رسم کند. مرکز (۴۰۰، ۳۰۰) و شعاع ۲۰۰ باشد.

نمایش راهنما
زاویه هر رأس: `theta = 2 * M_PI * i / n`. مختصات: `x = cx + r * cos(theta)`، `y = cy + r * sin(theta)`. از `<cmath>` برای sin و cos استفاده کنید.
04
تمرین•حل کامل دارد

برنامه‌ای بنویسید که مثلثی متساوی‌الاضلاع رسم کند و سپس آن را با سه میانه به ۶ مثلث هم‌مساحت تقسیم کند. (نکته: میانه، خطی از هر رأس تا نقطه‌ی میانی ضلع مقابل است؛ سه میانه همدیگر را در مرکز ثقل — میانگین مختصات سه رأس — قطع می‌کنند.)

نمایش راهنما
برای مثلث متساوی‌الاضلاع با مرکز (cx, cy) و شعاع محیطی r، سه رأس در زاویه‌های ۰، ۱۲۰ و ۲۴۰ درجه قرار دارند. نقطه‌ی میانی هر ضلع را با میانگین مختصات دو سرش حساب کنید و هر رأس را به نقطه‌ی میانی ضلع مقابل وصل کنید؛ سه میانه‌ی کامل مثلث را دقیقاً به ۶ ناحیه تقسیم می‌کنند.
// نکات-کلیدی۶
  • 01برای رسم دایره محاطی در مربع، شعاع دایره برابر نیم‌ضلع مربع و مرکز آن با مرکز مربع منطبق است.
  • 02برای تقسیم مثلث به n قسمت با خطوط از یک رأس، نقاط تقسیم روی ضلع مقابل را با فرمول `px = x1 + (x2-x1)*i/n` محاسبه می‌کنیم.
  • 03برای تولید عدد تصادفی در بازه `[a, b]` از فرمول `a + rand() % (b - a + 1)` و برای عدم تکرار از `srand(time(NULL))` استفاده کنید.
  • 04چندضلعی منتظم n-ضلعی را می‌توان با محاسبه رئوس روی دایره (`cos`, `sin` با زاویه `2π*i/n`) رسم کرد.
  • 05برای شبکه‌ای از دسته‌های دایره هم‌مرکز از سه حلقه تودرتو استفاده می‌شود: ردیف، ستون، و دایره‌های هر دسته.
  • 06کتابخانه `graphics.h` قدیمی است؛ برای پروژه‌های واقعی از raylib یا SFML استفاده کنید و منطق الگوریتم‌ها را به آن‌ها منتقل کنید.
گام بعدی پیشنهادی

ماتریس‌ها و عملیات ماتریسی

پیمایش، ضرب، یافتن ماکزیمم سطر، ماتریس مثلثی و تولید تصادفی

۴۵ دقیقهپیشرفته۲۶ بخش

شروع درس

جستجوی سریع در درس‌ها

نام درس، موضوع یا کلمه کلیدی را بنویسید و با Enter به آن بروید