fork download
  1. /* -----------------------------------------------------------------------
  2.  * Από: migf1
  3.  *
  4.  * Πολύ απλοϊκό παράδειγμα προγράμματος κονσόλας που παράγει στο 1ο καρτεσιανό
  5.  * τεταρτημόριο τα εξής:
  6.  * α) το γράφημα μιας συνάρτησης: f(x) = a*x + b
  7.  * β) μια γραμμή μεταξύ δυο σημείων: (x1,y1) και (x2,y2)
  8.  * γ) έναν κύκλο με κέντρο στο σημείο: (x,y) και ακτίνα radius
  9.  * δ) μια έλλειψη που οριοθετείται από παραλληλόγραμμο με αντικριστές κορυφές
  10.  * τα σημεία: (x1,y1) πάνω αριστερά και (x2,y2) κάτω δεξιά
  11.  *
  12.  * Μπορείτε να αλλάξετε τιμές σε οποιοδήποτε από τα x, pt2.x, x2, pt2.y, y2 & radius,
  13.  * αλλά σημειώστε πως το πρόγραμμα απεικονίζει μονάχα όσα σημεία παράγονται στην
  14.  * περιοχή: (0,0) ... (74,22)
  15.  *
  16.  * ΣΗΜΕΙΩΣΕΙΣ ΥΛΟΠΟΙΗΣΗΣ:
  17.  * Οι αλγόριθμοι για τον σχεδιασμό της γραμμής του κύκλου και της έλλειψης
  18.  * είναι ΕΤΟΙΜΕΣ υλοποιήσεις των αλγορίθμων Bresenham, που χρησιμοποιήσα
  19.  * ατόφιους (με μόνη αλλαγή την προσαρμογή τους στις δομές δεδομέννων Screen
  20.  * και Point του παρόντος προγράμματος).
  21.  *
  22.  * Δείτε επίσης:
  23.  * http://f...content-available-to-author-only...s.at/easyfilter/bresenham.html
  24.  * http://e...content-available-to-author-only...a.org/wiki/Midpoint_circle_algorithm
  25.  *
  26.  * Tο πρόγραμμα δεν κάνει ούτε scaling ούτε κανονικό clipping και απεικονίζει
  27.  * ΜΟΝΑΧΑ το 1ο τεταρτημόριο του καρτεσιανού επιπέδου, με το σημείο (0,0) να
  28.  * βρίσκεται στην κάτω αριστερή μεριά της οθόνης.
  29.  * Ο κύριος σκοπός για τον οποίον γράφτηκε το πρόγραμμα ήταν η παρουσίαση μιας
  30.  * απλοϊκής υλοποίησης buffered σχεδιασμού (οι συναρτήσεις αναβοσβήνουν τα
  31.  * κατάλληλα pixels μέσα στο buffer, το οποίο κατόπιν τυπώνεται στην οθόνη
  32.  * σειρά προς σειρά, μεσω της συνάρτησης: draw_screen() ).
  33.  * -----------------------------------------------------------------------
  34.  */
  35.  
  36. #include <stdio.h>
  37. #include <stdlib.h> // for exit()
  38. #include <string.h> // for memset()
  39.  
  40. #define MAXCOLS 75 // μέγιστο πλάτος της οθόνης μας
  41. #define MAXROWS 23 // μέγιστο ύψος της οθόνης μας
  42.  
  43. #define PIXEL_ON '#' // χαρακτήρας απεικόνισης "αναμμένων" pixels
  44. #define PIXEL_OFF '.' // χαρακτήρας απεικόνισης "σβησμένων" pixels
  45.  
  46. // έλεγχος για pixels εκτός ορίων
  47. #define VALIDPIXEL(x,y, w,h) ( (y) > -1 && (y) < (h) && (x) > -1 && (x) < (w) )
  48.  
  49. #define REVAXIS(y,h) (h) - (y) - 1 // προσαρμόζει την συντεταγμένη y ώστε το σημείο
  50. // που της αντιστοιχεί να απεικονιστεί στην
  51. // αντεστραμμένη φορά του άξονά (χρήσιμο για τον
  52. // άξονα Υ που τον θέλουμε να μετράει από κάτω
  53. // προς τα πάνω)
  54.  
  55. #define ABS(x) ( (x) < 0 ? -(x) : (x) )
  56.  
  57. typedef struct point { // δομή καρτεσιανού σημείου
  58. int x; // καρτεσιανή συντεταγμένη x του σημείου
  59. int y; // καρτεσιανή συντεταγμένη y του σημείου
  60. } Point;
  61.  
  62. typedef struct screen { // δομή για το buffer της οθόνης μας
  63. int nrows; // τρέχον πλάτος της οθόνης μας
  64. int ncols; // τρέχον ύψος της οθόνης μας
  65. char pixel[MAXROWS][MAXCOLS]; // το buffer της οθόνης μας
  66. } Screen;
  67.  
  68. // ------------------------------------------------------------------------------------
  69. // set_pixel:
  70. //
  71. // "Ανάβει" το pixel x,y στο buffer της οθόνης. Θα εμφανιστεί αναμένο όταν αργότερα
  72. // τυπωθεί το buffer μέσω της συνάρτησης: draw_screen
  73. //
  74. void set_pixel( Screen *screen, int x, int y )
  75. {
  76. // απόρριψη pixels που βγαίνουν εκτός οθόνης
  77. if ( !VALIDPIXEL(x,y, screen->ncols, screen->nrows ) )
  78. return;
  79. // προσαρμογή του y ώστε το μέτρημα για την
  80. y = REVAXIS(y, screen->nrows); // απεικόνιση να ξεκινά από κάτω προς τα επανω
  81. screen->pixel[y][x] = PIXEL_ON;
  82.  
  83. return;
  84. }
  85.  
  86. // ------------------------------------------------------------------------------------
  87. // Η συνάρτηση που παράγει το 1ο γράφημα, δοκιμάστε και με άλλες τιμές
  88. //
  89. int f( int x )
  90. {
  91. return x/3 + 1;
  92. }
  93.  
  94. // ------------------------------------------------------------------------------------
  95. // set_f():
  96. //
  97. // "Ανάβει" τα pixels που αντιστοιχούν στο γράφημα της συνάρτησης f(), στο buffer της
  98. // οθόνης (θα εμφανιστούν αναμμένα όταν αργότερα τυπωθεί το buffer μέσω της συνάρτησης:
  99. // draw_screen() )
  100. //
  101. void set_f( Screen *screen )
  102. {
  103. register int x;
  104. for (x=0; x < screen->ncols; x++)
  105. set_pixel( screen, x, f(x) );
  106.  
  107. return;
  108. }
  109.  
  110. // ------------------------------------------------------------------------------------
  111. // set_line():
  112. //
  113. // "Ανάβει" τα pixels της γραμμής που οριοθετείται από τα σημεία pt1 και pt2, στο
  114. // buffer της οθόνης (θα εμφανιστούν αναμμένα όταν αργότερα τυπωθεί το buffer μέσω
  115. // της συνάρτησης: draw_screen() )
  116. //
  117. void set_line( Screen *screen, Point pt1, Point pt2)
  118. {
  119. int dx = ABS( pt2.x - pt1.x );
  120. int dy = -ABS( pt2.y - pt1.y );
  121. int sx = (pt1.x < pt2.x) ? 1 : -1;
  122. int sy = (pt1.y < pt2.y) ? 1 : -1;
  123. int err = dx + dy, e2; // error value e_xy
  124.  
  125. for (;;)
  126. {
  127. set_pixel(screen, pt1.x, pt1.y);
  128. if ( pt1.x == pt2.x && pt1.y == pt2.y )
  129. break;
  130. e2 = 2 * err;
  131. if (e2 >= dy) { // e_xy + e_x > 0
  132. err += dy;
  133. pt1.x += sx;
  134. }
  135. if (e2 <= dx) { // e_xy + e_y < 0 */
  136. err += dx;
  137. pt1.y += sy;
  138. }
  139. }
  140.  
  141. return;
  142. }
  143.  
  144. // ------------------------------------------------------------------------------------
  145. // set_circle():
  146. //
  147. // "Ανάβει" τα pixels της περιφέρειας του κύκλου με κέντρο το σημείο: center και ακτίνα
  148. // radius, στο buffer της οθόνης (θα εμφανιστούν αναμμένα όταν αργότερα τυπωθεί το
  149. // buffer μέσω της συνάρτησης: draw_screen() )
  150. //
  151. void set_circle(Screen *screen, Point center, int radius)
  152. {
  153. int x = -radius, y = 0, err = 2-2*radius; // II. Quadrant
  154. do {
  155. set_pixel(screen, center.x-x, center.y+y); // I. Quadrant
  156. set_pixel(screen, center.x-y, center.y-x); // II. Quadrant
  157. set_pixel(screen, center.x+x, center.y-y); // III. Quadrant
  158. set_pixel(screen, center.x+y, center.y+x); // IV. Quadrant
  159. radius = err;
  160. if (radius > x) // e_xy + e_x > 0
  161. err += ++x * 2 + 1;
  162. if (radius <= y)
  163. err += ++y * 2 + 1; // e_xy + e_y < 0
  164. } while (x < 0);
  165.  
  166. return;
  167. }
  168.  
  169. // ------------------------------------------------------------------------------------
  170. void set_ellipse( Screen *screen, Point rsta, Point rend )
  171. {
  172. // values of diameter
  173. int a = ABS( rend.x - rsta.x );
  174. int b = ABS( rend.y - rsta.y );
  175. int b1 = b & 1;
  176.  
  177. // error increment
  178. long dx = 4 * (1-a) * b * b;
  179. long dy = 4 * (b1+1) *a * a;
  180.  
  181. // error of 1.step
  182. long err = dx + dy + b1 * a * a;
  183. long e2;
  184.  
  185. if (rsta.x > rend.x) { // if called with swapped points
  186. rsta.x = rend.x;
  187. rend.x += a;
  188. }
  189. if (rsta.y > rend.y) // ... exchange them
  190. rsta.y = rend.y;
  191.  
  192. // starting pixel
  193. rsta.y += (b+1)/2;
  194. rend.y = rsta.y-b1;
  195.  
  196. a *= 8 * a;
  197. b1 = 8 * b * b;
  198.  
  199. do {
  200. set_pixel(screen, rend.x, rsta.y); // I. Quadrant
  201. set_pixel(screen, rsta.x, rsta.y); // II. Quadrant
  202. set_pixel(screen, rsta.x, rend.y); // III. Quadrant
  203. set_pixel(screen, rend.x, rend.y); // IV. Quadrant
  204. e2 = 2 * err;
  205. if (e2 >= dx) { // x step
  206. rsta.x++;
  207. rend.x--;
  208. err += dx += b1;
  209. }
  210. if (e2 <= dy) { // y step
  211. rsta.y++;
  212. rend.y--;
  213. err += dy += a;
  214. }
  215. } while ( rsta.x <= rend.x );
  216.  
  217. while ( rsta.y - rend.y < b ) { // too early stop of flat ellipses a=1
  218. set_pixel(screen, rsta.x - 1, rsta.y);// -> finish tip of ellipse
  219. set_pixel(screen, rend.x + 1, rsta.y++);
  220. set_pixel(screen, rsta.x - 1, rend.y);
  221. set_pixel(screen, rend.x + 1, rend.y--);
  222. }
  223.  
  224. return;
  225. }
  226.  
  227. // ------------------------------------------------------------------------------------
  228. // "Σβήνει" όλα τα pixels στο buffer της οθόνης (α εμφανιστούν σβησμένα όταν αργότερα
  229. // τυπωθεί η οθόνη μέσω της συνάρτησης: draw_screen() )
  230. //
  231. void clear_screen( Screen *screen )
  232. {
  233. // γρήγορος κώδικας
  234. memset( &screen->pixel, PIXEL_OFF, screen->nrows * screen->ncols * sizeof(char));
  235.  
  236. /*** DISABLED: αργός εναλλακτικός κώδικας, αλλά ενδεχομένως πιο συμβατός
  237. register int x,y;
  238.  
  239. for (y=0; y < screen->nrows; y++)
  240. for (x=0; x < screen->ncols; x++)
  241. screen->pixel[y][x] = PIXEL_OFF;
  242. ***/
  243.  
  244. return;
  245. }
  246.  
  247. // ------------------------------------------------------------------------------------
  248. // draw_screen():
  249. //
  250. // Τυπώνει όλα τα pixels του buffer (αναμμένα και σβηστά) καθώς και την αρίθμηση
  251. // των αξόνων Χ και Υ
  252. //
  253. void draw_screen( Screen screen )
  254. {
  255. register int x, y;
  256.  
  257. for (y=0; y < screen.nrows; y++)
  258. {
  259. // τύπωμα ετικετών αριστερά από τον άξονα Υ
  260. int ylab = y;
  261. printf("%3d ", REVAXIS(ylab, screen.nrows) );
  262.  
  263. // τύπωμα των pixels της y-οστής σειράς του buffer
  264. for (x=0; x < screen.ncols; x++)
  265. putchar( screen.pixel[y][x] );
  266. putchar('\n');
  267. }
  268.  
  269. // τύπωμα ετικετών κάτω από τον άξονα Χ
  270. printf("Y/X ");
  271. for (x=0; x < screen.ncols; x++)
  272. printf("%d", x%10);
  273. putchar('\n');
  274.  
  275. return;
  276. }
  277.  
  278. // ------------------------------------------------------------------------------------
  279. int main( void )
  280. {
  281. char s[255+1] = ""; // βοηθητικό string (άνευ σημασίας)
  282.  
  283. /*
  284. * ορισμός του buffer της οθόνης & αρχικοποίηση των τρεχουσών διαστάσεών του
  285. */
  286. Screen screen = { .ncols = MAXCOLS, .nrows = MAXROWS };
  287.  
  288. /*
  289. * Σχεδίαση γραφήματος της συνάρτησης: f(x) = a*x+b
  290. * (πειραματιστείτε με διάφορες τιμές των a και b, στη γραμμή 69)
  291. */
  292.  
  293. printf("> press ENTER for graph of: f(x) = x/3+1 ...");
  294. fgets(s, 255+1, stdin); putchar('\n');
  295. clear_screen( &screen ); // σβήσιμο όλων των pixels στο buffer
  296. set_f( &screen); // σχεδίαση της f(x) στο buffer
  297. draw_screen( screen ); // τύπωμα όλων των pixels του buffer
  298.  
  299. /*
  300. * Σχεδίαση γραμμής μεταξύ 2 σημείων: pt1 και pt2
  301. * (πειραματιστείτε με διάφορες τιμές)
  302. */
  303. // τα σημεία που οριοθετούν τη γραμμή
  304. Point pt1 = { .x=2, .y=14 }, pt2 = { .x=64, .y=2};
  305. printf( "> press ENTER for line between points (%d,%d) and (%d,%d)...",
  306. pt1.x, pt1.y, pt2.x, pt2.y
  307. );
  308. fgets(s, 255+1, stdin); putchar('\n');
  309. clear_screen( &screen ); // σβήσιμο όλων των pixels στο buffer
  310. set_line( &screen, pt1, pt2 ); // σχεδίαση της γραμμής στο buffer
  311. draw_screen( screen ); // τύπωμα όλων των pixels του buffer
  312.  
  313. /*
  314. * Σχεδίαση κύκλου με κέντρο στο σημείο: center και ακτίνα: radius
  315. * (πειραματιστείτε με διάφορες τιμές)
  316. */
  317.  
  318. Point center = { .x=30, .y=11 }; // το κέντρο του κύκλου
  319. int radius = 10; // η ακτίνα του κύκλου
  320. printf( "> press ENTER for circle with center (%d,%d) and radius %d...",
  321. center.x, center.y, radius
  322. );
  323. fgets(s, 255+1, stdin); putchar('\n');
  324. clear_screen( &screen ); // σβήσιμο όλων των pixels στο buffer
  325. set_circle( &screen, center, radius ); // σχεδίαση του κύκλου στο buffer
  326. draw_screen( screen ); // τύπωμα όλων των pixels του buffer
  327.  
  328. /*
  329. * Σχεδίαση έλλειψης που οριοθετείται από παραλληλόγραμο με την
  330. * επάνω αριστερή του γωνία στο σημείο: psta και την κάτω δεξιά
  331. * γωνία του στο σημείο: pend
  332. * (πειραματιστείτε με διάφορες τιμές)
  333. */
  334. // τα σημεία που οριοθετούν το παραλληλόγραμο
  335. Point psta = { .x=2, .y=20 }, pend = { .x=60, .y=2};
  336. printf( "> press ENTER for ellipsis in rect: (%d,%d)-(%d,%d) ...",
  337. psta.x, psta.y, pend.x, pend.y
  338. );
  339. fgets(s, 255+1, stdin); putchar('\n');
  340. clear_screen( &screen ); // σβήσιμο όλων των pixels στο buffer
  341. set_ellipse( &screen, psta, pend ); // σχεδίαση της έλλειψης στο buffer
  342. draw_screen( screen ); // τύπωμα όλων των pixels του buffer
  343.  
  344. /*
  345. * Τερματισμός του προγράμματος
  346. */
  347. printf("> press ENTER to exit...");
  348. fgets(s, 255+1, stdin);
  349.  
  350. exit( EXIT_SUCCESS );
  351. }
  352.  
