داشتم فکر میکردم که یه اسم مناسب برای اینجا انتخاب کنم...
که هم به برنامه نویسی مربوط باشه
هم به اسم خودم
همینطور که داشتم فکر میکردم یاد حرکت یکی از دوستان(جواهری) افتادم که اومده بود و اسمش رو با فونت لوگو java نوشته بود و و به جای ۴ حرف اولش لوگو جاوا رو گذاشته بود...
بعد گفتم اسم منم این پتانسیل داره که Javad رو ۴ حرف اولش رو نماد جاوا بزارم و اینجوری باشه که Java + d
دیدم اما من که اصلا علاقه ای به جاوا ندارم کار هم نکردم
چه زبانی رو هم کار کردم هم دوست دارم؟
C,C++,C#,...
و اگه جای java بیام لوگو C بزارم به کلمه CD میرسم.
و از اون جایی که CD فاز نوستالژیک داره و بهم حس و حال خوبی میده و احتمالا مطالبی که داخل اینجا میزارم برای شما دوستان قدیمی هست، اما جالبه رو بزارم...
پس همراه باشید با کانال 💿CD
💿Records 0
🗃️CD Archive
که هم به برنامه نویسی مربوط باشه
هم به اسم خودم
همینطور که داشتم فکر میکردم یاد حرکت یکی از دوستان(جواهری) افتادم که اومده بود و اسمش رو با فونت لوگو java نوشته بود و و به جای ۴ حرف اولش لوگو جاوا رو گذاشته بود...
بعد گفتم اسم منم این پتانسیل داره که Javad رو ۴ حرف اولش رو نماد جاوا بزارم و اینجوری باشه که Java + d
دیدم اما من که اصلا علاقه ای به جاوا ندارم کار هم نکردم
چه زبانی رو هم کار کردم هم دوست دارم؟
C,C++,C#,...
و اگه جای java بیام لوگو C بزارم به کلمه CD میرسم.
و از اون جایی که CD فاز نوستالژیک داره و بهم حس و حال خوبی میده و احتمالا مطالبی که داخل اینجا میزارم برای شما دوستان قدیمی هست، اما جالبه رو بزارم...
پس همراه باشید با کانال 💿CD
💿Records 0
🗃️CD Archive
Telegram
CD
🗃CD Archive 🗃
💿Records 0 : introduction
💿Records 1 : Base 10 (fun)
💿Records 2 : Moon rotation animation in CMD (fun)
💿Records 3 : 3D cube rotation animation in CMD (fun)
💿Records 4 : Git
💿Records 5 : Download video stream from web
💿Records 6 : TOR (Disc…
💿Records 0 : introduction
💿Records 1 : Base 10 (fun)
💿Records 2 : Moon rotation animation in CMD (fun)
💿Records 3 : 3D cube rotation animation in CMD (fun)
💿Records 4 : Git
💿Records 5 : Download video stream from web
💿Records 6 : TOR (Disc…
طی تکامل انسان وقتی شروع کرد به شمردن از انگشت های دستش کمک گرفت تا باهاش بشماره...
حالا چون 10 تا انگشت دست داریم
شمارش بر مبنای 10 انجام شد...
و انسان های اولیه بیشترین عددی که میتونستین با انگشت های دستشون بشمارن عدد 10 بود...
اما تو دنیایی امروز شما با 10 تا انگشت چه بازهای از اعداد میتونید بشمارید؟
هر انگشت ما دو حالت داره
باز و بسته
مثل کامپیوتر که فقط جریان قطع برق و وصل برق رو میفهمه...
حالا بیایم به جای اینکه کل انگشت هامون رو یک مبنا در نظر بگیرم و از 0 تا 10 نمایش بدیم.
بیایم و هر انگشت رو مبنا قرار بدیم
و چون دوتا حالت باز و بسته داره مبنای دو نظر میگیرم.
انگشت اول
2^0
انگشت دوم
2^1
.
.
.
انگشت دهم
2^9
مقدار داشته باشه...
حالا کمترین عددی که میتونید نمایش بدید حالتی هست که همه انگشت ها بسته باشه و مقدار 0 بگیره، به عدد 0 میرسیم...
و بیشترین عددی که میتونیم نمایش بدیم حالتی هست که همه انگشت ها باز باشه و مقدار ارزش اون انگشت رو داشته باشیم که میشه
1+2+4+8+...+512
یا به عبارتی
(2^10)-1=1023
اگه انگشت های شصتمون هم مثل باقي انگشت ها سه بخشی بود
میتونستیم تا
(4^10)-1=1,048,575
بشماریم...
انسان های اولیه با دیدگاهشون به 10تا انگشت هاشون 10 تا ارزش دادن
الان میتونید با دیدی که دارید به 10 تا انگشتتون 1023 ارزش بدید
هر کس با دیدگاه خودش به یه چیزی ارزش میده!
💿Records 1
🗃️CD Archive
حالا چون 10 تا انگشت دست داریم
شمارش بر مبنای 10 انجام شد...
و انسان های اولیه بیشترین عددی که میتونستین با انگشت های دستشون بشمارن عدد 10 بود...
اما تو دنیایی امروز شما با 10 تا انگشت چه بازهای از اعداد میتونید بشمارید؟
هر انگشت ما دو حالت داره
باز و بسته
مثل کامپیوتر که فقط جریان قطع برق و وصل برق رو میفهمه...
حالا بیایم به جای اینکه کل انگشت هامون رو یک مبنا در نظر بگیرم و از 0 تا 10 نمایش بدیم.
بیایم و هر انگشت رو مبنا قرار بدیم
و چون دوتا حالت باز و بسته داره مبنای دو نظر میگیرم.
انگشت اول
2^0
انگشت دوم
2^1
.
.
.
انگشت دهم
2^9
مقدار داشته باشه...
حالا کمترین عددی که میتونید نمایش بدید حالتی هست که همه انگشت ها بسته باشه و مقدار 0 بگیره، به عدد 0 میرسیم...
و بیشترین عددی که میتونیم نمایش بدیم حالتی هست که همه انگشت ها باز باشه و مقدار ارزش اون انگشت رو داشته باشیم که میشه
1+2+4+8+...+512
یا به عبارتی
(2^10)-1=1023
اگه انگشت های شصتمون هم مثل باقي انگشت ها سه بخشی بود
میتونستیم تا
(4^10)-1=1,048,575
بشماریم...
انسان های اولیه با دیدگاهشون به 10تا انگشت هاشون 10 تا ارزش دادن
الان میتونید با دیدی که دارید به 10 تا انگشتتون 1023 ارزش بدید
هر کس با دیدگاه خودش به یه چیزی ارزش میده!
💿Records 1
🗃️CD Archive
Telegram
CD
🗃CD Archive 🗃
💿Records 0 : introduction
💿Records 1 : Base 10 (fun)
💿Records 2 : Moon rotation animation in CMD (fun)
💿Records 3 : 3D cube rotation animation in CMD (fun)
💿Records 4 : Git
💿Records 5 : Download video stream from web
💿Records 6 : TOR (Disc…
💿Records 0 : introduction
💿Records 1 : Base 10 (fun)
💿Records 2 : Moon rotation animation in CMD (fun)
💿Records 3 : 3D cube rotation animation in CMD (fun)
💿Records 4 : Git
💿Records 5 : Download video stream from web
💿Records 6 : TOR (Disc…
یک روز سر حل تمرین برای آمادگی آزمون درس مبانی کامپیوتر داشتیم مبحث for & if رو کار میکردیم و برای تمرین مثال های مثل رسم مثلث، لوزی و... رو با ستاره میزدیم.
به شوخی گفتم سر امتحان بهتون میگم دایره بزنید.
و همون جا خودم شروع کردن زدن.
همونطور که میدونید تو صفحه مختصات به مرکز مبدا مختصات فرمول دایره به شعاع r برابر هست با
حالا صرفا لازم هست که فضای دوبعدی مون رو شبیه سازی کنیم.
با انجام دوتا for تو در تو از منفی r تا مثبت r حرکت کنه.
⚠️چرا برای درون دایره و بیرون دایره از دو تا علامت * یا space استفاده کردیم؟
چون فاصله هر خط تو CMD به اندازه دوتا کارکتر هست، و اگه با یکدونه بنویسیم دایرهمون تبدیل میشه به بیضی.
به شوخی گفتم سر امتحان بهتون میگم دایره بزنید.
و همون جا خودم شروع کردن زدن.
همونطور که میدونید تو صفحه مختصات به مرکز مبدا مختصات فرمول دایره به شعاع r برابر هست با
(x^2)+(y^2)<(r^2)
حالا صرفا لازم هست که فضای دوبعدی مون رو شبیه سازی کنیم.
با انجام دوتا for تو در تو از منفی r تا مثبت r حرکت کنه.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int r;
printf("Please Enter Radius of the moon(Max=45):");
scanf("%d",&r);
for(int y = r; y > -r; y--){
for(int x = -r; x < r; x++)
{
if(pow(x,2) + pow(y,2) < pow(r,2)){
printf("**");
}
else{
printf(" ");
}
}
printf("\n");
}
return 0;
}
⚠️چرا برای درون دایره و بیرون دایره از دو تا علامت * یا space استفاده کردیم؟
چون فاصله هر خط تو CMD به اندازه دوتا کارکتر هست، و اگه با یکدونه بنویسیم دایرهمون تبدیل میشه به بیضی.
حالا که تونستیم دایره رسم کنیم میخوایم یک انیمیشن برای نمایش چرخش ماه نمایش بدیم!
چرا ماه رو به صورت حلال میبینیم؟
سایه زمین میفته روی ماه و بخشی از ماه (که سایه زمین روش هست) نور خورشید رو بازتاب نمیکنه!
پس کاری که باید بکنیم ساده است :
دوتا دایره تعریف کنیم یکیش رو ثابت نگه داریم و دایره دیگری رو حرکت بدیم و از بالا سمت چپ تا پایین سمت راست دایره دوم رو حرکت میدیم!
و شرطمون رو به این تغییر میدیم که روی دایره اول باشه ولی روی دایره دوم نباشه!
اگه بود کارکتر رو چاپ بکنه در غیر اینصورت اسپیس چاپ کنه !
چرا ماه رو به صورت حلال میبینیم؟
سایه زمین میفته روی ماه و بخشی از ماه (که سایه زمین روش هست) نور خورشید رو بازتاب نمیکنه!
پس کاری که باید بکنیم ساده است :
دوتا دایره تعریف کنیم یکیش رو ثابت نگه داریم و دایره دیگری رو حرکت بدیم و از بالا سمت چپ تا پایین سمت راست دایره دوم رو حرکت میدیم!
و شرطمون رو به این تغییر میدیم که روی دایره اول باشه ولی روی دایره دوم نباشه!
اگه بود کارکتر رو چاپ بکنه در غیر اینصورت اسپیس چاپ کنه !
این هم از کدش
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
void draw (int i, int j, int r,int k)
{
if(pow((j),2)+pow((i),2)<= pow(r,2) && !(pow((j-k),2)+pow((i-k),2)<= pow(r,2)))
{
printf("0O");
return ;
}
else
{
printf(" ");
return ;
}
}
int main()
{
int r;
printf("Please Enter Radius of the moon(Max=45):");
scanf("%d",&r);
for(int k=-(sqrt(2)*r);k<=(sqrt(2)*r);k++)
{
printf("\x1b[2J");
for(int j=-r;j<=r;j++){
for(int i=-r;i<=r;i++){
draw(i,j,r,k);
}
printf("\n");
}
}
return 0;
}
کاری که امروز میخوایم بکنیم ساخت یک مکعب 3بعدی در حال چرخش هست.
بریم که مراحل مطالعات لازم رو براش شروع کنیم
بریم که مراحل مطالعات لازم رو براش شروع کنیم
خب اول از همه میرسیم به تبدیل مختصات سهبعدی که باید انجام بدیم و چیزی که با سرچ بدست آوردم و از صفحه wikipedia پیدا کردم این هست!
CD
حالا با کمک maple و ضربشون در ماتریس [i,k,j] به ماتریس زیر رسیدم... Vector[row](3, [(i*cos(B) - (-j*sin(A) + k*cos(A))*sin(B))*cos(C) + (j*cos(A) + k*sin(A))*sin(C), -(i*cos(B) - (-j*sin(A) + k*cos(A))*sin(B))*sin(C) + (j*cos(A) + k*sin(A))*cos(C), i*sin(B)…
تابع calculateX در این برنامه، مسئول محاسبه مختصات جدید x یک نقطه در فضای سهبعدی بعد از چرخش آن حول محورهای مختلف (چرخش در فضای سهبعدی) است. این تابع با استفاده از زوایای چرخش
A، B و C (به ترتیب حول محورهایx، y و z)، مختصات جدید x را محاسبه میکند.
این تابع سه ورودی دارد که مختصات اصلی یک نقطه در فضای سهبعدی هستند:
i: مختصهی x
j: مختصهی y
k: مختصهی z
تابع calculateX به همراه توابع مشابه دیگر (calculateY و calculateZ) مسئول انجام چرخش سهبعدی بر روی مختصات مکعب است تا این مکعب به صورت چرخان در صفحهنمایش دوبعدی ظاهر شود.
A، B و C (به ترتیب حول محورهایx، y و z)، مختصات جدید x را محاسبه میکند.
این تابع سه ورودی دارد که مختصات اصلی یک نقطه در فضای سهبعدی هستند:
i: مختصهی x
j: مختصهی y
k: مختصهی z
تابع calculateX به همراه توابع مشابه دیگر (calculateY و calculateZ) مسئول انجام چرخش سهبعدی بر روی مختصات مکعب است تا این مکعب به صورت چرخان در صفحهنمایش دوبعدی ظاهر شود.
float calculateX(int i, int j, int k) {
return j * sin(A) * sin(B) * cos(C) - k * cos(A) * sin(B) * cos(C) +
j * cos(A) * sin(C) + k * sin(A) * sin(C) + i * cos(B) * cos(C);
}
float calculateY(int i, int j, int k) {
return j * cos(A) * cos(C) + k * sin(A) * cos(C) -
j * sin(A) * sin(B) * sin(C) + k * cos(A) * sin(B) * sin(C) -
i * cos(B) * sin(C);
}
float calculateZ(int i, int j, int k) {
return k * cos(A) * cos(B) - j * sin(A) * cos(B) + i * sin(B);
}تابع
ورودیهای تابع:
-
-
-
-
مراحل عملکرد:
1. محاسبهی مختصات سهبعدی جدید:
- تابع ابتدا با استفاده از توابع calculateX، calculateY و calculateZ، مختصات سهبعدی جدید نقطه را بعد از اعمال چرخشها (با توجه به زوایای ( A )، ( B )، و ( C )) محاسبه میکند. این توابع، مختصات نقطه را پس از چرخش حول محورهای مختلف به دست میآورند.
2. محاسبهی مختصات عمق (z):
- مقدار مختصهی ( z ) بعد از چرخش به فاصلهای از دوربین اضافه میشود تا نقطه از دید دوربین نمایش داده شود:
3. محاسبهی "معکوس فاصله از دوربین" (ooz):
- مقدار
4. تبدیل مختصات سهبعدی به دوبعدی:
- با استفاده از مقدارهای محاسبهشده، تابع مختصات دوبعدی (مختصات x و y برای نمایش در صفحهنمایش) را محاسبه میکند. این مقادیر به عنوان مختصات پیکسلی نقطه در صفحهی دوبعدی استفاده میشوند:
این فرمولها با استفاده از
5. رسم نقطه روی صفحهنمایش:
- پس از محاسبهی مختصات ( xp ) و ( yp ) (مختصات دوبعدی در صفحهنمایش)، تابع بررسی میکند که آیا این نقطه در محدودهی نمایش (درون مرزهای صفحهنمایش) قرار دارد یا خیر. اگر نقطه در محدوده باشد و مقدار
در این حالت، مقدار
نتیجه کلی:
تابع
calculateForSurface در این برنامه وظیفه محاسبه مختصات دوبعدی یک نقطه از سطح مکعب را بر عهده دارد. این تابع مختصات سهبعدی یک نقطه از سطح مکعب را دریافت میکند، آنها را با توجه به چرخشهای مکعب به مختصات دوبعدی تبدیل میکند و سپس آن نقطه را روی صفحهنمایش دوبعدی بهصورت کاراکتر ASCII نمایش میدهد.ورودیهای تابع:
-
cubeX: مختصهی ( x ) در فضای سهبعدی.-
cubeY: مختصهی ( y ) در فضای سهبعدی.-
cubeZ: مختصهی ( z ) در فضای سهبعدی.-
ch: کاراکتر ASCII که قرار است در محل محاسبهشده نمایش داده شود.مراحل عملکرد:
1. محاسبهی مختصات سهبعدی جدید:
- تابع ابتدا با استفاده از توابع calculateX، calculateY و calculateZ، مختصات سهبعدی جدید نقطه را بعد از اعمال چرخشها (با توجه به زوایای ( A )، ( B )، و ( C )) محاسبه میکند. این توابع، مختصات نقطه را پس از چرخش حول محورهای مختلف به دست میآورند.
2. محاسبهی مختصات عمق (z):
- مقدار مختصهی ( z ) بعد از چرخش به فاصلهای از دوربین اضافه میشود تا نقطه از دید دوربین نمایش داده شود:
z = calculateZ(cubeX, cubeY, cubeZ) + distanceFromCam;
3. محاسبهی "معکوس فاصله از دوربین" (ooz):
- مقدار
ooz برابر معکوس مقدار ( z ) است که برای محاسبهی مقیاسبندی استفاده میشود:ooz = 1 / z;
4. تبدیل مختصات سهبعدی به دوبعدی:
- با استفاده از مقدارهای محاسبهشده، تابع مختصات دوبعدی (مختصات x و y برای نمایش در صفحهنمایش) را محاسبه میکند. این مقادیر به عنوان مختصات پیکسلی نقطه در صفحهی دوبعدی استفاده میشوند:
xp = (int)(width / 2 + horizontalOffset + K1 * ooz * x * 2);
yp = (int)(height / 2 + K1 * ooz * y);
این فرمولها با استفاده از
K1 (یک ثابت برای مقیاسبندی)، مختصات سهبعدی ( x ) و ( y ) را به مختصات دوبعدی صفحهنمایش تبدیل میکنند.5. رسم نقطه روی صفحهنمایش:
- پس از محاسبهی مختصات ( xp ) و ( yp ) (مختصات دوبعدی در صفحهنمایش)، تابع بررسی میکند که آیا این نقطه در محدودهی نمایش (درون مرزهای صفحهنمایش) قرار دارد یا خیر. اگر نقطه در محدوده باشد و مقدار
ooz بزرگتر از مقدار موجود در بافر عمق (zBuffer) باشد (یعنی نقطه نزدیکتر به دوربین باشد): if (idx >= 0 && idx < width * height) {
if (ooz > zBuffer[idx]) {
zBuffer[idx] = ooz;
buffer[idx] = ch;
}
}
در این حالت، مقدار
ooz در بافر عمق ذخیره میشود و کاراکتر ASCII مربوطه (ch) در موقعیت محاسبهشدهی آن قرار میگیرد.نتیجه کلی:
تابع
calculateForSurface یک نقطه از سطح مکعب را بعد از اعمال چرخشها و تغییرات سهبعدی به مختصات دوبعدی تبدیل کرده و آن را با کاراکتر ASCII مربوطه روی صفحهی کنسول رسم میکند. همچنین از طریق مقایسهی عمق نقطه (مقدار z)، تضمین میکند که سطحهای نزدیکتر به دوربین بر روی سطحهای دورتر نمایش داده شوند.void calculateForSurface(float cubeX, float cubeY, float cubeZ, int ch) {
x = calculateX(cubeX, cubeY, cubeZ);
y = calculateY(cubeX, cubeY, cubeZ);
z = calculateZ(cubeX, cubeY, cubeZ) + distanceFromCam;
ooz = 1 / z;
xp = (int)(width / 2 + horizontalOffset + K1 * ooz * x * 2);
yp = (int)(height / 2 + K1 * ooz * y);
idx = xp + yp * width;
if (idx >= 0 && idx < width * height) {
if (ooz > zBuffer[idx]) {
zBuffer[idx] = ooz;
buffer[idx] = ch;
}
}
}در این بخش از کد، از تابع
خط اول:
buffer: این آرایهای است که کاراکترهای ASCII را برای نمایش مکعب در صفحهنمایش ذخیره میکند.
backgroundASCIICode: یک کد ASCII که نمایانگر کاراکتر پسزمینه (فضای خالی) است. این مقدار برابر با
width * height: تعداد کل خانههای موجود در آرایه
این خط از کد کل بافر
خط دوم:
zBuffer: آرایهای که عمق هر نقطه (مقدار \( z \)) را در خود نگه میدارد. از این آرایه برای اطمینان از این استفاده میشود که نقاط نزدیکتر به دوربین روی نقاط دورتر نمایش داده شوند.
- `0`: تمام خانههای این آرایه با صفر مقداردهی میشوند. این یعنی در ابتدا هیچ نقطهای از مکعب در صفحه رسم نشده است.
width * height * 4`: اندازهی کل آرایه
این خط از کد آرایهی
هدف کلی:
این دو خط کد در ابتدای هر فریم:
1. buffer را با کاراکتر پسزمینه (معمولاً فضای خالی) پر میکند تا صفحهنمایش تمیز شود.
2. zBuffer را صفر میکند تا بتواند عمق نقاط جدید را بدون تأثیر از مقادیر قبلی محاسبه کند.
این عملیاتها برای آمادهسازی هر فریم جدید ضروری هستند تا انیمیشن چرخش مکعب به درستی اجرا شود.
memset استفاده میشود تا آرایههای buffer و zBuffer با مقادیر مشخصی مقداردهی اولیه شوند. به طور دقیقتر:خط اول:
memset(buffer, backgroundASCIICode, width * height);
buffer: این آرایهای است که کاراکترهای ASCII را برای نمایش مکعب در صفحهنمایش ذخیره میکند.
backgroundASCIICode: یک کد ASCII که نمایانگر کاراکتر پسزمینه (فضای خالی) است. این مقدار برابر با
' ' (فضای خالی) است.width * height: تعداد کل خانههای موجود در آرایه
buffer است که معادل با تعداد کل کاراکترهایی است که روی صفحهنمایش کنسول نشان داده میشوند.این خط از کد کل بافر
buffer را با کاراکتر پسزمینه پر میکند (مثلاً فضای خالی یا یک کاراکتر دیگر). این کار هر فریم قبل از اینکه مکعب دوباره رسم شود، انجام میشود تا صفحهنمایش تمیز شود.خط دوم:
memset(zBuffer, 0, width * height * 4);
zBuffer: آرایهای که عمق هر نقطه (مقدار \( z \)) را در خود نگه میدارد. از این آرایه برای اطمینان از این استفاده میشود که نقاط نزدیکتر به دوربین روی نقاط دورتر نمایش داده شوند.
- `0`: تمام خانههای این آرایه با صفر مقداردهی میشوند. این یعنی در ابتدا هیچ نقطهای از مکعب در صفحه رسم نشده است.
width * height * 4`: اندازهی کل آرایه
zBuffer که برابر با تعداد کل پیکسلهای صفحه ضربدر اندازهی هر عنصر (۴ بایت برای هر مقدار عمق) است.این خط از کد آرایهی
zBuffer را قبل از هر فریم با صفر مقداردهی میکند تا در هر فریم جدید مقادیر عمق نقاط از نو محاسبه شوند.هدف کلی:
این دو خط کد در ابتدای هر فریم:
1. buffer را با کاراکتر پسزمینه (معمولاً فضای خالی) پر میکند تا صفحهنمایش تمیز شود.
2. zBuffer را صفر میکند تا بتواند عمق نقاط جدید را بدون تأثیر از مقادیر قبلی محاسبه کند.
این عملیاتها برای آمادهسازی هر فریم جدید ضروری هستند تا انیمیشن چرخش مکعب به درستی اجرا شود.