1 /***************************************************************************
2 * export_2d.cpp is part of Math Graphic Library
3 * Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Lesser General Public License as *
7 * published by the Free Software Foundation; either version 3 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Lesser General Public *
16 * License along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include "mgl2/canvas.h"
21 #include "mgl2/canvas_cf.h"
22 #include "mgl2/font.h"
23 #include <time.h>
24 #include <algorithm>
25 #include <sys/stat.h>
26 #undef _GR_
27 #define _GR_ ((mglCanvas *)(*gr))
28 #define _Gr_ ((mglCanvas *)(gr))
29 void mgl_printf(void *fp, bool gz, const char *str, ...);
30 //-----------------------------------------------------------------------------
mgl_get_dash(unsigned short d,mreal w,char dlm)31 static const char *mgl_get_dash(unsigned short d, mreal w,char dlm)
32 {
33 static std::string s;
34 if(d==0xffff) return "";
35 int f=0, p=d&1, n=p?0:1;
36 s = p ? "" : "0";
37 for(int i=0;i<16;i++)
38 {
39 int j = i;//15-i;
40 if(((d>>j)&1) == p) f++;
41 else
42 {
43 s += mgl_str_num(f*w)+dlm;
44 p = (d>>j)&1; f = 1; n++;
45 }
46 }
47 s += mgl_str_num(f*w) + ((n%2) ? "" : " 0");
48 return s.c_str();
49 }
50 //-----------------------------------------------------------------------------
mgl_is_same(HMGL gr,long i,mreal wp,uint32_t cp,int st)51 bool MGL_LOCAL_PURE mgl_is_same(HMGL gr, long i, mreal wp,uint32_t cp, int st)
52 {
53 const mglPrim &pr=_Gr_->GetPrm(i);
54 if(abs(pr.type)!=1) return false;
55 if(pr.w>=1 && wp!=pr.w) return false;
56 if(pr.w<1 && wp!=1) return false;
57 if(st!=pr.n3) return false;
58 return (cp==_Gr_->GetPrmCol(i));
59 }
60 //-----------------------------------------------------------------------------
put_line(HMGL gr,long i,mreal wp,uint32_t cp,int st)61 std::vector<long> static put_line(HMGL gr, long i, mreal wp, uint32_t cp,int st)
62 {
63 std::vector<long> ids;
64 long n1=gr->GetPrm(i).n1, n2=gr->GetPrm(i).n2;
65 if(n1>n2) { n1=gr->GetPrm(i).n2; n2=gr->GetPrm(i).n1; }
66 if(n1<0 || n2<0) return ids;
67 const mglPnt &pp1 = gr->GetPnt(n1), &pp2 = gr->GetPnt(n2);
68 mreal x0=pp1.x, y0=pp1.y;
69 bool ok=true;
70 long j; // first point
71 while(ok) // try to find starting point
72 {
73 for(ok=false,j=i+1;j<gr->GetPrmNum();j++)
74 {
75 mglPrim &q = gr->GetPrm(j);
76 if(q.type>1) break;
77 if(mgl_is_same(gr, j, wp,cp,st) && q.type==1 && q.n1>=0 && q.n2>=0) // previous point
78 {
79 const mglPnt &p1 = gr->GetPnt(q.n1);
80 const mglPnt &p2 = gr->GetPnt(q.n2);
81 if(p2.x==x0 && p2.y==y0)
82 {
83 ok = true; ids.push_back(q.n1);
84 x0 = p1.x; y0 = p1.y; q.type = -1;
85 }
86 else if(p1.x==x0 && p1.y==y0)
87 {
88 ok = true; ids.push_back(q.n2);
89 x0 = p2.x; y0 = p2.y; q.type = -1;
90 }
91 }
92 }
93 }
94 std::reverse(ids.begin(),ids.end());
95 ids.push_back(n1); ids.push_back(n2);
96 x0 = pp2.x; y0 = pp2.y; ok = true;
97 while(ok) // try to find starting point
98 {
99 for(ok=false,j=i+1;j<gr->GetPrmNum();j++)
100 {
101 mglPrim &q = gr->GetPrm(j);
102 if(q.type>1) break;
103 if(mgl_is_same(gr, j,wp,cp,st) && q.type==1 && q.n1>=0 && q.n2>=0) // next point
104 {
105 const mglPnt &p1 = gr->GetPnt(q.n1);
106 const mglPnt &p2 = gr->GetPnt(q.n2);
107 if(p2.x==x0 && p2.y==y0)
108 {
109 ok = true; ids.push_back(q.n1);
110 x0 = p1.x; y0 = p1.y; q.type = -1;
111 }
112 else if(p1.x==x0 && p1.y==y0)
113 {
114 ok = true; ids.push_back(q.n2);
115 x0 = p2.x; y0 = p2.y; q.type = -1;
116 }
117 }
118 }
119 }
120 return ids;
121 }
122 //-----------------------------------------------------------------------------
123 //put_desc(fp,"%c%c%c_%04x {", "np %d %d mt %d %d ll %d %d ll cp fill\n",
124 //"np %d %d mt ", "%d %d ll ", "cp dr\n", "} def")
put_desc(HMGL gr,void * fp,bool gz,const char * pre,const char * ln1,const char * ln2,const char * ln3,const char * suf)125 void static put_desc(HMGL gr, void *fp, bool gz, const char *pre, const char *ln1, const char *ln2, const char *ln3, const char *suf)
126 {
127 long n=0;
128 for(long i=0;i<gr->GetPrmNum();i++) if(gr->GetPrm(i).type==4) n++;
129 if(n==0) return; // no glyphs
130 wchar_t *g = new wchar_t[n];
131 int *s = new int[n]; n=0;
132 for(long i=0;i<gr->GetPrmNum();i++)
133 {
134 const mglPrim &q = gr->GetPrm(i);
135 if(q.type!=4 || (q.n3&8)) continue; // not a glyph
136 bool is=false;
137 for(long j=0;j<n;j++) if(g[j]==q.n4 && s[j]==(q.n3&7)) is = true;
138 if(is) continue; // glyph is described
139 // have to describe
140 g[n]=q.n4; s[n]=q.n3&7; n++; // add to list of described
141 // "%c%c%c_%04x {"
142 mgl_printf(fp, gz, pre, q.n3&1?'b':'n', q.n3&2?'i':'n', q.n4);
143 const mglGlyph &g = gr->GetGlf(q.n4);
144 int nl=g.nl;
145 const short *ln=g.line;
146 bool np=true;
147 if(ln && nl>0) for(long ik=0;ik<nl;ik++)
148 {
149 long ii = 2*ik;
150 if(ln[ii]==0x3fff && ln[ii+1]==0x3fff) // line breakthrough
151 { mgl_printf(fp, gz, "%s",ln3); np=true; continue; }
152 else if(np) mgl_printf(fp, gz, ln1,ln[ii],ln[ii+1]);
153 else mgl_printf(fp, gz, ln2,ln[ii],ln[ii+1]);
154 np=false;
155 }
156 mgl_printf(fp, gz, "%s%s",ln3,suf); // finish glyph description suf="} def"
157 }
158 delete []g; delete []s;
159 }
160 //-----------------------------------------------------------------------------
mgl_eps_pattern(void * fp,bool gz,const mglPrim & q)161 bool MGL_NO_EXPORT mgl_eps_pattern(void *fp, bool gz, const mglPrim &q)
162 {
163 static uint64_t pd=MGL_SOLID_MASK; // mask if !=MGL_SOLID_MASK
164 static mreal pw=0; // width (like pen width) if !=0
165 static int ang=0; // angle (default is 0,45,90,315)
166 int aa = 45*int(0.5+q.angl/45.);
167 if(q.m==MGL_SOLID_MASK || q.w<=0) return false;
168 if(q.m==pd && q.w==pw && aa==ang) return true;
169 pd = q.m; pw=q.w; ang=aa;
170 mreal d = ang%90 ? 4*M_SQRT2*pw : 4*pw;
171 mgl_printf(fp, gz, "<<\n/PaintType 2 /PatternType 1 /TilingType 1\n");
172 mgl_printf(fp, gz, "/BBox [-%g -%g %g %g] /XStep %g /YStep %g\n", d,d,d,d, 2*d,2*d);
173 if(ang%90)
174 {
175 mgl_printf(fp, gz, "/PaintProc { gsave %d rotate\n",-ang);
176 for(int i=-8;i<8;i++) for(int j=-8;j<8;j++)
177 {
178 int ii = (8+i)&7, jj = (8+j)&7; // TODO reduce number of used rectangles
179 if(pd & (1L<<(ii+8*jj)))
180 mgl_printf(fp, gz, "%g %g %g %g rf\n",i*pw,j*pw,pw,pw);
181 }
182 mgl_printf(fp, gz, "grestore}\n>> pat\n");
183 }
184 else
185 {
186 mgl_printf(fp, gz, "/PaintProc { gsave %d rotate\n",-ang);
187 for(int i=-4;i<4;i++) for(int j=-4;j<4;j++)
188 {
189 int ii = (8+i)&7, jj = (8+j)&7;
190 if(pd & (1L<<(ii+8*jj)))
191 mgl_printf(fp, gz, "%g %g %g %g rf\n",i*pw,j*pw,pw,pw);
192 }
193 mgl_printf(fp, gz, "grestore}\n>> pat\n");
194 }
195 return true;
196 }
197 //-----------------------------------------------------------------------------
mgl_write_eps(HMGL gr,const char * fname,const char * descr)198 void MGL_EXPORT mgl_write_eps(HMGL gr, const char *fname,const char *descr)
199 {
200 if(!fname || *fname==0) return;
201 if(gr->GetPrmNum()<1) return;
202 _Gr_->clr(MGL_FINISHED); _Gr_->PreparePrim(1);
203 time_t now; time(&now);
204
205 bool gz = fname[strlen(fname)-1]=='z';
206 void *fp;
207 if(!strcmp(fname,"-")) fp = stdout; // allow to write in stdout
208 else fp = gz ? (void*)gzopen(fname,"wt") : (void*)fopen(fname,"wt");
209 if(!fp) { gr->SetWarn(mglWarnOpen,fname); return; }
210 int w = _Gr_->GetWidth(), h = _Gr_->GetHeight();
211
212 int x1=gr->BBoxX1, x2=gr->BBoxX2<0?w:gr->BBoxX2, y1=gr->BBoxY1, y2=gr->BBoxY2<0?h:gr->BBoxY2;
213 if(x2>w) x2=w;
214 if(y2>h) y2=h;
215 if(x1<0 || x1>=x2) { x1=0; x2=w; }
216 if(y1<0 || y1>=y2) { y1=0; y2=h; }
217
218 if(gz)
219 {
220 unsigned len = strlen(fname), pos=0;
221 char *buf = new char[len+4];
222 memcpy(buf,fname,len);
223 if(buf[len-3]=='.') pos = len-2;
224 else if(buf[len-2]=='.') pos = len-1;
225 else { buf[len-1]='.'; pos = len; }
226 if(pos) { buf[pos]=buf[pos+1]='b'; buf[pos+2]=0; }
227 FILE *fb = fopen(buf,"w");
228 fprintf(fb, "%%%%BoundingBox: %d %d %d %d\n", x1, h-y2, x2, h-y1);
229 fclose(fb); delete []buf;
230 }
231
232 const std::string loc = setlocale(LC_NUMERIC, "C");
233 mgl_printf(fp, gz, "%%!PS-Adobe-3.0 EPSF-3.0\n%%%%BoundingBox: %d %d %d %d\n", x1, h-y2, x2, h-y1);
234 mgl_printf(fp, gz, "%%%%Created by MathGL library\n%%%%Title: %s\n",descr ? descr : fname);
235 mgl_printf(fp, gz, "%%%%CreationDate: %s\n",ctime(&now));
236 mgl_printf(fp, gz, "%%%%LanguageLevel: 2\n50 dict begin");
237 mgl_printf(fp, gz, "/lw {setlinewidth} def\n/rgb {setrgbcolor} def\n");
238 mgl_printf(fp, gz, "/np {newpath} def\n/cp {closepath} def\n");
239 mgl_printf(fp, gz, "/ll {lineto} def\n/mt {moveto} def\n");
240 mgl_printf(fp, gz, "/rl {rlineto} def\n/rm {rmoveto} def\n/dr {stroke} def\n");
241 mgl_printf(fp, gz, "/ss {%g} def\n",0.35*gr->mark_size());
242 mgl_printf(fp, gz, "/s2 {%g} def\n",0.7*gr->mark_size());
243 mgl_printf(fp, gz, "/sm {-%g} def\n",0.35*gr->mark_size());
244 mgl_printf(fp, gz, "/m_c {ss 0.3 mul 0 360 arc} def\n");
245 mgl_printf(fp, gz, "/d0 {[] 0 setdash} def\n/sd {setdash} def\n");
246 mgl_printf(fp, gz, "/pat {[1 0 0 1 0 0] makepattern /Mask exch def [/Pattern /DeviceRGB] setcolorspace} def\n");
247 mgl_printf(fp, gz, "/mask {Mask setpattern} def\n/rf {rectfill} def\n");
248
249 bool m_p=false,m_x=false,m_d=false,m_v=false,m_t=false,
250 m_s=false,m_a=false,m_o=false,m_T=false,
251 m_V=false,m_S=false,m_D=false,m_Y=false,m_l=false,
252 m_L=false,m_r=false,m_R=false,m_X=false,m_P=false;
253 // add mark definition if present
254 for(long i=0;i<gr->GetPrmNum();i++)
255 {
256 const mglPrim &q = gr->GetPrm(i);
257 if(q.type>0) continue;
258 if(q.n4=='+') m_p = true;
259 if(q.n4=='x') m_x = true;
260 if(q.n4=='s') m_s = true;
261 if(q.n4=='d') m_d = true;
262 if(q.n4=='v') m_v = true;
263 if(q.n4=='^') m_t = true;
264 if(q.n4=='*') m_a = true;
265 if(q.n4=='o' || q.n4=='O' || q.n4=='C') m_o = true;
266 if(q.n4=='S') m_S = true;
267 if(q.n4=='D') m_D = true;
268 if(q.n4=='V') m_V = true;
269 if(q.n4=='T') m_T = true;
270 if(q.n4=='<') m_l = true;
271 if(q.n4=='L') m_L = true;
272 if(q.n4=='>') m_r = true;
273 if(q.n4=='R') m_R = true;
274 if(q.n4=='Y') m_Y = true;
275 if(q.n4=='P') m_P = true;
276 if(q.n4=='X') m_X = true;
277 }
278 if(m_P) { m_p=true; m_s=true; }
279 if(m_X) { m_x=true; m_s=true; }
280 if(m_p) mgl_printf(fp, gz, "/m_p {sm 0 rm s2 0 rl sm sm rm 0 s2 rl d0} def\n");
281 if(m_x) mgl_printf(fp, gz, "/m_x {sm sm rm s2 s2 rl 0 sm 2 mul rm sm 2 mul s2 rl d0} def\n");
282 if(m_s) mgl_printf(fp, gz, "/m_s {sm sm rm 0 s2 rl s2 0 rl 0 sm 2 mul rl cp d0} def\n");
283 if(m_d) mgl_printf(fp, gz, "/m_d {sm 0 rm ss ss rl ss sm rl sm sm rl cp d0} def\n");
284 if(m_v) mgl_printf(fp, gz, "/m_v {sm ss 2 div rm s2 0 rl sm sm 1.5 mul rl d0 cp} def\n");
285 if(m_t) mgl_printf(fp, gz, "/m_t {sm sm 2 div rm s2 0 rl sm ss 1.5 mul rl d0 cp} def\n");
286 if(m_a) mgl_printf(fp, gz, "/m_a {sm 0 rm s2 0 rl sm 1.6 mul sm 0.8 mul rm ss 1.2 mul ss 1.6 mul rl 0 sm 1.6 mul rm sm 1.2 mul ss 1.6 mul rl d0} def\n");
287 if(m_o) mgl_printf(fp, gz, "/m_o {ss 0 360 d0 arc} def\n");
288 if(m_S) mgl_printf(fp, gz, "/m_S {sm sm rm 0 s2 rl s2 0 rl 0 sm 2 mul rl cp} def\n");
289 if(m_D) mgl_printf(fp, gz, "/m_D {sm 0 rm ss ss rl ss sm rl sm sm rl cp} def\n");
290 if(m_V) mgl_printf(fp, gz, "/m_V {sm ss 2 div rm s2 0 rl sm sm 1.5 mul rl cp} def\n");
291 if(m_T) mgl_printf(fp, gz, "/m_T {sm sm 2 div rm s2 0 rl sm ss 1.5 mul rl cp} def\n");
292 if(m_Y) mgl_printf(fp, gz, "/m_Y {0 sm rm 0 ss rl sm ss rl s2 0 rm sm sm rl d0} def\n");
293 if(m_r) mgl_printf(fp, gz, "/m_r {sm 2 div sm rm 0 s2 rl ss 1.5 mul sm rl d0 cp} def\n");
294 if(m_l) mgl_printf(fp, gz, "/m_l {ss 2 div sm rm 0 s2 rl sm 1.5 mul sm rl d0 cp} def\n");
295 if(m_R) mgl_printf(fp, gz, "/m_R {sm 2 div sm rm 0 s2 rl ss 1.5 mul sm rl cp} def\n");
296 if(m_L) mgl_printf(fp, gz, "/m_L {ss 2 div sm rm 0 s2 rl sm 1.5 mul sm rl cp} def\n");
297 if(m_P) mgl_printf(fp, gz, "/m_P {m_p 0 sm rm m_s} def\n");
298 if(m_X) mgl_printf(fp, gz, "/m_X {m_x ss sm rm m_s} def\n");
299 // if(m_C) mgl_printf(fp, gz, "/m_C {m_c m_o} def\n");
300 mgl_printf(fp, gz, "0 setlinecap\n1 setlinejoin\n\n"); // manual setting round line cap
301
302 // Write background image first
303 const unsigned char *img = mgl_get_background(gr);
304 bool same = true;
305 unsigned char white[3]={255,255,255};
306 #pragma omp parallel for
307 for(long i=0;i<w*h;i++) if(memcmp(img,img+4*i,3)) same=false;
308 if(!same)
309 {
310 mgl_printf(fp, gz, "gsave\t%d %d translate\n",x1,h-y2);
311 mgl_printf(fp, gz, "%d %d 8 [1 0 0 1 0 0] {<", x2-x1,y2-y1);
312 for(long j=y2-1;j>=y1;j--) for(long i=x1;i<x2;i++)
313 {
314 if((i+w*(h-j-1))%40==0 && i+j>0) mgl_printf(fp, gz, "\n");
315 mgl_printf(fp, gz, "%02x%02x%02x",img[4*(i+w*j)],img[4*(i+w*j)+1],img[4*(i+w*j)+2]);
316 }
317 mgl_printf(fp, gz, "\n>} false 3 colorimage\ngrestore\n\n");
318 }
319 else if(memcmp(img,white,3))
320 mgl_printf(fp, gz, "np 0 0 mt 0 %d ll %d %d ll %d 0 ll cp %g %g %g rgb fill\n", y2-y1, x2-x1, y2-y1, x2-x1, img[0]/255., img[1]/255., img[2]/255.);
321
322 // write definition for all glyphs
323 put_desc(gr,fp,gz,"/%c%c_%04x { np\n", "\t%d %d mt ", "%d %d ll ", "cp\n", "} def\n");
324 // write primitives
325 mreal wp=-1;
326 float qs_old=gr->mark_size()/gr->FontFactor();
327 mglRGBA cp;
328 int st=0;
329 char str[256]="", msk[256]="";
330 for(long i=0;i<gr->GetPrmNum();i++)
331 {
332 const mglPrim &q = gr->GetPrm(i);
333 if(q.type<0) continue; // q.n1>=0 always
334 cp.c = _Gr_->GetPrmCol(i);
335 const mglPnt &p1 = gr->GetPnt(q.n1);
336 if(q.type>1)
337 {
338 snprintf(str,256,"%.2g %.2g %.2g rgb ", cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.); str[255]=0;
339 snprintf(msk,256,"%.2g %.2g %.2g mask ", cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.); msk[255]=0;
340 }
341
342 if(q.type==0) // mark
343 {
344 mreal x0 = p1.x,y0 = p1.y;
345 // snprintf(str,256,"%.2g lw %.2g %.2g %.2g rgb ", 50*q.s*q.w>1?50*q.s*q.w:1, cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.);
346 snprintf(str,256,"%.2g lw %.2g %.2g %.2g rgb ", q.w>1?q.w:1, cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.);
347 str[255]=0; wp=1; // NOTE: this may renew line style if a mark inside!
348 if(q.s!=qs_old)
349 {
350 mgl_printf(fp, gz, "/ss {%g} def\n",q.s);
351 mgl_printf(fp, gz, "/s2 {%g} def\n",q.s*2);
352 mgl_printf(fp, gz, "/sm {-%g} def\n",q.s);
353 qs_old = q.s;
354 }
355 switch(q.n4)
356 {
357 case '+': mgl_printf(fp, gz, "np %g %g mt m_p %sdr\n",x0,y0,str); break;
358 case 'x': mgl_printf(fp, gz, "np %g %g mt m_x %sdr\n",x0,y0,str); break;
359 case 's': mgl_printf(fp, gz, "np %g %g mt m_s %sdr\n",x0,y0,str); break;
360 case 'd': mgl_printf(fp, gz, "np %g %g mt m_d %sdr\n",x0,y0,str); break;
361 case '*': mgl_printf(fp, gz, "np %g %g mt m_a %sdr\n",x0,y0,str); break;
362 case 'v': mgl_printf(fp, gz, "np %g %g mt m_v %sdr\n",x0,y0,str); break;
363 case '^': mgl_printf(fp, gz, "np %g %g mt m_t %sdr\n",x0,y0,str); break;
364 case 'S': mgl_printf(fp, gz, "np %g %g mt m_S %sfill\n",x0,y0,str); break;
365 case 'D': mgl_printf(fp, gz, "np %g %g mt m_D %sfill\n",x0,y0,str); break;
366 case 'V': mgl_printf(fp, gz, "np %g %g mt m_V %sfill\n",x0,y0,str); break;
367 case 'T': mgl_printf(fp, gz, "np %g %g mt m_T %sfill\n",x0,y0,str); break;
368 case 'o': mgl_printf(fp, gz, "%g %g m_o %sdr\n",x0,y0,str);break;
369 case 'O': mgl_printf(fp, gz, "%g %g m_o %sfill\n",x0,y0,str);break;
370 case 'Y': mgl_printf(fp, gz, "np %g %g mt m_Y %sdr\n",x0,y0,str); break;
371 case '<': mgl_printf(fp, gz, "np %g %g mt m_l %sdr\n",x0,y0,str); break;
372 case '>': mgl_printf(fp, gz, "np %g %g mt m_r %sdr\n",x0,y0,str); break;
373 case 'L': mgl_printf(fp, gz, "np %g %g mt m_L %sfill\n",x0,y0,str); break;
374 case 'R': mgl_printf(fp, gz, "np %g %g mt m_R %sfill\n",x0,y0,str); break;
375 case 'P': mgl_printf(fp, gz, "np %g %g mt m_P %sdr\n",x0,y0,str); break;
376 case 'X': mgl_printf(fp, gz, "np %g %g mt m_X %sdr\n",x0,y0,str); break;
377 case 'C': mgl_printf(fp, gz, "%g %g m_o %g %g m_c %sdr\n",x0,y0,x0,y0,str); break;
378 case '.': mgl_printf(fp, gz, "%g %g m_c %sfill\n",x0,y0,str);
379 }
380 }
381 else if(q.type==3) // quad
382 {
383 const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3), &p4=gr->GetPnt(q.n4);
384 if(cp.r[3]) // TODO && gr->quad_vis(p1,p2,p3,p4))
385 {
386 bool mask = mgl_eps_pattern(fp,gz,q);
387 mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll %g %g ll cp %sfill\n", p1.x, p1.y, p2.x, p2.y, p4.x, p4.y, p3.x, p3.y, mask?msk:str);
388 }
389 }
390 else if(q.type==2) // trig
391 {
392 const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3);
393 if(cp.r[3]) // TODO && gr->trig_vis(p1,p2,p3))
394 {
395 bool mask = mgl_eps_pattern(fp,gz,q);
396 mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll cp %sfill\n", p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, mask?msk:str);
397 }
398 }
399 else if(q.type==1) // line
400 {
401 snprintf(str,256,"%.2g lw %.2g %.2g %.2g rgb ", q.w>1 ? q.w:1., cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.);
402 str[255]=0; wp = q.w>1 ? q.w:1; st = q.n3;
403 std::vector<long> ids = put_line(gr,i,wp,cp.c,st);
404 for(size_t j=0;j<ids.size();j++)
405 {
406 const mglPnt &p = gr->GetPnt(ids[j]);
407 float x0 = p.x, y0 = p.y;
408 mgl_printf(fp, gz, j==0?"np %g %g mt ":"%g %g ll ",x0,y0);
409 }
410 const char *sd = mgl_get_dash(q.n3,q.w,' ');
411 if(sd && sd[0]) mgl_printf(fp, gz, "%s [%s] %g sd dr\n",str,sd,q.w*q.s);
412 else mgl_printf(fp, gz, "%s d0 dr\n",str);
413 }
414 else if(q.type==4) // glyph
415 {
416 float phi = gr->GetGlyphPhi(gr->GetPnt(q.n2),q.w);
417 if(mgl_isnan(phi)) continue;
418 mreal ss = q.s/2, xx = p1.u, yy = p1.v, zz = q.p;
419 mgl_printf(fp, gz, "gsave\t%g %g translate %g %g scale %g rotate %s\n",
420 p1.x, p1.y, ss, ss, -phi, str);
421 if(q.n3&8) // this is "line"
422 {
423 mreal dy = 0.004,f=fabs(zz);
424 mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll %g %g ll cp ",
425 xx,yy+dy, xx+f,yy+dy, xx+f,yy-dy, xx,yy-dy);
426 }
427 else
428 mgl_printf(fp, gz, "%.3g %.3g translate %g %g scale %c%c_%04x ",
429 xx, yy, zz, zz, q.n3&1?'b':'n', q.n3&2?'i':'n', q.n4);
430 if(q.n3&4) mgl_printf(fp, gz, "dr");
431 else mgl_printf(fp, gz, "eofill");
432 mgl_printf(fp, gz, " grestore\n");
433 }
434 }
435 for(long i=0;i<gr->GetPrmNum();i++)
436 {
437 mglPrim &q = gr->GetPrm(i);
438 if(q.type==-1) q.type = 1;
439 }
440 mgl_printf(fp, gz, "\nshowpage\n%%%%EOF\n");
441 if(strcmp(fname,"-")) { if(gz) gzclose((gzFile)fp); else fclose((FILE *)fp); }
442 setlocale(LC_NUMERIC, loc.c_str());
443 }
mgl_write_eps_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)444 void MGL_EXPORT mgl_write_eps_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
445 { char *s=new char[l+1]; memcpy(s,fname,l); s[l]=0;
446 char *d=new char[n+1]; memcpy(d,descr,n); d[n]=0;
447 mgl_write_eps(_GR_,s,d); delete []s; delete []d; }
448 //-----------------------------------------------------------------------------
mgl_write_svg(HMGL gr,const char * fname,const char * descr)449 void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
450 {
451 if(!fname || *fname==0) return;
452 if(gr->GetPrmNum()<1) return;
453 _Gr_->clr(MGL_FINISHED); _Gr_->PreparePrim(1);
454 time_t now; time(&now);
455
456 bool gz = fname[strlen(fname)-1]=='z';
457 long hh = _Gr_->GetHeight(), ww = _Gr_->GetWidth();
458 void *fp = stdout; // allow to write in stdout
459 bool head = true;
460 if(strcmp(fname,"-")) fp = gz ? (void*)gzopen(fname,"wt") : (void*)fopen(fname,"wt");
461 else head = false;
462 if(!fp) { gr->SetWarn(mglWarnOpen,fname); return; }
463
464 int x1=gr->BBoxX1, x2=gr->BBoxX2<0?ww:gr->BBoxX2, y1=gr->BBoxY1, y2=gr->BBoxY2<0?hh:gr->BBoxY2;
465 if(x2>ww) x2=ww;
466 if(y2>hh) y2=hh;
467 if(x1<0 || x1>=x2) { x1=0; x2=ww; }
468 if(y1<0 || y1>=y2) { y1=0; y2=hh; }
469 ww = x2-x1; hh = y2-y1;
470
471 const std::string loc = setlocale(LC_NUMERIC, "C");
472 if(head)
473 {
474 mgl_printf(fp, gz, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
475 mgl_printf(fp, gz, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20000303 Stylable//EN\" \"http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd\">\n");
476 mgl_printf(fp, gz, "<svg width=\"%d\" height=\"%d\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", ww, hh);
477 mgl_printf(fp, gz, "<!--Created by MathGL library-->\n");
478 mgl_printf(fp, gz, "<!--Title: %s-->\n<!--CreationDate: %s-->\n\n",descr?descr:fname,ctime(&now));
479 }
480 else
481 {
482 mgl_printf(fp, gz, "<!--Created by MathGL library-->\n");
483 mgl_printf(fp, gz, "<svg width=\"%d\" height=\"%d\">\n", ww, hh);
484 }
485
486 // write definition for all glyphs
487 put_desc(gr,fp,gz,"<defs><g id=\"%c%c_%04x\"><path d=\"", "\tM %d %d ",
488 "L %d %d ", "Z\n", "\"/></g></defs>\n");
489
490 // Write background image first
491 const unsigned char *img = mgl_get_background(gr);
492 bool same = true;
493 unsigned char white[3]={255,255,255};
494 #pragma omp parallel for
495 for(long i=0;i<ww*hh;i++) if(memcmp(img,img+4*i,3)) same=false;
496 if(!same)
497 { // TODO write as <image width="100" height="100" xlink:href="data:image/png;base64,...">
498 /* mgl_printf(fp, gz, "%d %d 8 [1 0 0 1 0 0] {<", ww,hh,1+ww*hh/40);
499 for(long j=hh-1;j>=0;j--) for(long i=0;i<ww;i++)
500 {
501 if((i+ww*(hh-j-1))%40==0 && i+j>0) mgl_printf(fp, gz, "\n");
502 mgl_printf(fp, gz, "%02x%02x%02x",img[4*(i+ww*j)],img[4*(i+ww*j)+1],img[4*(i+ww*j)+2]);
503 }
504 mgl_printf(fp, gz, "\n>} false 3 colorimage\n\n");*/
505 }
506 else if(memcmp(img,white,3))
507 {
508 mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\" opacity=\"%g\">\n", img[0], img[1], img[2], img[3]/255.);
509 mgl_printf(fp, gz, "<path d=\"M 0 0 L 0 %ld L %ld %ld L %ld 0 Z\"/> </g>\n", hh, ww, hh, ww);
510 }
511
512
513 // currentColor -> inherit ???
514 mgl_printf(fp, gz, "<g fill=\"none\" stroke=\"none\" stroke-width=\"0.5\" stroke-linecap=\"butt\" stroke-linejoin=\"round\">\n");
515 // write primitives
516 mreal wp=-1;
517 int st=0;
518 mglRGBA cp;
519
520 // hh += (y2+y1)/2;
521 for(long i=0;i<gr->GetPrmNum();i++)
522 {
523 const mglPrim &q = gr->GetPrm(i);
524 if(q.type<0) continue; // q.n1>=0 always
525 cp.c = _Gr_->GetPrmCol(i);
526 const mglPnt &p1=gr->GetPnt(q.n1);
527 if(q.type==0)
528 {
529 mreal x=p1.x-x1,y=hh-p1.y,s=q.s;
530 if(!strchr("xsSoO",q.n4)) s *= 1.1;
531 wp = 1;
532 if(strchr("SDVTLR",q.n4))
533 mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
534 else
535 mgl_printf(fp, gz, "<g stroke=\"#%02x%02x%02x\" stroke-width=\"%g\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]), q.w>1?q.w:1);
536 // mgl_printf(fp, gz, "<g stroke=\"#%02x%02x%02x\" stroke-width=\"%g\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]), 50*q.s*q.w>1?50*q.s*q.w:1);
537 switch(q.n4)
538 {
539 case 'P':
540 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g M %g %g L %g %g M %g %g L %g %g L %g %g L %g %g L %g %g\"/>\n",
541 x-s,y,x+s,y,x,y-s,x,y+s, x-s,y-s,x+s,y-s,x+s,y+s,x-s,y+s,x-s,y-s); break;
542 case '+':
543 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g M %g %g L %g %g\"/>\n", x-s,y,x+s,y,x,y-s,x,y+s); break;
544 case 'X':
545 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g M %g %g L %g %g M %g %g L %g %g L %g %g L %g %g L %g %g\"/>\n",
546 x-s,y-s,x+s,y+s,x+s,y-s,x-s,y+s, x-s,y-s,x+s,y-s,x+s,y+s,x-s,y+s,x-s,y-s); break;
547 case 'x':
548 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g M %g %g L %g %g\"/>\n", x-s,y-s,x+s,y+s,x+s,y-s,x-s,y+s); break;
549 case 's':
550 case 'S':
551 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g L %g %gZ\"/>\n", x-s,y-s,x+s,y-s,x+s,y+s,x-s,y+s); break;
552 case 'd':
553 case 'D':
554 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g L %g %gZ\"/>\n", x-s,y,x,y-s,x+s,y,x,y+s); break;
555 case 'v':
556 case 'V':
557 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %gZ\"/>\n", x-s,y-s/2,x+s,y-s/2,x,y+s); break;
558 case '^':
559 case 'T':
560 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %gZ\"/>\n", x-s,y+s/2,x+s,y+s/2,x,y-s); break;
561 case '<':
562 case 'L':
563 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %gZ\"/>\n", x+s/2,y+s,x+s/2,y-s,x-s,y); break;
564 case '>':
565 case 'R':
566 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %gZ\"/>\n", x-s/2,y+s,x-s/2,y-s,x+s,y); break;
567 case 'Y':
568 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g M %g %g L %g %g\"/>\n", x,y-s, x,y, x+s,y+s, x,y, x-s,y+s); break;
569 case 'C':
570 mgl_printf(fp, gz, "<circle style=\"fill:#%02x%02x%02x\" cx=\"%g\" cy=\"%g\" r=\"0.15\"/>\n<circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
571 int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),x,y,x,y,s); break;
572 case 'o':
573 mgl_printf(fp, gz, "<circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n", x,y,s); break;
574 case 'O':
575 mgl_printf(fp, gz, "<circle style=\"fill:#%02x%02x%02x\" cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
576 int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),x,y,s); break;
577 case '*':
578 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g M %g %g L %g %g M %g %g L %g %g\"/>\n",
579 x-s,y,x+s,y,x-0.6*s,y-0.8*s,x+0.6*s,y+0.8*s,x+0.6*s,y-0.8*s,x-0.6*s,y+0.8*s); break;
580 case '.':
581 mgl_printf(fp, gz, "<circle style=\"fill:#%02x%02x%02x\" cx=\"%g\" cy=\"%g\" r=\"0.15\"/>\n",
582 int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),x,y); break;
583 }
584 mgl_printf(fp, gz, "</g>\n");
585 }
586 else if(q.type==1)
587 {
588 mgl_printf(fp,gz,"<g stroke=\"#%02x%02x%02x\"",int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
589 if(q.n3)
590 {
591 mgl_printf(fp, gz, " stroke-dasharray=\"%s\"", mgl_get_dash(q.n3,q.w,','));
592 // mgl_printf(fp, gz, " stroke-dashoffset=\"%g\"", q.s*q.w);
593 mgl_printf(fp, gz, " stroke-dashoffset=\"%g\"", q.w);
594 }
595 if(q.w>1) mgl_printf(fp, gz, " stroke-width=\"%g\"", q.w);
596 wp = q.w>1 ? q.w:1; st = q.n3;
597 std::vector<long> ids = put_line(gr,i,wp,cp.c,st);
598 for(size_t j=0;j<ids.size();j++)
599 {
600 const mglPnt &p = gr->GetPnt(ids[j]);
601 mgl_printf(fp, gz, j==0?"><path d=\" M %g %g":" L %g %g",p.x-x1,hh-p.y);
602 }
603 mgl_printf(fp, gz, "\"/> </g>\n");
604 }
605 else if(q.type==2 && cp.r[3])
606 {
607 const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3);
608 mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\" opacity=\"%g\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),cp.r[3]/255.);
609 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g Z\"/> </g>\n", p1.x-x1, hh-p1.y, p2.x-x1, hh-p2.y, p3.x-x1, hh-p3.y);
610 }
611 else if(q.type==3 && cp.r[3])
612 {
613 const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3), &p4=gr->GetPnt(q.n4);
614 mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\" opacity=\"%g\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),cp.r[3]/255.);
615 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g L %g %g Z\"/> </g>\n", p1.x-x1, hh-p1.y, p2.x-x1, hh-p2.y, p4.x-x1, hh-p4.y, p3.x-x1, hh-p3.y);
616 }
617 else if(q.type==4)
618 {
619 float phi = gr->GetGlyphPhi(gr->GetPnt(q.n2),q.w);
620 if(mgl_isnan(phi)) continue;
621 mreal ss = q.s/2, xx = p1.u, yy = p1.v, zz = q.p;
622 if(q.n3&8) // this is "line"
623 {
624 mgl_printf(fp, gz, "<g transform=\"translate(%g,%g) scale(%.3g,%.3g) rotate(%g)\"", p1.x-x1, hh-p1.y, ss, -ss, -phi);
625 if(q.n3&4)
626 mgl_printf(fp, gz, " stroke=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
627 else
628 mgl_printf(fp, gz, " fill=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
629 mreal dy = 0.004,f=fabs(zz);
630 mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g L %g %g\"/></g>\n", xx,yy+dy, xx+f,yy+dy, xx+f,yy-dy, xx,yy-dy);
631 }
632 else
633 {
634 ss *= zz;
635 mgl_printf(fp, gz, "<g transform=\"translate(%g,%g) scale(%.3g,%.3g) rotate(%g)\"", p1.x-x1, hh-p1.y, ss, -ss, -q.w);
636 if(q.n3&4)
637 mgl_printf(fp, gz, " stroke=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
638 else
639 mgl_printf(fp, gz, " fill=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
640 mgl_printf(fp, gz, "<use x=\"%g\" y=\"%g\" xlink:href=\"#%c%c_%04x\"/></g>\n", xx/zz, yy/zz, q.n3&1?'b':'n', q.n3&2?'i':'n', q.n4);
641 }
642 }
643 }
644
645 for(long i=0;i<gr->GetPrmNum();i++)
646 { mglPrim &q=gr->GetPrm(i); if(q.type==-1) q.type = 1; }
647 mgl_printf(fp, gz, "</g></svg>");
648 if(strcmp(fname,"-")) { if(gz) gzclose((gzFile)fp); else fclose((FILE *)fp); }
649 setlocale(LC_NUMERIC, loc.c_str());
650 }
mgl_write_svg_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)651 void MGL_EXPORT mgl_write_svg_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
652 { char *s=new char[l+1]; memcpy(s,fname,l); s[l]=0;
653 char *d=new char[n+1]; memcpy(d,descr,n); d[n]=0;
654 mgl_write_svg(_GR_,s,d); delete []s; delete []d; }
655 //-----------------------------------------------------------------------------
mgl_write_tex(HMGL gr,const char * fname,const char * descr)656 void MGL_EXPORT mgl_write_tex(HMGL gr, const char *fname,const char *descr)
657 {
658 if(gr->GetPrmNum()<1) return;
659 _Gr_->clr(MGL_FINISHED); _Gr_->PreparePrim(1);
660
661 FILE *fp = fopen(fname,"w");
662 if(!fp) { gr->SetWarn(mglWarnOpen,fname); return; }
663 const std::string loc = setlocale(LC_NUMERIC, "C"); fwide(fp,1);
664 fwprintf(fp, L"%% Created by MathGL library\n%% Title: %s\n\n",descr?descr:fname);
665 // provide marks
666 fwprintf(fp, L"\\providecommand{\\mglp}[4]{\\draw[#3] (#1-#4, #2) -- (#1+#4,#2) (#1,#2-#4) -- (#1,#2+#4);}\n");
667 fwprintf(fp, L"\\providecommand{\\mglx}[4]{\\draw[#3] (#1-#4, #2-#4) -- (#1+#4,#2+#4) (#1+#4,#2-#4) -- (#1-#4,#2+#4);}\n");
668 fwprintf(fp, L"\\providecommand{\\mgls}[4]{\\draw[#3] (#1-#4, #2-#4) -- (#1+#4,#2-#4) -- (#1+#4,#2+#4) -- (#1-#4,#2+#4) -- cycle;}\n");
669 fwprintf(fp, L"\\providecommand{\\mglS}[4]{\\fill[#3] (#1-#4, #2-#4) -- (#1+#4,#2-#4) -- (#1+#4,#2+#4) -- (#1-#4,#2+#4) -- cycle;}\n");
670 fwprintf(fp, L"\\providecommand{\\mgld}[4]{\\draw[#3] (#1, #2-#4) -- (#1+#4,#2) -- (#1,#2+#4) -- (#1-#4,#2) -- cycle;}\n");
671 fwprintf(fp, L"\\providecommand{\\mglD}[4]{\\fill[#3] (#1, #2-#4) -- (#1+#4,#2) -- (#1,#2+#4) -- (#1-#4,#2) -- cycle;}\n");
672 fwprintf(fp, L"\\providecommand{\\mglv}[4]{\\draw[#3] (#1-#4, #2+#4/2) -- (#1+#4,#2+#4/2) -- (#1,#2-#4) -- cycle;}\n");
673 fwprintf(fp, L"\\providecommand{\\mglV}[4]{\\fill[#3] (#1-#4, #2+#4/2) -- (#1+#4,#2+#4/2) -- (#1,#2-#4) -- cycle;}\n");
674 fwprintf(fp, L"\\providecommand{\\mglt}[4]{\\draw[#3] (#1-#4, #2-#4/2) -- (#1+#4,#2-#4/2) -- (#1,#2+#4) -- cycle;}\n");
675 fwprintf(fp, L"\\providecommand{\\mglT}[4]{\\fill[#3] (#1-#4, #2-#4/2) -- (#1+#4,#2-#4/2) -- (#1,#2+#4) -- cycle;}\n");
676 fwprintf(fp, L"\\providecommand{\\mgll}[4]{\\draw[#3] (#1+#4/2, #2-#4) -- (#1+#4/2,#2+#4) -- (#1-#4,#2) -- cycle;}\n");
677 fwprintf(fp, L"\\providecommand{\\mglL}[4]{\\fill[#3] (#1+#4/2, #2-#4) -- (#1+#4/2,#2+#4) -- (#1-#4,#2) -- cycle;}\n");
678 fwprintf(fp, L"\\providecommand{\\mglr}[4]{\\draw[#3] (#1-#4/2, #2-#4) -- (#1-#4/2,#2+#4) -- (#1+#4,#2) -- cycle;}\n");
679 fwprintf(fp, L"\\providecommand{\\mglR}[4]{\\fill[#3] (#1-#4/2, #2-#4) -- (#1-#4/2,#2+#4) -- (#1+#4,#2) -- cycle;}\n");
680 fwprintf(fp, L"\\providecommand{\\mglR}[4]{\\draw[#3] (#1, #2-#4) -- (#1,#2) -- (#1-#4,#2+#4) (#1,#2) -- (#1+#4,#2+#4);}\n");
681 fwprintf(fp, L"\\providecommand{\\mgla}[4]{\\draw[#3] (#1-#4, #2) -- (#1+#4,#2) (#1-0.6*#4,#2-0.8*#4) -- (#1+0.6*#4,#2+0.8*#4) (#1-0.6*#4,#2+0.8*#4) -- (#1+0.6*#4,#2-0.8*#4);}\n");
682 fwprintf(fp, L"\\providecommand{\\mglY}[4]{\\draw[#3] (#1, #2-#4) -- (#1,#2) (#1-#4,#2+#4) -- (#1,#2) (#1+#4,#2+#4) -- (#1,#2);}\n");
683 fwprintf(fp, L"\\providecommand{\\mglo}[4]{\\draw[#3] (#1, #2) circle (#4);}\n");
684 fwprintf(fp, L"\\providecommand{\\mglO}[4]{\\fill[#3] (#1, #2) circle (#4);}\n");
685 fwprintf(fp, L"\\providecommand{\\mglc}[3]{\\draw[#3] (#1, #2) circle (%g);}\n\n", 4e-4*gr->mark_size());
686 fwprintf(fp, L"\\begin{tikzpicture}\n");
687
688 // write primitives first
689 mreal wp=-1;
690 int st=0;
691 mglRGBA cp;
692 char cname[128];
693
694 for(long i=0;i<gr->GetPrmNum();i++)
695 {
696 const mglPrim &q = gr->GetPrm(i);
697 if(q.type<0) continue; // q.n1>=0 always
698 cp.c = _Gr_->GetPrmCol(i);
699 snprintf(cname,128,"color={rgb,255:red,%d;green,%d;blue,%d}",cp.r[0],cp.r[1],cp.r[2]); cname[127]=0;
700
701 const mglPnt &p1=gr->GetPnt(q.n1);
702 mreal x=p1.x/100,y=p1.y/100,s=q.s/100;
703 if(q.type==0)
704 {
705 if(!strchr("xsSoO",q.n4)) s *= 1.1;
706 wp = 1;
707 switch(q.n4) // NOTE: no thickness for marks in TeX
708 {
709 case 'P':
710 fwprintf(fp, L"\\mglp{%.4g}{%.4g}{%s}{%.4g} \\mgls{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s,x,y,cname,s); break;
711 case 'X':
712 fwprintf(fp, L"\\mglx{%.4g}{%.4g}{%s}{%.4g} \\mgls{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s,x,y,cname,s); break;
713 case 'C':
714 fwprintf(fp, L"\\mglc{%.4g}{%.4g}{%s}{%.4g} \\mglo{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s,x,y,cname,s); break;
715 case '+': fwprintf(fp, L"\\mglp{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
716 case 'x': fwprintf(fp, L"\\mglx{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
717 case 's': fwprintf(fp, L"\\mgls{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
718 case 'S': fwprintf(fp, L"\\mglS{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
719 case 'd': fwprintf(fp, L"\\mgld{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
720 case 'D': fwprintf(fp, L"\\mglD{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
721 case '^': fwprintf(fp, L"\\mglt{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
722 case 'T': fwprintf(fp, L"\\mglT{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
723 case 'v': fwprintf(fp, L"\\mglv{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
724 case 'V': fwprintf(fp, L"\\mglV{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
725 case '<': fwprintf(fp, L"\\mgll{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
726 case 'L': fwprintf(fp, L"\\mglL{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
727 case '>': fwprintf(fp, L"\\mglr{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
728 case 'R': fwprintf(fp, L"\\mglR{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
729 case 'Y': fwprintf(fp, L"\\mglY{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
730 case 'o': fwprintf(fp, L"\\mglo{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
731 case 'O': fwprintf(fp, L"\\mglO{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
732 case '*': fwprintf(fp, L"\\mgla{%.4g}{%.4g}{%s}{%.4g}\n", x,y,cname,s); break;
733 default: fwprintf(fp, L"\\mglc{%.4g}{%.4g}{%s}\n", x,y,cname); break;
734 }
735 }
736 else if(q.type==2 && cp.r[3])
737 {
738 const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3);
739 if(cp.r[3]<255)
740 fwprintf(fp, L"\\fill[%s, fill opacity=%.4g] (%.4g,%.4g) -- (%.4g,%.4g) -- (%.4g,%.4g) -- cycle;\n", cname,cp.r[3]/255., x,y, p2.x/100,p2.y/100, p3.x/100,p3.y/100);
741 else
742 fwprintf(fp, L"\\fill[%s, fill] (%.4g,%.4g) -- (%.4g,%.4g) -- (%.4g,%.4g) -- cycle;\n", cname, x,y, p2.x/100,p2.y/100, p3.x/100,p3.y/100);
743 }
744 else if(q.type==3 && cp.r[3])
745 {
746 const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3), &p4=gr->GetPnt(q.n4);
747 if(cp.r[3]<255)
748 fwprintf(fp, L"\\fill[%s, fill opacity=%.4g] (%.4g,%.4g) -- (%.4g,%.4g) -- (%.4g,%.4g) -- (%.4g,%.4g) -- cycle;\n", cname,cp.r[3]/255., x,y, p2.x/100,p2.y/100, p4.x/100,p4.y/100, p3.x/100,p3.y/100);
749 else
750 fwprintf(fp, L"\\fill[%s, fill] (%.4g,%.4g) -- (%.4g,%.4g) -- (%.4g,%.4g) -- (%.4g,%.4g) -- cycle;\n", cname, x,y, p2.x/100,p2.y/100, p4.x/100,p4.y/100, p3.x/100,p3.y/100);
751
752 }
753 else if(q.type==1) // lines
754 {
755 //const char *dash[]={"", "8 8","4 4","1 3","7 4 1 4","3 2 1 2"};
756 const char *w[]={"semithick","thick","very thick","ultra thick"};
757 int iw=int(q.w-0.5); if(iw>3) iw=3;
758 if(iw<0) fwprintf(fp,L"\\draw[%s] ",cname);
759 else fwprintf(fp,L"\\draw[%s,%s] ",cname,w[iw]);
760 // TODO: add line dashing
761 wp = q.w>1 ? q.w:1; st = q.n3;
762 std::vector<long> ids = put_line(gr,i,wp,cp.c,st);
763 for(size_t j=0;j<ids.size();j++)
764 {
765 const mglPnt &p = gr->GetPnt(ids[j]);
766 float x0 = p.x, y0 = p.y;
767 fwprintf(fp, j==0?L"(%.4g,%.4g)":L" -- (%.4g,%.4g)",0.01*x0,y0*0.01);
768 }
769 fwprintf(fp, L";\n");
770 }
771 else if(q.type==6 && mgl_isnum(q.p)) // text
772 {
773 const mglText &t = gr->GetPtx(q.n3);
774 mreal dy = q.w*cos(q.p*M_PI/180)/100, dx = q.w*sin(q.p*M_PI/180)/100;
775 int f,a; mglGetStyle(t.stl.c_str(), &f, &a);
776 std::string ss=cname;
777 if((a&3)==0) ss.append(",anchor=base west");
778 if((a&3)==1) ss.append(",anchor=base");
779 if((a&3)==2) ss.append(",anchor=base east");
780 // if(f&MGL_FONT_ITAL) ss.append(",font=\\itshape");
781 // if(f&MGL_FONT_BOLD) ss.append(",font=\\bfshape");
782 if(t.text.find('\\')!=std::string::npos || t.text.find('{')!=std::string::npos || t.text.find('_')!=std::string::npos || t.text.find('^')!=std::string::npos)
783 fwprintf(fp,L"\\draw[%s] (%.4g,%.4g) node[rotate=%.2g]{$%ls$};\n", ss.c_str(),x-dx,y-dy, -q.p, t.text.c_str());
784 else
785 fwprintf(fp,L"\\draw[%s] (%.4g,%.4g) node[rotate=%.2g]{%ls};\n", ss.c_str(),x-dx,y-dy, -q.p, t.text.c_str());
786 }
787 }
788 fwprintf(fp, L"\\end{tikzpicture}\n");
789 for(long i=0;i<gr->GetPrmNum();i++)
790 { mglPrim &q=gr->GetPrm(i); if(q.type==-1) q.type = 1; }
791 fclose(fp);
792 setlocale(LC_NUMERIC, loc.c_str());
793
794 // provide main file for viewing figure
795 fp=fopen("mglmain.tex","wt");
796 if(fp)
797 {
798 fprintf(fp, "%% this file just show figure\n");
799 fprintf(fp, "\\documentclass{article}\n\\usepackage{tikz}\n");
800 fprintf(fp, "\\usepackage[T2A]{fontenc}\n\\usepackage[utf8]{inputenc}\n");
801 fprintf(fp, "\\begin{document}\n\\input{%s}\n\\end{document}\n",fname);
802 fclose(fp);
803 }
804 }
mgl_write_tex_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)805 void MGL_EXPORT mgl_write_tex_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
806 { char *s=new char[l+1]; memcpy(s,fname,l); s[l]=0;
807 char *d=new char[n+1]; memcpy(d,descr,n); d[n]=0;
808 mgl_write_tex(_GR_,s,d); delete []s; delete []d; }
809 //-----------------------------------------------------------------------------
810