1 /* *************************************************************************
2 gdlgstream.cpp - graphic stream
3 -------------------
4 begin : July 22 2002
5 copyright : (C) 2002 by Marc Schellens
6 email : m_schellens@users.sf.net
7 ***************************************************************************/
8
9 /* *************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "includefirst.hpp"
19
20 #include <iostream>
21
22 #include "graphicsdevice.hpp"
23 #include "gdlgstream.hpp"
24 #include "initsysvar.hpp"
25
26 using namespace std;
27
28 // bool GDLGStream::plstreamInitCalled = false;
29
30 // void PLPlotAbortHandler(const char *c)
31 // {
32 // cout << "PLPlot abort handler: " << c << endl;
33 // }
34 //
35 // int PLPlotExitHandler(const char *c)
36 // {
37 // cout << "PLPlot exit handler: " << c << endl;
38 // return 0;
39 // }
40 //
41 // void GDLGStream::SetErrorHandlers()
42 // {
43 // plsexit( PLPlotExitHandler);
44 // plsabort( PLPlotAbortHandler);
45 // }
46
Thick(DFloat thick)47 void GDLGStream::Thick(DFloat thick)
48 {
49 //note that 'cmake' may not able to find correct value of HAVE_PLPLOT_WIDTH. Please report.
50 // in the meantime, you may edit "config.h" by hand.
51 #ifdef HAVE_PLPLOT_WIDTH
52 plstream::width(static_cast<PLFLT>(thick*thickFactor));
53 #else
54 plstream::wid(static_cast<PLINT>(floor((thick*thickFactor)-0.5)));
55 #endif
56 }
57
58 #define BLACK 0
59 #define WHITE 16777215
Color(ULong color,DLong decomposed)60 void GDLGStream::Color( ULong color, DLong decomposed) {
61 bool printer = (((*static_cast<DLongGDL*> (SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("FLAGS"), 0)))[0] & 512) == 512);
62 bool bw = (((*static_cast<DLongGDL*> (SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("FLAGS"), 0)))[0] & 16) == 0); //in that case,
63 //plplot postscript driver uses gray levels instead of colorindex, and 1 is black, not 0 !!!
64 if (decomposed == 0) {
65 if (printer && (color & 0xFF) == 0) { color=(bw)?WHITE:BLACK; //note that if bw other colors will be a gray value
66 GDLGStream::SetColorMap1SingleColor(color);
67 plstream::col1(1); //send specifically color ZERO = black.
68 return;
69 } else plstream::col0(color & 0xFF); //just set color index [0..255]. simple and fast.
70 } else {
71 if (printer && color == 0) color=(bw)?WHITE:BLACK;
72 GDLGStream::SetColorMap1SingleColor(color);
73 plstream::col1(1); //send specifically color ZERO = black.
74 return;
75 }
76 }
77 #undef BLACK
78
SetColorMap1SingleColor(ULong color)79 void GDLGStream::SetColorMap1SingleColor( ULong color)
80 {
81 PLINT red[2],green[2],blue[2];
82 red[0] =red[1] = color & 0xFF;
83 green[0] = green[1] =(color >> 8) & 0xFF;
84 blue[0]= blue[1]=(color >> 16) & 0xFF;
85 SetColorMap1(red, green, blue, 2);
86 }
87
SetColorMap1DefaultColors(PLINT ncolors,DLong decomposed)88 void GDLGStream::SetColorMap1DefaultColors(PLINT ncolors, DLong decomposed)
89 {
90 if (decomposed == 0) { //just copy Table0 to Table1 so that scale from 0 to 1 in table 1 goes through the whole table
91 PLINT r[ctSize], g[ctSize], b[ctSize];
92 GraphicsDevice::GetCT()->Get( r, g, b);
93 SetColorMap1(r, g, b, ctSize);
94 } else {
95 PLFLT r[2], g[2], b[2], pos[2];
96 r[0] = pos[0] = 0.0;
97 r[1] = pos[1] = 1.0;
98 g[0] = g[1] = 0.0;
99 b[0] = b[1] = 0.0;
100 SetColorMap1n(ncolors);
101 SetColorMap1l(TRUE,2,pos,r, g, b, NULL);
102 }
103 }
104
SetColorMap1Table(PLINT tableSize,BaseGDL * passed_colors,DLong decomposed)105 void GDLGStream::SetColorMap1Table( PLINT tableSize, BaseGDL *passed_colors, DLong decomposed)
106 { //cycle on passed colors to fill tableSize.
107 DLongGDL *colors=static_cast<DLongGDL*>(passed_colors);
108 DLong n=colors->N_Elements();
109 #ifdef _MSC_VER
110 PLINT *r = (PLINT*)alloca(sizeof(PLINT)*tableSize);
111 PLINT *g = (PLINT*)alloca(sizeof(PLINT)*tableSize);
112 PLINT *b = (PLINT*)alloca(sizeof(PLINT)*tableSize);
113 #else
114 PLINT r[tableSize], g[tableSize], b[tableSize];
115 #endif
116 if (decomposed == 0) {
117 PLINT red[ctSize], green[ctSize], blue[ctSize], col;
118 GraphicsDevice::GetCT()->Get( red, green, blue);
119 for (SizeT i=0; i< tableSize; ++i) {
120 col = (*colors)[i%n]& 0xFF;
121 r[i] = red[col];
122 g[i] = green[col];
123 b[i] = blue[col];
124 }
125 } else {
126 PLINT col;
127 for (SizeT i=0; i< tableSize; ++i) {
128 col = (*colors)[i%n];
129 r[i] = col & 0xFF;
130 g[i] = (col >> 8) & 0xFF;
131 b[i] = (col >> 16) & 0xFF;
132 }
133 }
134 SetColorMap1(r, g, b, tableSize);
135 }
136
SetColorMap1Ramp(DLong decomposed,PLFLT minlight)137 void GDLGStream::SetColorMap1Ramp(DLong decomposed, PLFLT minlight)
138 { //cycle on passed colors to fill table1 with ramp.
139 PLFLT h[2], l[2], s[2], pos[2];
140 h[0] = h[1] = s[0] = s[1] = pos[0] = 0.0;
141 l[0] = minlight;
142 l[1] = pos[1] = 1.0;
143 SetColorMap1n(256);
144 SetColorMap1l(FALSE,2,pos,h, l, s, NULL);
145 }
146 #define WHITEB 255
Background(ULong color,DLong decomposed)147 void GDLGStream::Background( ULong color, DLong decomposed)
148 {
149 if ((*static_cast<DLongGDL*>(SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("FLAGS"), 0)))[0] & 512 ) { ;//printer like PostScript
150 GraphicsDevice::GetDevice()->SetDeviceBckColor(WHITEB, WHITEB, WHITEB );
151 return;
152 }
153 DByte r,g,b;
154 PLINT red,green,blue;
155 if (decomposed == 0) { //just an index
156 GraphicsDevice::GetCT()->Get( color & 0xFF, r, g, b);
157 red=r; green=g; blue=b;
158 } else {
159 red = color & 0xFF;
160 green = (color >> 8) & 0xFF;
161 blue = (color >> 16) & 0xFF;
162 }
163 GraphicsDevice::GetDevice()->SetDeviceBckColor( red, green, blue);
164 }
DefaultBackground()165 void GDLGStream::DefaultBackground()
166 {
167 if ((*static_cast<DLongGDL*>(SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("FLAGS"), 0)))[0] & 512 ) { ;//printer like PostScript
168 GraphicsDevice::GetDevice()->SetDeviceBckColor(WHITEB, WHITEB, WHITEB );
169 return;
170 }
171 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset
172 DLong background=(*static_cast<DLongGDL*>(pStruct->GetTag(pStruct->Desc()->TagIndex("BACKGROUND"), 0)))[0];
173 DByte r,g,b;
174 PLINT red,green,blue;
175 if (GraphicsDevice::GetDevice()->GetDecomposed() == 0) { //just an index
176 GraphicsDevice::GetCT()->Get( background & 0xFF, r, g, b);
177 red=r; green=g; blue=b;
178 } else {
179 red = background & 0xFF;
180 green = (background >> 8) & 0xFF;
181 blue = (background >> 16) & 0xFF;
182 }
183 GraphicsDevice::GetDevice()->SetDeviceBckColor( red, green, blue);
184 }
185 #undef WHITEB
DefaultCharSize()186 void GDLGStream::DefaultCharSize() {
187 DStructGDL* d = SysVar::D();
188 DStructDesc* s = d->Desc();
189 int X_CH_SIZE = s->TagIndex("X_CH_SIZE");
190 int Y_CH_SIZE = s->TagIndex("Y_CH_SIZE");
191 int X_PX_CM = s->TagIndex("X_PX_CM");
192 int Y_PX_CM = s->TagIndex("Y_PX_CM");
193 DLong chx = (*static_cast<DLongGDL*> (d->GetTag(X_CH_SIZE, 0)))[0];
194 DLong chy = (*static_cast<DLongGDL*> (d->GetTag(Y_CH_SIZE, 0)))[0];
195 DFloat xpxcm = (*static_cast<DFloatGDL*> (d->GetTag(X_PX_CM, 0)))[0];
196 DFloat ypxcm = (*static_cast<DFloatGDL*> (d->GetTag(Y_PX_CM, 0)))[0];
197 DFloat xchsizemm = GetPlplotFudge() * chx * CM_IN_MM / xpxcm;
198 DFloat linespacingmm = GetPlplotFudge() * chy * CM_IN_MM / ypxcm;
199 schr(xchsizemm, 1.0, linespacingmm);
200 }
RenewPlplotDefaultCharsize(PLFLT newMmSize)201 void GDLGStream::RenewPlplotDefaultCharsize(PLFLT newMmSize)
202 {
203 plstream::schr(newMmSize, 1.0);
204 gdlDefaultCharInitialized=0;
205 GetPlplotDefaultCharSize();
206 }
207
GetPlplotDefaultCharSize()208 void GDLGStream::GetPlplotDefaultCharSize()
209 {
210
211 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"GetPlPlotDefaultCharsize()\n");
212 if (thePage.nbPages==0) {return;}
213 //dimensions in normalized, device and millimetres
214 if (gdlDefaultCharInitialized==1) {if (GDL_DEBUG_PLSTREAM) fprintf(stderr," Already initialized\n"); return;}
215 theDefaultChar.scale=1.0;
216 theDefaultChar.mmsx=pls->chrht; //millimeter
217 theDefaultChar.mmsy=pls->chrht;
218 theDefaultChar.fudge=GetPlplotFudge();
219 theDefaultChar.ndsx=mm2ndx(theDefaultChar.mmsx); //normalized device
220 theDefaultChar.ndsy=mm2ndy(theDefaultChar.mmsy);
221 theDefaultChar.dsy=theDefaultChar.ndsy*thePage.height;
222 theDefaultChar.dsx=theDefaultChar.ndsx*thePage.length;
223 theDefaultChar.mmspacing=theLineSpacing_in_mm;
224 theDefaultChar.nspacing=mm2ndy(theDefaultChar.mmspacing);
225 theDefaultChar.dspacing=theDefaultChar.nspacing*thePage.height;
226 theDefaultChar.wspacing=mm2wy(theDefaultChar.mmspacing);
227
228 theDefaultChar.wsx=mm2wx(theDefaultChar.mmsx); //world
229 theDefaultChar.wsy=mm2wy(theDefaultChar.mmsy);
230 if (GDL_DEBUG_PLSTREAM) fprintf(stderr," %fx%f,%f (mm)\n",theDefaultChar.mmsx ,theDefaultChar.mmsy ,theDefaultChar.mmspacing);
231 if (GDL_DEBUG_PLSTREAM) fprintf(stderr," %fx%f,%f (norm)\n",theDefaultChar.ndsx ,theDefaultChar.ndsy ,theDefaultChar.nspacing);
232 if (GDL_DEBUG_PLSTREAM) fprintf(stderr," %fx%f,%f (dev)\n",theDefaultChar.dsx ,theDefaultChar.dsy ,theDefaultChar.dspacing);
233 if (GDL_DEBUG_PLSTREAM) fprintf(stderr," %fx%f,%f (world)\n",theDefaultChar.wsx ,theDefaultChar.wsy ,theDefaultChar.wspacing);
234 gdlDefaultCharInitialized=1;
235 }
236
NextPlot(bool erase)237 void GDLGStream::NextPlot( bool erase )
238 {
239 DLongGDL* pMulti = SysVar::GetPMulti();
240
241 DLong nx = (*pMulti)[ 1];
242 DLong ny = (*pMulti)[ 2];
243 DLong nz = (*pMulti)[ 3];
244
245 DLong dir = (*pMulti)[ 4];
246
247 nx = (nx>0)?nx:1;
248 ny = (ny>0)?ny:1;
249 nz = (nz>0)?nz:1;
250 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"NextPlot(erase=%d)\n",erase);
251 // set subpage numbers in X and Y
252 // plstream::ssub( nx, ny ); // ssub does not change charsize it seems
253 ssub( nx, ny );
254 DLong pMod = (*pMulti)[0] % (nx*ny);
255
256 // if( (*pMulti)[0] <= 0 || (*pMulti)[0] == nx*ny) // clear and restart to first subpage
257 if( pMod == 0 ) // clear and restart to first subpage
258 {
259 if( erase )
260 {
261 eop(); // overridden (for Z-buffer)
262 //get background value (*not pen 0*, we try to avoid plplot's silly behaviour).
263 //use it for bop(), then reset the pen 0 to correct value.
264
265 PLINT red,green,blue;
266 DByte r,g,b;
267 PLINT red0,green0,blue0;
268
269 GraphicsDevice::GetCT()->Get(0,r,g,b);red=r;green=g;blue=b;
270
271 red0=GraphicsDevice::GetDevice()->BackgroundR();
272 green0=GraphicsDevice::GetDevice()->BackgroundG();
273 blue0=GraphicsDevice::GetDevice()->BackgroundB();
274 plstream::scolbg(red0,green0,blue0); //overwrites col[0]
275 plstream::bop(); // note: changes charsize
276 plstream::scolbg(red,green,blue); //resets col[0]
277 }
278
279 // plstream::adv(1); //advance to first subpage
280 adv(1); //advance to first subpage
281 (*pMulti)[0] = nx*ny*nz-1; //set PMULTI[0] to this page
282 }
283 else
284 {
285 if( dir == 0 )
286 {
287 // plstream::adv(nx*ny - pMod + 1);
288 adv(nx*ny - pMod + 1);
289 }
290 else
291 {
292 int p = nx*ny - pMod;
293 int pp = p*nx % (nx*ny) + p/ny + 1;
294 // plstream::adv(pp);
295 adv(pp);
296 }
297 if( erase )
298 {
299 --(*pMulti)[0];
300 }
301 }
302 // restore charsize to default for newpage
303 sizeChar(1.0);
304 }
305
NoSub()306 void GDLGStream::NoSub()
307 {
308 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"NoSub()\n");
309 ssub( 1, 1); // changes charsize ?
310 //plstream::adv( 0);
311 adv( 0);
312 // DefaultCharSize();
313 }
314
315
316 // default is a wrapper for gpage(). Is overriden by, e.g., X driver.
GetGeometry(long & xSize,long & ySize)317 void GDLGStream::GetGeometry( long& xSize, long& ySize)
318 {
319 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"GDLGStream::GetGeometry()\n");
320 PLFLT xp; PLFLT yp;
321 PLINT xleng; PLINT yleng;
322 PLINT plxoff; PLINT plyoff;
323 plstream::gpage( xp, yp, xleng, yleng, plxoff, plyoff); //for X-Window, wrapper give sizes from X11, not plplot which seems bugged.
324 // for PostScript, Page size is FIXED (720x540) and GDLPSStream::GetGeometry replies correctly
325
326 //since the page sizes for PS and EPS images are processed by GDL after plplot finishes
327 //its work, gpage will not output correct sizes
328 DString name = (*static_cast<DStringGDL*>(
329 SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("NAME"), 0)
330 ))[0];
331 if (name == "PS") {
332 xSize = (*static_cast<DLongGDL*>(SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("X_SIZE"), 0)))[0];
333 ySize = (*static_cast<DLongGDL*>(SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("Y_SIZE"), 0)))[0];
334 } else {
335 xSize = xleng;
336 ySize = yleng;
337 }
338 if (xSize<1.0||ySize<1) //plplot gives back crazy values! z-buffer for example!
339 {
340 PLFLT xmin,xmax,ymin,ymax;
341 plstream::gspa(xmin,xmax,ymin,ymax); //subpage in mm
342 xSize=min(1.0,xmax-xmin);
343 ySize=min(1.0,ymax-ymin);
344 }
345 if (GDL_DEBUG_PLSTREAM) fprintf(stderr," found (%ld %ld)\n", xSize, ySize);
346
347 }
348
349 // SA: embedded font attributes handling (IDL to plPlot syntax translation)
TranslateFormatCodes(const char * in,double * stringLength=NULL)350 std::string GDLGStream::TranslateFormatCodes(const char *in, double *stringLength=NULL)
351 {
352 bool debug = false;
353 static char errmsg[] = "No such font: ";
354 static std::string begin_unicode="#[";
355 static std::string end_unicode="]";
356 static const size_t errmsglen = strlen(errmsg);
357 static double fact[]={1.,0.9,0.666,0.5,0.45,0.33,0.2};
358 double base=1.0;
359
360 // TODO:
361 // - in IDL the D.FLAGS bit value ((!D.FLAGS AND 4096) EQ 0)
362 // is designed to indicate if the device does not support extended commands
363 // - unicode substitution for non-unicode terminals results in plplot controll
364 // sequences being printed
365 // do something about handling of !C and !S and !R
366 // - ... a look-up table instead of the long switch/case blocks ...
367
368 size_t len = strlen(in);
369 if (stringLength) *stringLength=0;
370 // skip conversion if the string is empty
371 if (len == 0) return "";
372
373
374 int default_fnt = activeFontCodeNum;
375 std::string out = std::string(internalFontCodes[default_fnt]);
376 //no, take current value, initialized to 3. was: activeFontCodeNum = default_fnt; // (current font number from the above table)
377 int curr_fnt = default_fnt; // (current font number from the above table)
378 int next_fnt = default_fnt; // (next letter font - same as curr_fnt save for the case of !G, !W and !M commands)
379 int curr_lev = 0; // (incremented with #u, decremented with #d)
380 int curr_pos = 0; // (current position in string)
381 int save_pos = 0; // (position in string used in !S/!R save/restore)
382
383 for (size_t i = 0; i < len; i++) {
384 if (in[i] == '!' && in[i + 1] != '!')
385 {
386 size_t j = 1; // number of characters analysed (after !)
387 switch (in[i + 1])
388 {
389 case '1' : // 2-char codes begining with !1
390 {
391 switch (in[i + 2])
392 {
393 case '6' : // !16 : Cyrillic
394 base=17./15.;//approx size of a hershey char with this font.
395 j++;
396 out += internalFontCodes[activeFontCodeNum = curr_fnt = next_fnt = 10 - 48 + in[i + 2]];
397 break;
398 case '8' : // !18 : Triplex Italic
399 base=16.5/15.;//approx size of a hershey char with this font.
400 j++;
401 out += internalFontCodes[activeFontCodeNum = curr_fnt = next_fnt = 10 - 48 + in[i + 2]];
402 break;
403 case '0' : // !10 : Special characters
404 case '1' : // !11 : Gothic English
405 case '2' : // !12 : Simplex Script
406 case '3' : // !13 : Complex Script
407 case '4' : // !14 : Gothic Italian
408 case '5' : // !15 : Gothic German
409 case '7' : // !17 : Triplex Roman
410 case '9' : // !19 :
411 base=1.0;
412 j++;
413 out += internalFontCodes[activeFontCodeNum = curr_fnt = next_fnt = 10 - 48 + in[i + 2]];
414 break;
415 default : // illegal command / end of string
416 errmsg[errmsglen - 2] = in[i + 1];
417 errmsg[errmsglen - 1] = in[i + 2];
418 j++;
419 Warning(errmsg);
420 }
421 break;
422 }
423 case '2' : // 2-char codes begining with !2
424 {
425 switch (in[i + 2])
426 {
427 case '0' : // !20 : Miscellaneous
428 base=17.5/15.;//approx size of a hershey char with this font.
429 j++;
430 out += internalFontCodes[activeFontCodeNum = curr_fnt = next_fnt = 20 - 48 + in[i + 2]];
431 break;
432 default : // illegal command / end of string
433 errmsg[errmsglen - 2] = in[i + 1];
434 errmsg[errmsglen - 1] = in[i + 2];
435 j++;
436 Warning(errmsg);
437 }
438 break;
439 }
440
441 case '7' : // complex greek
442 case '8' : // complex italic
443 base=16.5/15.; //approx size of a hershey char with these fonts.
444 out += internalFontCodes[activeFontCodeNum = next_fnt = curr_fnt = in[i + 1] - 48];
445 break;
446
447 case '3' : // simplex roman
448 case '4' : // greek script
449 case '5' : // duplex roman
450 case '6' : // complex roman
451 case '9' : // Math/special characters
452 base=1.0;
453 out += internalFontCodes[activeFontCodeNum = next_fnt = curr_fnt = in[i + 1] - 48];
454 break;
455
456 case 'M' : case 'm' : // one Math/special character
457 curr_fnt = 9;
458 break;
459 case 'G' : case 'g' : // one Gothic English character
460 curr_fnt = 11;
461 break;
462 case 'W' : case 'w' : // one Simplex Script character
463 curr_fnt = 12;
464 break;
465
466 case 'C' : case 'c' : // carriage return (TODO FIXME: does not work in PostScript!)
467 out += "#[0xD]";
468 break;
469
470 case 'X' : case 'x' : // reversion to entry font
471 out += internalFontCodes[curr_fnt = next_fnt = default_fnt];
472 break;
473
474 case 'S' : case 's' : // save position
475 save_pos = curr_pos;
476 break;
477
478 case 'L' : case 'l' : // 2nd level subscript
479 curr_lev--;
480 out += "#d";
481 // continues!
482 case 'B' : case 'b' : case 'D' : case 'd' : // subscript
483 case 'I' : case 'i' : // index
484 curr_lev--;
485 out += "#d";
486 break;
487 case 'R' : case 'r' : // restore position
488 for (; save_pos < curr_pos; curr_pos--) out += "#b";
489 // continues!
490 //case 'A' : case 'a' : // shift above the division line
491 //TODO: plplot seems not to support it ----> treated as upperscript for the moment
492 // case 'B' : case 'b' : // shift below the division line
493 //TODO: plplot seems not to support it ----> treated as subscript for the moment
494 case 'N' : case 'n' : // back to normal size
495 while (curr_lev != 0)
496 {
497 if (curr_lev > 0) out += "#d", curr_lev--;
498 else out += "#u", curr_lev++;
499 }
500 // assumed from examples in documentation
501 //if (in[i + 1] == 'N' || in[i + 1] == 'n') out += internalFontCodes[curr_fnt = next_fnt = default_fnt];
502 break;
503 case 'A' : case 'a' : case 'U' : case 'u' : // superscript
504 case 'E' : case 'e' : // exponent
505 curr_lev++;
506 out += "#u";
507 break;
508 case 'Z' : case 'z' : // unicode chars via "#[nnn]"
509 // first, the only two examples from IDL doc:
510 // - !Z(00B0) - degree symbol
511 // - !Z(U+0F1) - Spanish "n" with tilde (as in El ni\~no)
512 // searching for the left parenthesis
513 if (in[i + 2] != '(')
514 {
515 if (in[i + 2] == '!' && in[i + 3] == 'Z') break; // !Z!Z is valid
516 if (in[i + 2] == '\0') break; // end of string after !Z is valid
517 Warning("Error using Hershey characters: Parentheses required for !Z.");
518 goto retrn;
519 }
520 else
521 {
522 // searching for the right parenthesis
523 size_t right_par = i + 2;
524 while (in[++right_par] != ')') if (right_par == len)
525 {
526 Warning("Error using Hershey characters: Parentheses required for !Z.");
527 goto retrn;
528 }
529 size_t chars = 0;
530 while (j + i + 1 != right_par)
531 {
532 // tokenizing (plethora of other tokens is accepted by IDL!)
533 while (++j + i + 1 != right_par && in[j + i + 1] != ',') chars++;
534 if (in[j + i + 1 - chars] == 'U' && in[j + i + 2 - chars] == '+') chars-=2; // U+NNNN syntax
535 if (chars > 4)
536 {
537 Warning("Error using Hershey characters: !Z hexadecimal value too large.");
538 goto retrn;
539 }
540 else if (chars > 0)
541 {
542 out += "#[0x";
543 for (; chars > 0; chars--) out += in[j + i + 1 - chars];
544 out += "]";
545 curr_pos++;
546 }
547 }
548 j++; // right parenthesis
549 }
550 break;
551 case '\0' : // end of string
552 default : // unknown command
553 j--;
554 curr_pos++;
555 out += "!";
556 break;
557 }
558 i += j;
559 }
560 else
561 {
562 if (stringLength) *stringLength+=base*fact[curr_lev%7];
563 curr_pos++;
564 // handling IDL exclamation mark escape '!!'
565 if (in[i] == '!') {
566 i++;
567 if (stringLength) *stringLength+=base*fact[curr_lev%7];
568 }
569 // handling plplot number sign escape '##'
570 if
571 (
572 curr_fnt != 9 &&
573 curr_fnt != 10 &&
574 curr_fnt != 16 &&
575 curr_fnt != 20 &&
576 in[i] == '#'
577 ) out += "##";
578 else switch (curr_fnt)
579 {
580 case 9 : // math symbols
581 switch (in[i])
582 {
583 case '!' : out += "#(2229)"; break; // vertical line
584 case '%' : out += "#(218)"; break; // degree circle
585 case 'X' : out += "#(227)"; break; // x (cross) sign
586 case 'D' : // as below
587 case 'd' : out += "#(2265)"; break; // partial deriv sign
588 case 'r' : out += "#(2267)"; break; // square root sign bigger
589 case 'R' : out += "#(2411)"; break; // square root sign biggest
590 case 'S' : out += "#(2267)"; break; // square root sign
591 case 'I' : out += "#(2412)"; break; // big integral sign
592 case 'i' : out += "#(2268)"; break; // small integral sign
593 case '/' : out += "#(2237)"; break; // range (dot dash dot) sign
594 case '=' : out += "#(2239)"; break; // non equal sign
595 case '6' : out += "#(2261)"; break; // arrow right
596 case '7' : out += "#(2262)"; break; // arrow up
597 case '4' : out += "#(2263)"; break; // arrow left
598 case '5' : out += "#(2264)"; break; // arrow down
599 case 'f' : out += "#(2283)"; break; // female sex sign
600 case 'm' : out += "#(2285)"; break; // male sex sign
601 case '<' : out += "#(2407)"; break; // big curly brace left
602 case '>' : out += "#(2408)"; break; // big curly brace right
603 case '#' : out += "#(737)"; break; // two vertical lines
604 case '$' : out += "#(766)"; break; // infty
605 case '&' : out += "#(2276)"; break; // paragraph
606 case 'P' : out += "#(2147)"; break; // phi
607 case 'p' :
608 out += "#fsp";
609 out += internalFontCodes[curr_fnt]; break; // p script
610 case 'q' :
611 out += "#fsq";
612 out += internalFontCodes[curr_fnt]; break; // q script
613 case ':' : out += "#(2240)"; break; // equal by definition sign
614 case '.' : out += "#(850)"; break; // filled dot
615 case 'B' : out += "#(841)"; break; // empty square
616 case 'F' :
617 out += "#fsF";
618 out += internalFontCodes[curr_fnt]; break; // F script
619 case 'J' : out += "#(2269)"; break; // closed path integral
620 case 'O' : out += "#(2277)"; break; // 'upper' cross sign
621 case 'o' : out += "#(2278)"; break; // double cross sign
622 case 'j' :
623 out += "#fsj";
624 out += internalFontCodes[curr_fnt]; break; // j italic
625 case 's' : out += "#(687)"; break; // some greek zig-zag
626 case 't' :
627 out += "#fs#(634)"; break; // theta-like greek zig-zag
628 case 'A' : out += "#(2246)"; break; // similar / tilde
629 case 'T' : out += "#(740)"; break; // three dots
630 case 'U' : out += "#(741)"; break; // spades (card sign)
631 case 'V' : out += "#(743)"; break; // diamonds (card sign)
632 case 'W' : out += "#(745)"; break; // clover sign
633 case 'u' : out += "#(742)"; break; // hearts (card sign)
634 case 'v' : out += "#(744)"; break; // clubs (card sign)
635 case 'w' : out += "#(746)"; break; // ?
636 case '_' : // as below
637 case 127u : out += "#(830)"; break; // '---' sign
638 case 'H' : out += "#(908)"; break; // ?
639 case '@' : out += "#(2077)"; break; // ? kappa like
640 case 'n' : out += "#(2281)"; break; // circle with dot inside
641 case 'e' : out += "#(2260)"; break; // mirrored E
642 case 'E' : out += "#(2279)"; break; // element of
643 case 'G' : out += "#(2266)"; break; // nabla
644 case 'l' : out += "#(2243)"; break; // less or equal
645 case 'b' : out += "#(2244)"; break; // grater or equal
646 case '?' : out += "#(2245)"; break; // proportional
647 case '^' : // as below
648 case '~' : out += "#(2247)"; break; // ^
649 case '+' : out += "#(2233)"; break; // plus minus
650 case '-' : out += "#(2234)"; break; // minus plus
651 case '(' : out += "#(2403)"; break; // big bracket left
652 case ')' : out += "#(2404)"; break; // big bracket right
653 case '[' : // as below
654 case '{' : out += "#(2405)"; break; // big rect. brace left
655 case ']' : // as below
656 case '}' : out += "#(2406)"; break; // big rect. brace right
657 case 'h' : out += "#(909)"; break; // ? police badge-like
658 case 'x' : out += "#(738)"; break; // perpendicular sign
659 case 'a' : out += "#(739)"; break; // angle
660 case 'c' : out += "#(823)"; break; // ?
661 case '0' : out += "#(2256)"; break; // set theory C-like
662 case '1' : out += "#(2257)"; break; // set theory U-like
663 case '2' : out += "#(2258)"; break; // set theory )-like
664 case '3' : out += "#(2259)"; break; // set theory ^-like
665 case 'N' : out += "#(2311)"; break; // double wave
666 case '`' : out += "'"; break; // ` -> '
667 // empty chars:
668 case '8' : case '9' : case ';' : case 'K' : case 'L' : case 'M' : case 'Q' :
669 case 'Y' : case 'Z' : case '\\' : case 'k' : case 'y' : case 'z' : case '|' :
670 case 'g' :
671 // unsupported chars:
672 case 'C' : // tick sign
673 out += " "; break;
674 break;
675 default :
676 if ((unsigned char)in[i] > 127) { out+=begin_unicode; out+=to_string((unsigned char)in[i]); out+=end_unicode; } else out.append(in, i, 1); //use unicode
677 break;
678 }
679 break;
680 case 20 : // misc symbols
681 switch (in[i])
682 {
683 case 'b' : out += "#(851)"; break; // filled square
684 case ':' : // small filled triangle up
685 case 'C' : out += "#(852)"; break; // filled triangle up
686 case 'D' : out += "#(854)"; break; // filled triangle down
687 case '/' : out += "#(2323)"; break; // musical sharp sign
688 case 'M' : out += "#(874)"; break; // ?
689 case 'K' : out += "#(870)"; break; // palm sign
690 case '^' : // as below
691 case '~' : out += "#(834)"; break; // upside down triangle
692 case 'N' : out += "#(900)"; break; // circle smallest
693 case 'n' : out += "#(901)"; break; // circle smaller
694 case 'O' : out += "#(902)"; break; // circle small
695 case 'o' : out += "#(903)"; break; // circle
696 case 'P' : out += "#(904)"; break; // circle
697 case 'p' : out += "#(905)"; break; // circle big
698 case 'Q' : out += "#(906)"; break; // circle bigger
699 case 'q' : out += "#(907)"; break; // circle biggest
700 case '?' : out += "#(767)"; break; // flash
701 case '<' : out += "#(768)"; break; // paragraph-like
702 case 'A' : out += "#(754)"; break; // upper semicircle filled
703 case 'G' : out += "#(862)"; break; // two hammers
704 case 'E' : out += "#(856)"; break; // star
705 case 'e' : out += "#(857)"; break; // flag
706 case 'f' : out += "#(861)"; break; // ?
707 case 'g' : out += "#(863)"; break; // tower / look-out
708 case 'h' : out += "#(865)"; break; // grave
709 case 'L' : out += "#(872)"; break; // deciduous tree
710 case 'k' : out += "#(871)"; break; // coniferous tree
711 case '"' : out += "#(2409)"; break; // big inverted-s-like shape
712 case '$' : out += "#(2376)"; break; // ?
713 case '%' : out += "#(2382)"; break; // ?
714 case '`' :
715 case '\'' : out += "#(766)"; break; // infty
716 case '(' : out += "#(2374)"; break; // natural (music)
717 case ')' : out += "#(2375)"; break; // flat (music)
718 case '*' : out += "#(2372)"; break; // ? minim (music)
719 case '-' : // as below
720 case '+' : out += "#(2371)"; break; // ? 2xminim length note (music)
721 case ',' : out += "#(2329)"; break; // ? rest (music)
722 case '.' : out += "#(2380)"; break; // treble clef
723 case '0' : out += "#(2306)"; break; // ? Gothic-like m
724 case '1' : out += "#(2307)"; break; // ? underlined omega
725 case '2' : out += "#(2308)"; break; // ? Gothic-like m
726 case '3' : out += "#(2309)"; break; // NE double arrow
727 case '4' : out += "#(2310)"; break; // ?
728 case '5' : out += "#(2311)"; break; // ?
729 case '6' : out += "#(2312)"; break; // ?
730 case '7' : out += "#(2317)"; break; // ?
731 case '8' : out += "#(2318)"; break; // ?
732 case '9' : out += "#(2319)"; break; // ?
733 case '=' : out += "#(2377)"; break; // ?
734 case '>' : out += "#(831)"; break; // ?
735 case 'V' : out += "#(2291)"; break; // crescent
736 case 'W' : out += "#(2293)"; break; // 8-arm star
737 case 'X' : out += "#(2295)"; break; // ?
738 case 'Y' : out += "#(2302)"; break; // ?
739 case 'Z' : out += "#(2304)"; break; // 69 ;)
740 case 'r' : out += "#(2282)"; break; // ? female sex sign like
741 case 'u' : out += "#(2290)"; break; // ? P-like
742 case 'v' : out += "#(2292)"; break; // ?
743 case 'w' : out += "#(2294)"; break; // ? omega-like
744 case 'x' : out += "#(2301)"; break; // ? fountain-like
745 case 'y' : out += "#(2303)"; break; // ?
746 case '[' : // as below
747 case '{' : out += "#(2332)"; break; // ? ladder-like
748 case ']' : // as below
749 case '}' : out += "#(2381)"; break; // bass clef
750 case '_' : // as below
751 case 127 : out += "#(2410)"; break; // big s-like shape
752 case '!' : out += "#(764)"; break; // S-like
753 case '&' : out += "#(765)"; break; // tilde-like half-infty sign
754 case 'B' : out += "#(850)"; break; // filled dot
755 case 'F' : out += "#(860)"; break; // anchor
756 case 'I' : out += "#(866)"; break; // cross
757 case 'J' : out += "#(868)"; break; // Jewish star
758 case 'R' : out += "#(735)"; break; // square-like
759 case 'a' : out += "#(755)"; break; // filled triangle
760 case 'i' : out += "#(867)"; break; // small screscent
761 case 'j' : out += "#(869)"; break; // bell
762 case ' ' : out += "#(2328)"; break; // ?
763 case '#' : out += "#(2331)"; break; // ?
764 case 'S' : out += "#(2284)"; break; // empty circel with plus sign inside
765 case 'T' : out += "#(2287)"; break; // ?
766 case 'U' : out += "#(2289)"; break; // ? greep psi-like
767 case '\\' : // as below
768 case '|' : out += "#(833)"; break; // ? electrical ground sign-like
769 case 'c' : out += "#(853)"; break; // filled triangle left
770 case 'd' : out += "#(855)"; break; // filled triangle right
771 case '@' : out += "#(832)"; break; // ^
772 case 'H' : out += "#(864)"; break; // flower in a flowerpot
773 case 's' : out += "#(2286)"; break; // 4-like
774 case 't' : out += "#(2288)"; break; // ?
775 case ';' : out += "#(840)"; break; // empty circle
776 case 'l' : out += "#(873)"; break; // ?
777 case 'z' : out += "#(2305)"; break; // ?
778 case 'm' : out += "#(899)"; break; // smallest circle - dot
779 default :
780 if ((unsigned char)in[i] > 127) { out+=begin_unicode; out+=to_string((unsigned char)in[i]); out+=end_unicode; } else out.append(in, i, 1); //use unicode
781 break;
782 }
783 break;
784 case 16 : // Cyrillic
785 switch (in[i])
786 { // uppercase lowercase
787 case 'A' : out += "#(2801)"; break; case 'a' : out += "#(2901)"; break; // [a]
788 case 'B' : out += "#(2802)"; break; case 'b' : out += "#(2902)"; break; // [b]
789 case 'C' : out += "#(2803)"; break; case 'c' : out += "#(2903)"; break; // [v]
790 case 'D' : out += "#(2804)"; break; case 'd' : out += "#(2904)"; break; // [g]
791 case 'E' : out += "#(2805)"; break; case 'e' : out += "#(2905)"; break; // [d]
792 case 'F' : out += "#(2806)"; break; case 'f' : out += "#(2906)"; break; // [ye]
793 case 'G' : out += "#(2807)"; break; case 'g' : out += "#(2907)"; break; // [zsh]
794 case 'H' : out += "#(2808)"; break; case 'h' : out += "#(2908)"; break; // [z]
795 case 'I' : out += "#(2809)"; break; case 'i' : out += "#(2909)"; break; // [i/e]
796 case 'J' : out += "#(2810)"; break; case 'j' : out += "#(2910)"; break; // [ii]
797 case 'K' : out += "#(2811)"; break; case 'k' : out += "#(2911)"; break; // [k]
798 case 'L' : out += "#(2812)"; break; case 'l' : out += "#(2912)"; break; // [l]
799 case 'M' : out += "#(2813)"; break; case 'm' : out += "#(2913)"; break; // [m]
800 case 'N' : out += "#(2814)"; break; case 'n' : out += "#(2914)"; break; // [n]
801 case 'O' : out += "#(2815)"; break; case 'o' : out += "#(2915)"; break; // [o]
802 case 'P' : out += "#(2816)"; break; case 'p' : out += "#(2916)"; break; // [p]
803 case 'Q' : out += "#(2817)"; break; case 'q' : out += "#(2917)"; break; // [r]
804 case 'R' : out += "#(2818)"; break; case 'r' : out += "#(2918)"; break; // [s]
805 case 'S' : out += "#(2819)"; break; case 's' : out += "#(2919)"; break; // [t]
806 case 'T' : out += "#(2820)"; break; case 't' : out += "#(2920)"; break; // [u/woo]
807 case 'U' : out += "#(2821)"; break; case 'u' : out += "#(2921)"; break; // [f]
808 case 'V' : out += "#(2822)"; break; case 'v' : out += "#(2922)"; break; // [h]
809 case 'W' : out += "#(2823)"; break; case 'w' : out += "#(2923)"; break; // [c]
810 case 'X' : out += "#(2824)"; break; case 'x' : out += "#(2924)"; break; // [ch]
811 case 'Y' : out += "#(2825)"; break; case 'y' : out += "#(2925)"; break; // [sh]
812 case 'Z' : out += "#(2826)"; break; case 'z' : out += "#(2926)"; break; // [shch]
813 case '#' : out += "#(2827)"; break; case '<' : out += "#(2927)"; break; // hard sign
814 case '{' : case '[' : out += "#(2828)"; break; case '>' : out += "#(2928)"; break; // [y]
815 case '}' : case ']' : out += "#(2829)"; break; case '@' : out += "#(2929)"; break; // soft sign
816 case '%' : out += "#(2830)"; break; case '\\' : case '|' : out += "#(2930)"; break; // [eh]
817 case '"' : out += "#(2831)"; break; case '^' : case '~' : out += "#(2931)"; break; // [yu]
818 case 127u : case '_' : out += "#(2832)"; break; case ';' : out += "#(2932)"; break; // [ya]
819 default :
820 if ((unsigned char)in[i] > 127) { out+=begin_unicode; out+=to_string((unsigned char)in[i]); out+=end_unicode; } else out.append(in, i, 1); //use unicode
821 break;
822 }
823 break;
824 case 4 : // greek letters
825 case 7 :
826 switch (in[i])
827 {
828 // non-equivalent letters
829 case 'C' : out += "#gG"; break; case 'c' : out += "#gg"; break;
830 case 'F' : out += "#gZ"; break; case 'f' : out += "#gz"; break;
831 case 'G' : out += "#gY"; break; case 'g' : out += "#gy"; break;
832 case 'J' : out += "#gK"; break; case 'j' : out += "#gk"; break;
833 case 'K' : out += "#gL"; break; case 'k' : out += "#gl"; break;
834 case 'L' : out += "#gM"; break; case 'l' : out += "#gm"; break;
835 case 'M' : out += "#gN"; break; case 'm' : out += "#gn"; break;
836 case 'N' : out += "#gC"; break; case 'n' : out += "#gc"; break;
837 case 'Q' : out += "#gR"; break; case 'q' : out += "#gr"; break;
838 case 'R' : out += "#gS"; break; case 'r' : out += "#gs"; break;
839 case 'S' : out += "#gT"; break; case 's' : out += "#gt"; break;
840 case 'T' : out += "#gU"; break; case 't' : out += "#gu"; break;
841 case 'U' : out += "#gF"; break; case 'u' : out += "#gf"; break;
842 case 'V' : out += "#gX"; break; case 'v' : out += "#gx"; break;
843 case 'W' : out += "#gQ"; break; case 'w' : out += "#gq"; break;
844 case 'X' : out += "#gW"; break; case 'x' : out += "#gw"; break;
845 case 'Y' : case 'y' : out += "#(766)"; break;
846 case '{' : out += '['; break; case '}' : out += ']'; break;
847 // equivalent letters
848 case 'A' : case 'a' :
849 case 'B' : case 'b' :
850 case 'D' : case 'd' :
851 case 'E' : case 'e' :
852 case 'H' : case 'h' :
853 case 'I' : case 'i' :
854 case 'O' : case 'o' :
855 case 'P' : case 'p' :
856 out += "#g"; out.append(in, i, 1); break;
857 default :
858 if ((unsigned char)in[i] > 127) { out+=begin_unicode; out+=to_string((unsigned char)in[i]); out+=end_unicode; } else out.append(in, i, 1); //use unicode
859 break;
860 }
861 break;
862 case 3 : // simplex roman
863 switch ((unsigned char)in[i])
864 {
865 // unsupported chars
866 case '^' : case '~' : case '\\' :
867 out += " ";
868 break;
869 // 8th bit chars
870 case 144u : out += "1"; break;
871 case 154u : out += "#(218)"; break; // degree circle
872 case 163u : out += "#(272)"; break; // pound sign
873 case 167u : out += "#(2276)"; break; // paragraph
874 case 169u : out += "#(274)"; break; // copyright sign
875 case 174u : out += "#(273)"; break; // registered sign
876 case 181u : out += "#gm"; break; // greek mu
877 case 188u : out += "#(270)"; break; // 1/4
878 case 189u : out += "#(261)"; break; // 1/2
879 case 190u : out += "#(271)"; break; // 3/4
880 case 215u : out += "#(846)"; break; // cross sign
881 case 223u : out += "#fs#gb"; out += internalFontCodes[curr_fnt]; break; // beta script
882 default :
883 if ((unsigned char)in[i] > 127) { out+=begin_unicode; out+=to_string((unsigned char)in[i]); out+=end_unicode; } else out.append(in, i, 1); //use unicode
884 break;
885 }
886 break;
887 default : // simply pass the char
888 if ((unsigned char)in[i] > 127) { out+=begin_unicode; out+=to_string((unsigned char)in[i]); out+=end_unicode; } else out.append(in, i, 1); //use unicode
889 break;
890 }
891 curr_fnt = next_fnt;
892 }
893 }
894 activeFontCodeNum = curr_fnt;
895 //if gdlGetStringLength function is available, use it to give back a better value ("X" and "I" do not have the same width in hershey format!)
896 #if PLPLOT_PRIVATE_NOT_HIDDEN
897 if (stringLength) *stringLength=gdlGetStringLength(out)/this->mmCharLength();
898 #endif
899 return out;
900 retrn:
901 activeFontCodeNum = curr_fnt;
902 if (stringLength) *stringLength=0;
903 cout << "ERROR: GDLGStream::TranslateFormatCodes(\"" << in << "\") = \"" << out << "\"" << endl;
904 return "";
905 }
906
setSymbolSize(PLFLT scale)907 void GDLGStream::setSymbolSize( PLFLT scale )
908 {
909 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"setSymbolScale(%f)\n",scale);
910 plstream::ssym(0.0, scale);
911 theCurrentSymSize=scale;
912 }
913
setLineSpacing(PLFLT newSpacing)914 void GDLGStream::setLineSpacing(PLFLT newSpacing)
915 {
916 theLineSpacing_in_mm=newSpacing;
917 }
getSymbolSize()918 PLFLT GDLGStream::getSymbolSize(){return theCurrentSymSize;}
mtex(const char * side,PLFLT disp,PLFLT pos,PLFLT just,const char * text)919 void GDLGStream::mtex( const char *side, PLFLT disp, PLFLT pos, PLFLT just,
920 const char *text)
921 {
922 plstream::mtex(side,disp,pos,just,TranslateFormatCodes(text).c_str());
923 }
924
mtex3(const char * side,PLFLT disp,PLFLT pos,PLFLT just,const char * text)925 void GDLGStream::mtex3( const char *side, PLFLT disp, PLFLT pos, PLFLT just,
926 const char *text)
927 {
928 plstream::mtex3(side,disp,pos,just,TranslateFormatCodes(text).c_str());
929 }
ptex(PLFLT x,PLFLT y,PLFLT dx,PLFLT dy,PLFLT just,const char * text,double * stringCharLength)930 void GDLGStream::ptex( PLFLT x, PLFLT y, PLFLT dx, PLFLT dy, PLFLT just,
931 const char *text , double *stringCharLength)
932 {
933 plstream::ptex(x,y,dx,dy,just,TranslateFormatCodes(text,stringCharLength).c_str());
934 }
935
schr(PLFLT charwidthmm,PLFLT scale,PLFLT lineSpacingmm)936 void GDLGStream::schr( PLFLT charwidthmm, PLFLT scale , PLFLT lineSpacingmm)
937 {
938 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"schr(%f,%f,%f)\n",charwidthmm,scale,lineSpacingmm);
939 plstream::schr(charwidthmm, scale);
940 this->setLineSpacing(lineSpacingmm);
941 gdlDefaultCharInitialized=0;
942 CurrentCharSize(scale);
943 }
944
sizeChar(PLFLT scale)945 void GDLGStream::sizeChar( PLFLT scale )
946 {
947 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"SizeChar(%f)\n",scale);
948 plstream::schr(theDefaultChar.mmsx, scale);
949 // plstream::schr(0, scale);
950 CurrentCharSize(scale);
951 }
952
vpor(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax)953 void GDLGStream::vpor(PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax )
954 {
955 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"vpor(): requesting x[%f:%f],y[%f:%f] (normalized, subpage)\n",xmin,xmax,ymin,ymax);
956 //note that plplot apparently does not write the y=0 line of pixels (in device coords). IDL page is on the contrary limited to
957 // [0..1[ in both axes (normalized coordinates)
958 plstream::vpor(xmin, xmax, ymin, ymax);
959 theBox.nx1=xmin;
960 theBox.nx2=xmax;
961 theBox.ny1=ymin;
962 theBox.ny2=ymax;
963 PLFLT x1,x2,y1,y2;
964 plstream::gvpd(x1,x2,y1,y2); //retrieve NORMALIZED DEVICE coordinates of viewport
965 theBox.ndx1=x1;
966 theBox.ndx2=x2;
967 theBox.ndy1=y1;
968 theBox.ndy2=y2;
969 theBox.ondx=x1;
970 theBox.ondy=y1;
971 theBox.sndx=x2-x1;
972 theBox.sndy=y2-y1;
973
974 theBox.initialized=true;
975 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"vpor(): got x[%f:%f],x[%f:%f] (normalized, device)\n",theBox.ndx1,theBox.ndx2,theBox.ndy1,theBox.ndy2);
976 syncPageInfo();
977 }
978
wind(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax)979 void GDLGStream::wind( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax )
980 {
981 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"wind(): setting x[%f:%f],y[%f:%f] (world) \n",xmin,xmax,ymin,ymax);
982 //silly test to protect against plplot warnings ... side effects unkonwn.
983 if (xmin==xmax) {xmin=0; xmax=1;}
984 if (ymin==ymax) {ymin=0; ymax=1;}
985 plstream::wind(xmin, xmax, ymin, ymax);
986 theBox.wx1=xmin;
987 theBox.wx2=xmax;
988 theBox.wy1=ymin;
989 theBox.wy2=ymax;
990 updateBoxDeviceCoords();
991 UpdateCurrentCharWorldSize();
992 }
993
ssub(PLINT nx,PLINT ny)994 void GDLGStream::ssub(PLINT nx, PLINT ny)
995 {
996 plstream::ssub( nx, ny ); // does not appear to change charsize.
997 // set subpage numbers in X and Y
998 thePage.nbPages=nx*ny;
999 thePage.nx=nx;
1000 thePage.ny=ny;
1001 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"ssub() %dx%d pages\n",nx,ny);
1002 thePage.curPage=1;
1003 syncPageInfo();
1004 }
1005
adv(PLINT page)1006 void GDLGStream::adv(PLINT page)
1007 {
1008 plstream::adv(page);
1009 if (page==0) {thePage.curPage++;} else {thePage.curPage=page;}
1010 if (thePage.curPage > thePage.nbPages) thePage.curPage=1;
1011 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"adv() now at page %d\n",thePage.curPage);
1012 }
1013 //get region (3BPP data)
GetRegion(DLong & x_gdl,DLong & y_gdl,DLong & nx_gdl,DLong & ny_gdl)1014 bool GDLGStream::GetRegion(DLong& x_gdl, DLong& y_gdl, DLong& nx_gdl, DLong& ny_gdl){
1015 DByteGDL *bitmap = static_cast<DByteGDL*>(this->GetBitmapData());
1016 if (bitmap==NULL) return false; //need to GDLDelete bitmap on exit after this line.
1017
1018 bool error=false;
1019 DLong nx=bitmap->Dim(0);
1020 DLong ny=bitmap->Dim(1);
1021
1022 DLong xref,xval,xinc,yref,yval,yinc,xmax11,ymin11;
1023 long x_11=0;
1024 long y_11=0;
1025 xref=0;xval=0;xinc=1;
1026 yref=0;yval=0;yinc=1;
1027
1028 x_11=xval+(x_gdl-xref)*xinc;
1029 y_11=yval+(y_gdl-yref)*yinc;
1030 xmax11=xval+(x_gdl+nx_gdl-1-xref)*xinc;
1031 ymin11=yval+(y_gdl+ny_gdl-1-yref)*yinc;
1032 if (y_11 < 0 || y_11 > ny-1) error=true;
1033 if (x_11 < 0 || x_11 > nx-1) error=true;
1034 if (xmax11 < 0 || xmax11 > nx-1) error=true;
1035 if (ymin11 < 0 || ymin11 > ny-1) error=true;
1036 if (error) { GDLDelete(bitmap); return false; }
1037 GraphicsDevice* actDevice = GraphicsDevice::GetDevice();
1038 unsigned char* data=actDevice->SetCopyBuffer(nx_gdl*ny_gdl*3);
1039 for ( SizeT i =0; i < nx_gdl ; ++i ) {
1040 for ( SizeT j = 0; j < ny_gdl ; ++j ) {
1041 for ( SizeT k = 0 ; k < 3 ; ++k) data[3 * (j * nx_gdl + i) + k] = (*bitmap)[3 * ((j+y_11) * nx + (i+x_11)) + k];
1042 }
1043 }
1044 GDLDelete(bitmap);
1045 return true;
1046 }
1047
SetRegion(DLong & xs,DLong & ys,DLong & nx,DLong & ny)1048 bool GDLGStream::SetRegion(DLong& xs, DLong& ys, DLong& nx, DLong& ny){
1049 DLong pos[4]={xs,nx,ys,ny};
1050 GraphicsDevice* actDevice = GraphicsDevice::GetDevice();
1051 return this->PaintImage(actDevice->GetCopyBuffer(), nx, ny, pos, 1, 0);
1052 }
1053