אלגוריתם כהן-סאת'רלנד
מתוך ויקיפדיה, האנציקלופדיה החופשית
אלגוריתם כהן-סאת'רלנד (Cohen–Sutherland) הוא אלגוריתם בגרפיקה ממוחשבת המשמש לClipping של קווים בשניים או שלושה ממדים. האלגוריתם מחלק את המרחב הדו ממדי ל-9 חלקים, וב-3 ממדים מחלק ל-27 חלקים ואז קובע באופן יעיל את הקווים והחלקים של הקווים שנמצאים בחלק המרכזי (ה-viewport).
האלגוריתם פותח ב-1967 על ידי דני כהן ואיוואן סאת'רלנד.
האלגוריתם קובע אילו קווים או חלקים של קווים נמצאים ב-viewport על פי:
- שני קצוות הקו מצויים ב-viewport: הקו שייך
- שני קצוות הקו נמצאים על אותו אזור שאינו ב-viewport: הקו אינו שייך
- שני הקצוות באזורים שונים: להבדיל מהמקרים הקודמים שהם טריוואליים. כאן בוחר האלגוריתם את קצה של הקו שנמצא באזור שמחוץ ל-viewport (יש לפחות אחד כזה), ומחשב את נקודת החיתוך של הקו מהנקודה החיצונית עם גבולות הviewport (באמצעות משוואה פרמטרית של קו) והנקודה החדשה (החיתוך) מחליפה את הנקודה החיצונית ל-viewport. האלגוריתם ממשיך עד להגעה לאחד המקרים הטריוויאלים לעיל.
שימוש בoutcodes (בדו מימד):
| 1001 | 1000 | 1010 |
| 0001 | 0000 | 0010 |
| 0101 | 0100 | 0110 |
כל נקודה בקו מקבלת outcode מתאים למיקומה שמורכב מ4 ביטים (ובתלת מימד מ-6). הביט הראשון הוא 1 כאשר הנקודה מעל הviewport
אלגוריתם זה מוגבל לביצוע clipping במלבנים בלבד. אלגוריתם כללי יותר הפועל על פוליגונים קמורים הוא אלגוריתם Cyrus–Beck.
דוגמת מימוש[עריכה]
typedef int OutCode; const int INSIDE = 0; // 0000 const int LEFT = 1; // 0001 const int RIGHT = 2; // 0010 const int BOTTOM = 4; // 0100 const int TOP = 8; // 1000 // Compute the bit code for a point (x, y) using the clip rectangle // bounded diagonally by (xmin, ymin), and (xmax, ymax) // ASSUME THAT xmax, xmin, ymax and ymin are global constants. OutCode ComputeOutCode(double x, double y) { OutCode code; code = INSIDE; // initialised as being inside of clip window if (x < xmin) // to the left of clip window code |= LEFT; else if (x > xmax) // to the right of clip window code |= RIGHT; if (y < ymin) // below the clip window code |= BOTTOM; else if (y > ymax) // above the clip window code |= TOP; return code; } // Cohen–Sutherland clipping algorithm clips a line from // P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with // diagonal from (xmin, ymin) to (xmax, ymax). void CohenSutherlandLineClipAndDraw(double x0, double y0, double x1, double y1) { // compute outcodes for P0, P1, and whatever point lies outside the clip rectangle OutCode outcode0 = ComputeOutCode(x0, y0); OutCode outcode1 = ComputeOutCode(x1, y1); bool accept = false; while (true) { if (!(outcode0 | outcode1)) { // Bitwise OR is 0. Trivially accept and get out of loop accept = true; break; } else if (outcode0 & outcode1) { // Bitwise AND is not 0. Trivially reject and get out of loop break; } else { // failed both tests, so calculate the line segment to clip // from an outside point to an intersection with clip edge double x, y; // At least one endpoint is outside the clip rectangle; pick it. OutCode outcodeOut = outcode0? outcode0 : outcode1; // Now find the intersection point; // use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0) if (outcodeOut & TOP) { // point is above the clip rectangle x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0); y = ymax; } else if (outcodeOut & BOTTOM) { // point is below the clip rectangle x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0); y = ymin; } else if (outcodeOut & RIGHT) { // point is to the right of clip rectangle y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0); x = xmax; } else if (outcodeOut & LEFT) { // point is to the left of clip rectangle y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0); x = xmin; } //NOTE:***************************************************************************************** /* if you follow this algorithm exactly(at least for c#), then you will fall into an infinite loop in case a line crosses more than two segments. to avoid that problem, leave out the last else if(outcodeOut & LEFT) and just make it else*/ //********************************************************************************************** // Now we move outside point to intersection point to clip // and get ready for next pass. if (outcodeOut == outcode0) { x0 = x; y0 = y; outcode0 = ComputeOutCode(x0, y0); } else { x1 = x; y1 = y; outcode1 = ComputeOutCode(x1, y1); } } } if (accept) { // Following functions are left for implementation by user based on his platform(OpenGL/graphics.h etc.) DrawRectangle(xmin, ymin, xmax, ymax); LineSegment(x0, y0, x1, y1); } }