void ofxGtsSurface::setup(string filename) { FILE * fptr; GtsFile * fp; string filePath = ofToDataPath(filename); /* open first file */ if ((fptr = fopen (filePath.c_str(), "rt")) == NULL) { ofLog(OF_LOG_ERROR, "Cannot open file: " + filePath); return; } /* reads in first surface file */ surface = gts_surface_new(GTS_SURFACE_CLASS(gts_surface_class()), GTS_FACE_CLASS(gts_nface_class()), GTS_EDGE_CLASS(gts_nedge_class()), GTS_VERTEX_CLASS(gts_nvertex_class())); fp = gts_file_new(fptr); if (gts_surface_read (surface, fp)) { ofLog(OF_LOG_ERROR, filePath + " is not a valid GTS surface file"); loaded = false; gts_object_destroy(GTS_OBJECT(surface)); } else { ofLog(OF_LOG_NOTICE, "Gts surface file read: " + filePath); loaded = true; } gts_file_destroy (fp); fclose (fptr); }
void ofxGtsSurface::setup() { surface = gts_surface_new(GTS_SURFACE_CLASS(gts_surface_class()), GTS_FACE_CLASS(gts_nface_class()), GTS_EDGE_CLASS(gts_nedge_class()), GTS_VERTEX_CLASS(gts_nvertex_class())); loaded = true; }
void gts_triangulate_convex_polygon_test() { int i; gdouble v[5][3] = { {0.0, 0.0, 1.0}, {0.0, 2.0, 2.0}, {2.0, 3.0, 1.0}, {4.0, 1.0, 1.0}, {2.0, 0.0, 0.0} }; GtsEdgePool *pool = gts_edge_pool_new(gts_edge_pool_class()); GtsVertex *vtx[5]; GCList *polygon = NULL; GCList *wired = NULL; GtsSurfaceStats sstats; for (i = 0; i < 5; ++i) { vtx[i] = gts_vertex_new(gts_vertex_class(), v[i][0],v[i][1],v[i][2]); polygon = g_clist_append(polygon, vtx[i]); } polygon = g_clist_append(polygon, vtx[0]); polygon = g_clist_append(polygon, vtx[1]); wired = g_clist_append(wired, vtx[0]); wired = g_clist_append(wired, vtx[1]); wired = g_clist_append(wired, vtx[0]); wired = g_clist_append(wired, vtx[2]); GtsSurface *s = gts_surface_new(gts_surface_class(), gts_face_class(), gts_edge_class(), gts_vertex_class()); gts_triangulate_convex_polygon(s, pool, wired); g_assert(gts_surface_face_number(s) == 0); gts_triangulate_convex_polygon(s, pool, polygon); g_message("gts_surface_face_number = %d", gts_surface_face_number(s)); g_assert(gts_surface_face_number(s) == 3); gts_surface_stats(s, &sstats); g_assert(sstats.n_incompatible_faces == 0); g_assert(sstats.n_duplicate_faces == 0); g_assert(sstats.n_duplicate_edges == 0); g_assert(sstats.n_boundary_edges == 5); g_assert(sstats.n_non_manifold_edges == 0); g_assert(sstats.faces_per_edge.min == 1); g_assert(sstats.faces_per_edge.max == 2); g_message("Triangulate convex polygon PASS"); gts_object_destroy(GTS_OBJECT(pool)); }
static GtsSurface * happrox_list (GSList * points, gboolean keep_enclosing, gboolean closed, CostFunc cost_func, gpointer cost_data, GtsStopFunc stop_func, gpointer stop_data) { GtsSurface * s = gts_surface_new (gts_surface_class (), GTS_FACE_CLASS (list_face_class ()), gts_edge_class (), gts_vertex_class ()); GtsTriangle * t; GtsVertex * w1, * w2, * w3; GtsListFace * f; /* creates enclosing triangle */ t = gts_triangle_enclosing (gts_triangle_class (), points, 10.); gts_triangle_vertices (t, &w1, &w2, &w3); GTS_POINT (w1)->z = GTS_POINT (w2)->z = GTS_POINT (w3)->z = keep_enclosing ? -10. : -1e30; f = GTS_LIST_FACE (gts_face_new (s->face_class, t->e1, t->e2, t->e3)); gts_surface_add_face (s, GTS_FACE (f)); f->points = points; /* refine surface */ surface_hf_refine (s, cost_func, cost_data, stop_func, stop_data); /* destroy unused vertices */ gts_surface_foreach_face (s, (GtsFunc) destroy_unused, NULL); /* destroy enclosing triangle */ if (!keep_enclosing) { gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (w1)); gts_object_destroy (GTS_OBJECT (w2)); gts_object_destroy (GTS_OBJECT (w3)); gts_allow_floating_vertices = FALSE; } else if (closed) { GSList * l = gts_surface_boundary (s); GtsFace * f; g_assert (g_slist_length (l) == 3); f = gts_face_new (s->face_class, l->data, l->next->data, l->next->next->data); gts_surface_add_face (s, f); if (!gts_face_is_compatible (f, s)) gts_triangle_revert (GTS_TRIANGLE (f)); g_slist_free (l); gts_object_destroy (GTS_OBJECT (t)); } else gts_object_destroy (GTS_OBJECT (t)); return s; }
int main (int argc, char * argv[]) { GtsSurface * s; GtsBBox * bbox; gdouble delta; GtsPoint * p1, * p2, * p3; guint nt; GtsRange cluster_stats; GtsClusterGrid * cluster_grid; if (argc != 2) { fprintf (stderr, "usage: oocs DELTA < infile > outfile\n"); return 1; } s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); bbox = gts_bbox_new (gts_bbox_class (), s, 0., 0., 0., 0., 0., 0.); scanf ("%u", &nt); scanf ("%lf %lf %lf", &bbox->x1, &bbox->y1, &bbox->z1); scanf ("%lf %lf %lf", &bbox->x2, &bbox->y2, &bbox->z2); delta = atof (argv[1])*sqrt (gts_bbox_diagonal2 (bbox)); cluster_grid = gts_cluster_grid_new (gts_cluster_grid_class (), gts_cluster_class (), s, bbox, delta); p1 = gts_point_new (gts_point_class (), 0., 0., 0.); p2 = gts_point_new (gts_point_class (), 0., 0., 0.); p3 = gts_point_new (gts_point_class (), 0., 0., 0.); while (scanf ("%lf %lf %lf", &p1->x, &p1->y, &p1->z) == 3 && scanf ("%lf %lf %lf", &p2->x, &p2->y, &p2->z) == 3 && scanf ("%lf %lf %lf", &p3->x, &p3->y, &p3->z) == 3) gts_cluster_grid_add_triangle (cluster_grid, p1, p2, p3, NULL); cluster_stats = gts_cluster_grid_update (cluster_grid); gts_object_destroy (GTS_OBJECT (p1)); gts_object_destroy (GTS_OBJECT (p2)); gts_object_destroy (GTS_OBJECT (p3)); gts_object_destroy (GTS_OBJECT (cluster_grid)); fprintf (stderr, "Initial number of triangles: %u\n", nt); fprintf (stderr, "%d clusters of size: min: %g avg: %.1f|%.1f max: %g\n", cluster_stats.n, cluster_stats.min, cluster_stats.mean, cluster_stats.stddev, cluster_stats.max); gts_surface_print_stats (s, stderr); gts_surface_write (s, stdout); return 0; }
GtsSurface* process(const k3d::mesh& Mesh, const k3d::polyhedron::const_primitive& Polyhedron) { gts_surface = gts_surface_new(gts_surface_class(), gts_face_class(), gts_edge_class(), gts_vertex_class()); mesh_points = Mesh.points.get(); gts_vertices.assign(mesh_points->size(), 0); base::process(Mesh, Polyhedron); gts_vertices.clear(); mesh_points = 0; return gts_surface; }
static GtsObject * parent(GtsFace *face) { GtsSurface *p; p = gts_surface_new(gts_surface_class(), gts_face_class(), gts_edge_class(), gts_vertex_class()); if( p == NULL ) { PyErr_SetString(PyExc_MemoryError, "could not create parent"); return NULL; } gts_surface_add_face(p,face); return GTS_OBJECT(p); }
void ofxGtsSurface::createBoolean(ofxGtsSurface &source, ofxGtsSurface &result, BooleanOperation operation) { result.surface = gts_surface_new(GTS_SURFACE_CLASS(gts_surface_class()), GTS_FACE_CLASS(gts_nface_class()), GTS_EDGE_CLASS(gts_nedge_class()), GTS_VERTEX_CLASS(gts_nvertex_class())); switch(operation) { case BOOLEAN_INTERSECTION: gts_surface_inter_boolean(si, result.surface, GTS_1_IN_2); gts_surface_inter_boolean(si, result.surface, GTS_2_IN_1); result.loaded = true; break; case BOOLEAN_UNION: gts_surface_inter_boolean(si, result.surface, GTS_1_OUT_2); gts_surface_inter_boolean(si, result.surface, GTS_2_OUT_1); result.loaded = true; break; case BOOLEAN_DIFFERENCE: gts_surface_inter_boolean(si, result.surface, GTS_1_OUT_2); gts_surface_inter_boolean(si, result.surface, GTS_2_IN_1); gts_surface_foreach_face(si->s2, (GtsFunc)gts_triangle_revert, NULL); gts_surface_foreach_face(source.surface, (GtsFunc)gts_triangle_revert, NULL); result.loaded = true; break; case BOOLEAN_REVERSE_DIFFERENCE: // TODO: Reverse difference can cause crashes, is there a way to catch them? gts_surface_inter_boolean(si, result.surface, GTS_2_OUT_1); gts_surface_inter_boolean(si, result.surface, GTS_1_IN_2); gts_surface_foreach_face(si->s1, (GtsFunc)gts_triangle_revert, NULL); gts_surface_foreach_face(surface, (GtsFunc)gts_triangle_revert, NULL); result.loaded = true; break; } }
int main (int argc, char * argv[]) { GtsSurface * s; guint i; GtsFile * fp; guint nv = 1, ne = 1, nf = 1; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("gtstoc: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } printf (" GtsSurface * surface = gts_surface_new (gts_surface_class (),\n" " gts_face_class (),\n" " gts_edge_class (),\n" " gts_vertex_class ());\n\n"); gts_surface_foreach_vertex (s, (GtsFunc) write_vertex, &nv); printf ("\n"); gts_surface_foreach_edge (s, (GtsFunc) write_edge, &ne); printf ("\n"); gts_surface_foreach_face (s, (GtsFunc) write_face, &nf); printf (" \n"); for (i = 1; i < nf; i++) printf (" gts_surface_add_face (surface, f%u);\n", i); return 0; }
void gts_polygon_triangulate_test() { int i; gdouble v[12][3] = { {0.0, 0.0, 0.0}, {0.0, 3.0, 0.0}, {3.0, 3.0, 0.0}, {3.0, 1.0, 0.0}, {4.0, 1.0, 0.0}, {4.0, 3.0, 0.0}, {5.0, 3.0, 0.0}, {5.0, 0.0, 0.0}, {2.0, 0.0, 0.0}, {2.0, 2.0, 0.0}, {1.0, 2.0, 0.0}, {1.0, 0.0, 0.0}, }; GtsVector normal = {0,0,0}; GtsVertex *vtx[12]; GCList *polygon = NULL; GCList *triangle = NULL; GtsSurface *s, *s2; GtsEdgePool *pool = gts_edge_pool_new(gts_edge_pool_class()); gts_triangulate_test_stuff(); for (i = 0; i < 12; ++i) { vtx[i] = gts_vertex_new(gts_vertex_class(), v[i][0],v[i][1],v[i][2]); polygon = g_clist_append(polygon, vtx[i]); } for (i = 0; i < 3; ++i) { triangle = g_clist_prepend(triangle, vtx[i]); } s = gts_surface_new(gts_surface_class(), gts_face_class(), gts_edge_class(), gts_vertex_class()); s2 = gts_surface_new(gts_surface_class(), gts_face_class(), gts_edge_class(), gts_vertex_class()); // triangulate the polygon by using its own orientation polygon = gts_surface_add_polygon(s, pool, polygon, normal); // do some test ? g_assert(gts_surface_face_number(s) == 10); g_debug("area = %f", gts_surface_area(s)); g_assert(gts_surface_area(s) == 11.0); gts_object_destroy(GTS_OBJECT(pool)); // cleanup g_clist_free(triangle); g_clist_free(polygon); gts_object_destroy(GTS_OBJECT(s)); gts_object_destroy(GTS_OBJECT(s2)); g_message("Triangulate PASSED"); }
/* tri: * Main entry point to using GTS for triangulation. * Input is npt points with x and y coordinates stored either separately * in x[] and y[] (sepArr != 0) or consecutively in x[] (sepArr == 0). * Optionally, the input can include nsegs line segments, whose endpoint * indices are supplied in segs[2*i] and segs[2*i+1] yielding a constrained * triangulation. * * The return value is the corresponding gts surface, which can be queries for * the triangles and line segments composing the triangulation. */ static GtsSurface* tri(double *x, double *y, int npt, int *segs, int nsegs, int sepArr) { int i; GtsSurface *surface; GVertex **vertices = N_GNEW(npt, GVertex *); GtsEdge **edges = N_GNEW(nsegs, GtsEdge*); GSList *list = NULL; GtsVertex *v1, *v2, *v3; GtsTriangle *t; GtsVertexClass *vcl = (GtsVertexClass *) g_vertex_class(); GtsEdgeClass *ecl = GTS_EDGE_CLASS (gts_constraint_class ()); if (sepArr) { for (i = 0; i < npt; i++) { GVertex *p = (GVertex *) gts_vertex_new(vcl, x[i], y[i], 0); p->idx = i; vertices[i] = p; } } else { for (i = 0; i < npt; i++) { GVertex *p = (GVertex *) gts_vertex_new(vcl, x[2*i], x[2*i+1], 0); p->idx = i; vertices[i] = p; } } /* N.B. Edges need to be created here, presumably before the * the vertices are added to the face. In particular, they cannot * be added created and added vi gts_delaunay_add_constraint() below. */ for (i = 0; i < nsegs; i++) { edges[i] = gts_edge_new(ecl, (GtsVertex *) (vertices[ segs[ 2 * i]]), (GtsVertex *) (vertices[ segs[ 2 * i + 1]])); } for (i = 0; i < npt; i++) list = g_slist_prepend(list, vertices[i]); t = gts_triangle_enclosing(gts_triangle_class(), list, 100.); g_slist_free(list); gts_triangle_vertices(t, &v1, &v2, &v3); surface = gts_surface_new(gts_surface_class(), (GtsFaceClass *) g_face_class(), gts_edge_class(), gts_vertex_class()); gts_surface_add_face(surface, gts_face_new(gts_face_class(), t->e1, t->e2, t->e3)); for (i = 0; i < npt; i++) { GtsVertex *v1 = (GtsVertex *) vertices[i]; GtsVertex *v = gts_delaunay_add_vertex(surface, v1, NULL); /* if v != NULL, it is a previously added pt with the same * coordinates as v1, in which case we replace v1 with v */ if (v) { /* agerr (AGWARN, "Duplicate point %d %d\n", i, ((GVertex*)v)->idx); */ gts_vertex_replace (v1, v); } } for (i = 0; i < nsegs; i++) { gts_delaunay_add_constraint(surface,GTS_CONSTRAINT(edges[i])); } /* destroy enclosing triangle */ gts_allow_floating_vertices = TRUE; gts_allow_floating_edges = TRUE; /* gts_object_destroy(GTS_OBJECT(v1)); gts_object_destroy(GTS_OBJECT(v2)); gts_object_destroy(GTS_OBJECT(v3)); */ destroy(v1); destroy(v2); destroy(v3); gts_allow_floating_edges = FALSE; gts_allow_floating_vertices = FALSE; if (nsegs) delaunay_remove_holes(surface); free (edges); free(vertices); return surface; }
int main (int argc, char * argv[]) { GtsSurface * s; GtsFile * fp; int c = 0; gboolean verbose = FALSE; guint n, niter; gdouble lambda; gpointer data[4]; gboolean fold = FALSE; gdouble maxcosine2 = 0.; guint nfold = 1; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"fold", required_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvf:", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvf:"))) { #endif /* not HAVE_GETOPT_LONG */ case 'f': /* fold */ fold = TRUE; maxcosine2 = cos (atof (optarg)*3.14159265359/180.); maxcosine2 *= maxcosine2; break; case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: smooth [OPTION] LAMBDA NITER < file.gts > smooth.gts\n" "Smooth a GTS file by applying NITER iterations of a Laplacian filter\n" "of parameter LAMBDA.\n" "\n" " -f VAL --fold=VAL smooth only folds\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `smooth --help' for more information.\n"); return 1; /* failure */ } } if (optind >= argc) { /* missing lambda */ fprintf (stderr, "smooth: missing LAMBDA\n" "Try `smooth --help' for more information.\n"); return 1; /* failure */ } lambda = atof (argv[optind++]); if (optind >= argc) { /* missing niter */ fprintf (stderr, "smooth: missing NITER\n" "Try `smooth --help' for more information.\n"); return 1; /* failure */ } niter = atoi (argv[optind++]); s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("smooth: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } if (verbose) gts_surface_print_stats (s, stderr); data[0] = s; data[1] = λ data[2] = &maxcosine2; data[3] = &nfold; for (n = 1; n <= niter && (!fold || nfold > 0); n++) { if (fold) { nfold = 0; gts_surface_foreach_vertex (s, (GtsFunc) smooth_fold, data); } else gts_surface_foreach_vertex (s, (GtsFunc) smooth_vertex, data); if (verbose) fprintf (stderr, "\rIteration: %10u %3.0f%% ", n, 100.*n/niter); } if (verbose) { fputc ('\n', stderr); gts_surface_print_stats (s, stderr); } gts_surface_write (s, stdout); return 0; }
/* coarsen - produce a coarsened version of the input */ int main (int argc, char * argv[]) { GtsSurface * s; GtsPSurface * ps = NULL; gboolean verbose = FALSE; gboolean progressive = FALSE; gboolean log_cost = FALSE; guint number = 0; gdouble cmax = 0.0; StopOptions stop = NUMBER; CostOptions cost = COST_OPTIMIZED; MidvertexOptions mid = OPTIMIZED; GtsKeyFunc cost_func = NULL; GtsCoarsenFunc coarsen_func = NULL; GtsStopFunc stop_func = NULL; gpointer stop_data = NULL; int c = 0; GtsFile * fp; gdouble fold = PI/180.; GtsVolumeOptimizedParams params = { 0.5, 0.5, 0. }; gpointer coarsen_data = NULL, cost_data = NULL; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"angle", no_argument, NULL, 'a'}, {"progressive", no_argument, NULL, 'p'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {"number", required_argument, NULL, 'n'}, {"length", no_argument, NULL, 'l'}, {"midvertex", no_argument, NULL, 'm'}, {"cost", required_argument, NULL, 'c'}, {"fold", required_argument, NULL, 'f'}, {"vweight", required_argument, NULL, 'w'}, {"bweight", required_argument, NULL, 'b'}, {"sweight", required_argument, NULL, 's'}, {"log", no_argument, NULL, 'L'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvmc:n:lpf:w:b:s:La", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvmc:n:lpf:w:b:s:La"))) { #endif /* not HAVE_GETOPT_LONG */ case 'a': /* angle */ cost = COST_ANGLE; break; case 'L': /* log */ log_cost = TRUE; break; case 'p': /* write progressive surface */ progressive = TRUE; break; case 'n': /* stop by number */ stop = NUMBER; number = atoi (optarg); break; case 'c': /* stop by cost */ stop = COST; cmax = atof (optarg); break; case 'v': /* verbose */ verbose = TRUE; break; case 'm': /* midvertex */ mid = MIDVERTEX; break; case 'l': /* cost is length */ cost = COST_LENGTH; break; case 'f': /* fold angle */ fold = atof (optarg)*PI/180.; break; case 'w': /* volume optimized weight */ params.volume_weight = atof (optarg); break; case 'b': /* boundary optimized weight */ params.boundary_weight = atof (optarg); break; case 's': /* shape optimized weight */ params.shape_weight = atof (optarg); break; case 'h': /* help */ fprintf (stderr, "Usage: coarsen [OPTION] < file.gts\n" "Construct a coarsened version of the input.\n" "\n" " -n N, --number=N stop the coarsening process if the number of\n" " edges was to fall below N\n" " -c C, --cost=C stop the coarsening process if the cost of collapsing\n" " an edge is larger than C\n" " -m --midvertex use midvertex as replacement vertex\n" " default is volume optimized point\n" " -l --length use length^2 as cost function\n" " default is optimized point cost\n" " -f F, --fold=F set maximum fold angle to F degrees\n" " default is one degree\n" " -w W, --vweight=W set weight used for volume optimization\n" " default is 0.5\n" " -b W, --bweight=W set weight used for boundary optimization\n" " default is 0.5\n" " -s W, --sweight=W set weight used for shape optimization\n" " default is 0.0\n" " -p --progressive write progressive surface file\n" " -L --log logs the evolution of the cost\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `coarsen --help' for more information.\n"); return 1; /* failure */ } } /* read surface in */ s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("coarsen: the file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } /* if verbose on print stats */ if (verbose) { gts_surface_print_stats (s, stderr); fprintf (stderr, "# volume: %g area: %g\n", gts_surface_volume (s), gts_surface_area (s)); } /* select the right coarsening process */ switch (cost) { case COST_OPTIMIZED: cost_func = (GtsKeyFunc) gts_volume_optimized_cost; cost_data = ¶ms; break; case COST_LENGTH: cost_func = NULL; break; case COST_ANGLE: cost_func = (GtsKeyFunc) cost_angle; break; default: g_assert_not_reached (); } switch (mid) { case MIDVERTEX: coarsen_func = NULL; break; case OPTIMIZED: coarsen_func = (GtsCoarsenFunc) gts_volume_optimized_vertex; coarsen_data = ¶ms; break; default: g_assert_not_reached (); } if (log_cost) stop_func = (GtsStopFunc) stop_log_cost; else { switch (stop) { case NUMBER: if (verbose) stop_func = (GtsStopFunc) stop_number_verbose; else stop_func = (GtsStopFunc) gts_coarsen_stop_number; stop_data = &number; break; case COST: if (verbose) stop_func = (GtsStopFunc) stop_cost_verbose; else stop_func = (GtsStopFunc) gts_coarsen_stop_cost; stop_data = &cmax; break; default: g_assert_not_reached (); } } if (progressive) ps = gts_psurface_new (gts_psurface_class (), s, gts_split_class (), cost_func, cost_data, coarsen_func, coarsen_data, stop_func, stop_data, fold); else gts_surface_coarsen (s, cost_func, cost_data, coarsen_func, coarsen_data, stop_func, stop_data, fold); /* if verbose on print stats */ if (verbose) { fputc ('\n', stderr); gts_surface_print_stats (s, stderr); fprintf (stderr, "# volume: %g area: %g\n", gts_surface_volume (s), gts_surface_area (s)); } /* write resulting surface to standard output */ if (progressive) gts_psurface_write (ps, stdout); else gts_surface_write (s, stdout); return 0; /* success */ }
int main (int argc, char * argv[]) { GtsSurface * s; gboolean verbose = FALSE; int c = 0; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hv", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hv"))) { #endif /* not HAVE_GETOPT_LONG */ case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: merge [OPTION] file1.gts file2.gts ...\n" "Merges files and outputs the resulting GTS surface.\n" "\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `merge --help' for more information.\n"); return 1; /* failure */ } } s = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ()))); while (optind < argc) { FILE * f = fopen (argv[optind], "r"); GtsFile * fp; GtsSurface * s1; if (f == NULL) { fprintf (stderr, "merge: can not open file `%s'\n", argv[optind]); return 1; } fp = gts_file_new (f); s1 = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ()))); if (gts_surface_read (s1, fp)) { fprintf (stderr, "merge: `%s' is not a valid GTS surface file\n", argv[optind]); fprintf (stderr, "%s:%d:%d: %s\n", argv[optind], fp->line, fp->pos, fp->error); return 1; } gts_surface_merge (s, s1); gts_object_destroy (GTS_OBJECT (s1)); gts_file_destroy (fp); fclose (f); optind++; } if (verbose) gts_surface_print_stats (s, stderr); gts_surface_write (s, stdout); return 0; }
static GtsSurface * happrox (gray ** g, gint width, gint height, CostFunc cost_func, gpointer cost_data, GtsStopFunc stop_func, gpointer stop_data) { GtsSurface * s = gts_surface_new (gts_surface_class (), GTS_FACE_CLASS (list_face_class ()), gts_edge_class (), gts_vertex_class ()); GtsVertex * v1 = gts_vertex_new (s->vertex_class, 0., 0., g[0][0]); GtsVertex * v2 = gts_vertex_new (s->vertex_class, 0., height - 1, g[height - 1][0]); GtsVertex * v3 = gts_vertex_new (s->vertex_class, width - 1, 0., g[0][width - 1]); GtsVertex * v4 = gts_vertex_new (s->vertex_class, width - 1, height - 1, g[height - 1][width - 1]); guint i, j; GSList * corners = NULL; GtsTriangle * t; GtsVertex * w1, * w2, * w3; GtsListFace * f; /* creates enclosing triangle */ corners = g_slist_prepend (corners, v1); corners = g_slist_prepend (corners, v2); corners = g_slist_prepend (corners, v3); corners = g_slist_prepend (corners, v4); t = gts_triangle_enclosing (gts_triangle_class (), corners, 100.); g_slist_free (corners); gts_triangle_vertices (t, &w1, &w2, &w3); f = GTS_LIST_FACE (gts_face_new (s->face_class, t->e1, t->e2, t->e3)); gts_surface_add_face (s, GTS_FACE (f)); /* add PGM vertices (corners excepted) to point list of f */ for (i = 1; i < width - 1; i++) { for (j = 1; j < height - 1; j++) prepend (f, g, i, j); prepend (f, g, i, 0); prepend (f, g, i, height - 1); } for (j = 1; j < height - 1; j++) { prepend (f, g, 0, j); prepend (f, g, width - 1, j); } pgm_freearray (g, height); /* add four corners to initial triangulation */ g_assert (gts_delaunay_add_vertex_to_face (s, v1, GTS_FACE (f)) == NULL); f = GTS_LIST_FACE (gts_point_locate (GTS_POINT (v2), s, NULL)); g_assert (gts_delaunay_add_vertex_to_face (s, v2, GTS_FACE (f)) == NULL); f = GTS_LIST_FACE (gts_point_locate (GTS_POINT (v3), s, NULL)); g_assert (gts_delaunay_add_vertex_to_face (s, v3, GTS_FACE (f)) == NULL); f = GTS_LIST_FACE (gts_point_locate (GTS_POINT (v4), s, NULL)); g_assert (gts_delaunay_add_vertex_to_face (s, v4, GTS_FACE (f)) == NULL); /* refine surface */ surface_hf_refine (s, cost_func, cost_data, stop_func, stop_data); /* destroy unused vertices */ gts_surface_foreach_face (s, (GtsFunc) destroy_unused, NULL); /* destroy enclosing triangle */ gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (w1)); gts_object_destroy (GTS_OBJECT (w2)); gts_object_destroy (GTS_OBJECT (w3)); gts_allow_floating_vertices = FALSE; return s; }
int main (int argc, char * argv[]) { GtsSurface * s; GtsFile * fp; GtsMatrix * m; int c = 0; gboolean verbose = FALSE; gboolean revert = FALSE; gboolean normalize = FALSE; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); m = gts_matrix_identity (NULL); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"rx", required_argument, NULL, 'r'}, {"ry", required_argument, NULL, 'm'}, {"rz", required_argument, NULL, 'n'}, {"scale", required_argument, NULL, 's'}, {"sx", required_argument, NULL, 'R'}, {"sy", required_argument, NULL, 'M'}, {"sz", required_argument, NULL, 'N'}, {"tx", required_argument, NULL, 't'}, {"ty", required_argument, NULL, 'u'}, {"tz", required_argument, NULL, 'w'}, {"revert", no_argument, NULL, 'i'}, {"normalize", no_argument, NULL, 'o'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, { NULL } }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvr:m:n:s:R:M:N:it:u:w:o", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvr:m:n:s:R:M:N:it:u:w:o"))) { #endif /* not HAVE_GETOPT_LONG */ case 'o': /* normalize */ normalize = TRUE; break; case 'r': { /* rotate around x-axis */ gdouble angle, cosa, sina; GtsMatrix * rot, * p; rot = gts_matrix_identity (NULL); angle = atof (optarg)*PI/180.; cosa = cos (angle); sina = sin (angle); rot[1][1] = cosa; rot[1][2] = -sina; rot[2][1] = sina; rot[2][2] = cosa; p = gts_matrix_product (m, rot); gts_matrix_destroy (rot); gts_matrix_destroy (m); m = p; break; } case 'm': { /* rotate around y-axis */ gdouble angle, cosa, sina; GtsMatrix * rot, * p; rot = gts_matrix_identity (NULL); angle = atof (optarg)*PI/180.; cosa = cos (angle); sina = sin (angle); rot[0][0] = cosa; rot[0][2] = sina; rot[2][0] = -sina; rot[2][2] = cosa; p = gts_matrix_product (m, rot); gts_matrix_destroy (rot); gts_matrix_destroy (m); m = p; break; } case 'n': { /* rotate around z-axis */ gdouble angle, cosa, sina; GtsMatrix * rot, * p; rot = gts_matrix_identity (NULL); angle = atof (optarg)*PI/180.; cosa = cos (angle); sina = sin (angle); rot[0][0] = cosa; rot[0][1] = -sina; rot[1][0] = sina; rot[1][1] = cosa; p = gts_matrix_product (m, rot); gts_matrix_destroy (rot); gts_matrix_destroy (m); m = p; break; } case 's': { /* scale */ GtsMatrix * scale, * p; gdouble s = atof (optarg); scale = gts_matrix_identity (NULL); scale[0][0] = scale[1][1] = scale[2][2] = s; p = gts_matrix_product (m, scale); gts_matrix_destroy (scale); gts_matrix_destroy (m); m = p; break; } case 'R': { /* sx */ GtsMatrix * scale, * p; gdouble s = atof (optarg); scale = gts_matrix_identity (NULL); scale[0][0] = s; p = gts_matrix_product (m, scale); gts_matrix_destroy (scale); gts_matrix_destroy (m); m = p; break; } case 'M': { /* sy */ GtsMatrix * scale, * p; gdouble s = atof (optarg); scale = gts_matrix_identity (NULL); scale[1][1] = s; p = gts_matrix_product (m, scale); gts_matrix_destroy (scale); gts_matrix_destroy (m); m = p; break; } case 'N': { /* sz */ GtsMatrix * scale, * p; gdouble s = atof (optarg); scale = gts_matrix_identity (NULL); scale[2][2] = s; p = gts_matrix_product (m, scale); gts_matrix_destroy (scale); gts_matrix_destroy (m); m = p; break; } case 't': /* tx */ m[0][3] += atof (optarg); break; case 'u': /* ty */ m[1][3] += atof (optarg); break; case 'w': /* tz */ m[2][3] += atof (optarg); break; case 'i': /* revert */ revert = TRUE; break; case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: transform [OPTION] < file.gts\n" "Apply geometric transformations to the input.\n" "\n" " -r ANGLE --rx=ANGLE rotate around x-axis (angle in degrees)\n" " -m ANGLE --ry=ANGLE rotate around y-axis\n" " -n ANGLE --rz=ANGLE rotate around z-axis\n" " -s FACTOR --scale=FACTOR scale by FACTOR\n" " -R FACTOR --sx=FACTOR scale x-axis by FACTOR\n" " -M FACTOR --sy=FACTOR scale y-axis by FACTOR\n" " -N FACTOR --sz=FACTOR scale z-axis by FACTOR\n" " -t V --tx=V translate of V along x-axis\n" " -u V --ty=V translate of V along y-axis\n" " -w V --tz=V translate of V along z-axis\n" " -i --revert turn surface inside out\n" " -o --normalize fit the resulting surface in a cube of\n" " size 1 centered at the origin\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `transform --help' for more information.\n"); return 1; /* failure */ } } s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("transform: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } if (verbose) gts_surface_print_stats (s, stderr); if (revert) gts_surface_foreach_face (s, (GtsFunc) gts_triangle_revert, NULL); gts_surface_foreach_vertex (s, (GtsFunc) gts_point_transform, m); if (normalize) { GtsBBox * bb = gts_bbox_surface (gts_bbox_class (), s); gdouble scale = bb->x2 - bb->x1; GtsMatrix * sc; if (bb->y2 - bb->y1 > scale) scale = bb->y2 - bb->y1; if (bb->z2 - bb->z1 > scale) scale = bb->z2 - bb->z1; if (scale > 0.) scale = 1./scale; else scale = 1.; sc = gts_matrix_identity (NULL); sc[0][3] = - (bb->x1 + bb->x2)/2.; sc[1][3] = - (bb->y1 + bb->y2)/2.; sc[2][3] = - (bb->z1 + bb->z2)/2.; gts_surface_foreach_vertex (s, (GtsFunc) gts_point_transform, sc); sc[0][0] = sc[1][1] = sc[2][2] = scale; sc[0][3] = sc[1][3] = sc[2][3] = 0.; gts_surface_foreach_vertex (s, (GtsFunc) gts_point_transform, sc); gts_matrix_destroy (sc); } gts_surface_write (s, stdout); return 0; }
int main (int argc, char * argv[]) { guint i, j, nx, ny; gdouble cosa, sina; GtsSurface * surface; GSList * l, * vertices = NULL; GtsTriangle * t; GtsVertex * v1, * v2, * v3; GTimer * timer; if (argc != 4) { fprintf (stderr, "usage: cartesian nx ny angle\n"); return 0; } nx = strtol (argv[1], NULL, 0); ny = strtol (argv[2], NULL, 0); cosa = cos (strtod (argv[3], NULL)); sina = sin (strtod (argv[3], NULL)); timer = g_timer_new (); g_timer_start (timer); for (i = 0; i < nx; i++) { gdouble x = (gdouble) i/(gdouble) (nx - 1); for (j = 0; j < ny; j++) { gdouble y = (gdouble) j/(gdouble) (nx - 1); vertices = g_slist_prepend (vertices, gts_vertex_new (gts_vertex_class (), cosa*x - sina*y, sina*x + cosa*y, 0.)); } } t = gts_triangle_enclosing (gts_triangle_class (), vertices, 100.); gts_triangle_vertices (t, &v1, &v2, &v3); surface = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); gts_surface_add_face (surface, gts_face_new (gts_face_class (), t->e1, t->e2, t->e3)); g_timer_stop (timer); fprintf (stderr, "Input: %g s\n", g_timer_elapsed (timer, NULL)); g_timer_reset (timer); g_timer_start (timer); l = vertices; while (l) { g_assert (gts_delaunay_add_vertex (surface, l->data, NULL) == NULL); l = l->next; } gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (v1)); gts_object_destroy (GTS_OBJECT (v2)); gts_object_destroy (GTS_OBJECT (v3)); gts_allow_floating_vertices = FALSE; g_timer_stop (timer); fprintf (stderr, "Triangulation: %g s speed: %.0f vertex/s\n", g_timer_elapsed (timer, NULL), g_slist_length (vertices)/g_timer_elapsed (timer, NULL)); g_timer_reset (timer); g_timer_start (timer); gts_surface_write (surface, stdout); g_timer_stop (timer); fprintf (stderr, "Output: %g s\n", g_timer_elapsed (timer, NULL)); if (gts_delaunay_check (surface)) { fprintf (stderr, "WARNING: surface is not Delaunay\n"); return 0; } return 1; }
int main (int argc, char * argv[]) { GtsSurface * s; GtsFile * fp; GtsFace * first = NULL; int c = 0; gboolean verbose = FALSE; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); colormap = colormap_red_blue (); /* default */ /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"cmap", required_argument, NULL, 'c'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, { NULL } }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvc:", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvc:"))) { #endif /* not HAVE_GETOPT_LONG */ case 'c': { /* cmap */ FILE * fptr = fopen (optarg, "rt"); if (!fptr) { fprintf (stderr, "traverse: cannot open colormap file `%s'.\n", optarg); return 1; } colormap = colormap_read (fptr); fclose (fptr); break; } case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: traverse [OPTION] < file.gts > file.oogl\n" "Output an OOGL (geomview) surface colored according to the (graph) distance\n" "from a random face to the others\n" "\n" " -c FILE --cmap=FILE load FILE as colormap\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `traverse --help' for more information.\n"); return 1; /* failure */ } } s = gts_surface_new (gts_surface_class (), GTS_FACE_CLASS (depth_face_class ()), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("traverse: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } if (verbose) gts_surface_print_stats (s, stderr); gts_surface_foreach_face (s, (GtsFunc) pick_first_face, &first); gts_range_init (&depth_range); if (first) { GtsSurfaceTraverse * t = gts_surface_traverse_new (s, first); GtsFace * f; guint level; while ((f = gts_surface_traverse_next (t, &level))) { DEPTH_FACE (f)->depth = level; gts_range_add_value (&depth_range, level); } gts_surface_traverse_destroy (t); } gts_range_update (&depth_range); if (verbose) { fputs ("distance: ", stderr); gts_range_print (&depth_range, stderr); fputc ('\n', stderr); } gts_surface_write_oogl (s, stdout); return 0; }
/* set - compute set operations between surfaces */ int main (int argc, char * argv[]) { GtsSurface * s1, * s2, * s3; GtsSurfaceInter * si; GNode * tree1, * tree2; FILE * fptr; GtsFile * fp; int c = 0; gboolean verbose = TRUE; gboolean inter = FALSE; gboolean check_self_intersection = FALSE; gchar * operation, * file1, * file2; gboolean closed = TRUE, is_open1, is_open2; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"inter", no_argument, NULL, 'i'}, {"self", no_argument, NULL, 's'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvis", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvis"))) { #endif /* not HAVE_GETOPT_LONG */ case 's': /* self */ check_self_intersection = TRUE; break; case 'i': /* inter */ inter = TRUE; break; case 'v': /* verbose */ verbose = FALSE; break; case 'h': /* help */ fprintf (stderr, "Usage: set [OPTION] OPERATION FILE1 FILE2\n" "Compute set operations between surfaces, where OPERATION is either.\n" "union, inter, diff.\n" "\n" " -i --inter output an OOGL (Geomview) representation of the curve\n" " intersection of the surfaces\n" " -s --self checks that the surfaces are not self-intersecting\n" " if one of them is, the set of self-intersecting faces\n" " is written (as a GtsSurface) on standard output\n" " -v --verbose do not print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `set --help' for more information.\n"); return 1; /* failure */ } } if (optind >= argc) { /* missing OPERATION */ fprintf (stderr, "set: missing OPERATION\n" "Try `set --help' for more information.\n"); return 1; /* failure */ } operation = argv[optind++]; if (optind >= argc) { /* missing FILE1 */ fprintf (stderr, "set: missing FILE1\n" "Try `set --help' for more information.\n"); return 1; /* failure */ } file1 = argv[optind++]; if (optind >= argc) { /* missing FILE2 */ fprintf (stderr, "set: missing FILE2\n" "Try `set --help' for more information.\n"); return 1; /* failure */ } file2 = argv[optind++]; /* open first file */ if ((fptr = fopen (file1, "rt")) == NULL) { fprintf (stderr, "set: can not open file `%s'\n", file1); return 1; } /* reads in first surface file */ s1 = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ()))); fp = gts_file_new (fptr); if (gts_surface_read (s1, fp)) { fprintf (stderr, "set: `%s' is not a valid GTS surface file\n", file1); fprintf (stderr, "%s:%d:%d: %s\n", file1, fp->line, fp->pos, fp->error); return 1; } gts_file_destroy (fp); fclose (fptr); /* open second file */ if ((fptr = fopen (file2, "rt")) == NULL) { fprintf (stderr, "set: can not open file `%s'\n", file2); return 1; } /* reads in second surface file */ s2 = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ()))); fp = gts_file_new (fptr); if (gts_surface_read (s2, fp)) { fprintf (stderr, "set: `%s' is not a valid GTS surface file\n", file2); fprintf (stderr, "%s:%d:%d: %s\n", file2, fp->line, fp->pos, fp->error); return 1; } gts_file_destroy (fp); fclose (fptr); /* display summary information about both surfaces */ if (verbose) { gts_surface_print_stats (s1, stderr); gts_surface_print_stats (s2, stderr); } /* check that the surfaces are orientable manifolds */ if (!gts_surface_is_orientable (s1)) { fprintf (stderr, "set: surface `%s' is not an orientable manifold\n", file1); return 1; } if (!gts_surface_is_orientable (s2)) { fprintf (stderr, "set: surface `%s' is not an orientable manifold\n", file2); return 1; } /* check that the surfaces are not self-intersecting */ if (check_self_intersection) { GtsSurface * self_intersects; self_intersects = gts_surface_is_self_intersecting (s1); if (self_intersects != NULL) { fprintf (stderr, "set: surface `%s' is self-intersecting\n", file1); if (verbose) gts_surface_print_stats (self_intersects, stderr); gts_surface_write (self_intersects, stdout); gts_object_destroy (GTS_OBJECT (self_intersects)); return 1; } self_intersects = gts_surface_is_self_intersecting (s2); if (self_intersects != NULL) { fprintf (stderr, "set: surface `%s' is self-intersecting\n", file2); if (verbose) gts_surface_print_stats (self_intersects, stderr); gts_surface_write (self_intersects, stdout); gts_object_destroy (GTS_OBJECT (self_intersects)); return 1; } } /* build bounding box tree for first surface */ tree1 = gts_bb_tree_surface (s1); is_open1 = gts_surface_volume (s1) < 0. ? TRUE : FALSE; /* build bounding box tree for second surface */ tree2 = gts_bb_tree_surface (s2); is_open2 = gts_surface_volume (s2) < 0. ? TRUE : FALSE; si = gts_surface_inter_new (gts_surface_inter_class (), s1, s2, tree1, tree2, is_open1, is_open2); g_assert (gts_surface_inter_check (si, &closed)); if (!closed) { fprintf (stderr, "set: the intersection of `%s' and `%s' is not a closed curve\n", file1, file2); return 1; } s3 = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); if (!strcmp (operation, "union")) { gts_surface_inter_boolean (si, s3, GTS_1_OUT_2); gts_surface_inter_boolean (si, s3, GTS_2_OUT_1); } else if (!strcmp (operation, "inter")) { gts_surface_inter_boolean (si, s3, GTS_1_IN_2); gts_surface_inter_boolean (si, s3, GTS_2_IN_1); } else if (!strcmp (operation, "diff")) { gts_surface_inter_boolean (si, s3, GTS_1_OUT_2); gts_surface_inter_boolean (si, s3, GTS_2_IN_1); gts_surface_foreach_face (si->s2, (GtsFunc) gts_triangle_revert, NULL); gts_surface_foreach_face (s2, (GtsFunc) gts_triangle_revert, NULL); } else { fprintf (stderr, "set: operation `%s' unknown\n" "Try `set --help' for more information.\n", operation); return 1; } /* check that the resulting surface is not self-intersecting */ if (check_self_intersection) { GtsSurface * self_intersects; self_intersects = gts_surface_is_self_intersecting (s3); if (self_intersects != NULL) { fprintf (stderr, "set: the resulting surface is self-intersecting\n"); if (verbose) gts_surface_print_stats (self_intersects, stderr); gts_surface_write (self_intersects, stdout); gts_object_destroy (GTS_OBJECT (self_intersects)); return 1; } } /* display summary information about the resulting surface */ if (verbose) gts_surface_print_stats (s3, stderr); /* write resulting surface to standard output */ if (inter) { printf ("LIST {\n"); g_slist_foreach (si->edges, (GFunc) write_edge, stdout); printf ("}\n"); } else { GTS_POINT_CLASS (gts_vertex_class ())->binary = TRUE; gts_surface_write (s3, stdout); } /* destroy surfaces */ gts_object_destroy (GTS_OBJECT (s1)); gts_object_destroy (GTS_OBJECT (s2)); gts_object_destroy (GTS_OBJECT (s3)); gts_object_destroy (GTS_OBJECT (si)); /* destroy bounding box trees (including bounding boxes) */ gts_bb_tree_destroy (tree1, TRUE); gts_bb_tree_destroy (tree2, TRUE); return 0; }
/* sphere - generate a triangulated unit sphere by recursive subdivision. First approximation is an isocahedron; each level of refinement increases the number of triangles by a factor of 4. */ int main (int argc, char * argv[]) { GtsSurface * s; gboolean verbose = FALSE; guint level=4; int c = 0; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, { NULL } }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hv", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hv"))) { #endif /* not HAVE_GETOPT_LONG */ case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: sphere [OPTION] [level]\n" "Generate a triangulated unit sphere by recursive subdivision.\n" "First approximation is an isocahedron; each level of refinement\n" "increases the number of triangles by a factor of 4.\n" "level must be a positive integer setting the recursion level\n" "(geodesation order), default is 4.\n" "\n" "Documentation: http://mathworld.wolfram.com/GeodesicDome.html\n" "\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `sphere --help' for more information.\n"); return 1; /* failure */ } } /* read level */ if (optind < argc) level = atoi(argv[optind]); /* generate triangulated sphere */ s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); gts_surface_generate_sphere (s, level); /* if verbose on print stats */ if (verbose) gts_surface_print_stats (s, stderr); /* write generating surface to standard output */ gts_surface_write (s, stdout); return 0; /* success */ }
int main (int argc, char * argv[]) { GPtrArray * vertices; GtsFifo * edges; guint i, line; GtsTriangle * t; GtsVertex * v1, * v2, * v3; GtsSurface * surface; gboolean keep_hull = TRUE; gboolean verbose = FALSE; gboolean add_constraints = TRUE; gboolean remove_holes = FALSE; gboolean check_delaunay = FALSE; gboolean conform = FALSE; gboolean refine = FALSE; gboolean split_constraints = FALSE; gboolean randomize = FALSE; gboolean remove_duplicates = FALSE; gint steiner_max = -1; gdouble quality = 0., area = G_MAXDOUBLE; int c = 0, status = 0; const char * fname = NULL; GTimer * timer; /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"duplicates", no_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {"randomize", no_argument, NULL, 'r'}, {"hull", no_argument, NULL, 'b'}, {"noconst", no_argument, NULL, 'e'}, {"holes", no_argument, NULL, 'H'}, {"split", no_argument, NULL, 'S'}, {"check", no_argument, NULL, 'c'}, {"files", required_argument, NULL, 'f'}, {"conform", no_argument, NULL, 'o'}, {"steiner", required_argument, NULL, 's'}, {"quality", required_argument, NULL, 'q'}, {"area", required_argument, NULL, 'a'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvbecf:os:q:a:HSrd", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvbecf:os:q:a:HSrd"))) { #endif /* not HAVE_GETOPT_LONG */ case 'd': /* duplicates */ remove_duplicates = TRUE; break; case 'b': /* do not keep convex hull */ keep_hull = FALSE; break; case 'e': /* do not add constrained edges */ add_constraints = FALSE; break; case 'H': /* remove holes */ remove_holes = TRUE; break; case 'S': /* split constraints */ split_constraints = TRUE; break; case 'r': /* randomize */ randomize = TRUE; break; case 'c': /* check Delaunay property */ check_delaunay = TRUE; break; case 'f': /* generates files */ fname = optarg; break; case 'v': /* verbose */ verbose = TRUE; break; case 'o': /* conform */ conform = TRUE; break; case 's': /* steiner */ steiner_max = atoi (optarg); break; case 'q': /* quality */ conform = TRUE; refine = TRUE; quality = atof (optarg); break; case 'a': /* area */ conform = TRUE; refine = TRUE; area = atof (optarg); break; case 'h': /* help */ fprintf (stderr, "Usage: delaunay [OPTION] < file.gts\n" "Construct the constrained Delaunay triangulation of the input\n" "\n" " -b --hull do not keep convex hull\n" " -e --noconst do not add constrained edges\n" " -S --split split constraints (experimental)\n" " -H --holes remove holes from the triangulation\n" " -d --duplicates remove duplicate vertices\n" " -r --randomize shuffle input vertex list\n" " -c --check check Delaunay property\n" " -f FNAME --files=FNAME generate evolution files\n" " -o --conform generate conforming triangulation\n" " -s N --steiner=N maximum number of Steiner points for\n" " conforming triangulation (default is no limit)\n" " -q Q --quality=Q Set the minimum acceptable face quality\n" " -a A --area=A Set the maximum acceptable face area\n" " -v --verbose print statistics about the triangulation\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `delaunay --help' for more information.\n"); return 1; /* failure */ } } /* read file => two lists: vertices and constraints */ edges = gts_fifo_new (); vertices = g_ptr_array_new (); if (add_constraints) /* the edge class is a GtsConstraintClass */ line = read_list (vertices, edges, GTS_EDGE_CLASS (gts_constraint_class ()), stdin); else /* the edge class is a "normal" edge: GtsEdgeClass */ line = read_list (vertices, edges, gts_edge_class (), stdin); if (line > 0) { fprintf (stderr, "delaunay: error in input file at line %u\n", line); return 1; } timer = g_timer_new (); g_timer_start (timer); if (randomize) shuffle_array (vertices); /* create triangle enclosing all the vertices */ { GSList * list = NULL; for (i = 0; i < vertices->len; i++) list = g_slist_prepend (list, g_ptr_array_index (vertices, i)); t = gts_triangle_enclosing (gts_triangle_class (), list, 100.); g_slist_free (list); } gts_triangle_vertices (t, &v1, &v2, &v3); /* create surface with one face: the enclosing triangle */ surface = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); gts_surface_add_face (surface, gts_face_new (gts_face_class (), t->e1, t->e2, t->e3)); /* add vertices */ for (i = 0; i < vertices->len; i++) { GtsVertex * v1 = g_ptr_array_index (vertices, i); GtsVertex * v = gts_delaunay_add_vertex (surface, v1, NULL); g_assert (v != v1); if (v != NULL) { if (!remove_duplicates) { fprintf (stderr, "delaunay: duplicate vertex (%g,%g) in input file\n", GTS_POINT (v)->x, GTS_POINT (v)->y); return 1; /* Failure */ } else gts_vertex_replace (v1, v); } if (fname) { static guint nf = 1; char s[80]; FILE * fp; g_snprintf (s, 80, "%s.%u", fname, nf++); fp = fopen (s, "wt"); gts_surface_write_oogl (surface, fp); fclose (fp); if (check_delaunay && gts_delaunay_check (surface)) { fprintf (stderr, "delaunay: triangulation is not Delaunay\n"); return 1; } } } g_ptr_array_free (vertices, TRUE); /* add remaining constraints */ if (add_constraints) gts_fifo_foreach (edges, (GtsFunc) add_constraint, surface); /* destroy enclosing triangle */ gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (v1)); gts_object_destroy (GTS_OBJECT (v2)); gts_object_destroy (GTS_OBJECT (v3)); gts_allow_floating_vertices = FALSE; if (!keep_hull) gts_delaunay_remove_hull (surface); if (remove_holes) delaunay_remove_holes (surface); if (split_constraints) { gpointer data[2]; data[0] = surface; data[1] = edges; gts_fifo_foreach (edges, (GtsFunc) split_constraint, data); } if (conform) { guint encroached_number = gts_delaunay_conform (surface, steiner_max, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL); if (encroached_number == 0 && refine) { guint unrefined_number; gpointer data[2]; data[0] = &quality; data[1] = &area; unrefined_number = gts_delaunay_refine (surface, steiner_max, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL, (GtsKeyFunc) triangle_cost, data); if (verbose && unrefined_number > 0) fprintf (stderr, "delaunay: ran out of Steiner points (max: %d) during refinement\n" "%d unrefined faces left\n", steiner_max, unrefined_number); } else if (verbose && encroached_number > 0) fprintf (stderr, "delaunay: ran out of Steiner points (max: %d) during conforming\n" "Delaunay triangulation: %d encroached constraints left\n", steiner_max, encroached_number); } g_timer_stop (timer); if (verbose) { gts_surface_print_stats (surface, stderr); fprintf (stderr, "# Triangulation time: %g s speed: %.0f vertex/s\n", g_timer_elapsed (timer, NULL), gts_surface_vertex_number (surface)/g_timer_elapsed (timer, NULL)); } if (check_delaunay && gts_delaunay_check (surface)) { fprintf (stderr, "delaunay: triangulation is not Delaunay\n"); status = 1; /* failure */ } /* write triangulation */ gts_surface_write (surface, stdout); return status; }
int main (int argc, char * argv[]) { GtsSurface * surface = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); GtsVertex * v1 = gts_vertex_new (gts_vertex_class (), 0, 0, 0); GtsVertex * v2 = gts_vertex_new (gts_vertex_class (), 0, -0.5, 1); GtsVertex * v3 = gts_vertex_new (gts_vertex_class (), 0, 0.5, 1); GtsVertex * v4 = gts_vertex_new (gts_vertex_class (), 1, 0, 0); GtsVertex * v5 = gts_vertex_new (gts_vertex_class (), 0, -0.5, -1); GtsVertex * v6 = gts_vertex_new (gts_vertex_class (), 1, -0.5, -1); GtsVertex * v7 = gts_vertex_new (gts_vertex_class (), 1, 0.5, -1); GtsVertex * v8 = gts_vertex_new (gts_vertex_class (), 1, -0.5, 1); GtsVertex * v9 = gts_vertex_new (gts_vertex_class (), 1, 0.5, 1); GtsVertex * v10 = gts_vertex_new (gts_vertex_class (), 0, 0.5, -1); GtsEdge * e1 = gts_edge_new (gts_edge_class (), v1, v2); GtsEdge * e2 = gts_edge_new (gts_edge_class (), v1, v3); GtsEdge * e3 = gts_edge_new (gts_edge_class (), v2, v3); GtsEdge * e4 = gts_edge_new (gts_edge_class (), v4, v5); GtsEdge * e5 = gts_edge_new (gts_edge_class (), v4, v6); GtsEdge * e6 = gts_edge_new (gts_edge_class (), v5, v6); GtsEdge * e7 = gts_edge_new (gts_edge_class (), v1, v4); GtsEdge * e8 = gts_edge_new (gts_edge_class (), v1, v5); GtsEdge * e9 = gts_edge_new (gts_edge_class (), v6, v7); GtsEdge * e10 = gts_edge_new (gts_edge_class (), v4, v7); GtsEdge * e11 = gts_edge_new (gts_edge_class (), v1, v7); GtsEdge * e12 = gts_edge_new (gts_edge_class (), v8, v9); GtsEdge * e13 = gts_edge_new (gts_edge_class (), v4, v9); GtsEdge * e14 = gts_edge_new (gts_edge_class (), v4, v8); GtsEdge * e15 = gts_edge_new (gts_edge_class (), v5, v10); GtsEdge * e16 = gts_edge_new (gts_edge_class (), v1, v10); GtsEdge * e17 = gts_edge_new (gts_edge_class (), v10, v7); GtsEdge * e18 = gts_edge_new (gts_edge_class (), v1, v8); GtsEdge * e19 = gts_edge_new (gts_edge_class (), v2, v8); GtsEdge * e20 = gts_edge_new (gts_edge_class (), v4, v3); GtsEdge * e21 = gts_edge_new (gts_edge_class (), v3, v9); GtsFace * f1 = gts_face_new (gts_face_class (), e1, e2, e3); GtsFace * f2 = gts_face_new (gts_face_class (), e4, e5, e6); GtsFace * f3 = gts_face_new (gts_face_class (), e7, e4, e8); GtsFace * f4 = gts_face_new (gts_face_class (), e9, e5, e10); GtsFace * f5 = gts_face_new (gts_face_class (), e11, e10, e7); GtsFace * f6 = gts_face_new (gts_face_class (), e12, e13, e14); GtsFace * f7 = gts_face_new (gts_face_class (), e15, e16, e8); GtsFace * f8 = gts_face_new (gts_face_class (), e17, e11, e16); GtsFace * f9 = gts_face_new (gts_face_class (), e18, e14, e7); GtsFace * f10 = gts_face_new (gts_face_class (), e19, e18, e1); GtsFace * f11 = gts_face_new (gts_face_class (), e20, e13, e21); GtsFace * f12 = gts_face_new (gts_face_class (), e7, e20, e2); GtsVertex * v; GtsVolumeOptimizedParams params = { 0.5, 0.5, 0.0 }; GtsSplit * vs; gts_surface_add_face (surface, f1); gts_surface_add_face (surface, f2); gts_surface_add_face (surface, f3); gts_surface_add_face (surface, f4); gts_surface_add_face (surface, f5); gts_surface_add_face (surface, f6); gts_surface_add_face (surface, f7); gts_surface_add_face (surface, f8); gts_surface_add_face (surface, f9); gts_surface_add_face (surface, f10); gts_surface_add_face (surface, f11); gts_surface_add_face (surface, f12); g_assert (gts_edge_collapse_is_valid (e7)); v = gts_volume_optimized_vertex (e7, gts_vertex_class (), ¶ms); vs = gts_split_new (gts_split_class (), v, GTS_OBJECT (GTS_SEGMENT (e7)->v1), GTS_OBJECT (GTS_SEGMENT (e7)->v2)); gts_split_collapse (vs, gts_edge_class (), NULL); gts_surface_write (surface, stdout); return 0; }
/* stripe - Turns the input surface into triangle strips and outputs a Geomview representation of the result. */ int main (int argc, char * argv[]) { GtsSurface * s; GSList * strips = NULL, * i; gboolean verbose = FALSE; int c = 0; GtsFile * fp; /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hv", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hv"))) { #endif /* not HAVE_GETOPT_LONG */ case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: stripe [OPTION] < FILE\n" "Turns the input surface into triangle strips and outputs a\n" "Geomview representation of the result.\n" "\n" " -v --verbose print statistics about the surface and strips\n" " -h --help display this help and exit\n" "\n" "Report bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `stripe --help' for more information.\n"); return 1; /* failure */ } } /* read surface in */ s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("stripe: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } gts_file_destroy (fp); if (verbose) gts_surface_print_stats (s, stderr); strips = gts_surface_strip (s); /* if verbose on print stats */ if (verbose) { GtsRange l; gts_range_init (&l); i = strips; while (i) { gts_range_add_value (&l, g_slist_length (i->data)); i = i->next; } gts_range_update (&l); fprintf (stderr, "# Strips: %d\n# length : ", l.n); gts_range_print (&l, stderr); fputc ('\n', stderr); } puts ("LIST {\n"); i = strips; while (i) { GList * j = i->data; GtsTriangle * oldt = NULL; GtsColor c; c.r = rand ()/(gdouble) RAND_MAX; c.g = rand ()/(gdouble) RAND_MAX; c.b = rand ()/(gdouble) RAND_MAX; while (j) { GtsTriangle * t = j->data; GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1), * p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2), * p3 = GTS_POINT (gts_triangle_vertex (t)); printf ("OFF 3 1 3\n%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2 %g %g %g\n", p1->x, p1->y, p1->z, p2->x, p2->y, p2->z, p3->x, p3->y, p3->z, c.r, c.g, c.b); if (oldt) { GtsSegment * cs = GTS_SEGMENT (gts_triangles_common_edge (t, oldt)); GtsPoint * op1 = GTS_POINT (GTS_SEGMENT (oldt->e1)->v1), * op2 = GTS_POINT (GTS_SEGMENT (oldt->e1)->v2), * op3 = GTS_POINT (gts_triangle_vertex (oldt)); printf ("VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n", (op1->x + op2->x + op3->x)/3., (op1->y + op2->y + op3->y)/3., (op1->z + op2->z + op3->z)/3., (GTS_POINT (cs->v1)->x + GTS_POINT (cs->v2)->x)/2., (GTS_POINT (cs->v1)->y + GTS_POINT (cs->v2)->y)/2., (GTS_POINT (cs->v1)->z + GTS_POINT (cs->v2)->z)/2., (p1->x + p2->x + p3->x)/3., (p1->y + p2->y + p3->y)/3., (p1->z + p2->z + p3->z)/3.); } oldt = t; j = j->next; } i = i->next; } puts ("}\n"); return 0; /* success */ }
int spheroidsToSTL(const string& out, const shared_ptr<DemField>& dem, Real tol, const string& solid, int mask, bool append, bool clipCell, bool merge){ if(tol==0 || isnan(tol)) throw std::runtime_error("tol must be non-zero."); #ifndef WOO_GTS if(merge) throw std::runtime_error("woo.triangulated.spheroidsToSTL: merge=True only possible in builds with the 'gts' feature."); #endif // first traversal to find reference radius auto particleOk=[&](const shared_ptr<Particle>&p){ return (mask==0 || (p->mask & mask)) && (p->shape->isA<Sphere>() || p->shape->isA<Ellipsoid>() || p->shape->isA<Capsule>()); }; int numTri=0; if(tol<0){ LOG_DEBUG("tolerance is negative, taken as relative to minimum radius."); Real minRad=Inf; for(const auto& p: *dem->particles){ if(particleOk(p)) minRad=min(minRad,p->shape->equivRadius()); } if(isinf(minRad) || isnan(minRad)) throw std::runtime_error("Minimum radius not found (relative tolerance specified); no matching particles?"); tol=-minRad*tol; LOG_DEBUG("Minimum radius "<<minRad<<"."); } LOG_DEBUG("Triangulation tolerance is "<<tol); std::ofstream stl(out,append?(std::ofstream::app|std::ofstream::binary):std::ofstream::binary); // binary better, anyway if(!stl.good()) throw std::runtime_error("Failed to open output file "+out+" for writing."); Scene* scene=dem->scene; if(!scene) throw std::logic_error("DEM field has not associated scene?"); // periodicity, cache that for later use AlignedBox3r cell; /* wasteful memory-wise, but we need to store the whole triangulation in case *merge* is in effect, when it is only an intermediary result and will not be output as-is */ vector<vector<Vector3r>> ppts; vector<vector<Vector3i>> ttri; vector<Particle::id_t> iid; for(const auto& p: *dem->particles){ if(!particleOk(p)) continue; const auto sphere=dynamic_cast<Sphere*>(p->shape.get()); const auto ellipsoid=dynamic_cast<Ellipsoid*>(p->shape.get()); const auto capsule=dynamic_cast<Capsule*>(p->shape.get()); vector<Vector3r> pts; vector<Vector3i> tri; if(sphere || ellipsoid){ Real r=sphere?sphere->radius:ellipsoid->semiAxes.minCoeff(); // 1 is for icosahedron int tess=ceil(M_PI/(5*acos(1-tol/r))); LOG_DEBUG("Tesselation level for #"<<p->id<<": "<<tess); tess=max(tess,0); auto uSphTri(CompUtils::unitSphereTri20(/*0 for icosahedron*/max(tess-1,0))); const auto& uPts=std::get<0>(uSphTri); // unit sphere point coords pts.resize(uPts.size()); const auto& node=(p->shape->nodes[0]); Vector3r scale=(sphere?sphere->radius*Vector3r::Ones():ellipsoid->semiAxes); for(size_t i=0; i<uPts.size(); i++){ pts[i]=node->loc2glob(uPts[i].cwiseProduct(scale)); } tri=std::get<1>(uSphTri); // this makes a copy, but we need out own for capsules } if(capsule){ #ifdef WOO_VTK int subdiv=max(4.,ceil(M_PI/(acos(1-tol/capsule->radius)))); std::tie(pts,tri)=VtkExport::triangulateCapsule(static_pointer_cast<Capsule>(p->shape),subdiv); #else throw std::runtime_error("Triangulation of capsules is (for internal and entirely fixable reasons) only available when compiled with the 'vtk' features."); #endif } // do not write out directly, store first for later ppts.push_back(pts); ttri.push_back(tri); LOG_TRACE("#"<<p->id<<" triangulated: "<<tri.size()<<","<<pts.size()<<" faces,vertices."); if(scene->isPeriodic){ // make sure we have aabb, in skewed coords and such if(!p->shape->bound){ // this is a bit ugly, but should do the trick; otherwise we would recompute all that ourselves here if(sphere) Bo1_Sphere_Aabb().go(p->shape); else if(ellipsoid) Bo1_Ellipsoid_Aabb().go(p->shape); else if(capsule) Bo1_Capsule_Aabb().go(p->shape); } assert(p->shape->bound); const AlignedBox3r& box(p->shape->bound->box); AlignedBox3r cell(Vector3r::Zero(),scene->cell->getSize()); // possibly in skewed coords // central offset Vector3i off0; scene->cell->canonicalizePt(p->shape->nodes[0]->pos,off0); // computes off0 Vector3i off; // offset from the original cell //cerr<<"#"<<p->id<<" at "<<p->shape->nodes[0]->pos.transpose()<<", off0="<<off0<<endl; for(off[0]=off0[0]-1; off[0]<=off0[0]+1; off[0]++) for(off[1]=off0[1]-1; off[1]<=off0[1]+1; off[1]++) for(off[2]=off0[2]-1; off[2]<=off0[2]+1; off[2]++){ Vector3r dx=scene->cell->intrShiftPos(off); //cerr<<" off="<<off.transpose()<<", dx="<<dx.transpose()<<endl; AlignedBox3r boxOff(box); boxOff.translate(dx); //cerr<<" boxOff="<<boxOff.min()<<";"<<boxOff.max()<<" | cell="<<cell.min()<<";"<<cell.max()<<endl; if(boxOff.intersection(cell).isEmpty()) continue; // copy the entire triangulation, offset by dx vector<Vector3r> pts2(pts); for(auto& p: pts2) p+=dx; vector<Vector3i> tri2(tri); // same topology ppts.push_back(pts2); ttri.push_back(tri2); LOG_TRACE(" offset "<<off.transpose()<<": #"<<p->id<<": "<<tri2.size()<<","<<pts2.size()<<" faces,vertices."); } } } if(!merge){ LOG_DEBUG("Will export (unmerged) "<<ppts.size()<<" particles to STL."); stl<<"solid "<<solid<<"\n"; for(size_t i=0; i<ppts.size(); i++){ const auto& pts(ppts[i]); const auto& tri(ttri[i]); LOG_TRACE("Exporting "<<i<<" with "<<tri.size()<<" faces."); for(const Vector3i& t: tri){ Vector3r pp[]={pts[t[0]],pts[t[1]],pts[t[2]]}; // skip triangles which are entirely out of the canonical periodic cell if(scene->isPeriodic && clipCell && (!scene->cell->isCanonical(pp[0]) && !scene->cell->isCanonical(pp[1]) && !scene->cell->isCanonical(pp[2]))) continue; numTri++; Vector3r n=(pp[1]-pp[0]).cross(pp[2]-pp[1]).normalized(); stl<<" facet normal "<<n.x()<<" "<<n.y()<<" "<<n.z()<<"\n"; stl<<" outer loop\n"; for(auto p: {pp[0],pp[1],pp[2]}){ stl<<" vertex "<<p[0]<<" "<<p[1]<<" "<<p[2]<<"\n"; } stl<<" endloop\n"; stl<<" endfacet\n"; } } stl<<"endsolid "<<solid<<"\n"; stl.close(); return numTri; } #if WOO_GTS /***** Convert all triangulation to GTS surfaces, find their distances, isolate connected components, merge these components incrementally and write to STL *****/ // total number of points const size_t N(ppts.size()); // bounds for collision detection struct Bound{ Bound(Real _coord, int _id, bool _isMin): coord(_coord), id(_id), isMin(_isMin){}; Bound(): coord(NaN), id(-1), isMin(false){}; // just for allocation Real coord; int id; bool isMin; bool operator<(const Bound& b) const { return coord<b.coord; } }; vector<Bound> bounds[3]={vector<Bound>(2*N),vector<Bound>(2*N),vector<Bound>(2*N)}; /* construct GTS surface objects; all objects must be deleted explicitly! */ vector<GtsSurface*> ssurf(N); vector<vector<GtsVertex*>> vvert(N); vector<vector<GtsEdge*>> eedge(N); vector<AlignedBox3r> boxes(N); for(size_t i=0; i<N; i++){ LOG_TRACE("** Creating GTS surface for #"<<i<<", with "<<ttri[i].size()<<" faces, "<<ppts[i].size()<<" vertices."); AlignedBox3r box; // new surface object ssurf[i]=gts_surface_new(gts_surface_class(),gts_face_class(),gts_edge_class(),gts_vertex_class()); // copy over all vertices vvert[i].reserve(ppts[i].size()); eedge[i].reserve(size_t(1.5*ttri[i].size())); // each triangle consumes 1.5 edges, for closed surfs for(size_t v=0; v<ppts[i].size(); v++){ vvert[i].push_back(gts_vertex_new(gts_vertex_class(),ppts[i][v][0],ppts[i][v][1],ppts[i][v][2])); box.extend(ppts[i][v]); } // create faces, and create edges on the fly as needed std::map<std::pair<int,int>,int> edgeIndices; for(size_t t=0; t<ttri[i].size(); t++){ //const Vector3i& t(ttri[i][t]); //LOG_TRACE("Face with vertices "<<ttri[i][t][0]<<","<<ttri[i][t][1]<<","<<ttri[i][t][2]); Vector3i eIxs; for(int a:{0,1,2}){ int A(ttri[i][t][a]), B(ttri[i][t][(a+1)%3]); auto AB=std::make_pair(min(A,B),max(A,B)); auto ABI=edgeIndices.find(AB); if(ABI==edgeIndices.end()){ // this edge not created yet edgeIndices[AB]=eedge[i].size(); // last index eIxs[a]=eedge[i].size(); //LOG_TRACE(" New edge #"<<eIxs[a]<<": "<<A<<"--"<<B<<" (length "<<(ppts[i][A]-ppts[i][B]).norm()<<")"); eedge[i].push_back(gts_edge_new(gts_edge_class(),vvert[i][A],vvert[i][B])); } else { eIxs[a]=ABI->second; //LOG_TRACE(" Found edge #"<<ABI->second<<" for "<<A<<"--"<<B); } } //LOG_TRACE(" New face: edges "<<eIxs[0]<<"--"<<eIxs[1]<<"--"<<eIxs[2]); GtsFace* face=gts_face_new(gts_face_class(),eedge[i][eIxs[0]],eedge[i][eIxs[1]],eedge[i][eIxs[2]]); gts_surface_add_face(ssurf[i],face); } // make sure the surface is OK if(!gts_surface_is_orientable(ssurf[i])) LOG_ERROR("Surface of #"+to_string(iid[i])+" is not orientable (expect troubles)."); if(!gts_surface_is_closed(ssurf[i])) LOG_ERROR("Surface of #"+to_string(iid[i])+" is not closed (expect troubles)."); assert(!gts_surface_is_self_intersecting(ssurf[i])); // copy bounds LOG_TRACE("Setting bounds of surf #"<<i); boxes[i]=box; for(int ax:{0,1,2}){ bounds[ax][2*i+0]=Bound(box.min()[ax],/*id*/i,/*isMin*/true); bounds[ax][2*i+1]=Bound(box.max()[ax],/*id*/i,/*isMin*/false); } } /* broad-phase collision detection between GTS surfaces only those will be probed with exact algorithms below and merged if needed */ for(int ax:{0,1,2}) std::sort(bounds[ax].begin(),bounds[ax].end()); vector<Bound>& bb(bounds[0]); // run the search along x-axis, does not matter really std::list<std::pair<int,int>> int0; // broad-phase intersections for(size_t i=0; i<2*N; i++){ if(!bb[i].isMin) continue; // only start with lower bound // go up to the upper bound, but handle overflow safely (no idea why it would happen here) as well for(size_t j=i+1; j<2*N && bb[j].id!=bb[i].id; j++){ if(bb[j].isMin) continue; // this is handled by symmetry #if EIGEN_VERSION_AT_LEAST(3,2,5) if(!boxes[bb[i].id].intersects(boxes[bb[j].id])) continue; // no intersection along all axes #else // old, less elegant if(boxes[bb[i].id].intersection(boxes[bb[j].id]).isEmpty()) continue; #endif int0.push_back(std::make_pair(min(bb[i].id,bb[j].id),max(bb[i].id,bb[j].id))); LOG_TRACE("Broad-phase collision "<<int0.back().first<<"+"<<int0.back().second); } } /* narrow-phase collision detection between GTS surface this must be done via gts_surface_inter_new, since gts_surface_distance always succeeds */ std::list<std::pair<int,int>> int1; for(const std::pair<int,int> ij: int0){ LOG_TRACE("Testing narrow-phase collision "<<ij.first<<"+"<<ij.second); #if 0 GtsRange gr1, gr2; gts_surface_distance(ssurf[ij.first],ssurf[ij.second],/*delta ??*/(gfloat).2,&gr1,&gr2); if(gr1.min>0 && gr2.min>0) continue; LOG_TRACE(" GTS reports collision "<<ij.first<<"+"<<ij.second<<" (min. distances "<<gr1.min<<", "<<gr2.min); #else GtsSurface *s1(ssurf[ij.first]), *s2(ssurf[ij.second]); GNode* t1=gts_bb_tree_surface(s1); GNode* t2=gts_bb_tree_surface(s2); GtsSurfaceInter* I=gts_surface_inter_new(gts_surface_inter_class(),s1,s2,t1,t2,/*is_open_1*/false,/*is_open_2*/false); GSList* l=gts_surface_intersection(s1,s2,t1,t2); // list of edges describing intersection int n1=g_slist_length(l); // extra check by looking at number of faces of the intersected surface #if 1 GtsSurface* s12=gts_surface_new(gts_surface_class(),gts_face_class(),gts_edge_class(),gts_vertex_class()); gts_surface_inter_boolean(I,s12,GTS_1_OUT_2); gts_surface_inter_boolean(I,s12,GTS_2_OUT_1); int n2=gts_surface_face_number(s12); gts_object_destroy(GTS_OBJECT(s12)); #endif gts_bb_tree_destroy(t1,TRUE); gts_bb_tree_destroy(t2,TRUE); gts_object_destroy(GTS_OBJECT(I)); g_slist_free(l); if(n1==0) continue; #if 1 if(n2==0){ LOG_ERROR("n1==0 but n2=="<<n2<<" (no narrow-phase collision)"); continue; } #endif LOG_TRACE(" GTS reports collision "<<ij.first<<"+"<<ij.second<<" ("<<n<<" edges describe the intersection)"); #endif int1.push_back(ij); } /* connected components on the graph: graph nodes are 0…(N-1), graph edges are in int1 see http://stackoverflow.com/a/37195784/761090 */ typedef boost::subgraph<boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS,boost::property<boost::vertex_index_t,int>,boost::property<boost::edge_index_t,int>>> Graph; Graph graph(N); for(const auto& ij: int1) boost::add_edge(ij.first,ij.second,graph); vector<size_t> clusters(boost::num_vertices(graph)); size_t numClusters=boost::connected_components(graph,clusters.data()); for(size_t n=0; n<numClusters; n++){ // beginning cluster #n // first, count how many surfaces are in this cluster; if 1, things are easier int numThisCluster=0; int cluster1st=-1; for(size_t i=0; i<N; i++){ if(clusters[i]!=n) continue; numThisCluster++; if(cluster1st<0) cluster1st=(int)i; } GtsSurface* clusterSurf=NULL; LOG_DEBUG("Cluster "<<n<<" has "<<numThisCluster<<" surfaces."); if(numThisCluster==1){ clusterSurf=ssurf[cluster1st]; } else { clusterSurf=ssurf[cluster1st]; // surface of the cluster itself LOG_TRACE(" Initial cluster surface from "<<cluster1st<<"."); /* composed surface */ for(size_t i=0; i<N; i++){ if(clusters[i]!=n || ((int)i)==cluster1st) continue; LOG_TRACE(" Adding "<<i<<" to the cluster"); // ssurf[i] now belongs to cluster #n // trees need to be rebuild every time anyway, since the merged surface keeps changing in every cycle //if(gts_surface_face_number(clusterSurf)==0) LOG_ERROR("clusterSurf has 0 faces."); //if(gts_surface_face_number(ssurf[i])==0) LOG_ERROR("Surface #"<<i<<" has 0 faces."); GNode* t1=gts_bb_tree_surface(clusterSurf); GNode* t2=gts_bb_tree_surface(ssurf[i]); GtsSurfaceInter* I=gts_surface_inter_new(gts_surface_inter_class(),clusterSurf,ssurf[i],t1,t2,/*is_open_1*/false,/*is_open_2*/false); GtsSurface* merged=gts_surface_new(gts_surface_class(),gts_face_class(),gts_edge_class(),gts_vertex_class()); gts_surface_inter_boolean(I,merged,GTS_1_OUT_2); gts_surface_inter_boolean(I,merged,GTS_2_OUT_1); gts_object_destroy(GTS_OBJECT(I)); gts_bb_tree_destroy(t1,TRUE); gts_bb_tree_destroy(t2,TRUE); if(gts_surface_face_number(merged)==0){ LOG_ERROR("Cluster #"<<n<<": 0 faces after fusing #"<<i<<" (why?), adding #"<<i<<" separately!"); // this will cause an extra 1-particle cluster to be created clusters[i]=numClusters; numClusters+=1; } else { // not from global vectors (cleanup at the end), explicit delete! if(clusterSurf!=ssurf[cluster1st]) gts_object_destroy(GTS_OBJECT(clusterSurf)); clusterSurf=merged; } } } #if 0 LOG_TRACE(" GTS surface cleanups..."); pygts_vertex_cleanup(clusterSurf,.1*tol); // cleanup 10× smaller than tolerance pygts_edge_cleanup(clusterSurf); pygts_face_cleanup(clusterSurf); #endif LOG_TRACE(" STL: cluster "<<n<<" output"); stl<<"solid "<<solid<<"_"<<n<<"\n"; /* output cluster to STL here */ _gts_face_to_stl_data data(stl,scene,clipCell,numTri); gts_surface_foreach_face(clusterSurf,(GtsFunc)_gts_face_to_stl,(gpointer)&data); stl<<"endsolid\n"; if(clusterSurf!=ssurf[cluster1st]) gts_object_destroy(GTS_OBJECT(clusterSurf)); } // this deallocates also edges and vertices for(size_t i=0; i<ssurf.size(); i++) gts_object_destroy(GTS_OBJECT(ssurf[i])); return numTri; #endif /* WOO_GTS */ }
int main (int argc, char * argv[]) { gboolean verbose = FALSE; gboolean triangulate_holes = TRUE; gboolean write_holes = FALSE; int c = 0; CartesianGrid * grid; guint line = 0; GtsSurface * s; GTimer * timer; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"holes", no_argument, NULL, 'H'}, {"keep", no_argument, NULL, 'k'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, { NULL } }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvHk", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvHk"))) { #endif /* not HAVE_GETOPT_LONG */ case 'H': /* holes */ write_holes = TRUE; break; case 'k': /* keep */ triangulate_holes = FALSE; break; case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: cartesian [OPTION] < FILE\n" "Triangulates vertices of a regular cartesian mesh\n" "(possibly containing holes)\n" "\n" " -k --keep keep holes\n" " -H --holes write holes only\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `cartesian --help' for more information.\n"); return 1; /* failure */ } } grid = cartesian_grid_read (gts_vertex_class (), &line); if (grid == NULL) { fprintf (stderr, "cartesian: file on standard input is not a valid cartesian grid\n" "error at line %u\n", line); return 1; } timer = g_timer_new (); g_timer_start (timer); s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); cartesian_grid_triangulate (grid, s); if (triangulate_holes) { GtsSurface * holes = cartesian_grid_triangulate_holes (grid, s); if (write_holes) { gts_object_destroy (GTS_OBJECT (s)); s = holes; } else gts_surface_merge (s, holes); } g_timer_stop (timer); if (verbose) { gts_surface_print_stats (s, stderr); fprintf (stderr, "# Triangulation time: %g s speed: %.0f vertex/s\n", g_timer_elapsed (timer, NULL), gts_surface_vertex_number (s)/g_timer_elapsed (timer, NULL)); } gts_surface_write (s, stdout); return 0; /* success */ }
/* inside - check if points are inside a surface */ int main (int argc, char * argv[]) { GtsSurface * s1; GNode * tree1; GtsPoint P; FILE * fptr; GtsFile * fp; int c = 0, cnt = 0; double x,y,z; gboolean verbose = FALSE; gchar * file1, * file2; gboolean is_open1, is_inside; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "shv", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "shv"))) { #endif /* not HAVE_GETOPT_LONG */ case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: gtsinside [OPTION] FILE1 FILE2\n" "Test whether points are inside a closed surface.\n" "FILE1 is a surface file. FILE2 is a text file where each line\n" "contains the three coordinates of a point, separated with blanks.\n" "\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", "https://savannah.nongnu.org/projects/pyformex/"); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `gtsinside --help' for more information.\n"); return 1; /* failure */ } } if (optind >= argc) { /* missing FILE1 */ fprintf (stderr, "gtsinside: missing FILE1\n" "Try `inside --help' for more information.\n"); return 1; /* failure */ } file1 = argv[optind++]; if (optind >= argc) { /* missing FILE2 */ fprintf (stderr, "gtsinside: missing FILE2\n" "Try `gtsinside --help' for more information.\n"); return 1; /* failure */ } file2 = argv[optind++]; /* open first file */ if ((fptr = fopen (file1, "rt")) == NULL) { fprintf (stderr, "gtsinside: can not open file `%s'\n", file1); return 1; } /* reads in first surface file */ s1 = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ()))); fp = gts_file_new (fptr); if (gts_surface_read (s1, fp)) { fprintf (stderr, "gtsinside: `%s' is not a valid GTS surface file\n", file1); fprintf (stderr, "%s:%d:%d: %s\n", file1, fp->line, fp->pos, fp->error); return 1; } gts_file_destroy (fp); fclose (fptr); /* open second file */ if ((fptr = fopen (file2, "rt")) == NULL) { fprintf (stderr, "gtsinside: can not open file `%s'\n", file2); return 1; } /* display summary information about the surface */ if (verbose) { gts_surface_print_stats (s1, stderr); } /* check that the surface is an orientable manifold */ if (!gts_surface_is_orientable (s1)) { fprintf (stderr, "gtsinside: surface `%s' is not an orientable manifold\n", file1); return 1; } /* build bounding box tree for the surface */ tree1 = gts_bb_tree_surface (s1); is_open1 = gts_surface_volume (s1) < 0. ? TRUE : FALSE; /* scan file 2 for points and determine if it they are inside surface */ while ( fscanf(fptr, "%lg %lg %lg", &x, &y, &z) == 3 ) { P.x = x; P.y = y; P.z = z; is_inside = gts_point_is_inside_surface(&P,tree1,is_open1); if (is_inside) printf("%d\n",cnt); //printf("Point %d: %lf, %lf, %lf: %d\n",cnt,P.x,P.y,P.z,is_inside); cnt++; } if ( !feof(fptr) ) { fprintf (stderr, "gtsinside: error while reading points from file `%s'\n", file2); return 1; } fclose (fptr); /* destroy surface */ gts_object_destroy (GTS_OBJECT (s1)); /* destroy bounding box tree (including bounding boxes) */ gts_bb_tree_destroy (tree1, TRUE); return 0; }
int main (int argc, char * argv[]) { GtsSurface * s; gboolean verbose = FALSE; gdouble threshold; int c = 0; GtsFile * fp; GtsRange angle; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, { NULL } }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hv", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hv"))) { #endif /* not HAVE_GETOPT_LONG */ case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: optimize [OPTION] THRESHOLD < FILE\n" "\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Report bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `optimize --help' for more information.\n"); return 1; /* failure */ } } if (optind >= argc) { /* missing threshold */ fprintf (stderr, "optimize: missing THRESHOLD\n" "Try `optimize --help' for more information.\n"); return 1; /* failure */ } threshold = strtod (argv[optind], NULL); if (threshold < 0.0) { /* threshold must be positive */ fprintf (stderr, "optimize: THRESHOLD must be >= 0.0\n" "Try `optimize --help' for more information.\n"); return 1; /* failure */ } /* read surface in */ s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("optimize: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } /* if verbose on print stats */ if (verbose) { gts_surface_print_stats (s, stderr); gts_range_init (&angle); gts_surface_foreach_edge (s, (GtsFunc) angle_stats, &angle); gts_range_update (&angle); fputs ("# angle : ", stderr); gts_range_print (&angle, stderr); fputc ('\n', stderr); } surface_optimize (s, -threshold); /* if verbose on print stats */ if (verbose) { gts_surface_print_stats (s, stderr); gts_range_init (&angle); gts_surface_foreach_edge (s, (GtsFunc) angle_stats, &angle); gts_range_update (&angle); fputs ("# angle : ", stderr); gts_range_print (&angle, stderr); fputc ('\n', stderr); } /* write surface */ gts_surface_write (s, stdout); return 0; /* success */ }
int main (int argc, char * argv[]) { int c = 0; gboolean verbose = FALSE; gboolean revert = FALSE; GtsSurface * s; GtsFile * fp; while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"revert", no_argument, NULL, 'r'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvr", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvr"))) { #endif /* not HAVE_GETOPT_LONG */ case 'r': /* revert */ revert = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: gts2stl [OPTION]... < input.gts > output.stl\n" "Convert a GTS file to STL format.\n" "\n" " -r, --revert revert face normals\n" " -v, --verbose display surface statistics\n" " -h, --help display this help and exit\n" "\n" "Report bugs to %s\n", GTS_MAINTAINER); return 0; break; case 'v': verbose = TRUE; break; case '?': /* wrong options */ fprintf (stderr, "Try `gts2stl --help' for more information.\n"); return 1; } } s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("gts2stl: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } if (revert) gts_surface_foreach_face (s, (GtsFunc) gts_triangle_revert, NULL); if (verbose) gts_surface_print_stats (s, stderr); puts ("solid"); gts_surface_foreach_face (s, (GtsFunc) write_face, NULL); puts ("endsolid"); return 0; }