PageRenderTime 27ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/mjl_fork_1/src/plcore.c

#
C | 2312 lines | 1360 code | 400 blank | 552 comment | 282 complexity | 6975587107950c6b97c6a3899daff82b MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* $Id: plcore.c 6212 2005-04-27 06:44:27Z rlaboiss $
  2. Central dispatch facility for PLplot.
  3. Also contains the PLplot main data structures, external access
  4. routines, and initialization calls.
  5. This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
  6. Copyright (C) 2004 Joao Cardoso
  7. Copyright (C) 2004, 2005 Rafael Laboissiere
  8. Copyright (C) 2004 Andrew Ross
  9. Copyright (C) 2004 Andrew Roach
  10. Copyright (C) 2005 Alan W. Irwin
  11. Copyright (C) 2005 Thomas J. Duck
  12. This file is part of PLplot.
  13. PLplot is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Library Public License as published
  15. by the Free Software Foundation; either version 2 of the License, or
  16. (at your option) any later version.
  17. PLplot is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. GNU Library General Public License for more details.
  21. You should have received a copy of the GNU Library General Public License
  22. along with PLplot; if not, write to the Free Software
  23. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. */
  25. #define DEBUG
  26. #define NEED_PLDEBUG
  27. #include "plcore.h"
  28. #ifdef ENABLE_DYNDRIVERS
  29. #include <ltdl.h>
  30. #endif
  31. /*--------------------------------------------------------------------------*\
  32. * Driver Interface
  33. *
  34. * These routines are the low-level interface to the driver -- all calls to
  35. * driver functions must pass through here. For implementing driver-
  36. * specific functions, the escape function is provided. The command stream
  37. * gets duplicated to the plot buffer here.
  38. *
  39. * All functions that result in graphics actually being plotted (rather than
  40. * just a change of state) are filtered as necessary before being passed on.
  41. * The default settings do not require any filtering, i.e. PLplot physical
  42. * coordinates are the same as the device physical coordinates (currently
  43. * this can't be changed anyway), and a global view equal to the entire page
  44. * is used.
  45. *
  46. * The reason one wants to put view-specific filtering here is that if
  47. * enabled, the plot buffer should receive the unfiltered data stream. This
  48. * allows a specific view to be used from an interactive device (e.g. TCL/TK
  49. * driver) but be restored to the full view at any time merely by
  50. * reprocessing the contents of the plot buffer.
  51. *
  52. * The metafile, on the other hand, *should* be affected by changes in the
  53. * view, since this is a crucial editing capability. It is recommended that
  54. * the initial metafile be created without a restricted global view, and
  55. * modification of the view done on a per-plot basis as desired during
  56. * subsequent processing.
  57. *
  58. \*--------------------------------------------------------------------------*/
  59. enum {AT_BOP, DRAWING, AT_EOP};
  60. /* Initialize device. */
  61. /* The plot buffer must be called last. */
  62. /* The following array of chars is used both here and in plsym.c for
  63. * translating the Greek characters from the #g escape sequences into
  64. * the Hershey and Unicode codings
  65. */
  66. const char plP_greek_mnemonic[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
  67. void
  68. plP_init(void)
  69. {
  70. plsc->page_status = AT_EOP;
  71. (*plsc->dispatch_table->pl_init) ((struct PLStream_struct *) plsc);
  72. if (plsc->plbuf_write)
  73. plbuf_init(plsc);
  74. }
  75. /* End of page */
  76. /* The plot buffer must be called first. */
  77. /* Ignore instruction if already at eop. */
  78. void
  79. plP_eop(void)
  80. {
  81. int skip_driver_eop = 0;
  82. if (plsc->page_status == AT_EOP)
  83. return;
  84. plsc->page_status = AT_EOP;
  85. if (plsc->plbuf_write)
  86. plbuf_eop(plsc);
  87. /* Call user eop handler if present. */
  88. if (plsc->eop_handler != NULL)
  89. (*plsc->eop_handler) (plsc->eop_data, &skip_driver_eop);
  90. if (!skip_driver_eop)
  91. (*plsc->dispatch_table->pl_eop) ((struct PLStream_struct *) plsc);
  92. }
  93. /* Set up new page. */
  94. /* The plot buffer must be called last. */
  95. /* Ignore if already at bop. */
  96. /* It's not actually necessary to be AT_EOP here, so don't check for it. */
  97. void
  98. plP_bop(void)
  99. {
  100. int skip_driver_bop = 0;
  101. plP_subpInit();
  102. if (plsc->page_status == AT_BOP)
  103. return;
  104. plsc->page_status = AT_BOP;
  105. plsc->nplwin = 0;
  106. /* Call user bop handler if present. */
  107. if (plsc->bop_handler != NULL)
  108. (*plsc->bop_handler) (plsc->bop_data, &skip_driver_bop);
  109. if (!skip_driver_bop)
  110. (*plsc->dispatch_table->pl_bop) ((struct PLStream_struct *) plsc);
  111. if (plsc->plbuf_write)
  112. plbuf_bop(plsc);
  113. }
  114. /* Tidy up device (flush buffers, close file, etc). */
  115. void
  116. plP_tidy(void)
  117. {
  118. if (plsc->tidy) {
  119. (*plsc->tidy) (plsc->tidy_data);
  120. plsc->tidy = NULL;
  121. plsc->tidy_data = NULL;
  122. }
  123. (*plsc->dispatch_table->pl_tidy) ((struct PLStream_struct *) plsc);
  124. if (plsc->plbuf_write)
  125. plbuf_tidy(plsc);
  126. plsc->OutFile = NULL;
  127. }
  128. /* Change state. */
  129. void
  130. plP_state(PLINT op)
  131. {
  132. (*plsc->dispatch_table->pl_state) ((struct PLStream_struct *) plsc, op);
  133. if (plsc->plbuf_write)
  134. plbuf_state(plsc, op);
  135. }
  136. /* Escape function, for driver-specific commands. */
  137. void
  138. plP_esc(PLINT op, void *ptr)
  139. {
  140. (*plsc->dispatch_table->pl_esc) ((struct PLStream_struct *) plsc, op, ptr);
  141. if (plsc->plbuf_write)
  142. plbuf_esc(plsc, op, ptr);
  143. }
  144. /* Set up plot window parameters. */
  145. /* The plot buffer must be called first */
  146. /* Some drivers (metafile, Tk) need access to this data */
  147. void
  148. plP_swin(PLWindow *plwin)
  149. {
  150. PLWindow *w;
  151. PLINT clpxmi, clpxma, clpymi, clpyma;
  152. /* Provide plot buffer with unfiltered window data */
  153. if (plsc->plbuf_write)
  154. plbuf_esc(plsc, PLESC_SWIN, (void *) plwin);
  155. w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS];
  156. w->dxmi = plwin->dxmi;
  157. w->dxma = plwin->dxma;
  158. w->dymi = plwin->dymi;
  159. w->dyma = plwin->dyma;
  160. if (plsc->difilt) {
  161. xscl[0] = plP_dcpcx(w->dxmi);
  162. xscl[1] = plP_dcpcx(w->dxma);
  163. yscl[0] = plP_dcpcy(w->dymi);
  164. yscl[1] = plP_dcpcy(w->dyma);
  165. difilt(xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma);
  166. w->dxmi = plP_pcdcx(xscl[0]);
  167. w->dxma = plP_pcdcx(xscl[1]);
  168. w->dymi = plP_pcdcy(yscl[0]);
  169. w->dyma = plP_pcdcy(yscl[1]);
  170. }
  171. w->wxmi = plwin->wxmi;
  172. w->wxma = plwin->wxma;
  173. w->wymi = plwin->wymi;
  174. w->wyma = plwin->wyma;
  175. /* If the driver wants to process swin commands, call it now */
  176. /* It must use the filtered data, which it can get from *plsc */
  177. if (plsc->dev_swin) {
  178. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  179. PLESC_SWIN, NULL );
  180. }
  181. }
  182. /*--------------------------------------------------------------------------*\
  183. * Drawing commands.
  184. \*--------------------------------------------------------------------------*/
  185. /* Draw line between two points */
  186. /* The plot buffer must be called first so it gets the unfiltered data */
  187. void
  188. plP_line(short *x, short *y)
  189. {
  190. PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
  191. plsc->page_status = DRAWING;
  192. if (plsc->plbuf_write)
  193. plbuf_line(plsc, x[0], y[0], x[1], y[1]);
  194. if (plsc->difilt) {
  195. for (i = 0; i < npts; i++) {
  196. xscl[i] = x[i];
  197. yscl[i] = y[i];
  198. }
  199. difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  200. plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline);
  201. }
  202. else {
  203. grline(x, y, npts);
  204. }
  205. }
  206. /* Draw polyline */
  207. /* The plot buffer must be called first */
  208. void
  209. plP_polyline(short *x, short *y, PLINT npts)
  210. {
  211. PLINT i, clpxmi, clpxma, clpymi, clpyma;
  212. plsc->page_status = DRAWING;
  213. if (plsc->plbuf_write)
  214. plbuf_polyline(plsc, x, y, npts);
  215. if (plsc->difilt) {
  216. for (i = 0; i < npts; i++) {
  217. xscl[i] = x[i];
  218. yscl[i] = y[i];
  219. }
  220. difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  221. plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
  222. grpolyline);
  223. }
  224. else {
  225. grpolyline(x, y, npts);
  226. }
  227. }
  228. /* Fill polygon */
  229. /* The plot buffer must be called first */
  230. /* Here if the desired area fill capability isn't present, we mock up */
  231. /* something in software */
  232. static int foo;
  233. void
  234. plP_fill(short *x, short *y, PLINT npts)
  235. {
  236. PLINT i, clpxmi, clpxma, clpymi, clpyma;
  237. plsc->page_status = DRAWING;
  238. if (plsc->plbuf_write) {
  239. plsc->dev_npts = npts;
  240. plsc->dev_x = x;
  241. plsc->dev_y = y;
  242. plbuf_esc(plsc, PLESC_FILL, NULL);
  243. }
  244. /* Account for driver ability to do fills */
  245. if (plsc->patt == 0 && ! plsc->dev_fill0) {
  246. if ( ! foo) {
  247. plwarn("Driver does not support hardware solid fills, switching to software fill.\n");
  248. foo = 1;
  249. }
  250. plsc->patt = 8;
  251. plpsty(plsc->patt);
  252. }
  253. if (plsc->dev_fill1) {
  254. plsc->patt = -ABS(plsc->patt);
  255. }
  256. /* Perform fill. Here we MUST NOT allow the software fill to pass through the
  257. driver interface filtering twice, else we get the infamous 2*rotation for
  258. software fills on orientation swaps.
  259. */
  260. if (plsc->patt > 0)
  261. plfill_soft(x, y, npts);
  262. else {
  263. if (plsc->difilt) {
  264. for (i = 0; i < npts; i++) {
  265. xscl[i] = x[i];
  266. yscl[i] = y[i];
  267. }
  268. difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  269. plP_plfclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
  270. grfill);
  271. }
  272. else {
  273. grfill(x, y, npts);
  274. }
  275. }
  276. }
  277. /* Account for driver ability to draw text itself */
  278. /*
  279. #define DEBUG_TEXT
  280. */
  281. #define hex2dec( a ) isdigit(a) ? a - 48 : (toupper(a) - 65) + 10
  282. /*--------------------------------------------------------------------------*\
  283. * int text2num( char *text, char end, PLUNICODE *num)
  284. * char *text - pointer to the text to be parsed
  285. * char end - end character (i.e. ')' or ']' to stop parsing
  286. * PLUNICODE *num - pointer to an PLUNICODE to store the value
  287. *
  288. * Function takes a string, which can be either hex or decimal,
  289. * and converts it into an PLUNICODE, stopping at either a null,
  290. * or the character pointed to by 'end'. It is a bit brain-dead,
  291. * and probably should make more checks, but it works.
  292. \*--------------------------------------------------------------------------*/
  293. int text2num( const char *text, char end, PLUNICODE *num)
  294. {
  295. int base=10;
  296. unsigned short i=0;
  297. *num=0;
  298. if (text[1]=='x')
  299. {
  300. base=16;
  301. i=2;
  302. }
  303. while ((text[i]!=end)&&(text[i]!=0))
  304. {
  305. *num*=base;
  306. *num+=hex2dec(text[i]);
  307. i++;
  308. }
  309. return(i);
  310. }
  311. /*--------------------------------------------------------------------------*\
  312. * int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower)
  313. * char *text - pointer to the text to be parsed
  314. * unsigned char *hexdigit - pointer to hex value that is stored.
  315. * unsigned char *hexpower - pointer to hex power (left shift) that is stored.
  316. *
  317. * Function takes a pointer to a string, which is looked up in a table
  318. * to determine the corresponding FCI (font characterization integer)
  319. * hex digit value and hex power (left shift).
  320. * If the lookup succeeds, hexdigit and hexpower are set to the appropriate
  321. * values in the table, and the function returns the number of characters
  322. * in text that are consumed by the matching string in the table lookup.
  323. *
  324. * If the lookup fails, hexdigit is set to 0, hexpower is set to and
  325. * impossible value, and the function returns 0.
  326. \*--------------------------------------------------------------------------*/
  327. int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower)
  328. {
  329. typedef struct
  330. {
  331. char *ptext;
  332. unsigned char hexdigit;
  333. unsigned char hexpower;
  334. }
  335. TextLookupTable;
  336. /* This defines the various font control commands and the corresponding
  337. * hexdigit and hexpower in the FCI.
  338. */
  339. #define N_TextLookupTable 10
  340. const TextLookupTable lookup[N_TextLookupTable] = {
  341. {"<sans-serif/>", PL_FCI_SANS, PL_FCI_FAMILY},
  342. {"<serif/>", PL_FCI_SERIF, PL_FCI_FAMILY},
  343. {"<monospace/>", PL_FCI_MONO, PL_FCI_FAMILY},
  344. {"<script/>", PL_FCI_SCRIPT, PL_FCI_FAMILY},
  345. {"<symbol/>", PL_FCI_SYMBOL, PL_FCI_FAMILY},
  346. {"<upright/>", PL_FCI_UPRIGHT, PL_FCI_STYLE},
  347. {"<italic/>", PL_FCI_ITALIC, PL_FCI_STYLE},
  348. {"<oblique/>", PL_FCI_OBLIQUE, PL_FCI_STYLE},
  349. {"<medium/>", PL_FCI_MEDIUM, PL_FCI_WEIGHT},
  350. {"<bold/>", PL_FCI_BOLD, PL_FCI_WEIGHT}
  351. };
  352. int i, length;
  353. for (i=0; i<N_TextLookupTable; i++) {
  354. length = strlen(lookup[i].ptext);
  355. if (! strncmp(text, lookup[i].ptext, length)) {
  356. *hexdigit = lookup[i].hexdigit;
  357. *hexpower = lookup[i].hexpower;
  358. return(length);
  359. }
  360. }
  361. *hexdigit = 0;
  362. *hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE;
  363. return(0);
  364. }
  365. PLUNICODE unicode_buffer[1024];
  366. void
  367. plP_text(PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
  368. PLINT refx, PLINT refy, const char *string)
  369. {
  370. if (plsc->dev_text) { /* Does the device render it's own text ? */
  371. EscText args;
  372. short len=0;
  373. char skip;
  374. unsigned short i,j, k;
  375. PLUNICODE code;
  376. char esc;
  377. int idx;
  378. args.base = base;
  379. args.just = just;
  380. args.xform = xform;
  381. args.x = x;
  382. args.y = y;
  383. args.refx = refx;
  384. args.refy = refy;
  385. if (plsc->dev_unicode) { /* Does the device also understand unicode ? */
  386. PLINT ig;
  387. PLUNICODE fci, fcisave;
  388. unsigned char hexdigit, hexpower;
  389. if (string!=NULL) { /* If the string isn't blank, then we will continue */
  390. len=strlen(string); /* this length is only used in the loop counter, we will work out the length of the unicode string as we go */
  391. plgesc(&esc);
  392. /* At this stage we will do some translations into unicode, like conversion to
  393. * Greek , and will save other translations such as superscript for the driver to
  394. * do later on. As we move through the string and do the translations, we will get
  395. * rid of the esc character sequence, just replacing it with unicode.
  396. */
  397. /* Obtain FCI (font characterization integer) for start of string. */
  398. plgfci(&fci);
  399. for (j=i=0;i<len;i++) { /* Walk through the strings, and convert some stuff to unicode on the fly */
  400. skip=0;
  401. if (string[i]==esc) {
  402. switch(string[i+1]) {
  403. case '(': /* hershey code */
  404. i+=2+text2num(&string[i+2],')',&code);
  405. idx=plhershey2unicode(code);
  406. /* momentarily switch to symbol font. */
  407. fcisave = fci;
  408. plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
  409. unicode_buffer[j++]= fci;
  410. unicode_buffer[j++]=(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
  411. /* if unicode_buffer[j-1] corresponds to the escape character
  412. * must unescape it by appending one more. This will probably
  413. * always be necessary since it is likely unicode_buffer
  414. * will always have to contain escape characters that are
  415. * interpreted by the device driver.
  416. */
  417. if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
  418. fci = fcisave;
  419. unicode_buffer[j]= fci;
  420. skip=1;
  421. break;
  422. case '[': /* unicode */
  423. i+=2+text2num(&string[i+2],']',&code);
  424. /* momentarily switch to symbol font. */
  425. fcisave = fci;
  426. plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
  427. unicode_buffer[j++]= fci;
  428. unicode_buffer[j++]=code;
  429. /* if unicode_buffer[j-1] corresponds to the escape character
  430. * must unescape it by appending one more. This will probably
  431. * always be necessary since it is likely unicode_buffer
  432. * will always have to contain escape characters that are
  433. * interpreted by the device driver.
  434. */
  435. if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
  436. fci = fcisave;
  437. unicode_buffer[j] = fci;
  438. skip=1;
  439. break;
  440. case '<': /* change font*/
  441. i+=2;
  442. if ('0' <= string[i] && string[i] <= '9' ) {
  443. i+=text2num(&string[i],'>', &code);
  444. if (code & PL_FCI_MARK) {
  445. /* code is a complete FCI (font characterization
  446. * integer): change FCI to this value.
  447. */
  448. fci = code;
  449. unicode_buffer[j]=fci;
  450. skip=1;
  451. }
  452. else {
  453. /* code is not complete FCI. Change
  454. * FCI with hex power in rightmost hex
  455. * digit and hex digit value in second rightmost
  456. * hex digit.
  457. */
  458. hexdigit = (code >> 4) & PL_FCI_HEXDIGIT_MASK;
  459. hexpower = code & PL_FCI_HEXPOWER_MASK;
  460. plP_hex2fci(hexdigit, hexpower, &fci);
  461. unicode_buffer[j]=fci;
  462. skip=1;
  463. }
  464. }
  465. else {
  466. /* align i on "<" because that is what text2fci
  467. * expects. */
  468. i--;
  469. i+=text2fci(&string[i], &hexdigit, &hexpower);
  470. if (hexpower < 7) {
  471. plP_hex2fci(hexdigit, hexpower, &fci);
  472. unicode_buffer[j]=fci;
  473. skip=1;
  474. }
  475. }
  476. break;
  477. case 'f': /* Deprecated Hershey-style font change*/
  478. case 'F': /* Deprecated Hershey-style font change*/
  479. /* We implement an approximate response here so that reasonable
  480. * results are obtained for unicode fonts, but this
  481. * method is deprecated and the #<nnn> or
  482. * #<command string> methods should be used instead
  483. * to change unicode fonts in mid-string.
  484. */
  485. fci = PL_FCI_MARK;
  486. if (string[i+2] == 'n') {
  487. /* medium, upright, sans-serif */
  488. plP_hex2fci(PL_FCI_SANS, PL_FCI_FAMILY, &fci);
  489. } else if (string[i+2] == 'r') {
  490. /* medium, upright, serif */
  491. plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
  492. } else if (string[i+2] == 'i') {
  493. /* medium, italic, serif */
  494. plP_hex2fci(PL_FCI_ITALIC, PL_FCI_STYLE, &fci);
  495. plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
  496. } else if (string[i+2] == 's') {
  497. /* medium, upright, script */
  498. plP_hex2fci(PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci);
  499. } else
  500. fci = PL_FCI_IMPOSSIBLE;
  501. if (fci != PL_FCI_IMPOSSIBLE){
  502. i+=2;
  503. unicode_buffer[j] = fci;
  504. skip = 1;
  505. }
  506. break;
  507. case 'g': /* Greek font */
  508. case 'G': /* Greek font */
  509. /* Get the index in the lookup table
  510. * 527 = upper case alpha displacement in Hershey Table
  511. * 627 = lower case alpha displacement in Hershey Table
  512. */
  513. /* momentarily switch to symbol font. */
  514. fcisave = fci;
  515. plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
  516. unicode_buffer[j++]= fci;
  517. ig = plP_strpos(plP_greek_mnemonic, string[i+2]);
  518. if (ig >= 0) {
  519. if (ig >= 24)
  520. ig = ig + 100 - 24;
  521. idx=plhershey2unicode(ig+527);
  522. unicode_buffer[j++]=(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
  523. i+=2;
  524. skip=1; /* skip is set if we have copied something into the unicode table */
  525. }
  526. else {
  527. /* Use "unknown" unicode character if string[i+2] is not in
  528. * the Greek array.*/
  529. unicode_buffer[j++]=(PLUNICODE)0x00;
  530. i+=2;
  531. skip=1; /* skip is set if we have copied something into the unicode table */
  532. }
  533. fci = fcisave;
  534. unicode_buffer[j]= fci;
  535. break;
  536. }
  537. }
  538. if (skip==0) {
  539. #ifdef HAVE_LIBUNICODE
  540. unicode_char_t unichar;
  541. char* ptr =
  542. unicode_get_utf8 (string + i, &unichar);
  543. if (ptr == NULL) {
  544. char buf[80];
  545. strncpy (buf, string, 30);
  546. sprintf (buf, "UTF-8 string is malformed: %s%s",
  547. buf, strlen (string) > 30 ? "[...]" : "");
  548. plabort (buf);
  549. }
  550. unicode_buffer [j] = (PLUNICODE) unichar;
  551. i += ptr - (string + i) - 1;
  552. #else
  553. unicode_buffer[j]=string[i];
  554. #endif
  555. /* Search for escesc (an unescaped escape) in the input string
  556. * and adjust unicode_buffer accordingly).
  557. */
  558. if (unicode_buffer[j] == esc && string[i+1] == esc) {
  559. i++;
  560. unicode_buffer[++j] = esc;
  561. }
  562. }
  563. j++;
  564. }
  565. if (j > 0) {
  566. args.unicode_array_len=j; /* Much easier to set the length than work it out later :-) */
  567. args.unicode_array=&unicode_buffer[0]; /* Get address of the unicode buffer (even though it is currently static) */
  568. args.string=NULL; /* Since we are using unicode, we want this to be NULL */
  569. } else
  570. /* Don't print anything, if there is no unicode to print! */
  571. return;
  572. }
  573. } else {
  574. args.string = string;
  575. }
  576. if (plsc->plbuf_write)
  577. plbuf_esc(plsc, PLESC_HAS_TEXT, &args);
  578. plP_esc(PLESC_HAS_TEXT, &args);
  579. #ifndef DEBUG_TEXT
  580. } else {
  581. #endif
  582. plstr(base, xform, refx, refy, string);
  583. }
  584. }
  585. static void
  586. grline(short *x, short *y, PLINT npts)
  587. {
  588. (*plsc->dispatch_table->pl_line) ( (struct PLStream_struct *) plsc,
  589. x[0], y[0], x[1], y[1] );
  590. }
  591. static void
  592. grpolyline(short *x, short *y, PLINT npts)
  593. {
  594. (*plsc->dispatch_table->pl_polyline) ( (struct PLStream_struct *) plsc,
  595. x, y, npts );
  596. }
  597. static void
  598. grfill(short *x, short *y, PLINT npts)
  599. {
  600. plsc->dev_npts = npts;
  601. plsc->dev_x = x;
  602. plsc->dev_y = y;
  603. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  604. PLESC_FILL, NULL );
  605. }
  606. /*--------------------------------------------------------------------------*\
  607. * void difilt
  608. *
  609. * Driver interface filter -- passes all coordinates through a variety
  610. * of filters. These include filters to change :
  611. *
  612. * - mapping of meta to physical coordinates
  613. * - plot orientation
  614. * - window into plot (zooms)
  615. * - window into device (i.e set margins)
  616. *
  617. * The filters are applied in the order specified above. Because the
  618. * orientation change comes first, subsequent window specifications affect
  619. * the new coordinates (i.e. after a 90 degree flip, what was x is now y).
  620. * This is the only way that makes sense from a graphical interface
  621. * (e.g. TCL/TK driver).
  622. *
  623. * Where appropriate, the page clip limits are modified.
  624. \*--------------------------------------------------------------------------*/
  625. void
  626. difilt(PLINT *xscl, PLINT *yscl, PLINT npts,
  627. PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
  628. {
  629. PLINT i, x, y;
  630. /* Map meta coordinates to physical coordinates */
  631. if (plsc->difilt & PLDI_MAP) {
  632. for (i = 0; i < npts; i++) {
  633. xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
  634. yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
  635. }
  636. }
  637. /* Change orientation */
  638. if (plsc->difilt & PLDI_ORI) {
  639. for (i = 0; i < npts; i++) {
  640. x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
  641. y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
  642. xscl[i] = x;
  643. yscl[i] = y;
  644. }
  645. }
  646. /* Change window into plot space */
  647. if (plsc->difilt & PLDI_PLT) {
  648. for (i = 0; i < npts; i++) {
  649. xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
  650. yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
  651. }
  652. }
  653. /* Change window into device space and set clip limits */
  654. /* (this is the only filter that modifies them) */
  655. if (plsc->difilt & PLDI_DEV) {
  656. for (i = 0; i < npts; i++) {
  657. xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
  658. yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
  659. }
  660. *clpxmi = plsc->diclpxmi;
  661. *clpxma = plsc->diclpxma;
  662. *clpymi = plsc->diclpymi;
  663. *clpyma = plsc->diclpyma;
  664. }
  665. else {
  666. *clpxmi = plsc->phyxmi;
  667. *clpxma = plsc->phyxma;
  668. *clpymi = plsc->phyymi;
  669. *clpyma = plsc->phyyma;
  670. }
  671. }
  672. void
  673. sdifilt(short *xscl, short *yscl, PLINT npts,
  674. PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
  675. {
  676. int i;
  677. short x, y;
  678. /* Map meta coordinates to physical coordinates */
  679. if (plsc->difilt & PLDI_MAP) {
  680. for (i = 0; i < npts; i++) {
  681. xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
  682. yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
  683. }
  684. }
  685. /* Change orientation */
  686. if (plsc->difilt & PLDI_ORI) {
  687. for (i = 0; i < npts; i++) {
  688. x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
  689. y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
  690. xscl[i] = x;
  691. yscl[i] = y;
  692. }
  693. }
  694. /* Change window into plot space */
  695. if (plsc->difilt & PLDI_PLT) {
  696. for (i = 0; i < npts; i++) {
  697. xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
  698. yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
  699. }
  700. }
  701. /* Change window into device space and set clip limits */
  702. /* (this is the only filter that modifies them) */
  703. if (plsc->difilt & PLDI_DEV) {
  704. for (i = 0; i < npts; i++) {
  705. xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
  706. yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
  707. }
  708. *clpxmi = plsc->diclpxmi;
  709. *clpxma = plsc->diclpxma;
  710. *clpymi = plsc->diclpymi;
  711. *clpyma = plsc->diclpyma;
  712. }
  713. else {
  714. *clpxmi = plsc->phyxmi;
  715. *clpxma = plsc->phyxma;
  716. *clpymi = plsc->phyymi;
  717. *clpyma = plsc->phyyma;
  718. }
  719. }
  720. /*--------------------------------------------------------------------------*\
  721. * void pldi_ini
  722. *
  723. * Updates driver interface, making sure everything is in order.
  724. * Even if filter is not being used, the defaults need to be set up.
  725. \*--------------------------------------------------------------------------*/
  726. static void
  727. setdef_diplt()
  728. {
  729. plsc->dipxmin = 0.0;
  730. plsc->dipxmax = 1.0;
  731. plsc->dipymin = 0.0;
  732. plsc->dipymax = 1.0;
  733. }
  734. static void
  735. setdef_didev()
  736. {
  737. plsc->mar = 0.0;
  738. plsc->aspect = 0.0;
  739. plsc->jx = 0.0;
  740. plsc->jy = 0.0;
  741. }
  742. static void
  743. setdef_diori()
  744. {
  745. plsc->diorot = 0.;
  746. }
  747. static void
  748. pldi_ini(void)
  749. {
  750. if (plsc->level >= 1) {
  751. if (plsc->difilt & PLDI_MAP) /* Coordinate mapping */
  752. calc_dimap();
  753. if (plsc->difilt & PLDI_ORI) /* Orientation */
  754. calc_diori();
  755. else
  756. setdef_diori();
  757. if (plsc->difilt & PLDI_PLT) /* Plot window */
  758. calc_diplt();
  759. else
  760. setdef_diplt();
  761. if (plsc->difilt & PLDI_DEV) /* Device window */
  762. calc_didev();
  763. else
  764. setdef_didev();
  765. }
  766. }
  767. /*--------------------------------------------------------------------------*\
  768. * void pldid2pc
  769. *
  770. * Converts input values from relative device coordinates to relative plot
  771. * coordinates. This function must be called when selecting a plot window
  772. * from a display driver, since the coordinates chosen by the user are
  773. * necessarily device-specific.
  774. \*--------------------------------------------------------------------------*/
  775. void
  776. pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
  777. {
  778. PLFLT pxmin, pymin, pxmax, pymax;
  779. PLFLT sxmin, symin, sxmax, symax;
  780. PLFLT rxmin, rymin, rxmax, rymax;
  781. if (plsc->difilt & PLDI_DEV) {
  782. pldebug("pldid2pc",
  783. "Relative device coordinates (in): %f, %f, %f, %f\n",
  784. *xmin, *ymin, *xmax, *ymax);
  785. pxmin = plP_dcpcx(*xmin);
  786. pymin = plP_dcpcy(*ymin);
  787. pxmax = plP_dcpcx(*xmax);
  788. pymax = plP_dcpcy(*ymax);
  789. sxmin = (pxmin - plsc->didxb) / plsc->didxax;
  790. symin = (pymin - plsc->didyb) / plsc->didyay;
  791. sxmax = (pxmax - plsc->didxb) / plsc->didxax;
  792. symax = (pymax - plsc->didyb) / plsc->didyay;
  793. rxmin = plP_pcdcx(sxmin);
  794. rymin = plP_pcdcy(symin);
  795. rxmax = plP_pcdcx(sxmax);
  796. rymax = plP_pcdcy(symax);
  797. *xmin = (rxmin < 0) ? 0 : rxmin;
  798. *xmax = (rxmax > 1) ? 1 : rxmax;
  799. *ymin = (rymin < 0) ? 0 : rymin;
  800. *ymax = (rymax > 1) ? 1 : rymax;
  801. pldebug("pldid2pc",
  802. "Relative plot coordinates (out): %f, %f, %f, %f\n",
  803. rxmin, rymin, rxmax, rymax);
  804. }
  805. }
  806. /*--------------------------------------------------------------------------*\
  807. * void pldip2dc
  808. *
  809. * Converts input values from relative plot coordinates to relative
  810. * device coordinates.
  811. \*--------------------------------------------------------------------------*/
  812. void
  813. pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
  814. {
  815. PLFLT pxmin, pymin, pxmax, pymax;
  816. PLFLT sxmin, symin, sxmax, symax;
  817. PLFLT rxmin, rymin, rxmax, rymax;
  818. if (plsc->difilt & PLDI_DEV) {
  819. pldebug("pldip2pc",
  820. "Relative plot coordinates (in): %f, %f, %f, %f\n",
  821. *xmin, *ymin, *xmax, *ymax);
  822. pxmin = plP_dcpcx(*xmin);
  823. pymin = plP_dcpcy(*ymin);
  824. pxmax = plP_dcpcx(*xmax);
  825. pymax = plP_dcpcy(*ymax);
  826. sxmin = pxmin * plsc->didxax + plsc->didxb;
  827. symin = pymin * plsc->didyay + plsc->didyb;
  828. sxmax = pxmax * plsc->didxax + plsc->didxb;
  829. symax = pymax * plsc->didyay + plsc->didyb;
  830. rxmin = plP_pcdcx(sxmin);
  831. rymin = plP_pcdcy(symin);
  832. rxmax = plP_pcdcx(sxmax);
  833. rymax = plP_pcdcy(symax);
  834. *xmin = (rxmin < 0) ? 0 : rxmin;
  835. *xmax = (rxmax > 1) ? 1 : rxmax;
  836. *ymin = (rymin < 0) ? 0 : rymin;
  837. *ymax = (rymax > 1) ? 1 : rymax;
  838. pldebug("pldip2pc",
  839. "Relative device coordinates (out): %f, %f, %f, %f\n",
  840. rxmin, rymin, rxmax, rymax);
  841. }
  842. }
  843. /*--------------------------------------------------------------------------*\
  844. * void plsdiplt
  845. *
  846. * Set window into plot space
  847. \*--------------------------------------------------------------------------*/
  848. void
  849. c_plsdiplt(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
  850. {
  851. plsc->dipxmin = (xmin < xmax) ? xmin : xmax;
  852. plsc->dipxmax = (xmin < xmax) ? xmax : xmin;
  853. plsc->dipymin = (ymin < ymax) ? ymin : ymax;
  854. plsc->dipymax = (ymin < ymax) ? ymax : ymin;
  855. if (xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1.) {
  856. plsc->difilt &= ~PLDI_PLT;
  857. return;
  858. }
  859. plsc->difilt |= PLDI_PLT;
  860. pldi_ini();
  861. }
  862. /*--------------------------------------------------------------------------*\
  863. * void plsdiplz
  864. *
  865. * Set window into plot space incrementally (zoom)
  866. \*--------------------------------------------------------------------------*/
  867. void
  868. c_plsdiplz(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
  869. {
  870. if (plsc->difilt & PLDI_PLT) {
  871. xmin = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmin;
  872. ymin = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymin;
  873. xmax = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmax;
  874. ymax = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymax;
  875. }
  876. plsdiplt(xmin, ymin, xmax, ymax);
  877. }
  878. /*--------------------------------------------------------------------------*\
  879. * void calc_diplt
  880. *
  881. * Calculate transformation coefficients to set window into plot space.
  882. *
  883. * Note: if driver has requested to handle these commands itself, we must
  884. * send the appropriate escape command. If the driver succeeds it will
  885. * cancel the filter operation. The command is deferred until this point
  886. * to ensure that the driver has been initialized.
  887. \*--------------------------------------------------------------------------*/
  888. static void
  889. calc_diplt(void)
  890. {
  891. PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
  892. if (plsc->dev_di) {
  893. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  894. PLESC_DI, NULL );
  895. }
  896. if ( ! (plsc->difilt & PLDI_PLT))
  897. return;
  898. pxmin = plP_dcpcx(plsc->dipxmin);
  899. pxmax = plP_dcpcx(plsc->dipxmax);
  900. pymin = plP_dcpcy(plsc->dipymin);
  901. pymax = plP_dcpcy(plsc->dipymax);
  902. pxlen = pxmax - pxmin;
  903. pylen = pymax - pymin;
  904. pxlen = MAX(1, pxlen);
  905. pylen = MAX(1, pylen);
  906. plsc->dipxax = plsc->phyxlen / (double) pxlen;
  907. plsc->dipyay = plsc->phyylen / (double) pylen;
  908. plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin;
  909. plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin;
  910. }
  911. /*--------------------------------------------------------------------------*\
  912. * void plgdiplt
  913. *
  914. * Retrieve current window into plot space
  915. \*--------------------------------------------------------------------------*/
  916. void
  917. c_plgdiplt(PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax)
  918. {
  919. *p_xmin = plsc->dipxmin;
  920. *p_xmax = plsc->dipxmax;
  921. *p_ymin = plsc->dipymin;
  922. *p_ymax = plsc->dipymax;
  923. }
  924. /*--------------------------------------------------------------------------*\
  925. * void plsdidev
  926. *
  927. * Set window into device space using margin, aspect ratio, and
  928. * justification. If you want to just use the previous value for any of
  929. * these, just pass in the magic value PL_NOTSET.
  930. *
  931. * It is unlikely that one should ever need to change the aspect ratio
  932. * but it's in there for completeness.
  933. \*--------------------------------------------------------------------------*/
  934. void
  935. c_plsdidev(PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy)
  936. {
  937. plsetvar(plsc->mar, mar);
  938. plsetvar(plsc->aspect, aspect);
  939. plsetvar(plsc->jx, jx);
  940. plsetvar(plsc->jy, jy);
  941. if (mar == 0. && aspect == 0. && jx == 0. && jy == 0. &&
  942. ! (plsc->difilt & PLDI_ORI)) {
  943. plsc->difilt &= ~PLDI_DEV;
  944. return;
  945. }
  946. plsc->difilt |= PLDI_DEV;
  947. pldi_ini();
  948. }
  949. /*--------------------------------------------------------------------------*\
  950. * void calc_didev
  951. *
  952. * Calculate transformation coefficients to set window into device space.
  953. * Calculates relative window bounds and calls plsdidxy to finish the job.
  954. \*--------------------------------------------------------------------------*/
  955. static void
  956. calc_didev(void)
  957. {
  958. PLFLT lx, ly, aspect, aspdev;
  959. PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
  960. PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
  961. if (plsc->dev_di) {
  962. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  963. PLESC_DI, NULL );
  964. }
  965. if ( ! (plsc->difilt & PLDI_DEV))
  966. return;
  967. /* Calculate aspect ratio of physical device */
  968. lx = plsc->phyxlen / plsc->xpmm;
  969. ly = plsc->phyylen / plsc->ypmm;
  970. aspdev = lx / ly;
  971. if (plsc->difilt & PLDI_ORI)
  972. aspect = plsc->aspori;
  973. else
  974. aspect = plsc->aspect;
  975. if (aspect <= 0.)
  976. aspect = plsc->aspdev;
  977. /* Failsafe */
  978. plsc->mar = (plsc->mar > 0.5) ? 0.5 : plsc->mar;
  979. plsc->mar = (plsc->mar < 0.0) ? 0.0 : plsc->mar;
  980. plsc->jx = (plsc->jx > 0.5) ? 0.5 : plsc->jx;
  981. plsc->jx = (plsc->jx < -0.5) ? -0.5 : plsc->jx;
  982. plsc->jy = (plsc->jy > 0.5) ? 0.5 : plsc->jy;
  983. plsc->jy = (plsc->jy < -0.5) ? -0.5 : plsc->jy;
  984. /* Relative device coordinates that neutralize aspect ratio difference */
  985. xlen = (aspect < aspdev) ? (aspect / aspdev) : 1.0;
  986. ylen = (aspect < aspdev) ? 1.0 : (aspdev / aspect);
  987. xlen *= (1.0 - 2.*plsc->mar);
  988. ylen *= (1.0 - 2.*plsc->mar);
  989. xmin = (1. - xlen) * (0.5 + plsc->jx);
  990. xmax = xmin + xlen;
  991. ymin = (1. - ylen) * (0.5 + plsc->jy);
  992. ymax = ymin + ylen;
  993. /* Calculate transformation coefficients */
  994. pxmin = plP_dcpcx(xmin);
  995. pxmax = plP_dcpcx(xmax);
  996. pymin = plP_dcpcy(ymin);
  997. pymax = plP_dcpcy(ymax);
  998. pxlen = pxmax - pxmin;
  999. pylen = pymax - pymin;
  1000. pxlen = MAX(1, pxlen);
  1001. pylen = MAX(1, pylen);
  1002. plsc->didxax = pxlen / (double) plsc->phyxlen;
  1003. plsc->didyay = pylen / (double) plsc->phyylen;
  1004. plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi;
  1005. plsc->didyb = pymin - plsc->didyay * plsc->phyymi;
  1006. /* Set clip limits to conform to new page size */
  1007. plsc->diclpxmi = plsc->didxax * plsc->phyxmi + plsc->didxb;
  1008. plsc->diclpxma = plsc->didxax * plsc->phyxma + plsc->didxb;
  1009. plsc->diclpymi = plsc->didyay * plsc->phyymi + plsc->didyb;
  1010. plsc->diclpyma = plsc->didyay * plsc->phyyma + plsc->didyb;
  1011. }
  1012. /*--------------------------------------------------------------------------*\
  1013. * void plgdidev
  1014. *
  1015. * Retrieve current window into device space
  1016. \*--------------------------------------------------------------------------*/
  1017. void
  1018. c_plgdidev(PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy)
  1019. {
  1020. *p_mar = plsc->mar;
  1021. *p_aspect = plsc->aspect;
  1022. *p_jx = plsc->jx;
  1023. *p_jy = plsc->jy;
  1024. }
  1025. /*--------------------------------------------------------------------------*\
  1026. * void plsdiori
  1027. *
  1028. * Set plot orientation, specifying rotation in units of pi/2.
  1029. \*--------------------------------------------------------------------------*/
  1030. void
  1031. c_plsdiori(PLFLT rot)
  1032. {
  1033. plsc->diorot = rot;
  1034. if (rot == 0.) {
  1035. plsc->difilt &= ~PLDI_ORI;
  1036. pldi_ini();
  1037. return;
  1038. }
  1039. plsc->difilt |= PLDI_ORI;
  1040. pldi_ini();
  1041. }
  1042. /*--------------------------------------------------------------------------*\
  1043. * void calc_diori
  1044. *
  1045. * Calculate transformation coefficients to arbitrarily orient plot.
  1046. * Preserve aspect ratios so the output doesn't suck.
  1047. \*--------------------------------------------------------------------------*/
  1048. static void
  1049. calc_diori(void)
  1050. {
  1051. PLFLT r11, r21, r12, r22, cost, sint;
  1052. PLFLT x0, y0, lx, ly, aspect;
  1053. if (plsc->dev_di) {
  1054. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  1055. PLESC_DI, NULL );
  1056. }
  1057. if ( ! (plsc->difilt & PLDI_ORI))
  1058. return;
  1059. /* Center point of rotation */
  1060. x0 = (plsc->phyxma + plsc->phyxmi) / 2.;
  1061. y0 = (plsc->phyyma + plsc->phyymi) / 2.;
  1062. /* Rotation matrix */
  1063. r11 = cos(plsc->diorot * PI / 2.);
  1064. r21 = sin(plsc->diorot * PI / 2.);
  1065. r12 = -r21;
  1066. r22 = r11;
  1067. cost = ABS(r11);
  1068. sint = ABS(r21);
  1069. /* Flip aspect ratio as necessary. Grungy but I don't see a better way */
  1070. aspect = plsc->aspect;
  1071. if (aspect == 0.)
  1072. aspect = plsc->aspdev;
  1073. if (plsc->freeaspect)
  1074. plsc->aspori = aspect;
  1075. else
  1076. plsc->aspori = (aspect * cost + sint) / (aspect * sint + cost);
  1077. if ( ! (plsc->difilt & PLDI_DEV)) {
  1078. plsc->difilt |= PLDI_DEV;
  1079. setdef_didev();
  1080. }
  1081. calc_didev();
  1082. /* Compute scale factors */
  1083. lx = plsc->phyxlen;
  1084. ly = plsc->phyylen;
  1085. /* Transformation coefficients */
  1086. plsc->dioxax = r11;
  1087. plsc->dioxay = r21 * (lx / ly);
  1088. plsc->dioxb = (1. - r11) * x0 - r21 * y0 * (lx / ly);
  1089. plsc->dioyax = r12 * (ly / lx);
  1090. plsc->dioyay = r22;
  1091. plsc->dioyb = (1. - r22) * y0 - r12 * x0 * (ly / lx);
  1092. }
  1093. /*--------------------------------------------------------------------------*\
  1094. * void plgdiori
  1095. *
  1096. * Get plot orientation
  1097. \*--------------------------------------------------------------------------*/
  1098. void
  1099. c_plgdiori(PLFLT *p_rot)
  1100. {
  1101. *p_rot = plsc->diorot;
  1102. }
  1103. /*--------------------------------------------------------------------------*\
  1104. * void plsdimap
  1105. *
  1106. * Set up transformation from metafile coordinates. The size of the plot is
  1107. * scaled so as to preserve aspect ratio. This isn't intended to be a
  1108. * general-purpose facility just yet (not sure why the user would need it,
  1109. * for one).
  1110. \*--------------------------------------------------------------------------*/
  1111. void
  1112. c_plsdimap(PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
  1113. PLFLT dimxpmm, PLFLT dimypmm)
  1114. {
  1115. plsetvar(plsc->dimxmin, dimxmin);
  1116. plsetvar(plsc->dimxmax, dimxmax);
  1117. plsetvar(plsc->dimymin, dimymin);
  1118. plsetvar(plsc->dimymax, dimymax);
  1119. plsetvar(plsc->dimxpmm, dimxpmm);
  1120. plsetvar(plsc->dimypmm, dimypmm);
  1121. plsc->difilt |= PLDI_MAP;
  1122. pldi_ini();
  1123. }
  1124. /*--------------------------------------------------------------------------*\
  1125. * void calc_dimap
  1126. *
  1127. * Set up transformation from metafile coordinates. The size of the plot is
  1128. * scaled so as to preserve aspect ratio. This isn't intended to be a
  1129. * general-purpose facility just yet (not sure why the user would need it,
  1130. * for one).
  1131. \*--------------------------------------------------------------------------*/
  1132. static void
  1133. calc_dimap()
  1134. {
  1135. PLFLT lx, ly;
  1136. PLINT pxmin, pxmax, pymin, pymax;
  1137. PLFLT dimxlen, dimylen, pxlen, pylen;
  1138. if ((plsc->dimxmin == plsc->phyxmi) && (plsc->dimxmax == plsc->phyxma) &&
  1139. (plsc->dimymin == plsc->phyymi) && (plsc->dimymax == plsc->phyyma) &&
  1140. (plsc->dimxpmm == plsc->xpmm) && (plsc->dimypmm == plsc->ypmm)) {
  1141. plsc->difilt &= ~PLDI_MAP;
  1142. return;
  1143. }
  1144. /* Set default aspect ratio */
  1145. lx = (plsc->dimxmax - plsc->dimxmin + 1) / plsc->dimxpmm;
  1146. ly = (plsc->dimymax - plsc->dimymin + 1) / plsc->dimypmm;
  1147. plsc->aspdev = lx / ly;
  1148. /* Build transformation to correct physical coordinates */
  1149. dimxlen = plsc->dimxmax - plsc->dimxmin;
  1150. dimylen = plsc->dimymax - plsc->dimymin;
  1151. pxmin = plsc->phyxmi;
  1152. pxmax = plsc->phyxma;
  1153. pymin = plsc->phyymi;
  1154. pymax = plsc->phyyma;
  1155. pxlen = pxmax - pxmin;
  1156. pylen = pymax - pymin;
  1157. plsc->dimxax = pxlen / dimxlen;
  1158. plsc->dimyay = pylen / dimylen;
  1159. plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen;
  1160. plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen;
  1161. }
  1162. /*--------------------------------------------------------------------------*\
  1163. * void plflush()
  1164. *
  1165. * Flushes the output stream. Use sparingly, if at all.
  1166. \*--------------------------------------------------------------------------*/
  1167. void
  1168. c_plflush(void)
  1169. {
  1170. if (plsc->dev_flush) {
  1171. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  1172. PLESC_FLUSH, NULL );
  1173. }
  1174. else {
  1175. if (plsc->OutFile != NULL)
  1176. fflush(plsc->OutFile);
  1177. }
  1178. }
  1179. /*--------------------------------------------------------------------------*\
  1180. * Startup routines.
  1181. \*--------------------------------------------------------------------------*/
  1182. /*--------------------------------------------------------------------------*\
  1183. * void pllib_init()
  1184. *
  1185. * Initialize library. Called internally by every startup routine.
  1186. * Everything you want to always be initialized before plinit() is called
  1187. * you should put here. E.g. dispatch table setup, rcfile read, etc.
  1188. \*--------------------------------------------------------------------------*/
  1189. void
  1190. pllib_init()
  1191. {
  1192. if (lib_initialized) return;
  1193. lib_initialized = 1;
  1194. #ifdef ENABLE_DYNDRIVERS
  1195. /* Create libltdl resources */
  1196. lt_dlinit();
  1197. #endif
  1198. /* Initialize the dispatch table with the info from the static drivers table
  1199. and the available dynamic drivers. */
  1200. plInitDispatchTable();
  1201. }
  1202. /*--------------------------------------------------------------------------*\
  1203. * void plstar(nx, ny)
  1204. *
  1205. * Initialize PLplot, passing in the windows/page settings.
  1206. \*--------------------------------------------------------------------------*/
  1207. void
  1208. c_plstar(PLINT nx, PLINT ny)
  1209. {
  1210. pllib_init();
  1211. if (plsc->level != 0)
  1212. plend1();
  1213. plssub(nx, ny);
  1214. c_plinit();
  1215. }
  1216. /*--------------------------------------------------------------------------*\
  1217. * void plstart(devname, nx, ny)
  1218. *
  1219. * Initialize PLplot, passing the device name and windows/page settings.
  1220. \*--------------------------------------------------------------------------*/
  1221. void
  1222. c_plstart(const char *devname, PLINT nx, PLINT ny)
  1223. {
  1224. pllib_init();
  1225. if (plsc->level != 0)
  1226. plend1();
  1227. plssub(nx, ny);
  1228. plsdev(devname);
  1229. c_plinit();
  1230. }
  1231. /*--------------------------------------------------------------------------*\
  1232. * void plinit()
  1233. *
  1234. * Initializes PLplot, using preset or default options.
  1235. \*--------------------------------------------------------------------------*/
  1236. void
  1237. c_plinit(void)
  1238. {
  1239. PLFLT def_arrow_x[6] = {-0.5, 0.5, 0.3, 0.5, 0.3, 0.5};
  1240. PLFLT def_arrow_y[6] = {0.0, 0.0, 0.2, 0.0, -0.2, 0.0};
  1241. PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new;
  1242. PLINT mk = 0, sp = 0, inc = 0, del = 2000;
  1243. pllib_init();
  1244. if (plsc->level != 0)
  1245. plend1();
  1246. /* Set stream number */
  1247. plsc->ipls = ipls;
  1248. /* Set up devices */
  1249. pllib_devinit();
  1250. /* Auxiliary stream setup */
  1251. plstrm_init();
  1252. /* Initialize device & first page */
  1253. plP_init();
  1254. plP_bop();
  1255. plsc->level = 1;
  1256. /* Calculate factor such that the character aspect ratio is preserved
  1257. * when the overall aspect ratio is changed, i.e., if portrait mode is
  1258. * requested (only honored for subset of drivers) or if the aspect ratio
  1259. * is specified in any way, or if a 90 deg rotation occurs with
  1260. * -freeaspect. */
  1261. /* Case where plsc->aspect has a value.... (e.g., -a aspect on the
  1262. * command line or 2nd parameter of plsdidev specified) */
  1263. if (plsc->aspect > 0.) {
  1264. lx = plsc->phyxlen / plsc->xpmm;
  1265. ly = plsc->phyylen / plsc->ypmm;
  1266. aspect_old = lx / ly;
  1267. aspect_new = plsc->aspect;
  1268. plsc->caspfactor = sqrt(aspect_old/aspect_new);
  1269. }
  1270. /* Case of 90 deg rotations with -freeaspect (this is also how portraite
  1271. * mode is implemented for the drivers that honor -portrait). */
  1272. else if (plsc->freeaspect && ABS(cos(plsc->diorot * PI / 2.)) <= 1.e-5) {
  1273. lx = plsc->phyxlen / plsc->xpmm;
  1274. ly = plsc->phyylen / plsc->ypmm;
  1275. aspect_old = lx / ly;
  1276. aspect_new = ly / lx;
  1277. plsc->caspfactor = sqrt(aspect_old/aspect_new);
  1278. }
  1279. else
  1280. plsc->caspfactor = 1.;
  1281. /* Load fonts */
  1282. plsc->cfont = 1;
  1283. plfntld(initfont);
  1284. /* Set up subpages */
  1285. plP_subpInit();
  1286. /* Set up number of allowed digits before switching to scientific notation */
  1287. /* The user can always change this */
  1288. if (plsc->xdigmax == 0)
  1289. plsc->xdigmax = 4;
  1290. if (plsc->ydigmax == 0)
  1291. plsc->ydigmax = 4;
  1292. if (plsc->zdigmax == 0)
  1293. plsc->zdigmax = 3;
  1294. /* Switch to graphics mode and set color and arrow style*/
  1295. plgra();
  1296. plcol(1);
  1297. plstyl(0, &mk, &sp);
  1298. plpat(1, &inc, &del);
  1299. plsvect(def_arrow_x, def_arrow_y, 6, 0);
  1300. /* Set clip limits. */
  1301. plsc->clpxmi = plsc->phyxmi;
  1302. plsc->clpxma = plsc->phyxma;
  1303. plsc->clpymi = plsc->phyymi;
  1304. plsc->clpyma = plsc->phyyma;
  1305. /* Page aspect ratio. */
  1306. lx = plsc->phyxlen / plsc->xpmm;
  1307. ly = plsc->phyylen / plsc->ypmm;
  1308. plsc->aspdev = lx / ly;
  1309. /* Initialize driver interface */
  1310. pldi_ini();
  1311. /* Apply compensating factor to original xpmm and ypmm so that
  1312. * character aspect ratio is preserved when overall aspect ratio
  1313. * is changed. This must appear here in the code because previous
  1314. * code in this routine and in routines that it calls must use the original
  1315. * values of xpmm and ypmm before the compensating factor is applied. */
  1316. plP_gpixmm(&xpmm_loc, &ypmm_loc);
  1317. plP_setpxl(xpmm_loc*plsc->caspfactor, ypmm_loc/plsc->caspfactor);
  1318. }
  1319. /*--------------------------------------------------------------------------*\
  1320. * void plend()
  1321. *
  1322. * End a plotting session for all open streams.
  1323. \*--------------------------------------------------------------------------*/
  1324. void
  1325. c_plend(void)
  1326. {
  1327. PLINT i;
  1328. if (lib_initialized == 0) return;
  1329. for (i = PL_NSTREAMS-1; i >= 0; i--) {
  1330. if (pls[i] != NULL) {
  1331. plsstrm(i);
  1332. c_plend1();
  1333. }
  1334. }
  1335. plfontrel();
  1336. #ifdef ENABLE_DYNDRIVERS
  1337. /* Release the libltdl resources */
  1338. lt_dlexit();
  1339. /* Free up memory allocated to the dispatch tables */
  1340. for (i = 0; i < npldynamicdevices; i++) {
  1341. free_mem(loadable_device_list[i].devnam);
  1342. free_mem(loadable_device_list[i].description);
  1343. free_mem(loadable_device_list[i].drvnam);
  1344. free_mem(loadable_device_list[i].tag);
  1345. }
  1346. free_mem(loadable_device_list);
  1347. for (i = 0; i < nloadabledrivers; i++) {
  1348. free_mem(loadable_driver_list[i].drvnam);
  1349. }
  1350. free_mem(loadable_driver_list);
  1351. for (i = nplstaticdevices; i < npldrivers; i++) {
  1352. free_mem(dispatch_table[i]->pl_MenuStr);
  1353. free_mem(dispatch_table[i]->pl_DevName);
  1354. free_mem(dispatch_table[i]);
  1355. }
  1356. #endif
  1357. for (i = 0; i < nplstaticdevices; i++) {
  1358. free_mem(dispatch_table[i]);
  1359. }
  1360. free_mem(dispatch_table);
  1361. plP_FreeDrvOpts();
  1362. lib_initialized = 0;
  1363. }
  1364. /*--------------------------------------------------------------------------*\
  1365. * void plend1()
  1366. *
  1367. * End a plotting session for the current stream only. After the stream is
  1368. * ended the memory associated with the stream's PLStream data structure is
  1369. * freed (for stream > 0), and the stream counter is set to 0 (the default).
  1370. \*--------------------------------------------------------------------------*/
  1371. void
  1372. c_plend1(void)
  1373. {
  1374. if (plsc->level > 0) {
  1375. plP_eop();
  1376. plP_tidy();
  1377. plsc->level = 0;
  1378. }
  1379. /* Move from plP_tidy because FileName may be set even if level == 0 */
  1380. if (plsc->FileName)
  1381. free_mem(plsc->FileName);
  1382. /* Free all malloc'ed stream memory */
  1383. free_mem(plsc->cmap0);
  1384. free_mem(plsc->cmap1);
  1385. free_mem(plsc->plwindow);
  1386. free_mem(plsc->geometry);
  1387. free_mem(plsc->dev);
  1388. free_mem(plsc->BaseName);
  1389. if (plsc->program) free_mem(plsc->program);
  1390. if (plsc->server_name) free_mem(plsc->server_name);
  1391. if (plsc->server_host) free_mem(plsc->server_host);
  1392. if (plsc->server_port) free_mem(plsc->server_port);
  1393. if (plsc->user) free_mem(plsc->user);
  1394. if (plsc->plserver) free_mem(plsc->plserver);
  1395. if (plsc->auto_path) free_mem(plsc->auto_path);
  1396. if (plsc->arrow_x) free_mem(plsc->arrow_x);
  1397. if (plsc->arrow_y) free_mem(plsc->arrow_y);
  1398. /* Free malloc'ed stream if not in initial stream, else clear it out */
  1399. if (ipls > 0) {
  1400. free_mem(plsc);
  1401. pls[ipls] = NULL;
  1402. plsstrm(0);
  1403. }
  1404. else {
  1405. memset((char *) pls[ipls], 0, sizeof(PLStream));
  1406. }
  1407. }
  1408. /*--------------------------------------------------------------------------*\
  1409. * void plsstrm
  1410. *
  1411. * Set stream number. If the data structure for a new stream is
  1412. * unallocated, we allocate it here.
  1413. \*--------------------------------------------------------------------------*/
  1414. void
  1415. c_plsstrm(PLINT strm)
  1416. {
  1417. if (strm < 0 || strm >= PL_NSTREAMS) {
  1418. fprintf(stderr,
  1419. "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
  1420. (int) strm, PL_NSTREAMS);
  1421. }
  1422. else {
  1423. ipls = strm;
  1424. if (pls[ipls] == NULL) {
  1425. pls[ipls] = (PLStream *) malloc((size_t) sizeof(PLStream));
  1426. if (pls[ipls] == NULL)
  1427. plexit("plsstrm: Out of memory.");
  1428. memset((char *) pls[ipls], 0, sizeof(PLStream));
  1429. }
  1430. plsc = pls[ipls];
  1431. plsc->ipls = ipls;
  1432. }
  1433. }
  1434. /*--------------------------------------------------------------------------*\
  1435. * void plgstrm
  1436. *
  1437. * Get current stream number.
  1438. \*--------------------------------------------------------------------------*/
  1439. void
  1440. c_plgstrm(PLINT *p_strm)
  1441. {
  1442. *p_strm = ipls;
  1443. }
  1444. /*--------------------------------------------------------------------------*\
  1445. * void plmkstrm
  1446. *
  1447. * Creates a new stream and makes it the default. Differs from using
  1448. * plsstrm(), in that a free stream number is found, and returned.
  1449. *
  1450. * Unfortunately, I /have/ to start at stream 1 and work upward, since
  1451. * stream 0 is preallocated. One of the BIG flaws in the PLplot API is
  1452. * that no initial, library-opening call is required. So stream 0 must be
  1453. * preallocated, and there is no simple way of determining whether it is
  1454. * already in use or not.
  1455. \*--------------------------------------------------------------------------*/
  1456. void
  1457. c_plmkstrm(PLINT *p_strm)
  1458. {
  1459. int i;
  1460. for (i = 1; i < PL_NSTREAMS; i++) {
  1461. if (pls[i] == NULL)
  1462. break;
  1463. }
  1464. if (i == PL_NSTREAMS) {
  1465. fprintf(stderr, "plmkstrm: Cannot create new stream\n");
  1466. *p_strm = -1;
  1467. }
  1468. else {
  1469. *p_strm = i;
  1470. plsstrm(i);
  1471. }
  1472. plstrm_

Large files files are truncated, but you can click here to view the full file