Graphics.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /* Graphics.cpp
  2. *
  3. * Copyright (C) 1992-2008,2010-2018 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <stdarg.h>
  19. #include "GraphicsP.h"
  20. #include "enums_getText.h"
  21. #include "Graphics_enums.h"
  22. #include "enums_getValue.h"
  23. #include "Graphics_enums.h"
  24. #include "GuiP.h"
  25. #include "Preferences.h"
  26. /***** Methods *****/
  27. Thing_implement (Graphics, Thing, 0);
  28. enum kGraphics_cjkFontStyle theGraphicsCjkFontStyle;
  29. void Graphics_prefs () {
  30. Preferences_addEnum (U"Graphics.cjkFontStyle", & theGraphicsCjkFontStyle, kGraphics_cjkFontStyle, (int) kGraphics_cjkFontStyle::DEFAULT);
  31. }
  32. void structGraphics :: v_destroy () noexcept {
  33. Melder_free (record);
  34. Graphics_Parent :: v_destroy ();
  35. }
  36. static void computeTrafo (Graphics me) {
  37. double worldScaleX, worldScaleY, workScaleX, workScaleY;
  38. Melder_assert (my d_x2WC != my d_x1WC);
  39. worldScaleX = (my d_x2NDC - my d_x1NDC) / (my d_x2WC - my d_x1WC);
  40. Melder_assert (my d_y2WC != my d_y1WC);
  41. worldScaleY = (my d_y2NDC - my d_y1NDC) / (my d_y2WC - my d_y1WC);
  42. my deltaX = my d_x1NDC - my d_x1WC * worldScaleX;
  43. my deltaY = my d_y1NDC - my d_y1WC * worldScaleY;
  44. Melder_assert (my d_x2wNDC != my d_x1wNDC);
  45. workScaleX = (my d_x2DC - my d_x1DC) / (my d_x2wNDC - my d_x1wNDC);
  46. my deltaX = my d_x1DC - (my d_x1wNDC - my deltaX) * workScaleX;
  47. my scaleX = worldScaleX * workScaleX;
  48. Melder_assert (my d_y2wNDC != my d_y1wNDC);
  49. if (my yIsZeroAtTheTop) {
  50. workScaleY = ((int) my d_y1DC - (int) my d_y2DC) / (my d_y2wNDC - my d_y1wNDC);
  51. my deltaY = my d_y2DC - (my d_y1wNDC - my deltaY) * workScaleY;
  52. } else {
  53. workScaleY = ((int) my d_y2DC - (int) my d_y1DC) / (my d_y2wNDC - my d_y1wNDC);
  54. my deltaY = my d_y1DC - (my d_y1wNDC - my deltaY) * workScaleY;
  55. }
  56. my scaleY = worldScaleY * workScaleY;
  57. }
  58. /***** WORKSTATION FUNCTIONS *****/
  59. void Graphics_init (Graphics me, int resolution) {
  60. my resolution = resolution;
  61. if (resolution == 90) {
  62. my resolutionNumber = kGraphics_resolution::DPI_90;
  63. } else if (resolution == 96) {
  64. my resolutionNumber = kGraphics_resolution::DPI_96;
  65. } else if (resolution == 100) {
  66. my resolutionNumber = kGraphics_resolution::DPI_100;
  67. } else if (resolution == 180) {
  68. my resolutionNumber = kGraphics_resolution::DPI_180;
  69. } else if (resolution == 200) {
  70. my resolutionNumber = kGraphics_resolution::DPI_200;
  71. } else if (resolution == 300) {
  72. my resolutionNumber = kGraphics_resolution::DPI_300;
  73. } else if (resolution == 360) {
  74. my resolutionNumber = kGraphics_resolution::DPI_360;
  75. } else if (resolution == 600) {
  76. my resolutionNumber = kGraphics_resolution::DPI_600;
  77. } else if (resolution == 720) {
  78. my resolutionNumber = kGraphics_resolution::DPI_720;
  79. } else if (resolution == 900) {
  80. my resolutionNumber = kGraphics_resolution::DPI_900;
  81. } else if (resolution == 1200) {
  82. my resolutionNumber = kGraphics_resolution::DPI_1200;
  83. } else {
  84. Melder_fatal (U"Unsupported resolution ", resolution, U" dpi.");
  85. }
  86. my d_x1DC = my d_x1DCmin = 0; my d_x2DC = my d_x2DCmax = 32767;
  87. my d_y1DC = my d_y1DCmin = 0; my d_y2DC = my d_y2DCmax = 32767;
  88. my d_x1WC = my d_x1NDC = my d_x1wNDC = 0.0;
  89. my d_x2WC = my d_x2NDC = my d_x2wNDC = 1.0;
  90. my d_y1WC = my d_y1NDC = my d_y1wNDC = 0.0;
  91. my d_y2WC = my d_y2NDC = my d_y2wNDC = 1.0;
  92. computeTrafo (me);
  93. my lineWidth = 1.0;
  94. my arrowSize = 1.0;
  95. my speckleSize = 1.0;
  96. my font = kGraphics_font::HELVETICA;
  97. my fontSize = 10;
  98. my fontStyle = Graphics_NORMAL;
  99. my record = nullptr;
  100. my irecord = my nrecord = 0;
  101. my percentSignIsItalic = 1;
  102. my numberSignIsBold = 1;
  103. my circumflexIsSuperscript = 1;
  104. my underscoreIsSubscript = 1;
  105. my dollarSignIsCode = 0;
  106. my atSignIsLink = 0;
  107. }
  108. autoGraphics Graphics_create (int resolution) {
  109. autoGraphics me = Thing_new (Graphics);
  110. Graphics_init (me.get(), resolution);
  111. return me;
  112. }
  113. int Graphics_getResolution (Graphics me) {
  114. return my resolution;
  115. }
  116. void Graphics_setWsViewport (Graphics me,
  117. integer x1DC, integer x2DC, integer y1DC, integer y2DC)
  118. {
  119. if (x1DC < my d_x1DCmin || x2DC > my d_x2DCmax || y1DC < my d_y1DCmin || y2DC > my d_y2DCmax) {
  120. Melder_warning (U"Graphics_setWsViewport: coordinates too large:\n",
  121. x1DC, U"..", x2DC, U" x ", y1DC, U"..", y2DC,
  122. U" goes outside ",
  123. my d_x1DCmin, U"..", my d_x2DCmax, U" x ", my d_y1DCmin, U"..", my d_y2DCmax,
  124. U"."
  125. );
  126. x1DC = my d_x1DCmin;
  127. x2DC = my d_x2DCmax;
  128. y1DC = my d_y1DCmin;
  129. y2DC = my d_y2DCmax;
  130. }
  131. my d_x1DC = x1DC;
  132. my d_x2DC = x2DC;
  133. my d_y1DC = y1DC;
  134. my d_y2DC = y2DC;
  135. #if gdi
  136. if (my screen && my printer) {
  137. GraphicsScreen mescreen = (GraphicsScreen) me;
  138. /*
  139. * Map page coordinates to paper coordinates.
  140. */
  141. mescreen -> d_x1DC -= GetDeviceCaps (mescreen -> d_gdiGraphicsContext, PHYSICALOFFSETX);
  142. mescreen -> d_x2DC -= GetDeviceCaps (mescreen -> d_gdiGraphicsContext, PHYSICALOFFSETX);
  143. mescreen -> d_y1DC -= GetDeviceCaps (mescreen -> d_gdiGraphicsContext, PHYSICALOFFSETY);
  144. mescreen -> d_y2DC -= GetDeviceCaps (mescreen -> d_gdiGraphicsContext, PHYSICALOFFSETY);
  145. }
  146. #endif
  147. computeTrafo (me);
  148. }
  149. void Graphics_resetWsViewport (Graphics me,
  150. integer x1DC, integer x2DC, integer y1DC, integer y2DC)
  151. {
  152. my d_x1DC = x1DC;
  153. my d_x2DC = x2DC;
  154. my d_y1DC = y1DC;
  155. my d_y2DC = y2DC;
  156. computeTrafo (me);
  157. }
  158. void Graphics_inqWsViewport (Graphics me, integer *x1DC, integer *x2DC, integer *y1DC, integer *y2DC) {
  159. *x1DC = my d_x1DC;
  160. *x2DC = my d_x2DC;
  161. *y1DC = my d_y1DC;
  162. *y2DC = my d_y2DC;
  163. }
  164. void Graphics_setWsWindow (Graphics me, double x1NDC, double x2NDC, double y1NDC, double y2NDC) {
  165. my d_x1wNDC = x1NDC;
  166. my d_x2wNDC = x2NDC;
  167. my d_y1wNDC = y1NDC;
  168. my d_y2wNDC = y2NDC;
  169. computeTrafo (me);
  170. if (my recording)
  171. { op (SET_WS_WINDOW, 4); put (x1NDC); put (x2NDC); put (y1NDC); put (y2NDC); }
  172. }
  173. void Graphics_inqWsWindow (Graphics me, double *x1NDC, double *x2NDC, double *y1NDC, double *y2NDC) {
  174. *x1NDC = my d_x1wNDC;
  175. *x2NDC = my d_x2wNDC;
  176. *y1NDC = my d_y1wNDC;
  177. *y2NDC = my d_y2wNDC;
  178. }
  179. /***** CO-ORDINATE TRANFORMATIONS *****/
  180. void Graphics_DCtoWC (Graphics me, integer xDC, integer yDC, double *xWC, double *yWC) {
  181. if (my yIsZeroAtTheTop) {
  182. *xWC = (xDC + 0.5 - my deltaX) / my scaleX;
  183. *yWC = (yDC - 0.5 - my deltaY) / my scaleY;
  184. } else {
  185. *xWC = (xDC + 0.5 - my deltaX) / my scaleX;
  186. *yWC = (yDC + 0.5 - my deltaY) / my scaleY;
  187. }
  188. }
  189. #define wdx(x) ((x) * my scaleX + my deltaX)
  190. #define wdy(y) ((y) * my scaleY + my deltaY)
  191. void Graphics_WCtoDC (Graphics me, double xWC, double yWC, integer *xDC, integer *yDC) {
  192. *xDC = wdx (xWC);
  193. *yDC = wdy (yWC);
  194. }
  195. /***** OUTPUT PRIMITIVES, RECORDABLE *****/
  196. void Graphics_setViewport (Graphics me, double x1NDC, double x2NDC, double y1NDC, double y2NDC) {
  197. trace (U"enter ", x1NDC, U" ", x2NDC, U" ", y1NDC, U" ", y2NDC);
  198. my d_x1NDC = x1NDC;
  199. my d_x2NDC = x2NDC;
  200. my d_y1NDC = y1NDC;
  201. my d_y2NDC = y2NDC;
  202. computeTrafo (me);
  203. if (my recording)
  204. { op (SET_VIEWPORT, 4); put (x1NDC); put (x2NDC); put (y1NDC); put (y2NDC); }
  205. }
  206. void Graphics_setInner (Graphics me) {
  207. double margin = 2.8 * my fontSize * my resolution / 72.0;
  208. double wDC = (my d_x2DC - my d_x1DC) / (my d_x2wNDC - my d_x1wNDC) * (my d_x2NDC - my d_x1NDC);
  209. double hDC = labs (my d_y2DC - my d_y1DC) / (my d_y2wNDC - my d_y1wNDC) * (my d_y2NDC - my d_y1NDC);
  210. double dx = 1.5 * margin / wDC;
  211. double dy = margin / hDC;
  212. my horTick = 0.06 * dx, my vertTick = 0.09 * dy;
  213. if (dx > 0.4) dx = 0.4;
  214. if (dy > 0.4) dy = 0.4;
  215. my horTick /= 1 - 2 * dx, my vertTick /= 1 - 2 * dy;
  216. my outerViewport.x1NDC = my d_x1NDC;
  217. my outerViewport.x2NDC = my d_x2NDC;
  218. my outerViewport.y1NDC = my d_y1NDC;
  219. my outerViewport.y2NDC = my d_y2NDC;
  220. my d_x1NDC = (1 - dx) * my outerViewport.x1NDC + dx * my outerViewport.x2NDC;
  221. my d_x2NDC = (1 - dx) * my outerViewport.x2NDC + dx * my outerViewport.x1NDC;
  222. my d_y1NDC = (1 - dy) * my outerViewport.y1NDC + dy * my outerViewport.y2NDC;
  223. my d_y2NDC = (1 - dy) * my outerViewport.y2NDC + dy * my outerViewport.y1NDC;
  224. trace (U"done ", my d_x1NDC, U" ", my d_x2NDC, U" ", my d_y1NDC, U" ", my d_y2NDC);
  225. computeTrafo (me);
  226. if (my recording) { op (SET_INNER, 0); }
  227. }
  228. void Graphics_unsetInner (Graphics me) {
  229. my d_x1NDC = my outerViewport.x1NDC;
  230. my d_x2NDC = my outerViewport.x2NDC;
  231. my d_y1NDC = my outerViewport.y1NDC;
  232. my d_y2NDC = my outerViewport.y2NDC;
  233. trace (U"done ", my d_x1NDC, U" ", my d_x2NDC, U" ", my d_y1NDC, U" ", my d_y2NDC);
  234. computeTrafo (me);
  235. if (my recording)
  236. { op (UNSET_INNER, 0); }
  237. }
  238. void Graphics_setWindow (Graphics me, double x1WC, double x2WC, double y1WC, double y2WC) {
  239. Melder_assert (x1WC != x2WC);
  240. Melder_assert (y1WC != y2WC);
  241. my d_x1WC = x1WC;
  242. my d_x2WC = x2WC;
  243. my d_y1WC = y1WC;
  244. my d_y2WC = y2WC;
  245. computeTrafo (me);
  246. if (my recording)
  247. { op (SET_WINDOW, 4); put (x1WC); put (x2WC); put (y1WC); put (y2WC); }
  248. }
  249. /***** INQUIRIES TO CURRENT GRAPHICS *****/
  250. void Graphics_inqViewport (Graphics me, double *x1NDC, double *x2NDC, double *y1NDC, double *y2NDC) {
  251. *x1NDC = my d_x1NDC;
  252. *x2NDC = my d_x2NDC;
  253. *y1NDC = my d_y1NDC;
  254. *y2NDC = my d_y2NDC;
  255. }
  256. void Graphics_inqWindow (Graphics me, double *x1WC, double *x2WC, double *y1WC, double *y2WC) {
  257. *x1WC = my d_x1WC;
  258. *x2WC = my d_x2WC;
  259. *y1WC = my d_y1WC;
  260. *y2WC = my d_y2WC;
  261. }
  262. Graphics_Viewport Graphics_insetViewport
  263. (Graphics me, double x1rel, double x2rel, double y1rel, double y2rel)
  264. {
  265. trace (U"enter");
  266. Graphics_Viewport previous;
  267. previous.x1NDC = my d_x1NDC;
  268. previous.x2NDC = my d_x2NDC;
  269. previous.y1NDC = my d_y1NDC;
  270. previous.y2NDC = my d_y2NDC;
  271. Graphics_setViewport
  272. (me, (1 - x1rel) * my d_x1NDC + x1rel * my d_x2NDC,
  273. x2rel * my d_x2NDC + (1 - x2rel) * my d_x1NDC,
  274. (1 - y1rel) * my d_y1NDC + y1rel * my d_y2NDC,
  275. y2rel * my d_y2NDC + (1 - y2rel) * my d_y1NDC);
  276. return previous;
  277. }
  278. void Graphics_resetViewport (Graphics me, Graphics_Viewport viewport) {
  279. trace (U"enter");
  280. Graphics_setViewport (me, viewport.x1NDC, viewport.x2NDC, viewport.y1NDC, viewport.y2NDC);
  281. }
  282. /* Millimetres. */
  283. double Graphics_dxMMtoWC (Graphics me, double dx_mm) {
  284. return dx_mm * my resolution / (25.4 * my scaleX);
  285. }
  286. double Graphics_dyMMtoWC (Graphics me, double dy_mm) {
  287. return my yIsZeroAtTheTop ?
  288. dy_mm * my resolution / (-25.4 * my scaleY) : dy_mm * my resolution / (25.4 * my scaleY);
  289. }
  290. double Graphics_distanceWCtoMM (Graphics me, double x1WC, double y1WC, double x2WC, double y2WC) {
  291. double dxDC = (x1WC - x2WC) * my scaleX;
  292. double dyDC = (y1WC - y2WC) * my scaleY;
  293. return sqrt (dxDC * dxDC + dyDC * dyDC) * 25.4 / my resolution;
  294. }
  295. double Graphics_dxWCtoMM (Graphics me, double dxWC) {
  296. return dxWC * my scaleX * 25.4 / my resolution;
  297. }
  298. double Graphics_dyWCtoMM (Graphics me, double dyWC) {
  299. return my yIsZeroAtTheTop ?
  300. dyWC * my scaleY * -25.4 / my resolution : dyWC * my scaleY * 25.4 / my resolution;
  301. }
  302. /* End of file Graphics.cpp */