1 /* Copyright (C) 1992-1998 The Geometry Center
2 * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3 *
4 * This file is part of Geomview.
5 *
6 * Geomview is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * Geomview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Geomview; see the file COPYING. If not, write
18 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19 * USA, or visit http://www.gnu.org.
20 */
21
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #if 0
27 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
28 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
29 #endif
30
31 #include <stdio.h>
32 #include <time.h>
33 #include "polylistP.h"
34 #include "hpoint3.h"
35 #include "mg.h"
36 #include "mgP.h"
37 #include "mgps.h"
38 #include "mgpsP.h"
39 #include "mgpstri.h"
40
41 #define TOL 0.05
42 #define AREA 25000
43 #ifndef max
44 # define max(a,b) ((a) > (b) ? (a) : (b))
45 #endif
46
47 /*static double areaThreshold;*/
48 static FILE *psout;
49
50 static void smoothLine(CPoint3 *p0, CPoint3 *p1);
51 static void smoothTriangle(CPoint3 *p0, CPoint3 *p1, CPoint3 *p2);
52 /*static double triArea(double *p0, double *p1, double *p2);*/
53 static double cdelta(double *p0, double *p1);
54 static void subdivtri(double *v0, double *v1, double *v2);
55 static void plerp(double *v0, double *v1, double *l);
56 static void outtri(double *v0, double *v1, double *v2);
57
58 /* PS page initialization stuff follows */
59
60 #define PNTS (72.0)
61 #define BORDPAGEMARGIN (0.25)
62 #define BORDPAGEXSIZE ( 8.5-2.0*BORDPAGEMARGIN)
63 #define BORDPAGEYSIZE (11.0-2.0*BORDPAGEMARGIN)
64
65 #define FULLPAGEMARGIN (0.00)
66 #define FULLPAGEXSIZE ( 8.5-2.0*FULLPAGEMARGIN)
67 #define FULLPAGEYSIZE (11.0-2.0*FULLPAGEMARGIN)
68
69 static double pagexsize = BORDPAGEXSIZE;
70 static double pageysize = BORDPAGEYSIZE;
71 static double pagemargin = BORDPAGEMARGIN;
72
73 void
MGPS_startPS(FILE * outf,ColorA * col,double aspect,int width,int height)74 MGPS_startPS(FILE *outf, ColorA *col, double aspect, int width, int height)
75 {
76 double imgxinches, imgyinches;
77 double pagexinches, pageyinches, pageaspect;
78 double dx, dy;
79 double xmargin, ymargin;
80 time_t tm;
81
82 psout = outf;
83 time(&tm);
84 fprintf(psout,"%%!PS-Adobe-2.0 EPSF-1.2\n");
85 fprintf(psout,"%%%%Title: Geomview Snapshot\n");
86 fprintf(psout,"%%%%Creator: Geomview\n");
87 fprintf(psout,"%%%%CreationDate: %s", ctime(&tm));
88 fprintf(psout,"%%%%For: %s\n", getenv("USER"));
89
90 /* areaThreshold = (width*height)/(double)AREA;*/
91 dx = width;
92 dy = height;
93
94 if (aspect>1.0)
95 {
96 pagexinches = pageysize;
97 pageyinches = pagexsize;
98 }
99 else
100 {
101 pagexinches = pagexsize;
102 pageyinches = pageysize;
103 }
104 pageaspect = pagexinches/pageyinches;
105 if (aspect<=pageaspect)
106 {
107 imgyinches = pageyinches;
108 imgxinches = imgyinches*aspect;
109 xmargin = pagemargin+(pagexinches-imgxinches)/2.0;
110 ymargin = pagemargin;
111 }
112 else
113 {
114 imgxinches = pagexinches;
115 imgyinches = imgxinches/aspect;
116 xmargin = pagemargin;
117 ymargin = pagemargin+(pageyinches-imgyinches)/2.0;
118 }
119 if (aspect>1.0)
120 fprintf(psout,"%%%%BoundingBox: %d %d %d %d\n",
121 (int)(PNTS*ymargin),
122 (int)(PNTS*xmargin),
123 (int)(PNTS*(ymargin+imgyinches)),
124 (int)(PNTS*(xmargin+imgxinches)));
125 else
126 fprintf(psout,"%%%%BoundingBox: %d %d %d %d\n",
127 (int)(PNTS*xmargin),
128 (int)(PNTS*ymargin),
129 (int)(PNTS*(xmargin+imgxinches)),
130 (int)(PNTS*(ymargin+imgyinches)));
131
132 fprintf(psout,"%%%%EndComments\n");
133 fprintf(psout,"gsave\n");
134 fprintf(psout,"1 setlinecap 1 setlinejoin\n");
135
136 if (aspect>1.0)
137 {
138 fprintf(psout,"%f %f translate\n",0.0,PNTS*FULLPAGEYSIZE);
139 fprintf(psout,"-90.0 rotate\n");
140 }
141 fprintf(psout,"%f %f translate\n", PNTS*xmargin, PNTS*ymargin);
142 fprintf(psout,"%f %f scale\n",PNTS*imgxinches/dx,PNTS*imgyinches/dy);
143
144 /* Now set up commands */
145 fprintf(psout,"[ %% stack mark\n");
146 fprintf(psout,"/poly {\n");
147 fprintf(psout," setrgbcolor newpath moveto\n");
148 fprintf(psout," counttomark 2 idiv { lineto } repeat closepath fill\n");
149 fprintf(psout,"} bind def\n");
150
151 fprintf(psout,"/epoly {\n");
152 fprintf(psout," setrgbcolor newpath moveto\n");
153 fprintf(psout," counttomark 4 sub 2 idiv { lineto } repeat closepath\n");
154 fprintf(psout,"gsave fill grestore setrgbcolor setlinewidth stroke\n");
155 fprintf(psout,"} bind def\n");
156
157 fprintf(psout,"/lines {\n");
158 fprintf(psout," setlinewidth setrgbcolor newpath moveto\n");
159 fprintf(psout," counttomark 2 idiv { lineto } repeat stroke\n");
160 fprintf(psout,"} bind def\n");
161
162 fprintf(psout,"/clines {\n");
163 fprintf(psout," setlinewidth setrgbcolor newpath moveto\n");
164 fprintf(psout," counttomark 2 idiv { lineto } repeat closepath stroke\n");
165 fprintf(psout,"} bind def\n");
166
167 fprintf(psout,"/circ {\n");
168 fprintf(psout," setrgbcolor newpath 0 360 arc fill\n");
169 fprintf(psout,"} bind def\n");
170
171 fprintf(psout,"/tri {\n");
172 fprintf(psout," setrgbcolor newpath moveto lineto lineto\n");
173 fprintf(psout," closepath fill\n");
174 fprintf(psout,"} bind def\n");
175
176 fprintf(psout,"/l {\n");
177 fprintf(psout," setrgbcolor newpath moveto lineto stroke\n");
178 fprintf(psout,"} bind def\n");
179
180 fprintf(psout,"%%\n");
181 fprintf(psout,"0 0 moveto %d 0 lineto %d %d lineto 0 %d lineto\n",
182 width, width, height, height);
183 fprintf(psout,"%g %g %g setrgbcolor closepath fill\n",
184 col->r, col->g, col->b);
185 }
186
MGPS_finishPS(void)187 void MGPS_finishPS(void)
188 {
189 fprintf(psout,"pop\ngrestore\nshowpage\n\n");
190 }
191
MGPS_polyline(CPoint3 * pts,int num,double width,int * col)192 void MGPS_polyline(CPoint3 *pts, int num, double width, int *col)
193 {
194 int i;
195
196 if (num == 1)
197 {
198 fprintf(psout, "%g %g %g %g %g %g circ\n",
199 pts[0].x, pts[0].y, (width + 1.0) / 2.0,
200 col[0]/255.0, col[1]/255.0, col[2]/255.0);
201 return;
202 }
203 for (i=0; i<num; i++)
204 fprintf(psout, "%g %g ", pts[i].x, pts[i].y);
205 fprintf(psout, "%g %g %g ", col[0]/255.0, col[1]/255.0, col[2]/255.0);
206 fprintf(psout, "%g lines\n", width);
207 }
208
MGPS_spolyline(CPoint3 * pts,int num,double width)209 void MGPS_spolyline(CPoint3 *pts, int num, double width)
210 {
211 int i;
212
213 if (num == 1)
214 {
215 fprintf(psout, "%g %g %g %g %g %g circ\n",
216 pts[0].x, pts[0].y, (width + 1.0) / 2.0,
217 pts[0].vcol.r, pts[0].vcol.g, pts[0].vcol.b);
218 return;
219 }
220 fprintf(psout, "%g setlinewidth\n", width);
221 for (i=0; i<num-1; i++)
222 smoothLine(&(pts[i]), &(pts[i+1]));
223 }
224
MGPS_poly(CPoint3 * pts,int num,int * col)225 void MGPS_poly(CPoint3 *pts, int num, int *col)
226 {
227 int i;
228
229 for (i=0; i<num; i++)
230 fprintf(psout, "%g %g ", pts[i].x, pts[i].y);
231 fprintf(psout, "%g %g %g ", col[0]/255.0, col[1]/255.0, col[2]/255.0);
232 fprintf(psout, "poly\n");
233 }
234
MGPS_epoly(CPoint3 * pts,int num,int * col,double ewidth,int * ecol)235 void MGPS_epoly(CPoint3 *pts, int num, int *col,
236 double ewidth, int *ecol)
237 {
238 int i;
239
240 fprintf(psout, "%g ", ewidth);
241 fprintf(psout, "%g %g %g ", ecol[0]/255.0, ecol[1]/255.0, ecol[2]/255.0);
242 for (i=0; i<num; i++)
243 fprintf(psout, "%g %g ", pts[i].x, pts[i].y);
244 fprintf(psout, "%g %g %g ", col[0]/255.0, col[1]/255.0, col[2]/255.0);
245 fprintf(psout, "epoly\n");
246 }
247
MGPS_spoly(CPoint3 * pts,int num)248 void MGPS_spoly(CPoint3 *pts, int num)
249 {
250 int i;
251
252 for (i=2; i<num; i++)
253 smoothTriangle(pts, pts+i-1, pts+i);
254 }
255
MGPS_sepoly(CPoint3 * pts,int num,double ewidth,int * ecol)256 void MGPS_sepoly(CPoint3 *pts, int num, double ewidth, int *ecol)
257 {
258 int i;
259
260 for (i=2; i<num; i++)
261 smoothTriangle(pts, pts+i-1, pts+i);
262 for (i=0; i<num; i++)
263 fprintf(psout, "%g %g ", pts[i].x, pts[i].y);
264 fprintf(psout, "%g %g %g ", ecol[0]/255.0, ecol[1]/255.0, ecol[2]/255.0);
265 fprintf(psout, "%g clines\n", ewidth);
266 }
267
smoothLine(CPoint3 * p0,CPoint3 * p1)268 static void smoothLine(CPoint3 *p0, CPoint3 *p1)
269 {
270 double x0[5], x1[5], delta;
271 int num, i;
272
273 x0[0] = p0->x; x0[1] = p0->y;
274 x0[2] = p0->vcol.r; x0[3] = p0->vcol.g; x0[4] = p0->vcol.b;
275 x1[0] = p1->x; x1[1] = p1->y;
276 x1[2] = p1->vcol.r; x1[3] = p1->vcol.g; x1[4] = p1->vcol.b;
277 delta = cdelta(x0, x1);
278 num = max(1, delta/TOL);
279 for (i=0; i<num; i++)
280 fprintf(psout, "%g %g %g %g %g %g %g l\n",
281 p0->x + (p1->x - p0->x)*i/(double)num,
282 p0->y + (p1->y - p0->y)*i/(double)num,
283 p0->x + (p1->x - p0->x)*(i+1)/(double)num,
284 p0->y + (p1->y - p0->y)*(i+1)/(double)num,
285 p0->vcol.r + (p1->vcol.r - p1->vcol.r)*i/(double)num,
286 p0->vcol.g + (p1->vcol.g - p1->vcol.g)*i/(double)num,
287 p0->vcol.b + (p1->vcol.b - p1->vcol.b)*i/(double)num);
288 }
289
290 /*
291 * pssubdivtriangle Draw a color shaded triangle by subdividing it in
292 * C code and generating many small triangles.
293 */
smoothTriangle(CPoint3 * p0,CPoint3 * p1,CPoint3 * p2)294 static void smoothTriangle(CPoint3 *p0, CPoint3 *p1, CPoint3 *p2)
295 {
296 double x0[5], x1[5], x2[5];
297
298 x0[0] = p0->x; x0[1] = p0->y;
299 x0[2] = p0->vcol.r; x0[3] = p0->vcol.g; x0[4] = p0->vcol.b;
300 x1[0] = p1->x; x1[1] = p1->y;
301 x1[2] = p1->vcol.r; x1[3] = p1->vcol.g; x1[4] = p1->vcol.b;
302 x2[0] = p2->x; x2[1] = p2->y;
303 x2[2] = p2->vcol.r; x2[3] = p2->vcol.g; x2[4] = p2->vcol.b;
304 subdivtri(x0,x1,x2);
305 }
306
cdelta(double * p0,double * p1)307 static double cdelta(double *p0, double *p1)
308 {
309 double dr, dg, db;
310
311 dr = p0[2] - p1[2];
312 if(dr<0)
313 dr = -dr;
314 dg = p0[3] - p1[3];
315 if(dg<0)
316 dg = -dg;
317 db = p0[4] - p1[4];
318 if(db<0)
319 db = -db;
320 return max(max(dr,dg),db);
321 }
322
323 #if 0
324 static double triArea(double *p0, double *p1, double *p2)
325 {
326 double a, b, c, s;
327 a = sqrt((p1[0]-p0[0])*(p1[0]-p0[0]) +
328 (p1[1]-p0[1])*(p1[1]-p0[1]) +
329 (p1[2]-p0[2])*(p1[2]-p0[2]));
330 b = sqrt((p2[0]-p0[0])*(p2[0]-p0[0]) +
331 (p2[1]-p0[1])*(p2[1]-p0[1]) +
332 (p2[2]-p0[2])*(p2[2]-p0[2]));
333 c = sqrt((p1[0]-p2[0])*(p1[0]-p2[0]) +
334 (p1[1]-p2[1])*(p1[1]-p2[1]) +
335 (p1[2]-p2[2])*(p1[2]-p2[2]));
336 s = (a+b+c)/2.0;
337 return sqrt(s*(s-a)*(s-b)*(s-c));
338 }
339 #endif
340
341 #define NONE 0x0
342 #define D0 0x1
343 #define D1 0x2
344 #define D2 0x4
345
subdivtri(double * v0,double * v1,double * v2)346 static void subdivtri(double *v0, double *v1, double *v2)
347 {
348 double d0, d1, d2;
349 double i0[5];
350 double i1[5];
351 double i2[5];
352 int code;
353
354 d0 = cdelta(v0,v1);
355 d1 = cdelta(v1,v2);
356 d2 = cdelta(v2,v0);
357 code = NONE;
358 if (d0 > TOL)
359 code |= D0;
360 if (d1 > TOL)
361 code |= D1;
362 if (d2 > TOL)
363 code |= D2;
364 /*
365 if (triArea(v0, v1, v2) < areaThreshold)
366 code = NONE;
367 */
368 switch(code)
369 {
370 case NONE:
371 outtri(v0,v1,v2);
372 break;
373 case D0:
374 plerp(v0,v1,i0);
375 subdivtri(v0,i0,v2);
376 subdivtri(v2,i0,v1);
377 break;
378 case D1:
379 plerp(v1,v2,i0);
380 subdivtri(v1,i0,v0);
381 subdivtri(v0,i0,v2);
382 break;
383 case D2:
384 plerp(v2,v0,i0);
385 subdivtri(v2,i0,v1);
386 subdivtri(v1,i0,v0);
387 break;
388 case D0|D1:
389 plerp(v0,v1,i0);
390 plerp(v1,v2,i1);
391 subdivtri(v0,i0,v2);
392 subdivtri(v2,i0,i1);
393 subdivtri(v1,i1,i0);
394 break;
395 case D1|D2:
396 plerp(v1,v2,i0);
397 plerp(v2,v0,i1);
398 subdivtri(v1,i0,v0);
399 subdivtri(v0,i0,i1);
400 subdivtri(v2,i1,i0);
401 break;
402 case D2|D0:
403 plerp(v2,v0,i0);
404 plerp(v0,v1,i1);
405 subdivtri(v2,i0,v1);
406 subdivtri(v1,i0,i1);
407 subdivtri(v0,i1,i0);
408 break;
409 case D2|D1|D0:
410 plerp(v0,v1,i0);
411 plerp(v1,v2,i1);
412 plerp(v2,v0,i2);
413 subdivtri(v0,i0,i2);
414 subdivtri(v1,i1,i0);
415 subdivtri(v2,i2,i1);
416 subdivtri(i0,i1,i2);
417 break;
418 }
419 }
420
plerp(double * v0,double * v1,double * l)421 static void plerp(double *v0, double *v1, double *l)
422 {
423 l[0] = (v0[0]+v1[0])/2.0;
424 l[1] = (v0[1]+v1[1])/2.0;
425 l[2] = (v0[2]+v1[2])/2.0;
426 l[3] = (v0[3]+v1[3])/2.0;
427 l[4] = (v0[4]+v1[4])/2.0;
428 }
429
outtri(double * v0,double * v1,double * v2)430 static void outtri(double *v0, double *v1, double *v2)
431 {
432 double ar, ag, ab;
433
434 fprintf(psout,"%g %g ",v0[0],v0[1]);
435 fprintf(psout,"%g %g ",v1[0],v1[1]);
436 fprintf(psout,"%g %g ",v2[0],v2[1]);
437 ar = (v0[2]+v1[2]+v2[2])/3.0;
438 ag = (v0[3]+v1[3]+v2[3])/3.0;
439 ab = (v0[4]+v1[4]+v2[4])/3.0;
440 fprintf(psout,"%g %g %g tri\n",ar,ag,ab);
441 }
442