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; }
/* This function is modified from the original in GTS in order to avoid * deallocating any objects referenced by the live-objects table. The * approach is similar to what is used for replace() in vertex.c. */ GList* pygts_vertices_merge(GList* vertices, gdouble epsilon, gboolean (* check) (GtsVertex *, GtsVertex *)) { GPtrArray *array; GList *i, *next; GNode *kdtree; GtsVertex *v; GtsBBox *bbox; GSList *selected, *j; GtsVertex *sv; PygtsObject *obj; PygtsVertex *vertex=NULL; GSList *parents=NULL, *ii,*cur; g_return_val_if_fail(vertices != NULL, 0); array = g_ptr_array_new(); i = vertices; while (i) { g_ptr_array_add(array, i->data); i = g_list_next(i); } kdtree = gts_kdtree_new(array, NULL); g_ptr_array_free(array, TRUE); i = vertices; while(i) { v = (GtsVertex*)i->data; if (!GTS_OBJECT(v)->reserved) { /* Do something only if v is active */ /* build bounding box */ bbox = gts_bbox_new(gts_bbox_class(), v, GTS_POINT(v)->x - epsilon, GTS_POINT(v)->y - epsilon, GTS_POINT(v)->z - epsilon, GTS_POINT(v)->x + epsilon, GTS_POINT(v)->y + epsilon, GTS_POINT(v)->z + epsilon); /* select vertices which are inside bbox using kdtree */ j = selected = gts_kdtree_range(kdtree, bbox, NULL); while(j) { sv = (GtsVertex*)j->data; if( sv!=v && !GTS_OBJECT(sv)->reserved && (!check||(*check)(sv, v)) ) { /* sv is not v and is active */ if( (obj = (PygtsObject*)g_hash_table_lookup(obj_table,GTS_OBJECT(sv))) !=NULL ) { vertex = PYGTS_VERTEX(obj); /* Detach and save any parent segments */ ii = sv->segments; while(ii!=NULL) { cur = ii; ii = g_slist_next(ii); if(PYGTS_IS_PARENT_SEGMENT(cur->data)) { sv->segments = g_slist_remove_link(sv->segments, cur); parents = g_slist_prepend(parents,cur->data); g_slist_free_1(cur); } } } gts_vertex_replace(sv, v); GTS_OBJECT(sv)->reserved = sv; /* mark sv as inactive */ /* Reattach the parent segments */ if( vertex != NULL ) { ii = parents; while(ii!=NULL) { sv->segments = g_slist_prepend(sv->segments, ii->data); ii = g_slist_next(ii); } g_slist_free(parents); parents = NULL; } vertex = NULL; } j = g_slist_next(j); } g_slist_free(selected); gts_object_destroy(GTS_OBJECT(bbox)); } i = g_list_next(i); } gts_kdtree_destroy(kdtree); /* destroy inactive vertices and removes them from list */ /* we want to control vertex destruction */ gts_allow_floating_vertices = TRUE; i = vertices; while (i) { v = (GtsVertex*)i->data; next = g_list_next(i); if(GTS_OBJECT(v)->reserved) { /* v is inactive */ if( g_hash_table_lookup(obj_table,GTS_OBJECT(v))==NULL ) { gts_object_destroy(GTS_OBJECT(v)); } else { GTS_OBJECT(v)->reserved = 0; } vertices = g_list_remove_link(vertices, i); g_list_free_1(i); } i = next; } gts_allow_floating_vertices = FALSE; return vertices; }
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; }
static void prepend_triangle_bbox (GtsTriangle * t, GSList ** bboxes) { *bboxes = g_slist_prepend (*bboxes, gts_bbox_triangle (gts_bbox_class (), t)); }
/** * gts_bb_tree_new: * @bboxes: a list of #GtsBBox. * * Builds a new hierarchy of bounding boxes for @bboxes. At each * level, the GNode->data field contains a #GtsBBox bounding box of * all the children. The tree is binary and is built by repeatedly * cutting in two approximately equal halves the bounding boxes at * each level until a leaf node (i.e. a bounding box given in @bboxes) * is reached. In order to minimize the depth of the tree, the cutting * direction is always chosen as perpendicular to the longest * dimension of the bounding box. * * Returns: a new hierarchy of bounding boxes. */ GNode * gts_bb_tree_new (GSList * bboxes) { GSList * i, * positive = NULL, * negative = NULL; GNode * node; GtsBBox * bbox; guint dir, np = 0, nn = 0; gdouble * p1, * p2; gdouble cut; g_return_val_if_fail (bboxes != NULL, NULL); if (bboxes->next == NULL) /* leaf node */ return g_node_new (bboxes->data); bbox = gts_bbox_bboxes (gts_bbox_class (), bboxes); node = g_node_new (bbox); if (bbox->x2 - bbox->x1 > bbox->y2 - bbox->y1) { if (bbox->z2 - bbox->z1 > bbox->x2 - bbox->x1) dir = 2; else dir = 0; } else if (bbox->z2 - bbox->z1 > bbox->y2 - bbox->y1) dir = 2; else dir = 1; p1 = (gdouble *) &bbox->x1; p2 = (gdouble *) &bbox->x2; cut = (p1[dir] + p2[dir])/2.; i = bboxes; while (i) { bbox = i->data; p1 = (gdouble *) &bbox->x1; p2 = (gdouble *) &bbox->x2; if ((p1[dir] + p2[dir])/2. > cut) { positive = g_slist_prepend (positive, bbox); np++; } else { negative = g_slist_prepend (negative, bbox); nn++; } i = i->next; } if (!positive) { GSList * last = g_slist_nth (negative, (nn - 1)/2); positive = last->next; last->next = NULL; } else if (!negative) { GSList * last = g_slist_nth (positive, (np - 1)/2); negative = last->next; last->next = NULL; } g_node_prepend (node, gts_bb_tree_new (positive)); g_slist_free (positive); g_node_prepend (node, gts_bb_tree_new (negative)); g_slist_free (negative); return node; }