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