|
02-12-2010, 17:39
|
|
|
|
חבר מתאריך: 21.12.04
הודעות: 30,021
|
|
גראפיקה ממוחשבת, פתרון תרגילים לציור אובייקטים דו מימדיים
היי חברה'.
היה לנו תרגיל במכללה לבנות סוג של צייר פרמיטיבי שיודע לצייר את הצורות הבאות:
- קו ישר, בהינתן 2 נקודות מהמשתמש (קצוות הקו).
- מעגל, בהינתן 2 נקודות מהמשתמש - נקודת מרכז המעגל, ונקודה נוספת הנמצאת על היקפו.
- פוליגון, בהינתן 2 נקודות מהמשתמש - נקודת מרכז המעגל החוסם ואחד הקודקודים של הפוליגון, ומספר הפאות של הפוליגון (מספר הפיאות כמובן יגדיר איזה סוג פוליגון זה יהיה - משולש, ריבוע, מחומש, משושה וכו').
- עקומת בזייה (bezier curve), בהינתן 4 נקודות בקרה. 2 נקודות מהוות את נקודת ההתחלה ונקודת הסיום של העקומה, ונקודות הבקרה הנוספות מושכות את העקומה לכיוונן והן למעשה מהוות את המשיקים לנקודות הסיום וההתחלה (יש הסבר הרבה יותר ויזואלי בויקיפדיה).
היתה לנו בחירה מלאה בשפת התכנות לביצוע המשימה, והבחירה הטבעית היתה להשתמש בשפה שמממשת גראפיקה בצורה קלה (כמו ג'אווה), אבל רציתי בכוונה ללכת עם הראש בקיר ולנסות ליצור את הצורות כתמונות בעזרת PHP.
כמובן, שלצייר צורות זו לא בעיה ב PHP, והפונקציה המוכנה היחידה שמותר היה לנו להשתמש בה, היתה ציור של פיקסל בודד. המטלה דורשת ציור כל הצורות ע"י לולאות שיציירו את כל הפיקסלים אחד אחרי השני מבלי להשתמש בפונקציות מוכנות של ציור מעגלים, קווים ישרים וכו'.
להלן הקודים שלי לציור הצורות. השתמשתי בטופס ששולח את הפרמטרים מהמשתמש באמצעות GET - אקשר פה כדי שתוכלו לשחק עם התוצר הסופי.
קו ישר:
קוד PHP:
<?php header ('Content-type: image/png'); // Get points from user $x0 = $_GET['fromX']; $y0 = $_GET['fromY']; $x1 = $_GET['toX']; $y1 = $_GET['toY']; // Calculate canvas size $canvasX = max($x0, $x1) + 50; $canvasY = max($y0, $y1) + 50; // Creating the image and setting colors $im = @imagecreatetruecolor($canvasX, $canvasY) or die('Cannot Initialize new GD image stream'); $color = imagecolorallocate($im, 0, 0, 0); // color of drawn line $transparent_color = imagecolorallocate($im, 255, 0, 0); // color that will represent transparency imagecolortransparent($im, $transparent_color); // set transparency color imagefilledrectangle($im,0,0,$canvasX,$canvasY,$tr ansparent_color); // fill image with transparent color // Calculating deltaY and deltaX $dy = $y1 - $y0; $dx = $x1 - $x0; // setting directions of drawing if ($dx < 0) { $dx = $dx * -1; $sx = -1; } else { $sx = 1; } if ($dy < 0) { $dy = $dy * -1; $sy = -1; } else { $sy = 1; } imagesetpixel($im, $x0, $y0, $color); // choose primary axis and draw on that axis if ($dx > $dy) { $errp = 2*$dy - $dx; $yp = $y0; for ($xp = $x0 ; $xp != $x1 ; $xp+=$sx) { if ($errp > 0) { $yp+=$sy; $errp -= $dx * 2; } $errp += $dy * 2; imagesetpixel($im, $xp, $yp, $color); } } else { $errp = 2*$dx - $dy; $xp = $x0; for ($yp = $y0 ; $yp != $y1 ; $yp+=$sy) { if ($errp > 0) { $xp+=$sx; $errp -= $dy * 2; } $errp += $dx * 2; imagesetpixel($im, $xp, $yp, $color); } } // draw the image from memory to file imagepng($im); imagedestroy($im); ?>
מעגל:
קוד PHP:
<?php header ('Content-type: image/png'); // get parameters from user $radius = $_GET['radius']; $y = $radius; $x_center = $_GET['centerX']; $y_center = $_GET['centerY']; $p = 3 - 2* $radius; $canvasX = $x_center + $radius + 50; $canvasY = $y_center + $radius + 50; $im = imagecreate ($canvasX, $canvasY) or die('Cannot Initialize new GD image stream'); $color = imagecolorallocate($im, 0, 0, 0); // color of drawn circle $transparent_color = imagecolorallocate($im, 255, 0, 0); // color that will represent transparency imagecolortransparent($im, $transparent_color); // set transparency color imagefilledrectangle($im,0,0,$canvasX,$canvasY,$tr ansparent_color); // fill image with transparent color // draw the circle by calculating the y value for each x for ($x = 0 ; $x < $y ; $x++) { imagesetpixel($im, $x_center + $x , $y_center + $y, $color); imagesetpixel($im, $x_center - $x , $y_center + $y, $color); imagesetpixel($im, $x_center + $x , $y_center - $y, $color); imagesetpixel($im, $x_center - $x , $y_center - $y, $color); imagesetpixel($im, $x_center + $y , $y_center + $x, $color); imagesetpixel($im, $x_center - $y , $y_center + $x, $color); imagesetpixel($im, $x_center + $y , $y_center - $x, $color); imagesetpixel($im, $x_center - $y , $y_center - $x, $color); if ($p < 0) { $p = $p + 4 * $x + 6; } else { $p = $p + 4 * ($x - $y) + 10; $y--; } } // draw the final step outside of the loop if ($x == $y) { imagesetpixel($im, $x_center + $x , $y_center + $y, $color); imagesetpixel($im, $x_center - $x , $y_center + $y, $color); imagesetpixel($im, $x_center + $x , $y_center - $y, $color); imagesetpixel($im, $x_center - $x , $y_center - $y, $color); imagesetpixel($im, $x_center + $y , $y_center + $x, $color); imagesetpixel($im, $x_center - $y , $y_center + $x, $color); imagesetpixel($im, $x_center + $y , $y_center - $x, $color); imagesetpixel($im, $x_center - $y , $y_center - $x, $color); } // draw the image from memory to file imagepng($im); imagedestroy($im); ?>
פוליגון:
קוד PHP:
<?php header ('Content-type: image/png'); // Getting parameters from user $radius = $_GET['radius']; $x_center = $_GET['centerX']; $y_center = $_GET['centerY']; $sides = $_GET['sides']; $vertexX = $_GET['vertexX']; $vertexY = $_GET['vertexY']; // Set canvas size $canvasX = $x_center + $radius + 50; $canvasY = $y_center + $radius + 50; // Creating the image and setting colors $im = @imagecreatetruecolor ($canvasX, $canvasY) or die('Cannot Initialize new GD image stream'); $color = imagecolorallocate($im, 0, 0, 0); // color of the drawn polygon $transparent_color = imagecolorallocate($im, 255, 0, 0); // color that will represent transparency imagecolortransparent($im, $transparent_color); // set transparency color imagefilledrectangle($im,0,0,$canvasX,$canvasY,$tr ansparent_color); // fill image with transparent color $fromX = $vertexX; $fromY = $vertexY; for ($x = 0 ; $x < $sides ; $x++) { $t = ($x+1) * M_PI * 2 / $sides; // calculating rorating angle $cteta = cos($t); $steta = sin($t); $vertexX1 = $vertexX - $x_center; // moving circle to center of axis so can be $vertexY1 = $vertexY - $y_center; $vertexX2 = $cteta * $vertexX1 - $steta * $vertexY1; // rotating axis x of point $vertexY2 = $steta * $vertexX1 + $cteta * $vertexY1; // rotating asix y of point $nextX = $vertexX2 + $x_center; // moving point back to true location $nextY = $vertexY2 + $y_center; imageline($im, $fromX, $fromY, $nextX, $nextY, $color); /****************************BEGINING OF BREZENHAM'S LINE ALGORITHM****************************** $x0 = $fromX; $y0 = $fromY; $x1 = $nextX; $y1 = $nextY; $dy = $y1 - $y0; $dx = $x1 - $x0;
if ($dx < 0) { $dx = $dx * -1; $sx = -1; } else { $sx = 1; } if ($dy < 0) { $dy = $dy * -1; $sy = -1; } else { $sy = 1; }
imagesetpixel($im, $x0, $y0, $color); if ($dx > $dy) { $errp = 2*$dy - $dx; $yp = $y0; for ($xp = $x0 ; $xp != $x1 ; $xp+=$sx) { if ($errp > 0) { $yp+=$sy; $errp -= $dx * 2; } $errp += $dy * 2; imagesetpixel($im, $xp, $yp, $color); } } else { $errp = 2*$dx - $dy; $xp = $x0; for ($yp = $y0 ; $yp != $y1 ; $yp+=$sy) { if ($errp > 0) { $xp+=$sx; $errp -= $dy * 2; } $errp += $dx * 2; imagesetpixel($im, $xp, $yp, $color); } } /******************************END OF BRAZENHAM LINE ALGORITHM***************************/ $fromX = $nextX; $fromY = $nextY; } // drawing the image from memory to file, and fixing alignment to presentive DIV (for polygon.php) imagecopy($im, $im, 0, 0, 150, 0, $canvasX-150, $canvasY); imagefilledrectangle($im,$canvasX-150,0,$canvasX+150,$canvasY,$transparent_color); // fill image with transparent color imagepng($im); imagedestroy($im); ?>
הערה לפוליגון - פונקציית ברזנהיים צריכה לצייר קו ישר מנקודה לנקודה. משום מה - פה זה לא עבד לי כמו שצריך אבל השארתי אותה כמו שהיא בהערה, והשתמשתי מעליה בפונקציה מובנית של ציור קו ישר. אם מישהו רוצה לבדוק למה זה לא הולך - הוא מוזמן. בפונקציה הבאה של העקומה, השתמשתי בדיוק באותו קוד וזה כן עובד... קטע מוזר...
עקומת בזייה
קוד PHP:
<?php header ('Content-type: image/png'); // Getting data from user $lines = $_GET['lines']; $p1x = $_GET['p1x']; $p1y = $_GET['p1y']; $p2x = $_GET['p2x']; $p2y = $_GET['p2y']; $p3x = $_GET['p3x']; $p3y = $_GET['p3y']; $p4x = $_GET['p4x']; $p4y = $_GET['p4y']; // Calculate the canvas size according to greatest value of X and Y $max = max($p1x, $p2x); $max2 = max($p3x, $p4x); $canvasX = max($max, $max2) + 50; $max = max($p1y, $p2y); $max2 = max($p3y, $p4y); $canvasY = max($max, $max2) + 50; // Creating the image and setting colors $im = @imagecreatetruecolor ($canvasX, $canvasY) or die('Cannot Initialize new GD image stream'); $color = imagecolorallocate($im, 0, 0, 0); // color of the drawn curve $transparent_color = imagecolorallocate($im, 255, 0, 0); // color that will represent transparency imagecolortransparent($im, $transparent_color); // set transparency color imagefilledrectangle($im,0,0,$canvasX,$canvasY,$tr ansparent_color); // fill image with transparent color // Calculating parameters according to Bezier matrix $aX = (-1) * $p1x + 3 * $p2x - 3 * $p3x + $p4x; $bX = 3 * $p1x - 6 * $p2x + 3 * $p3x; $cX = (-3) * $p1x + 3 * $p2x; $dX = $p1x; $aY = (-1) * $p1y + 3 * $p2y - 3 * $p3y + $p4y; $bY = 3 * $p1y - 6 * $p2y + 3 * $p3y; $cY = (-3) * $p1y + 3 * $p2y; $dY = $p1y; $prevTempX = $p1x; $prevTempY = $p1y; // draw lines from point to point using brasenham algorithm for ($t = 0; $t < 1; $t = $t + (1 / $lines)) { // Finding the next point on the curve (nextX,nextY) $nextX = round($aX * $t * $t * $t + $bX * $t * $t + $cX * $t + $dX); $nextY = round($aY * $t * $t * $t + $bY * $t * $t + $cY * $t + $dY); /****************************BEGINING OF BREZENHAM'S LINE ALGORITHM******************************/ $x0 = $prevTempX; $y0 = $prevTempY; $x1 = $nextX; $y1 = $nextY; $dy = $y1 - $y0; $dx = $x1 - $x0;
if ($dx < 0) { $dx = $dx * -1; $sx = -1; } else { $sx = 1; } if ($dy < 0) { $dy = $dy * -1; $sy = -1; } else { $sy = 1; }
imagesetpixel($im, $x0, $y0, $color); if ($dx > $dy) { $errp = 2*$dy - $dx; $yp = $y0; for ($xp = $x0 ; $xp != $x1 ; $xp+=$sx) { if ($errp > 0) { $yp+=$sy; $errp -= $dx * 2; } $errp += $dy * 2; imagesetpixel($im, $xp, $yp, $color); } } else { $errp = 2*$dx - $dy; $xp = $x0; for ($yp = $y0 ; $yp != $y1 ; $yp+=$sy) { if ($errp > 0) { $xp+=$sx; $errp -= $dy * 2; } $errp += $dx * 2; imagesetpixel($im, $xp, $yp, $color); } } /******************************END OF BRAZENHAM LINE ALGORITHM***************************/ $prevTempX = $nextX; $prevTempY = $nextY; } //draw the final line between the last found point and the final point (p4) imageline($im, $nextX, $nextY, $p4x, $p4y, $color); imagepng($im); imagedestroy($im); ?>
תהנו
|
|