stdin
Standard input is empty
compilation info
prog.c: In function ‘main’:
prog.c:294: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result
prog.c:308: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result
prog.c:323: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result
prog.c:339: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result
prog.c:348: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result
stdout
> press ENTER for graph of: f(x) = x/3+1 ...
 22 ...............................................................###.........
 21 ............................................................###............
 20 .........................................................###...............
 19 ......................................................###..................
 18 ...................................................###.....................
 17 ................................................###........................
 16 .............................................###...........................
 15 ..........................................###..............................
 14 .......................................###.................................
 13 ....................................###....................................
 12 .................................###.......................................
 11 ..............................###..........................................
 10 ...........................###.............................................
  9 ........................###................................................
  8 .....................###...................................................
  7 ..................###......................................................
  6 ...............###.........................................................
  5 ............###............................................................
  4 .........###...............................................................
  3 ......###..................................................................
  2 ...###.....................................................................
  1 ###........................................................................
  0 ...........................................................................
Y/X 012345678901234567890123456789012345678901234567890123456789012345678901234
> press ENTER for line between points (2,14) and (64,2)...
 22 ...........................................................................
 21 ...........................................................................
 20 ...........................................................................
 19 ...........................................................................
 18 ...........................................................................
 17 ...........................................................................
 16 ...........................................................................
 15 ...........................................................................
 14 ..###......................................................................
 13 .....#####.................................................................
 12 ..........#####............................................................
 11 ...............######......................................................
 10 .....................#####.................................................
  9 ..........................#####............................................
  8 ...............................#####.......................................
  7 ....................................#####..................................
  6 .........................................#####.............................
  5 ..............................................######.......................
  4 ....................................................#####..................
  3 .........................................................#####.............
  2 ..............................................................###..........
  1 ...........................................................................
  0 ...........................................................................
