fork(2) download
  1. /* -----------------------------------------------------------------------
  2.  * Από: migf1 Primitive Text Graphics Plotter v1.5
  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. #include <ctype.h> // for tolower()
  40.  
  41. #define MAXCOLS 75 // μέγιστο πλάτος της οθόνης μας
  42. #define MAXROWS 23 // μέγιστο ύψος της οθόνης μας
  43.  
  44. #define PIXEL_ON '#' // χαρακτήρας απεικόνισης "αναμμένων" pixels
  45. #define PIXEL_OFF '.' // χαρακτήρας απεικόνισης "σβησμένων" pixels
  46.  
  47. // έλεγχος για pixels εκτός ορίων
  48. #define VALIDPIXEL(x,y, w,h) ( (y) > -1 && (y) < (h) && (x) > -1 && (x) < (w) )
  49.  
  50. #define REVAXIS(y,h) (h) - (y) - 1 // προσαρμόζει την συντεταγμένη y ώστε το σημείο
  51. // που της αντιστοιχεί να απεικονιστεί στην
  52. // αντεστραμμένη φορά του άξονά (χρήσιμο για τον
  53. // άξονα Υ που τον θέλουμε να μετράει από κάτω
  54. // προς τα πάνω)
  55.  
  56. #define ABS(x) ( (x) < 0 ? -(x) : (x) )
  57.  
  58. #define PAUSE() do{\
  59. char myinbuf[256]; \
  60. printf("press ENTER to continue..."); \
  61. fgets(myinbuf, 256, stdin); \
  62. }while(0)
  63.  
  64.  
  65. typedef struct point { // δομή καρτεσιανού σημείου
  66. int x; // καρτεσιανή συντεταγμένη x του σημείου
  67. int y; // καρτεσιανή συντεταγμένη y του σημείου
  68. } Point;
  69.  
  70. typedef struct screen { // δομή για το buffer της οθόνης μας
  71. int nrows; // τρέχον πλάτος της οθόνης μας
  72. int ncols; // τρέχον ύψος της οθόνης μας
  73. char pixel[MAXROWS][MAXCOLS]; // το buffer της οθόνης μας
  74. } Screen;
  75.  
  76. // ------------------------------------------------------------------------------------
  77. // set_pixel:
  78. //
  79. // "Ανάβει" το pixel x,y στο buffer της οθόνης. Θα εμφανιστεί αναμένο όταν αργότερα
  80. // τυπωθεί το buffer μέσω της συνάρτησης: draw_screen
  81. //
  82. void set_pixel( Screen *screen, int x, int y )
  83. {
  84. // απόρριψη pixels που βγαίνουν εκτός οθόνης
  85. if ( !VALIDPIXEL(x,y, screen->ncols, screen->nrows ) )
  86. return;
  87. // προσαρμογή του y ώστε το μέτρημα για την
  88. y = REVAXIS(y, screen->nrows); // απεικόνιση να ξεκινά από κάτω προς τα επανω
  89. screen->pixel[y][x] = PIXEL_ON;
  90.  
  91. return;
  92. }
  93.  
  94. // ------------------------------------------------------------------------------------
  95. // Η συνάρτηση που παράγει το 1ο γράφημα, δοκιμάστε και με άλλες τιμές
  96. //
  97. int f( int x, float a, float b )
  98. {
  99. return a*x + b;
  100. }
  101.  
  102. // ------------------------------------------------------------------------------------
  103. // plot_f():
  104. //
  105. // "Ανάβει" τα pixels που αντιστοιχούν στο γράφημα της συνάρτησης f(), στο buffer της
  106. // οθόνης (θα εμφανιστούν αναμμένα όταν αργότερα τυπωθεί το buffer μέσω της συνάρτησης:
  107. // draw_screen() )
  108. //
  109. void plot_f( Screen *screen, float a, float b )
  110. {
  111. register int x;
  112. for (x=0; x < screen->ncols; x++)
  113. set_pixel( screen, x, f(x, a, b) );
  114.  
  115. return;
  116. }
  117.  
  118. // ------------------------------------------------------------------------------------
  119. // plot_line():
  120. // αλγόριθμος: http://f...content-available-to-author-only...s.at/easyfilter/bresenham.html
  121. //
  122. // "Ανάβει" τα pixels της γραμμής που οριοθετείται από τα σημεία pt1 και pt2, στο
  123. // buffer της οθόνης (θα εμφανιστούν αναμμένα όταν αργότερα τυπωθεί το buffer μέσω
  124. // της συνάρτησης: draw_screen() )
  125. //
  126. void plot_line( Screen *screen, Point pt1, Point pt2)
  127. {
  128. int dx = ABS( pt2.x - pt1.x );
  129. int dy = -ABS( pt2.y - pt1.y );
  130. int sx = (pt1.x < pt2.x) ? 1 : -1;
  131. int sy = (pt1.y < pt2.y) ? 1 : -1;
  132. int err = dx + dy, e2; // error value e_xy
  133.  
  134. for (;;)
  135. {
  136. set_pixel(screen, pt1.x, pt1.y);
  137. if ( pt1.x == pt2.x && pt1.y == pt2.y )
  138. break;
  139. e2 = 2 * err;
  140. if (e2 >= dy) { // e_xy + e_x > 0
  141. err += dy;
  142. pt1.x += sx;
  143. }
  144. if (e2 <= dx) { // e_xy + e_y < 0 */
  145. err += dx;
  146. pt1.y += sy;
  147. }
  148. }
  149.  
  150. return;
  151. }
  152.  
  153. // ------------------------------------------------------------------------------------
  154. // plot_circle():
  155. // αλγόριθμος: http://f...content-available-to-author-only...s.at/easyfilter/bresenham.html
  156. //
  157. // "Ανάβει" τα pixels της περιφέρειας του κύκλου με κέντρο το σημείο: center και ακτίνα
  158. // radius, στο buffer της οθόνης (θα εμφανιστούν αναμμένα όταν αργότερα τυπωθεί το
  159. // buffer μέσω της συνάρτησης: draw_screen() )
  160. //
  161. void plot_circle(Screen *screen, Point center, int radius)
  162. {
  163. int x = -radius, y = 0, err = 2-2*radius; // II. Quadrant
  164. do {
  165. set_pixel(screen, center.x-x, center.y+y); // I. Quadrant
  166. set_pixel(screen, center.x-y, center.y-x); // II. Quadrant
  167. set_pixel(screen, center.x+x, center.y-y); // III. Quadrant
  168. set_pixel(screen, center.x+y, center.y+x); // IV. Quadrant
  169. radius = err;
  170. if (radius > x) // e_xy + e_x > 0
  171. err += ++x * 2 + 1;
  172. if (radius <= y)
  173. err += ++y * 2 + 1; // e_xy + e_y < 0
  174. } while (x < 0);
  175.  
  176. return;
  177. }
  178.  
  179. // ------------------------------------------------------------------------------------
  180. // plot_ellipse():
  181. // αλγόριθμος: http://f...content-available-to-author-only...s.at/easyfilter/bresenham.html
  182. //
  183. // "Ανάβει" στο buffer της οθόνης τα pixels της περιφέρειας της έλλειψης που
  184. // οριοθετείται από ένα παραλληλόγραμμο με την πάνω-αριστερή γωνία του στο
  185. // σημείο: rsta και την κάτω-δεξιά γωνία στου στο σημείο: rend (τα pixels θσ
  186. // εμφανιστούν αναμμένα όταν αργότερα τυπωθεί το buffer μέσω της συνάρτησης:
  187. // draw_screen() )
  188. //
  189. void plot_ellipse( Screen *screen, Point rsta, Point rend )
  190. {
  191. // values of diameter
  192. int a = ABS( rend.x - rsta.x );
  193. int b = ABS( rend.y - rsta.y );
  194. int b1 = b & 1;
  195.  
  196. // error increment
  197. long dx = 4 * (1-a) * b * b;
  198. long dy = 4 * (b1+1) *a * a;
  199.  
  200. // error of 1.step
  201. long err = dx + dy + b1 * a * a;
  202. long e2;
  203.  
  204. if (rsta.x > rend.x) { // if called with swapped points
  205. rsta.x = rend.x;
  206. rend.x += a;
  207. }
  208. if (rsta.y > rend.y) // ... exchange them
  209. rsta.y = rend.y;
  210.  
  211. // starting pixel
  212. rsta.y += (b+1)/2;
  213. rend.y = rsta.y-b1;
  214.  
  215. a *= 8 * a;
  216. b1 = 8 * b * b;
  217.  
  218. do {
  219. set_pixel(screen, rend.x, rsta.y); // I. Quadrant
  220. set_pixel(screen, rsta.x, rsta.y); // II. Quadrant
  221. set_pixel(screen, rsta.x, rend.y); // III. Quadrant
  222. set_pixel(screen, rend.x, rend.y); // IV. Quadrant
  223. e2 = 2 * err;
  224. if (e2 >= dx) { // x step
  225. rsta.x++;
  226. rend.x--;
  227. err += dx += b1;
  228. }
  229. if (e2 <= dy) { // y step
  230. rsta.y++;
  231. rend.y--;
  232. err += dy += a;
  233. }
  234. } while ( rsta.x <= rend.x );
  235.  
  236. while ( rsta.y - rend.y < b ) { // too early stop of flat ellipses a=1
  237. set_pixel(screen, rsta.x - 1, rsta.y);// -> finish tip of ellipse
  238. set_pixel(screen, rend.x + 1, rsta.y++);
  239. set_pixel(screen, rsta.x - 1, rend.y);
  240. set_pixel(screen, rend.x + 1, rend.y--);
  241. }
  242.  
  243. return;
  244. }
  245.  
  246. // ------------------------------------------------------------------------------------
  247. // "Σβήνει" όλα τα pixels στο buffer της οθόνης (α εμφανιστούν σβησμένα όταν αργότερα
  248. // τυπωθεί η οθόνη μέσω της συνάρτησης: draw_screen() )
  249. //
  250. void clear_screen( Screen *screen )
  251. {
  252. // γρήγορος κώδικας
  253. memset( &screen->pixel, PIXEL_OFF, screen->nrows * screen->ncols * sizeof(char));
  254.  
  255. /*** DISABLED: αργός εναλλακτικός κώδικας, αλλά ενδεχομένως πιο συμβατός
  256. register int x,y;
  257.  
  258. for (y=0; y < screen->nrows; y++)
  259. for (x=0; x < screen->ncols; x++)
  260. screen->pixel[y][x] = PIXEL_OFF;
  261. ***/
  262.  
  263. return;
  264. }
  265.  
  266. // ------------------------------------------------------------------------------------
  267. // draw_screen():
  268. //
  269. // Τυπώνει όλα τα pixels του buffer (αναμμένα και σβηστά) καθώς και την αρίθμηση
  270. // των αξόνων Χ και Υ
  271. //
  272. void draw_screen( Screen screen )
  273. {
  274. register int x, y;
  275.  
  276. for (y=0; y < screen.nrows; y++)
  277. {
  278. // τύπωμα ετικετών αριστερά από τον άξονα Υ
  279. int ylab = y;
  280. printf("%3d ", REVAXIS(ylab, screen.nrows) );
  281.  
  282. // τύπωμα των pixels της y-οστής σειράς του buffer
  283. for (x=0; x < screen.ncols; x++)
  284. putchar( screen.pixel[y][x] );
  285. putchar('\n');
  286. }
  287.  
  288. // τύπωμα ετικετών κάτω από τον άξονα Χ
  289. printf("Y/X ");
  290. for (x=0; x < screen.ncols; x++)
  291. printf("%d", x%10);
  292. putchar('\n');
  293.  
  294. return;
  295. }
  296.  
  297. // ------------------------------------------------------------------------------------
  298. void show_help( void )
  299. {
  300. puts("\n\tHELP:\n\n\tA sample program in C for plotting primitive 2D text graphics.");
  301. puts("\tIt shows buffered plotting of a Line, a Circle, an Ellipse");
  302. puts("\tand a function of the form: f(x) = a * x + b");
  303.  
  304. puts("\n\tIt also shows how to read input lines as strings, brake 'em");
  305. puts("\tup to tokens, and convert those tokens to desirable numbers");
  306. puts("\t(using atoi() and atof() for keeping things simple).");
  307.  
  308. puts("\n\tFor each plot you will be first asked for appropriate input:");
  309. puts("\t-\ta and b, for the function");
  310. puts("\t-\tstarting and ending points, for the line");
  311. puts("\t-\tcenter point and radius, for the circle");
  312. puts("\t-\ttop-left and right-bottom points for the ellipse");
  313. puts("\t\t( they define the rectangle the ellipse \"lives in\" )");
  314.  
  315. puts("\n\tComas, dashes, parenthesis, spaces and tabs are ignored");
  316. puts("\tduring the input. Any other non-numerical input is either");
  317. puts("\tignored or cause the conversion to produce 0 as the result");
  318. puts("\tof the converted numbers.");
  319.  
  320. puts("\n\tEXCEPTION: in the main menu, only the first input char is checked");
  321.  
  322. printf("\n\t");
  323.  
  324. return;
  325. }
  326. // ------------------------------------------------------------------------------------
  327. void show_menu( void )
  328. {
  329. puts("\n\n\n\n\n\n\n\n\n\n\n\n\n");
  330. printf("%38s\n", "by migf1");
  331. puts("\n\tPrimitive Text Graphics Plotter\n\t-------------------------------");
  332. puts("\th\t: Help");
  333. puts("\tf\t: plot F(x) = a*x + b");
  334. puts("\tl\t: plot a Line");
  335. puts("\tc\t: plot a Circle");
  336. puts("\te\t: plot an Ellipse");
  337. puts("\tx\t: eXit");
  338. printf("\tselect: ");
  339.  
  340. return;
  341. }
  342.  
  343. // ------------------------------------------------------------------------------------
  344. int s_tokenize(char *s, char *tokens[], int maxtokens, const char *delimiters)
  345. {
  346. register int i=0;
  347.  
  348. tokens[0] = strtok(s, delimiters);
  349. if (tokens[0] == NULL)
  350. return 0;
  351. for (i=1; i < maxtokens && (tokens[i]=strtok(NULL, delimiters)) != NULL; i++);
  352.  
  353. return i;
  354. }
  355.  
  356. // ------------------------------------------------------------------------------------
  357. void exec_selected( Screen *screen, char choice )
  358. {
  359. Point ptsta, ptend;
  360. float a, b; int radius, ntoks;
  361. char input[255+1] = ""; char *tokens[4]; const char *delims = "\n\t (),-";
  362.  
  363. switch( choice )
  364. {
  365. case 'h': // HELP
  366. show_help();
  367. PAUSE();
  368. break;
  369.  
  370. case 'f': // FUNCTION: y = a*x + b
  371. puts("\n\tPlotting: y = a * x + b ...");
  372.  
  373. // διάβασμα του a
  374. do {
  375. printf("\tenter a: ");
  376. fgets(input, 255+1, stdin);
  377. ntoks = s_tokenize(input, tokens, 1, delims);
  378. } while ( ntoks < 1);
  379. a = atof(input);
  380.  
  381. // διάβασμα του b
  382. do {
  383. printf("\tenter b: ");
  384. fgets(input, 255+1, stdin);
  385. ntoks = s_tokenize(input, tokens, 1, delims);
  386. } while ( ntoks < 1);
  387. b = atof(input);
  388.  
  389. // σχεδιασμός του γραφήματος της συναρτησης
  390. clear_screen( screen );
  391. plot_f( screen, a, b);
  392. draw_screen( *screen );
  393.  
  394. printf("\tFunction: y = %.2f * x + %.2f ... ", a, b);
  395. PAUSE();
  396. break;
  397.  
  398. case 'l': // LINE
  399. puts("\n\tPlotting a line...");
  400.  
  401. // διάβασμα αρχικού σημείου: ptsta
  402. do {
  403. printf("\tenter 1st point (x,y): ");
  404. fgets(input, 255+1, stdin);
  405. ntoks = s_tokenize(input, tokens, 2, delims);
  406. } while( ntoks < 2);
  407. ptsta.x = atoi( tokens[0] );
  408. ptsta.y = atoi( tokens[1] );
  409.  
  410. // διάβασμα τελικού σημείου: ptend
  411. do {
  412. printf("\tenter 2nd point (x,y): ");
  413. fgets(input, 255+1, stdin);
  414. ntoks = s_tokenize(input, tokens, 2, delims);
  415. } while( ntoks < 2);
  416. ptend.x = atoi( tokens[0] );
  417. ptend.y = atoi( tokens[1] );
  418.  
  419. // σχεδιασμός της γραμμής
  420. clear_screen( screen );
  421. plot_line( screen, ptsta, ptend );
  422. draw_screen( *screen );
  423.  
  424. printf( "\tLine from (%d,%d) to (%d,%d) ... ",
  425. ptsta.x, ptsta.y, ptend.x, ptend.y );
  426. PAUSE();
  427. break;
  428.  
  429. case 'c': // CIRCLE
  430. puts("\n\tPlotting a circle...");
  431.  
  432. // διάβασμα κέντρου: ptsta
  433. do {
  434. printf("\tenter center point (x,y): ");
  435. fgets(input, 255+1, stdin);
  436. ntoks = s_tokenize(input, tokens, 2, delims);
  437. } while( ntoks < 2);
  438. ptsta.x = atoi( tokens[0] );
  439. ptsta.y = atoi( tokens[1] );
  440.  
  441. // διάβασμα της ακτίνας: radius
  442. do {
  443. printf("\tenter radius: ");
  444. fgets(input, 255+1, stdin);
  445. ntoks = s_tokenize(input, tokens, 1, delims);
  446. } while ( ntoks < 1);
  447. radius = atoi( input );
  448.  
  449. // σχεδιασμός της κύκλου
  450. clear_screen( screen );
  451. plot_circle( screen, ptsta, radius );
  452. draw_screen( *screen );
  453.  
  454. printf( "\tCircle with center (%d,%d) & radius %d ... ",
  455. ptsta.x, ptsta.y, radius );
  456. PAUSE();
  457.  
  458. break;
  459.  
  460. case 'e': // ELLIPSE
  461. puts("\n\tPlotting an ellipse...");
  462.  
  463. // διάβασμα πάνω-αριστερής γωνίας: ptsta
  464. do {
  465. printf("\tenter top-left point (x,y): ");
  466. fgets(input, 255+1, stdin);
  467. ntoks = s_tokenize(input, tokens, 2, delims);
  468. } while( ntoks < 2);
  469. ptsta.x = atoi( tokens[0] );
  470. ptsta.y = atoi( tokens[1] );
  471.  
  472. // διάβασμα κάτω-δεξιάς γωνίας: ptend
  473. do {
  474. printf("\tenter bottom-right point (x,y): ");
  475. fgets(input, 255+1, stdin);
  476. ntoks = s_tokenize(input, tokens, 2, delims);
  477. } while( ntoks < 2);
  478. ptend.x = atoi( tokens[0] );
  479. ptend.y = atoi( tokens[1] );
  480.  
  481. // σχεδιασμός της έλλειψης
  482. clear_screen( screen );
  483. plot_ellipse( screen, ptsta, ptend );
  484. draw_screen( *screen );
  485.  
  486. printf( "\tEllipse from (%d,%d) to (%d,%d) ... ",
  487. ptsta.x, ptsta.y, ptend.x, ptend.y );
  488. PAUSE();
  489. break;
  490.  
  491. case '\n': // empty selection
  492. break;
  493.  
  494. default:
  495. puts("\t*** error: unrecognised selection, try again");
  496. break;
  497. }
  498.  
  499. return;
  500. }
  501. // ------------------------------------------------------------------------------------
  502. int main( void )
  503. {
  504. char input[255+1] = "";
  505. Screen screen = { .ncols = MAXCOLS, .nrows = MAXROWS };
  506.  
  507. do {
  508. show_menu();
  509. fgets(input, 255+1, stdin);
  510. if ( tolower(*input) != 'x' )
  511. exec_selected( &screen, *input );
  512. } while ( *input != 'x' );
  513.  
  514. exit( EXIT_SUCCESS );
  515. }
  516.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty