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