کاری که امروز میخوایم بکنیم ساخت یک مکعب 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 را صفر میکند تا بتواند عمق نقاط جدید را بدون تأثیر از مقادیر قبلی محاسبه کند.
این عملیاتها برای آمادهسازی هر فریم جدید ضروری هستند تا انیمیشن چرخش مکعب به درستی اجرا شود.
CD
در این بخش از کد، از تابع memset استفاده میشود تا آرایههای buffer و zBuffer با مقادیر مشخصی مقداردهی اولیه شوند. به طور دقیقتر: خط اول: memset(buffer, backgroundASCIICode, width * height); buffer: این آرایهای است که کاراکترهای ASCII را برای نمایش مکعب…
این بخش از کد وظیفه دارد سطحهای مختلف مکعب را محاسبه و برای هر سطح آنها را با استفاده از کاراکترهای ASCII مختلف روی صفحه نمایش دهد. این کار با استفاده از دو حلقهی تو در تو انجام میشود که نقاط مختلف روی سطوح مکعب را بررسی میکنند و برای هر نقطه، تابع
توضیحات کلی:
- حلقههای تو در تو: این حلقهها کل سطح مکعب را نقطه به نقطه بررسی میکنند و برای هر نقطه مختصات سهبعدی آن را به مختصات دوبعدی تبدیل میکنند.
- کاراکترهای مختلف برای سطوح مکعب: هر سطح مکعب با یک کاراکتر ASCII متفاوت رسم میشود تا بتوانید هر سطح را به وضوح از دیگر سطوح تشخیص دهید.
- تابع calculateForSurface: این تابع مختصات دوبعدی نقطهای از سطح مکعب را محاسبه میکند و در صورت برآورده شدن شرایط (مثل عمق)، آن را روی صفحهنمایش قرار میدهد.
جزئیات هر خط:
1. حلقههای تو در تو:
- این دو حلقه مختصات نقاط مختلفی را روی سطوح مکعب بررسی میکنند.
- متغیر cubeX و cubeY به ترتیب نقاطی را در طول محورهای ( x ) و ( y ) روی سطحهای مختلف مکعب تکرار میکنند.
- حلقهها از مقدار -cubeWidth تا +cubeWidth برای هر دو متغیر تکرار میشوند. این یعنی کل سطح مکعب با در نظر گرفتن cubeWidth به عنوان اندازه هر ضلع پیمایش میشود.
- incrementSpeed: میزان تغییرات ( x ) و ( y ) در هر تکرار، که تعیین میکند نقاط با چه فاصلهای از هم بررسی شوند.
2. فراخوانی calculateForSurface برای هر سطح مکعب:
این تابع برای هر سطح مکعب ۶ بار برای نقاط مختلف فراخوانی میشود تا همهی شش سطح مکعب رسم شوند:
- سطح 1 (جلو):
این خط مسئول رسم سطح جلویی مکعب است که در مختصات ( z = -cubeWidth ) قرار دارد. هر نقطه روی این سطح با کاراکتر
- سطح 2 (راست):
این خط مسئول رسم سطح سمت راست مکعب است که در مختصات ( x = cubeWidth ) قرار دارد. این سطح با کاراکتر
- سطح 3 (چپ):
این خط مسئول رسم سطح سمت چپ مکعب است که در مختصات ( x = -cubeWidth ) قرار دارد و با کاراکتر
- سطح 4 (پشت):
این خط مسئول رسم سطح پشت مکعب است که در مختصات ( z = cubeWidth ) قرار دارد و با کاراکتر
- سطح 5 (بالا):
این خط مسئول رسم سطح بالای مکعب است که در مختصات ( y = -cubeWidth ) قرار دارد و با کاراکتر
- سطح 6 (پایین):
این خط مسئول رسم سطح پایین مکعب است که در مختصات ( y = cubeWidth ) قرار دارد و با کاراکتر
هدف:
این حلقهها برای رندر کردن و نمایش هر شش سطح مکعب استفاده میشوند. با این کار مکعب سهبعدی بهصورت چرخان در صفحهنمایش دوبعدی ASCII نمایش داده میشود.
calculateForSurface فراخوانی میشود تا مختصات دوبعدی آن نقطه روی صفحهنمایش محاسبه و نمایش داده شود.توضیحات کلی:
- حلقههای تو در تو: این حلقهها کل سطح مکعب را نقطه به نقطه بررسی میکنند و برای هر نقطه مختصات سهبعدی آن را به مختصات دوبعدی تبدیل میکنند.
- کاراکترهای مختلف برای سطوح مکعب: هر سطح مکعب با یک کاراکتر ASCII متفاوت رسم میشود تا بتوانید هر سطح را به وضوح از دیگر سطوح تشخیص دهید.
- تابع calculateForSurface: این تابع مختصات دوبعدی نقطهای از سطح مکعب را محاسبه میکند و در صورت برآورده شدن شرایط (مثل عمق)، آن را روی صفحهنمایش قرار میدهد.
جزئیات هر خط:
1. حلقههای تو در تو:
for (float cubeX = -cubeWidth; cubeX < cubeWidth; cubeX += incrementSpeed) {
for (float cubeY = -cubeWidth; cubeY < cubeWidth; cubeY += incrementSpeed) {
- این دو حلقه مختصات نقاط مختلفی را روی سطوح مکعب بررسی میکنند.
- متغیر cubeX و cubeY به ترتیب نقاطی را در طول محورهای ( x ) و ( y ) روی سطحهای مختلف مکعب تکرار میکنند.
- حلقهها از مقدار -cubeWidth تا +cubeWidth برای هر دو متغیر تکرار میشوند. این یعنی کل سطح مکعب با در نظر گرفتن cubeWidth به عنوان اندازه هر ضلع پیمایش میشود.
- incrementSpeed: میزان تغییرات ( x ) و ( y ) در هر تکرار، که تعیین میکند نقاط با چه فاصلهای از هم بررسی شوند.
2. فراخوانی calculateForSurface برای هر سطح مکعب:
این تابع برای هر سطح مکعب ۶ بار برای نقاط مختلف فراخوانی میشود تا همهی شش سطح مکعب رسم شوند:
- سطح 1 (جلو):
calculateForSurface(cubeX, cubeY, -cubeWidth, '@'); // Side 1
این خط مسئول رسم سطح جلویی مکعب است که در مختصات ( z = -cubeWidth ) قرار دارد. هر نقطه روی این سطح با کاراکتر
@ رسم میشود.- سطح 2 (راست):
calculateForSurface(cubeWidth, cubeY, cubeX, '$'); // Side 2
این خط مسئول رسم سطح سمت راست مکعب است که در مختصات ( x = cubeWidth ) قرار دارد. این سطح با کاراکتر
$ نمایش داده میشود.- سطح 3 (چپ):
calculateForSurface(-cubeWidth, cubeY, -cubeX, '~'); // Side 3
این خط مسئول رسم سطح سمت چپ مکعب است که در مختصات ( x = -cubeWidth ) قرار دارد و با کاراکتر
~ نمایش داده میشود.- سطح 4 (پشت):
calculateForSurface(-cubeX, cubeY, cubeWidth, '#'); // Side 4
این خط مسئول رسم سطح پشت مکعب است که در مختصات ( z = cubeWidth ) قرار دارد و با کاراکتر
# نمایش داده میشود.- سطح 5 (بالا):
calculateForSurface(cubeX, -cubeWidth, -cubeY, ';'); // Side 5
این خط مسئول رسم سطح بالای مکعب است که در مختصات ( y = -cubeWidth ) قرار دارد و با کاراکتر
; نمایش داده میشود.- سطح 6 (پایین):
calculateForSurface(cubeX, cubeWidth, cubeY, '+'); // Side 6
این خط مسئول رسم سطح پایین مکعب است که در مختصات ( y = cubeWidth ) قرار دارد و با کاراکتر
+ نمایش داده میشود.هدف:
این حلقهها برای رندر کردن و نمایش هر شش سطح مکعب استفاده میشوند. با این کار مکعب سهبعدی بهصورت چرخان در صفحهنمایش دوبعدی ASCII نمایش داده میشود.
for (float cubeX = -cubeWidth; cubeX < cubeWidth; cubeX += incrementSpeed) {
for (float cubeY = -cubeWidth; cubeY < cubeWidth; cubeY += incrementSpeed) {
calculateForSurface(cubeX, cubeY, -cubeWidth, '@'); // Side 1
calculateForSurface(cubeWidth, cubeY, cubeX, '$'); // Side 2
calculateForSurface(-cubeWidth, cubeY, -cubeX, '~'); // Side 3
calculateForSurface(-cubeX, cubeY, cubeWidth, '#'); // Side 4
calculateForSurface(cubeX, -cubeWidth, -cubeY, ';'); // Side 5
calculateForSurface(cubeX, cubeWidth, cubeY, '+'); // Side 6
}
}x1b[H یک کد کنترلی ANSI است که نشاندهندهی حرکت مکاننما (cursor) به بالای صفحهنمایش است.
x1b برابر با کاراکتر Escape (ESC) است.
[H دستور حرکت مکاننما به خانهی اول (بالا سمت چپ) صفحه است.
این بخش کد باعث میشود مکاننما در هر فریم به موقعیت شروع صفحه بازگردد تا محتوای جدید به جای اینکه زیر محتوای قبلی چاپ شود، از بالا دوباره چاپ گردد. این کار برای ایجاد توهم انیمیشن ضروری است، زیرا هر فریم جدید به جای پاک کردن صفحه و دوباره چاپ کردن، کل صفحه را دوبارهنویسی میکند.
x1b برابر با کاراکتر Escape (ESC) است.
[H دستور حرکت مکاننما به خانهی اول (بالا سمت چپ) صفحه است.
این بخش کد باعث میشود مکاننما در هر فریم به موقعیت شروع صفحه بازگردد تا محتوای جدید به جای اینکه زیر محتوای قبلی چاپ شود، از بالا دوباره چاپ گردد. این کار برای ایجاد توهم انیمیشن ضروری است، زیرا هر فریم جدید به جای پاک کردن صفحه و دوباره چاپ کردن، کل صفحه را دوبارهنویسی میکند.
printf("\x1b[H");
for (int k = 0; k < width * height; k++) {
putchar(k % width ? buffer[k] : 10);
}و در آخر با این بخش از کد مقدار زوایایی چرخش مکعب را تغییر میدیم
A += 0.05;
B += 0.05;
C += 0.01;
usleep(8000 * 2);
CD
Video
کل کد در نهایت شد :
💿Records 3
🗃️CD Archive
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
void usleep(__int64 usec)
{
HANDLE timer;
LARGE_INTEGER ft;
ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time
timer = CreateWaitableTimer(NULL, TRUE, NULL);
SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
WaitForSingleObject(timer, INFINITE);
CloseHandle(timer);
}
float A, B, C;
float cubeWidth = 10;
int width = 160, height = 44;
float zBuffer[160 * 44];
char buffer[160 * 44];
int backgroundASCIICode = ' ';
int distanceFromCam = 100;
float horizontalOffset;
float K1 = 40;
float incrementSpeed = 0.5;
float x, y, z;
float ooz;
int xp, yp;
int idx;
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);
}
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;
}
}
}
int main() {
printf("\x1b[2J");
while (1) {
memset(buffer, backgroundASCIICode, width * height);
memset(zBuffer, 0, width * height * 4);
cubeWidth = 20;
horizontalOffset = -2 * cubeWidth;
for (float cubeX = -cubeWidth; cubeX < cubeWidth; cubeX += incrementSpeed) {
for (float cubeY = -cubeWidth; cubeY < cubeWidth; cubeY += incrementSpeed) {
calculateForSurface(cubeX, cubeY, -cubeWidth, '@'); // Side 1
calculateForSurface(cubeWidth, cubeY, cubeX, '$'); // Side 2
calculateForSurface(-cubeWidth, cubeY, -cubeX, '~'); // Side 3
calculateForSurface(-cubeX, cubeY, cubeWidth, '#'); // Side 4
calculateForSurface(cubeX, -cubeWidth, -cubeY, ';'); // Side 5
calculateForSurface(cubeX, cubeWidth, cubeY, '+'); // Side 6
}
}
cubeWidth = 10;
horizontalOffset = 1 * cubeWidth;
printf("\x1b[H");
for (int k = 0; k < width * height; k++) {
putchar(k % width ? buffer[k] : 10);
}
A += 0.05;
B += 0.05;
C += 0.01;
usleep(8000 * 2);
}
return 0;
}
💿Records 3
🗃️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…
🗃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 1)
💿Records 6 : TOR (Disc 2)
💿Records 7 : Tor Manager - VPN (Disc 1)
💿Records 7 : Tor Manager - VPN (Disc 2)
انتقادات پیشنهادات خودتون رو به
@JavadAbdolahi
ارسال کنید 🌱🤍
💿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 1)
💿Records 6 : TOR (Disc 2)
💿Records 7 : Tor Manager - VPN (Disc 1)
💿Records 7 : Tor Manager - VPN (Disc 2)
انتقادات پیشنهادات خودتون رو به
@JavadAbdolahi
ارسال کنید 🌱🤍
تاحالا برات پیش اومده؟
یه ایده ناب به ذهنت میزنه، با هیجان شروع میکنی به کد زدن... کلی تغییر میدی، اما بعد میبینی مسیر اشتباه بوده! حالا میخوای برگردی به حالت قبلی، اما انقدر تغییرات زیاده که حتی "Ctrl + Z" هم جوابگو نیست!
اینجاست که Git مثل یک قهرمان وارد میشه! 🦸♂️
🔍 Git چیه؟
یک سیستم کنترل نسخه هوشمند که:
✅ تمام تغییرات کدتو به ترتیب ذخیره میکنه (مثل یه ماشین زمان!)
✅ اجازه میده به هر نسخه قبلی برگردی (حتی اگر ماهها پیش باشه)
✅ همکاری رو آسان میکنه (بدون ترس از گم شدن کدها!)
📌 چطوری کار میکنه؟
1️⃣ Commit (ثبت تغییرات):
- هر وقت به یه تغییر رضایت دادی، Git یه عکس فوری از کدت میگیره و اون رو با یه پیام ذخیره میکنه
2️⃣ Branch (شاخهبندی):
- میتونی نسخههای موازی از پروژه بسازی (مثلاً برای تست یه فیچر جدید بدون خراب کردن نسخه اصلی)
3️⃣ Merge (ادغام کردن):
- اگر تغییراتت اوکی بود، میتونی اونها رو به نسخه اصلی اضافه کنی
💡 چرا Git ضروریه؟
- دیگه هیچوقت کدتو گم نمیکنی!
- میتونی جرأت کنی و آزمایشهای جدید انجام بدی (اگر اشتباه شد، برمیگردی عقب!)
- توی کار تیمی، همه باهم بدون دردسر کد مینویسن!
🚀 توضیحات بیشتر تو کامنتا!
اگه دوست داری یاد بگیری چطوری از Git استفاده کنی، تو کامنت های این پست قراره به مرور آموزش رایگان Git رو شروع کنیم...
💿Records 4
🗃️CD Archive
یه ایده ناب به ذهنت میزنه، با هیجان شروع میکنی به کد زدن... کلی تغییر میدی، اما بعد میبینی مسیر اشتباه بوده! حالا میخوای برگردی به حالت قبلی، اما انقدر تغییرات زیاده که حتی "Ctrl + Z" هم جوابگو نیست!
اینجاست که Git مثل یک قهرمان وارد میشه! 🦸♂️
🔍 Git چیه؟
یک سیستم کنترل نسخه هوشمند که:
✅ تمام تغییرات کدتو به ترتیب ذخیره میکنه (مثل یه ماشین زمان!)
✅ اجازه میده به هر نسخه قبلی برگردی (حتی اگر ماهها پیش باشه)
✅ همکاری رو آسان میکنه (بدون ترس از گم شدن کدها!)
📌 چطوری کار میکنه؟
1️⃣ Commit (ثبت تغییرات):
- هر وقت به یه تغییر رضایت دادی، Git یه عکس فوری از کدت میگیره و اون رو با یه پیام ذخیره میکنه
2️⃣ Branch (شاخهبندی):
- میتونی نسخههای موازی از پروژه بسازی (مثلاً برای تست یه فیچر جدید بدون خراب کردن نسخه اصلی)
3️⃣ Merge (ادغام کردن):
- اگر تغییراتت اوکی بود، میتونی اونها رو به نسخه اصلی اضافه کنی
💡 چرا Git ضروریه؟
- دیگه هیچوقت کدتو گم نمیکنی!
- میتونی جرأت کنی و آزمایشهای جدید انجام بدی (اگر اشتباه شد، برمیگردی عقب!)
- توی کار تیمی، همه باهم بدون دردسر کد مینویسن!
🚀 توضیحات بیشتر تو کامنتا!
اگه دوست داری یاد بگیری چطوری از Git استفاده کنی، تو کامنت های این پست قراره به مرور آموزش رایگان Git رو شروع کنیم...
💿Records 4
🗃️CD Archive
دوران سختی بود🖤
گذشت
ادامه میدیم تا دورهم چیز های جدیدتر یادبگیریم✨🌱
فعالیت اینجا رو هم بیشتر میکنیم
دور هم مطالب جدید یادبگیریم
ایده های جدید
اهنگ گوش بدیم و…
به امید روزهای بهتر 🦔
گذشت
ادامه میدیم تا دورهم چیز های جدیدتر یادبگیریم✨🌱
فعالیت اینجا رو هم بیشتر میکنیم
دور هم مطالب جدید یادبگیریم
ایده های جدید
اهنگ گوش بدیم و…
به امید روزهای بهتر 🦔
2025-09-11 18-44-53.mkv
38.5 MB
خب یکی از مشکلاتی که اغلب بهش برمیخورید و تو زمان قطعی چند تا از دوستان پرسیده بودن این هست که دارید از یک سایتی فیلم میبینید و اون سایت دکمه دانلود فیلم نداره و با idm هم نمیتونید دانلود کنید
چیکار میکنیم؟
تو ویدئو کامل توضیح دادم چطوری یه فیلم رو که فقط میتونید استریم کنید رو دانلود کنید
پ.ن ۱: ببخشید صدا بده و به نسبت صدای فیلم زیاده
پ.ن ۲: نیاز به هیچ ابزاری ندارید بجز یه ویدیو پلیر روی سیستمتون
💿Records 5
🗃️CD Archive
چیکار میکنیم؟
تو ویدئو کامل توضیح دادم چطوری یه فیلم رو که فقط میتونید استریم کنید رو دانلود کنید
پ.ن ۱: ببخشید صدا بده و به نسبت صدای فیلم زیاده
پ.ن ۲: نیاز به هیچ ابزاری ندارید بجز یه ویدیو پلیر روی سیستمتون
💿Records 5
🗃️CD Archive
دوستان سلام. توی این پست میخوام از شبکه تور (Tor) باهاتون حرف بزنم؛ ابزاری که خیلی از ما اسمش رو شنیدیم، ولی شاید ندونیم دقیقاً چیه، چطور ساخته شد و چه استفادههای خوب و بدی میشه ازش کرد.
🕰 تاریخچه مختصر از شبکه تور
داستان تور از اواسط دهه ۱۹۹۰ در آزمایشگاه تحقیقاتی نیروی دریایی آمریکا شروع شد. اونجا دانشمندی به اسم پال سیورسون به همراه چند نفر دیگه، تکنیکی به اسم “پیاز مسیریابی” (Onion Routing) رو برای محافظت از ارتباطات اینترنتی جاسوسی آمریکا طراحی کردن.
چند سال بعد، دو برنامهنویس به اسمهای راجر دینگلداین و نیک متیوسون که تازه از دانشگاه MIT فارغالتحصیل شده بودن، با سیورسون همکاری کردن تا سال ۲۰۰۲ اولین نسخه از تور رو منتشر کنن که مخفف عبارت The Onion Router هست. نکته جالب اینه که این نرمافزار خیلی زود توسط نیروی دریایی به صورت متنباز در اختیار عموم گذاشته شد. چرا؟ چون هرچقدر کاربرای بیشتری ازش استفاده میکردن، ردگیری ترافیک اینترنت برای دشمنان سختتر میشد.
در نهایت، بنیانگذاران تور در سال ۲۰۰۶، پروژه تور رو به عنوان یک سازمان غیرانتفاعی ثبت کردن تا بتونن مستقل از دولت، روی حفظ حریم خصوصی و آزادی بیان کاربرای اینترنت کار کنن.
🔧 چطوری کار میکنه؟
اسمش رو گذاشتن تور چون روش کارش مثل پوست کندن یه پیازه! بیایین دقیقتر نگاه کنیم:
🔹 وقتی شما با مرورگر تور به یک سایت میرید، درخواست اینترنت شما نه یک بار، بلکه سه بار رمزگذاری میشه (لایه لایه مثل پیاز).
🔹 سپس این بسته سهلایه از سه کامپیوتر متفاوت (که بهشون گره یا Node میگن) عبور میکنه:
- گره ورودی (Entry Node / Guard Node): فقط آیپی شما رو میبینه، ولی نمیدونه مقصد کجاست.
- گره میانی (Middle Node): فقط میدونه از کجا اومده و به کجا میره بعدی، اما نه مبدأ واقعی و نه مقصد نهایی رو میبینه.
- گره خروجی (Exit Node): فقط میدونه به کدوم سایت دارید متصل میشید، ولی نمیدونه درخواست از طرف کیه.
🔹 هر گره فقط یک لایه از رمزگذاری رو باز میکنه (مثل پوست کندن یک لایه پیاز) و فقط آدرس گره بعدی رو میبینه. هیچ گرهای هم مبدأ و هم مقصد رو با هم نمیبینه. حتی خود پروژه تور هم نمیتونه بفهمه شما کجایید و چیکار میکنید.
🔹 این فرایند رو مسیریابی پیازی (Onion Routing) میگن. بر خلاف VPN که همه ترافیک رو به یه سرور مرکزی میفرسته و خودش هم میتونه لاگ نگه داره، تور غیرمتمرکز و چندلایه هست و هیچ نقطه مرکزی برای نفوذ وجود نداره.
🔹 نکته فنی جالب: تور در لایه TCP کار میکنه و از مکانیزم انتقال سلول (Cell-based streaming) استفاده میکنه که بستهها رو به قطعات ۵۱۲ بایتی به اسم سلول تقسیم میکنه تا تأخیر و تشخیص الگو سخت بشه.
🤍 استفادههای خوب
خب شاید بپرسید این تور به چه درد میخوره؟ استفادههای مثبت و انسانی خیلی زیادی داره، از جمله:
- حفظ امنیت روزنامهنگاران و افشاگران: در کشورهای خفقانآور، روزنامهنگارا از تور برای ارتباط امن با منابع خبری شون و ارسال گزارشات محرمانه استفاده میکنن بدون اینکه جانشون به خطر بیفته. حتی پلتفرمهایی مثل SecureDrop که مخصوص افشای اسناد هست، فقط از طریق تور در دسترسه.
- عبور از فیلترینگ: خیلی از مردم دنیا در کشورهایی زندگی میکنن که دسترسی به خیلی از سایتها آزاد نیست. تور میتونه بهشون کمک کنه به راحتی از این محدودیتا عبور کنن و به اینترنت باز و آزاد وصل بشن.
- حفظ حریم خصوصی روزمره: شما لازم نیست حتماً یک فعال سیاسی باشی تا حریم خصوصیت برات مهم باشه. خیلی از کاربرای معمولی از تور استفاده میکنن تا شرکتهای بزرگ ننتونن عادتهای گشتنشون رو رصد کنن و از اطلاعات شخصیشون سوءاستفاده نکنن.
- مقابله با دیتا ماینینگ: وقتی از تور استفاده میکنید، هیچ سایتی نمیتونه بر اساس آیپی واقعی شما، لوکیشن، نوع مرورگر یا رزولوشن صفحه (اثرانگشت دیجیتال) شما رو شناسایی کنه.
💿Records 6 - Disc 1
🗃CD Archive
🕰 تاریخچه مختصر از شبکه تور
داستان تور از اواسط دهه ۱۹۹۰ در آزمایشگاه تحقیقاتی نیروی دریایی آمریکا شروع شد. اونجا دانشمندی به اسم پال سیورسون به همراه چند نفر دیگه، تکنیکی به اسم “پیاز مسیریابی” (Onion Routing) رو برای محافظت از ارتباطات اینترنتی جاسوسی آمریکا طراحی کردن.
چند سال بعد، دو برنامهنویس به اسمهای راجر دینگلداین و نیک متیوسون که تازه از دانشگاه MIT فارغالتحصیل شده بودن، با سیورسون همکاری کردن تا سال ۲۰۰۲ اولین نسخه از تور رو منتشر کنن که مخفف عبارت The Onion Router هست. نکته جالب اینه که این نرمافزار خیلی زود توسط نیروی دریایی به صورت متنباز در اختیار عموم گذاشته شد. چرا؟ چون هرچقدر کاربرای بیشتری ازش استفاده میکردن، ردگیری ترافیک اینترنت برای دشمنان سختتر میشد.
در نهایت، بنیانگذاران تور در سال ۲۰۰۶، پروژه تور رو به عنوان یک سازمان غیرانتفاعی ثبت کردن تا بتونن مستقل از دولت، روی حفظ حریم خصوصی و آزادی بیان کاربرای اینترنت کار کنن.
🔧 چطوری کار میکنه؟
اسمش رو گذاشتن تور چون روش کارش مثل پوست کندن یه پیازه! بیایین دقیقتر نگاه کنیم:
🔹 وقتی شما با مرورگر تور به یک سایت میرید، درخواست اینترنت شما نه یک بار، بلکه سه بار رمزگذاری میشه (لایه لایه مثل پیاز).
🔹 سپس این بسته سهلایه از سه کامپیوتر متفاوت (که بهشون گره یا Node میگن) عبور میکنه:
- گره ورودی (Entry Node / Guard Node): فقط آیپی شما رو میبینه، ولی نمیدونه مقصد کجاست.
- گره میانی (Middle Node): فقط میدونه از کجا اومده و به کجا میره بعدی، اما نه مبدأ واقعی و نه مقصد نهایی رو میبینه.
- گره خروجی (Exit Node): فقط میدونه به کدوم سایت دارید متصل میشید، ولی نمیدونه درخواست از طرف کیه.
🔹 هر گره فقط یک لایه از رمزگذاری رو باز میکنه (مثل پوست کندن یک لایه پیاز) و فقط آدرس گره بعدی رو میبینه. هیچ گرهای هم مبدأ و هم مقصد رو با هم نمیبینه. حتی خود پروژه تور هم نمیتونه بفهمه شما کجایید و چیکار میکنید.
🔹 این فرایند رو مسیریابی پیازی (Onion Routing) میگن. بر خلاف VPN که همه ترافیک رو به یه سرور مرکزی میفرسته و خودش هم میتونه لاگ نگه داره، تور غیرمتمرکز و چندلایه هست و هیچ نقطه مرکزی برای نفوذ وجود نداره.
🔹 نکته فنی جالب: تور در لایه TCP کار میکنه و از مکانیزم انتقال سلول (Cell-based streaming) استفاده میکنه که بستهها رو به قطعات ۵۱۲ بایتی به اسم سلول تقسیم میکنه تا تأخیر و تشخیص الگو سخت بشه.
🤍 استفادههای خوب
خب شاید بپرسید این تور به چه درد میخوره؟ استفادههای مثبت و انسانی خیلی زیادی داره، از جمله:
- حفظ امنیت روزنامهنگاران و افشاگران: در کشورهای خفقانآور، روزنامهنگارا از تور برای ارتباط امن با منابع خبری شون و ارسال گزارشات محرمانه استفاده میکنن بدون اینکه جانشون به خطر بیفته. حتی پلتفرمهایی مثل SecureDrop که مخصوص افشای اسناد هست، فقط از طریق تور در دسترسه.
- عبور از فیلترینگ: خیلی از مردم دنیا در کشورهایی زندگی میکنن که دسترسی به خیلی از سایتها آزاد نیست. تور میتونه بهشون کمک کنه به راحتی از این محدودیتا عبور کنن و به اینترنت باز و آزاد وصل بشن.
- حفظ حریم خصوصی روزمره: شما لازم نیست حتماً یک فعال سیاسی باشی تا حریم خصوصیت برات مهم باشه. خیلی از کاربرای معمولی از تور استفاده میکنن تا شرکتهای بزرگ ننتونن عادتهای گشتنشون رو رصد کنن و از اطلاعات شخصیشون سوءاستفاده نکنن.
- مقابله با دیتا ماینینگ: وقتی از تور استفاده میکنید، هیچ سایتی نمیتونه بر اساس آیپی واقعی شما، لوکیشن، نوع مرورگر یا رزولوشن صفحه (اثرانگشت دیجیتال) شما رو شناسایی کنه.
💿Records 6 - Disc 1
🗃CD Archive
🔥3