You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
преди 21 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * libcucul Unicode canvas library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file line.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Line drawing
  15. *
  16. * This file contains line and polyline drawing functions, with both thin
  17. * and thick styles.
  18. */
  19. #include "config.h"
  20. #if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
  21. # include <inttypes.h>
  22. #else
  23. typedef unsigned char uint8_t;
  24. #endif
  25. #include <stdlib.h>
  26. #include "cucul.h"
  27. #include "cucul_internals.h"
  28. #if !defined(_DOXYGEN_SKIP_ME)
  29. struct line
  30. {
  31. int x1, y1;
  32. int x2, y2;
  33. char c;
  34. void (*draw) (cucul_t *, struct line*);
  35. };
  36. #endif
  37. static void clip_line(cucul_t*, struct line*);
  38. static uint8_t clip_bits(cucul_t*, int, int);
  39. static void draw_solid_line(cucul_t*, struct line*);
  40. static void draw_thin_line(cucul_t*, struct line*);
  41. /**
  42. * \brief Draw a line on the screen using the given character.
  43. *
  44. * \param x1 X coordinate of the first point.
  45. * \param y1 Y coordinate of the first point.
  46. * \param x2 X coordinate of the second point.
  47. * \param y2 Y coordinate of the second point.
  48. * \param c Character to draw the line with.
  49. * \return void
  50. */
  51. void cucul_draw_line(cucul_t *qq, int x1, int y1, int x2, int y2, char c)
  52. {
  53. struct line s;
  54. s.x1 = x1;
  55. s.y1 = y1;
  56. s.x2 = x2;
  57. s.y2 = y2;
  58. s.c = c;
  59. s.draw = draw_solid_line;
  60. clip_line(qq, &s);
  61. }
  62. /**
  63. * \brief Draw a polyline on the screen using the given character and
  64. * coordinate arrays. The first and last points are not connected,
  65. * so in order to draw a polygon you need to specify the starting
  66. * point at the end of the list as well.
  67. *
  68. * \param x Array of X coordinates. Must have \p n + 1 elements.
  69. * \param y Array of Y coordinates. Must have \p n + 1 elements.
  70. * \param n Number of lines to draw.
  71. * \param c Character to draw the lines with.
  72. * \return void
  73. */
  74. void cucul_draw_polyline(cucul_t *qq, int const x[], int const y[], int n, char c)
  75. {
  76. int i;
  77. struct line s;
  78. s.c = c;
  79. s.draw = draw_solid_line;
  80. for(i = 0; i < n; i++)
  81. {
  82. s.x1 = x[i];
  83. s.y1 = y[i];
  84. s.x2 = x[i+1];
  85. s.y2 = y[i+1];
  86. clip_line(qq, &s);
  87. }
  88. }
  89. /**
  90. * \brief Draw a thin line on the screen, using ASCII art.
  91. *
  92. * \param x1 X coordinate of the first point.
  93. * \param y1 Y coordinate of the first point.
  94. * \param x2 X coordinate of the second point.
  95. * \param y2 Y coordinate of the second point.
  96. * \return void
  97. */
  98. void cucul_draw_thin_line(cucul_t *qq, int x1, int y1, int x2, int y2)
  99. {
  100. struct line s;
  101. s.x1 = x1;
  102. s.y1 = y1;
  103. s.x2 = x2;
  104. s.y2 = y2;
  105. s.draw = draw_thin_line;
  106. clip_line(qq, &s);
  107. }
  108. /**
  109. * \brief Draw a thin polyline on the screen using the given coordinate
  110. * arrays and with ASCII art. The first and last points are not
  111. * connected, so in order to draw a polygon you need to specify the
  112. * starting point at the end of the list as well.
  113. *
  114. * \param x Array of X coordinates. Must have \p n + 1 elements.
  115. * \param y Array of Y coordinates. Must have \p n + 1 elements.
  116. * \param n Number of lines to draw.
  117. * \return void
  118. */
  119. void cucul_draw_thin_polyline(cucul_t *qq, int const x[], int const y[], int n)
  120. {
  121. int i;
  122. struct line s;
  123. s.draw = draw_thin_line;
  124. for(i = 0; i < n; i++)
  125. {
  126. s.x1 = x[i];
  127. s.y1 = y[i];
  128. s.x2 = x[i+1];
  129. s.y2 = y[i+1];
  130. clip_line(qq, &s);
  131. }
  132. }
  133. /*
  134. * XXX: The following functions are local.
  135. */
  136. /**
  137. * \brief Generic Cohen-Sutherland line clipping function.
  138. *
  139. * \param s a line structure
  140. * \return void
  141. */
  142. static void clip_line(cucul_t *qq, struct line* s)
  143. {
  144. uint8_t bits1, bits2;
  145. bits1 = clip_bits(qq, s->x1, s->y1);
  146. bits2 = clip_bits(qq, s->x2, s->y2);
  147. if(bits1 & bits2)
  148. return;
  149. if(bits1 == 0)
  150. {
  151. if(bits2 == 0)
  152. s->draw(qq, s);
  153. else
  154. {
  155. int tmp;
  156. tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
  157. tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
  158. clip_line(qq, s);
  159. }
  160. return;
  161. }
  162. if(bits1 & (1<<0))
  163. {
  164. s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
  165. s->x1 = 0;
  166. }
  167. else if(bits1 & (1<<1))
  168. {
  169. int xmax = qq->width - 1;
  170. s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
  171. s->x1 = xmax;
  172. }
  173. else if(bits1 & (1<<2))
  174. {
  175. s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
  176. s->y1 = 0;
  177. }
  178. else if(bits1 & (1<<3))
  179. {
  180. int ymax = qq->height - 1;
  181. s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
  182. s->y1 = ymax;
  183. }
  184. clip_line(qq, s);
  185. }
  186. /**
  187. * \brief Helper function for clip_line().
  188. *
  189. * \param x X coordinate of the point.
  190. * \param y Y coordinate of the point.
  191. * \return The clipping bits for the given point.
  192. */
  193. static uint8_t clip_bits(cucul_t *qq, int x, int y)
  194. {
  195. uint8_t b = 0;
  196. if(x < 0)
  197. b |= (1<<0);
  198. else if(x >= (int)qq->width)
  199. b |= (1<<1);
  200. if(y < 0)
  201. b |= (1<<2);
  202. else if(y >= (int)qq->height)
  203. b |= (1<<3);
  204. return b;
  205. }
  206. /**
  207. * \brief Solid line drawing function, using Bresenham's mid-point line
  208. * scan-conversion algorithm.
  209. *
  210. * \param s a line structure
  211. * \return void
  212. */
  213. static void draw_solid_line(cucul_t *qq, struct line* s)
  214. {
  215. int x1, y1, x2, y2;
  216. int dx, dy;
  217. int xinc, yinc;
  218. x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
  219. dx = abs(x2 - x1);
  220. dy = abs(y2 - y1);
  221. xinc = (x1 > x2) ? -1 : 1;
  222. yinc = (y1 > y2) ? -1 : 1;
  223. if(dx >= dy)
  224. {
  225. int dpr = dy << 1;
  226. int dpru = dpr - (dx << 1);
  227. int delta = dpr - dx;
  228. for(; dx>=0; dx--)
  229. {
  230. cucul_putchar(qq, x1, y1, s->c);
  231. if(delta > 0)
  232. {
  233. x1 += xinc;
  234. y1 += yinc;
  235. delta += dpru;
  236. }
  237. else
  238. {
  239. x1 += xinc;
  240. delta += dpr;
  241. }
  242. }
  243. }
  244. else
  245. {
  246. int dpr = dx << 1;
  247. int dpru = dpr - (dy << 1);
  248. int delta = dpr - dy;
  249. for(; dy >= 0; dy--)
  250. {
  251. cucul_putchar(qq, x1, y1, s->c);
  252. if(delta > 0)
  253. {
  254. x1 += xinc;
  255. y1 += yinc;
  256. delta += dpru;
  257. }
  258. else
  259. {
  260. y1 += yinc;
  261. delta += dpr;
  262. }
  263. }
  264. }
  265. }
  266. /**
  267. * \brief Thin line drawing function, using Bresenham's mid-point line
  268. * scan-conversion algorithm and ASCII art graphics.
  269. *
  270. * \param s a line structure
  271. * \return void
  272. */
  273. static void draw_thin_line(cucul_t *qq, struct line* s)
  274. {
  275. char *charmapx, *charmapy;
  276. int x1, y1, x2, y2;
  277. int dx, dy;
  278. int yinc;
  279. if(s->x2 >= s->x1)
  280. {
  281. if(s->y1 > s->y2)
  282. charmapx = ",'";
  283. else
  284. charmapx = "`.";
  285. x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
  286. }
  287. else
  288. {
  289. if(s->y1 > s->y2)
  290. charmapx = "`.";
  291. else
  292. charmapx = ",'";
  293. x2 = s->x1; y2 = s->y1; x1 = s->x2; y1 = s->y2;
  294. }
  295. dx = abs(x2 - x1);
  296. dy = abs(y2 - y1);
  297. if(y1 > y2)
  298. {
  299. charmapy = ",'";
  300. yinc = -1;
  301. }
  302. else
  303. {
  304. yinc = 1;
  305. charmapy = "`.";
  306. }
  307. if(dx >= dy)
  308. {
  309. int dpr = dy << 1;
  310. int dpru = dpr - (dx << 1);
  311. int delta = dpr - dx;
  312. int prev = 0;
  313. for(; dx>=0; dx--)
  314. {
  315. if(delta > 0)
  316. {
  317. cucul_putchar(qq, x1, y1, charmapy[1]);
  318. x1++;
  319. y1 += yinc;
  320. delta += dpru;
  321. prev = 1;
  322. }
  323. else
  324. {
  325. if(prev)
  326. cucul_putchar(qq, x1, y1, charmapy[0]);
  327. else
  328. cucul_putchar(qq, x1, y1, '-');
  329. x1++;
  330. delta += dpr;
  331. prev = 0;
  332. }
  333. }
  334. }
  335. else
  336. {
  337. int dpr = dx << 1;
  338. int dpru = dpr - (dy << 1);
  339. int delta = dpr - dy;
  340. for(; dy >= 0; dy--)
  341. {
  342. if(delta > 0)
  343. {
  344. cucul_putchar(qq, x1, y1, charmapx[0]);
  345. cucul_putchar(qq, x1 + 1, y1, charmapx[1]);
  346. x1++;
  347. y1 += yinc;
  348. delta += dpru;
  349. }
  350. else
  351. {
  352. cucul_putchar(qq, x1, y1, '|');
  353. y1 += yinc;
  354. delta += dpr;
  355. }
  356. }
  357. }
  358. }