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