Y/X 012345678901234567890123456789012345678901234567890123456789012345678901234
> press ENTER for circle with center (30,11) and radius 10...
 22 ...........................................................................
 21 ...........................#######.........................................
 20 .........................##.......##.......................................
 19 ........................#...........#......................................
 18 .......................#.............#.....................................
 17 ......................#...............#....................................
 16 .....................#.................#...................................
 15 .....................#.................#...................................
 14 ....................#...................#..................................
 13 ....................#...................#..................................
 12 ....................#...................#..................................
 11 ....................#...................#..................................
 10 ....................#...................#..................................
  9 ....................#...................#..................................
  8 ....................#...................#..................................
  7 .....................#.................#...................................
  6 .....................#.................#...................................
  5 ......................#...............#....................................
  4 .......................#.............#.....................................
  3 ........................#...........#......................................
  2 .........................##.......##.......................................
  1 ...........................#######.........................................
  0 ...........................................................................
Y/X 012345678901234567890123456789012345678901234567890123456789012345678901234
> press ENTER for ellipsis in rect: (2,20)-(60,2) ...
 22 ...........................................................................
 21 ...........................................................................
 20 ......................###################..................................
 19 ................######...................######............................
 18 ............####...............................####........................
 17 .........###.......................................###.....................
 16 ......###.............................................###..................
 15 .....#...................................................#.................
 14 ....#.....................................................#................
 13 ...#.......................................................#...............
 12 ..#.........................................................#..............
 11 ..#.........................................................#..............
 10 ..#.........................................................#..............
  9 ...#.......................................................#...............
  8 ....#.....................................................#................
  7 .....#...................................................#.................
  6 ......###.............................................###..................
  5 .........###.......................................###.....................
  4 ............####...............................####........................
  3 ................######...................######............................
  2 ......................###################..................................
  1 ...........................................................................
  0 ...........................................................................
Y/X 012345678901234567890123456789012345678901234567890123456789012345678901234
> press ENTER to exit...