1 /* GTS - Library for the manipulation of triangulated surfaces
2  * Copyright (C) 1999 St�phane Popinet
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include "config.h"
24 #ifdef HAVE_GETOPT_H
25 #  include <getopt.h>
26 #endif /* HAVE_GETOPT_H */
27 #ifdef HAVE_UNISTD_H
28 #  include <unistd.h>
29 #endif /* HAVE_UNISTD_H */
30 #include "gts.h"
31 
32 GtsRange depth_range;
33 
34 /* Colormap definition */
35 
36 typedef struct {
37   GPtrArray * colors;
38   gboolean reversed;
39 } Colormap;
40 
41 Colormap * colormap = NULL;
42 
color_new(gdouble r,gdouble g,gdouble b)43 static GtsColor * color_new (gdouble r, gdouble g, gdouble b)
44 {
45   GtsColor * c = g_malloc (sizeof (GtsColor));
46   c->r = r; c->g = g; c->b = b;
47   return c;
48 }
49 
colormap_read(FILE * fptr)50 static Colormap * colormap_read (FILE * fptr)
51 {
52   Colormap * cmap = g_malloc (sizeof (Colormap));
53   GtsColor c;
54   cmap->reversed = FALSE;
55   cmap->colors = g_ptr_array_new ();
56   while (fscanf (fptr, "%f %f %f", &c.r, &c.g, &c.b) == 3)
57     g_ptr_array_add (cmap->colors, color_new (c.r/255., c.g/255., c.b/255.));
58   return cmap;
59 }
60 
colormap_red_blue(void)61 static Colormap * colormap_red_blue (void)
62 {
63   Colormap * cmap = g_malloc (sizeof (Colormap));
64   cmap->reversed = FALSE;
65   cmap->colors = g_ptr_array_new ();
66   g_ptr_array_add (cmap->colors, color_new (1.0, 0.0, 0.0));
67   g_ptr_array_add (cmap->colors, color_new (0.0, 0.0, 1.0));
68   return cmap;
69 }
70 
colormap_color(Colormap * cmap,gdouble val)71 static GtsColor colormap_color (Colormap * cmap, gdouble val)
72 {
73   GtsColor c = {1., 1., 1.}, * c1, * c2;
74   guint i, n;
75   gdouble coef;
76 
77   g_return_val_if_fail (cmap != NULL, c);
78 
79   if (val > 1.0) val = 1.0;
80   else if (val < 0.0) val = 0.0;
81   if (cmap->reversed)
82     val = 1.0 - val;
83 
84   n = cmap->colors->len;
85   if (n == 0)
86     return c;
87   if (n == 1)
88     return *((GtsColor *)cmap->colors->pdata[0]);
89 
90   i = floor((gdouble)val*(gdouble)(n - 1));
91   if (i == n - 1)
92     return *((GtsColor *)cmap->colors->pdata[cmap->colors->len - 1]);
93   coef = val*(gdouble)(n - 1) - (gdouble)i;
94   c1 = cmap->colors->pdata[i];
95   c2 = cmap->colors->pdata[i+1];
96   c.r = c1->r + coef*(c2->r - c1->r);
97   c.g = c1->g + coef*(c2->g - c1->g);
98   c.b = c1->b + coef*(c2->b - c1->b);
99   return c;
100 }
101 
102 /* New Face class definition */
103 
104 typedef struct _DepthFace         DepthFace;
105 typedef struct _DepthFaceClass    DepthFaceClass;
106 
107 struct _DepthFace {
108   GtsFaceClass face;
109 
110   guint depth;
111 };
112 
113 struct _DepthFaceClass {
114   GtsFaceClass parent_class;
115 };
116 
117 #define DEPTH_FACE(obj)            GTS_OBJECT_CAST (obj,\
118 					           DepthFace,\
119 					           depth_face_class ())
120 #define DEPTH_FACE_CLASS(klass)    GTS_OBJECT_CLASS_CAST (klass,\
121 						         DepthFaceClass,\
122 						         depth_face_class())
123 #define IS_DEPTH_FACE(obj)         (gts_object_is_from_class (obj,\
124 						   depth_face_class ()))
125 
126 DepthFaceClass * depth_face_class                (void);
127 
depth_face_color(GtsObject * object)128 static GtsColor depth_face_color (GtsObject * object)
129 {
130   guint depth = DEPTH_FACE (object)->depth;
131 
132   return colormap_color (colormap, (gdouble) depth/depth_range.max);
133 }
134 
depth_face_class_init(DepthFaceClass * klass)135 static void depth_face_class_init (DepthFaceClass * klass)
136 {
137   /* overload color definition */
138   GTS_OBJECT_CLASS (klass)->color = depth_face_color;
139 }
140 
depth_face_init(DepthFace * dface)141 static void depth_face_init (DepthFace * dface)
142 {
143   dface->depth = 0;
144 }
145 
depth_face_class(void)146 DepthFaceClass * depth_face_class (void)
147 {
148   static DepthFaceClass * klass = NULL;
149 
150   if (klass == NULL) {
151     GtsObjectClassInfo depth_face_info = {
152       "DepthFace",
153       sizeof (DepthFace),
154       sizeof (DepthFaceClass),
155       (GtsObjectClassInitFunc) depth_face_class_init,
156       (GtsObjectInitFunc) depth_face_init,
157       (GtsArgSetFunc) NULL,
158       (GtsArgGetFunc) NULL
159     };
160     klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_face_class ()),
161 				  &depth_face_info);
162   }
163 
164   return klass;
165 }
166 
167 /* main functions */
168 
pick_first_face(GtsFace * f,GtsFace ** first)169 static void pick_first_face (GtsFace * f, GtsFace ** first)
170 {
171   if (*first == NULL)
172     *first = f;
173 }
174 
main(int argc,char * argv[])175 int main (int argc, char * argv[])
176 {
177   GtsSurface * s;
178   GtsFile * fp;
179   GtsFace * first = NULL;
180   int c = 0;
181   gboolean verbose = FALSE;
182 
183   colormap = colormap_red_blue (); /* default */
184 
185   /* parse options using getopt */
186   while (c != EOF) {
187 #ifdef HAVE_GETOPT_LONG
188     static struct option long_options[] = {
189       {"cmap", required_argument, NULL, 'c'},
190       {"help", no_argument, NULL, 'h'},
191       {"verbose", no_argument, NULL, 'v'}
192     };
193     int option_index = 0;
194     switch ((c = getopt_long (argc, argv, "hvc:",
195 			      long_options, &option_index))) {
196 #else /* not HAVE_GETOPT_LONG */
197     switch ((c = getopt (argc, argv, "hvc:"))) {
198 #endif /* not HAVE_GETOPT_LONG */
199     case 'c': { /* cmap */
200       FILE * fptr = fopen (optarg, "rt");
201       if (!fptr) {
202 	fprintf (stderr, "traverse: cannot open colormap file `%s'.\n",
203 		 optarg);
204 	return 1;
205       }
206       colormap = colormap_read (fptr);
207       fclose (fptr);
208       break;
209     }
210     case 'v': /* verbose */
211       verbose = TRUE;
212       break;
213     case 'h': /* help */
214       fprintf (stderr,
215              "Usage: traverse [OPTION] < file.gts > file.oogl\n"
216 	     "Output an OOGL (geomview) surface colored according to the (graph) distance\n"
217 	     "from a random face to the others\n"
218 	     "\n"
219 	     "  -c FILE --cmap=FILE  load FILE as colormap\n"
220 	     "  -v      --verbose    print statistics about the surface\n"
221 	     "  -h      --help       display this help and exit\n"
222 	     "\n"
223 	     "Reports bugs to %s\n",
224 	     GTS_MAINTAINER);
225       return 0; /* success */
226       break;
227     case '?': /* wrong options */
228       fprintf (stderr, "Try `traverse --help' for more information.\n");
229       return 1; /* failure */
230     }
231   }
232 
233   s = gts_surface_new (gts_surface_class (),
234 		       GTS_FACE_CLASS (depth_face_class ()),
235 		       gts_edge_class (),
236 		       gts_vertex_class ());
237   fp = gts_file_new (stdin);
238   if (gts_surface_read (s, fp)) {
239     fputs ("traverse: file on standard input is not a valid GTS file\n",
240 	   stderr);
241     fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error);
242     return 1; /* failure */
243   }
244 
245   if (verbose)
246     gts_surface_print_stats (s, stderr);
247 
248   gts_surface_foreach_face (s, (GtsFunc) pick_first_face, &first);
249   gts_range_init (&depth_range);
250   if (first) {
251     GtsSurfaceTraverse * t = gts_surface_traverse_new (s, first);
252     GtsFace * f;
253     guint level;
254     while ((f = gts_surface_traverse_next (t, &level))) {
255       DEPTH_FACE (f)->depth = level;
256       gts_range_add_value (&depth_range, level);
257     }
258     gts_surface_traverse_destroy (t);
259   }
260   gts_range_update (&depth_range);
261   if (verbose) {
262     fputs ("distance: ", stderr);
263     gts_range_print (&depth_range, stderr);
264     fputc ('\n', stderr);
265   }
266   gts_surface_write_oogl (s, stdout);
267 
268   return 0;
269 }
270