Beispiel #1
0
void gts_surface_suma (GtsSurface * s, 
                        float **NodeListp, int *N_Nodep, int *NodeDimp, 
                        int **FaceSetListp, int *N_FaceSetp, int *FaceSetDimp)
{
  guint n = 0;
  gpointer data[2];
  GtsSurfaceStats stats;
  float *NodeList = NULL;
  int *FaceSetList = NULL;
  
  g_return_if_fail (s != NULL);

  

  gts_surface_stats (s, &stats);
  
  /* get the stats  */
  if (debug) {
   fprintf (stderr,
	   "gts_surface_suma: Number of vertices %u\n",
	   stats.edges_per_vertex.n);
   fprintf (stderr,
	   "gts_surface_suma: Number of triangles %u\n",
	   stats.n_faces);
  }
  NodeList = (float *)calloc( stats.edges_per_vertex.n * 3, sizeof(float));
  FaceSetList = (int *)calloc(stats.n_faces * 3, sizeof(int)); 
  
  if (!NodeList || !FaceSetList) { 
   fprintf(stderr,"Critical Error gts_surface_suma: Could not allocate.\n");
   g_return_if_fail (0);
  }
  
  /* get the nodes */
  n = 0;
  data[0] = (gpointer)NodeList;
  data[1] = (gpointer)&n;
  gts_surface_foreach_vertex (s, (GtsFunc) vertex_load, data);
  
  /* get the facesets */
  n = 0;
  data[0] = (gpointer)FaceSetList;
  data[1] = (gpointer)&n; 
  gts_surface_foreach_face (s, (GtsFunc) face_load , data);
  
  /* don't know what these two are for, 
  assuming it has to do with the ->reserved business in vertex_load and face_load above */
  gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL);  
  gts_surface_foreach_face (s, (GtsFunc) gts_object_reset_reserved, NULL);  
  
  /* set results */
  *N_FaceSetp = (int)stats.n_faces;
  *N_Nodep = (int)stats.edges_per_vertex.n;
  *NodeListp = NodeList;
  *FaceSetListp = FaceSetList;
  *NodeDimp = 3;
  *FaceSetDimp = 3;
  return;
}
Beispiel #2
0
bool ofxGtsSurface::prepareBoolean(ofxGtsSurface &source) {
	if(!loaded || !source.loaded) {
		ofLog(OF_LOG_NOTICE, "Gts surface not loaded, could not perform boolean operation");
		return false;
	}
	
	if(!gts_surface_is_orientable(surface)) {
		ofLog(OF_LOG_ERROR, "Gts surface is not an orientable manifold, could not perform boolean operation");
		return false;
	}
	
	if(gts_surface_is_self_intersecting(surface)) {
		ofLog(OF_LOG_ERROR, "Gts surface self-intersects, could not perform boolean operation");
		return false;
	}
	
	if(!gts_surface_is_orientable(source.surface)) {
		ofLog(OF_LOG_ERROR, "Gts surface is not an orientable manifold, could not perform boolean operation");
		return false;
	}
	
	if(gts_surface_is_self_intersecting(source.surface)) {
		ofLog(OF_LOG_ERROR, "Gts surface self-intersects, could not perform boolean operation");
		return false;
	}
	
	GSList *bboxes = NULL;
	gts_surface_foreach_face(surface, (GtsFunc) prepend_triangle_bbox, &bboxes);
	/* build bounding box tree for first surface */
	tree1 = gts_bb_tree_new(bboxes);
	/* free list of bboxes */
	g_slist_free (bboxes);
	is_open1 = gts_surface_volume(surface) < 0. ? TRUE : FALSE;
	
	/* build bounding boxes for second surface */
	bboxes = NULL;
	gts_surface_foreach_face(source.surface, (GtsFunc) prepend_triangle_bbox, &bboxes);
	/* build bounding box tree for second surface */
	tree2 = gts_bb_tree_new(bboxes);
	/* free list of bboxes */
	g_slist_free (bboxes);
	is_open2 = gts_surface_volume (source.surface) < 0. ? TRUE : FALSE;
	
	si = gts_surface_inter_new (gts_surface_inter_class (), 
								surface, source.surface, tree1, tree2, is_open1, is_open2);
	
	gboolean closed = TRUE;
	gts_surface_inter_check(si, &closed);
	boolPerformed = true;
	if(!closed) {
		ofLog(OF_LOG_NOTICE, "Gts surface is not closed, could not perform boolean operation");
		return false;
	}

	return true;
}
Beispiel #3
0
void 
pygts_face_cleanup(GtsSurface * s)
{
  GSList *triangles = NULL;
  GSList * i;

  g_return_if_fail(s != NULL);

  /* build list of triangles */
  gts_surface_foreach_face(s, (GtsFunc) build_list, &triangles);
  
  /* remove duplicate and degenerate triangles */
  i = triangles;
  while(i) {
    GtsTriangle * t = (GtsTriangle*)i->data;
    if (!gts_triangle_is_ok(t)) {
      /* destroy t, its edges (if not used by any other triangle)
	 and its corners (if not used by any other edge) */
      if( g_hash_table_lookup(obj_table,GTS_OBJECT(t))==NULL ) {
	gts_object_destroy(GTS_OBJECT(t));
      }
      else {
	gts_surface_remove_face(PYGTS_SURFACE_AS_GTS_SURFACE(s),GTS_FACE(t));
      }
    }
    i = g_slist_next(i);
  }
  
  /* free list of triangles */
  g_slist_free(triangles);
}
Beispiel #4
0
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;
}
Beispiel #5
0
// TODO: Is there a better way to draw stuff
void ofxGtsSurface::draw(DrawType type) {
	
	if(!loaded) {
		//ofLog(OF_LOG_NOTICE, "Gts surface not loaded");
		return;
	}
	
	GtsFace * first = NULL;
	// TODO: Do we really need to do this just to get the first face?
	gts_surface_foreach_face (surface, (GtsFunc) pick_first_face, &first);
	
	if (first) {
		GtsSurfaceTraverse * t = gts_surface_traverse_new (surface, first);
		GtsFace * f;
		guint level;

		glBegin((type == TRIANGLES) ? GL_TRIANGLE_STRIP : GL_LINES);
		while ((f = gts_surface_traverse_next (t, &level))) {

			// Edge 1
			GtsPoint p1 = f->triangle.e1->segment.v1->p;
			GtsPoint p2 = f->triangle.e1->segment.v2->p;
			// Edge 2			
			GtsPoint p3 = f->triangle.e2->segment.v1->p;
			GtsPoint p4 = f->triangle.e2->segment.v2->p;
			// Edge 3
			GtsPoint p5 = f->triangle.e3->segment.v1->p;
			GtsPoint p6 = f->triangle.e3->segment.v2->p;
			

			// TODO: Figure out what is going on with the normals
			if(type==TRIANGLES) {
				ofPoint normal = calculateNormal(p1, p2, p3);
				glNormal3f(normal.x, normal.y, normal.z);
			}
			glVertex3f(p1.x, p1.y, p1.z);
			glVertex3f(p2.x, p2.y, p2.z);			
			glVertex3f(p3.x, p3.y, p3.z);
			
			
			if(type==TRIANGLES) {
				ofPoint normal = calculateNormal(p4, p5, p6);
				glNormal3f(normal.x, normal.y, normal.z);
			}
			glVertex3f(p4.x, p4.y, p4.z);			
			glVertex3f(p5.x, p5.y, p5.z);
			glVertex3f(p6.x, p6.y, p6.z);			
			
			
		}
		glEnd();
		gts_surface_traverse_destroy (t);
	}
}
Beispiel #6
0
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;
	}
	
}
Beispiel #7
0
/**
 * gts_bb_tree_surface:
 * @s: a #GtsSurface.
 *
 * Returns: a new hierarchy of bounding boxes bounding the faces of @s.
 */
GNode * gts_bb_tree_surface (GtsSurface * s)
{
  GSList * bboxes = NULL;
  GNode * tree;

  g_return_val_if_fail (s != NULL, NULL);

  gts_surface_foreach_face (s, (GtsFunc) prepend_triangle_bbox, &bboxes);
  tree = gts_bb_tree_new (bboxes);
  g_slist_free (bboxes);

  return tree;
}
Beispiel #8
0
static void surface_hf_refine (GtsSurface * s,
			       CostFunc cost_func,
			       gpointer cost_data,
			       GtsStopFunc stop_func,
			       gpointer stop_data)
{
  GtsEHeap * heap;
  gdouble top_cost;
  guint nv = 4;
  GtsListFace * f;
  gpointer data[3];

  g_return_if_fail (s != NULL);
  g_return_if_fail (cost_func != NULL);
  g_return_if_fail (stop_func != NULL);

  data[0] = heap = gts_eheap_new (NULL, NULL);
  data[1] = cost_func;
  data[2] = cost_data;
  gts_surface_foreach_face (s, (GtsFunc) list_face_update, data);
  while ((f = gts_eheap_remove_top (heap, &top_cost)) &&
	 !(*stop_func) (- top_cost, nv, stop_data)) {
    GtsVertex * v = LIST_FACE (f)->best;
    GSList * t, * i;

    LIST_FACE (f)->heap = NULL;
    gts_delaunay_add_vertex_to_face (s, v, GTS_FACE (f));
    i = t = gts_vertex_triangles (v, NULL);
    while (i) {
      list_face_update (i->data, data);
      i = i->next;
    }
    g_slist_free (t);
    nv++;
  }

  if (f)
    LIST_FACE (f)->heap = NULL;

  gts_eheap_foreach (heap, (GFunc) list_face_clear_heap, NULL);
  gts_eheap_destroy (heap);
}
Beispiel #9
0
/**
 * gts_bb_tree_surface_distance:
 * @tree: a bounding box tree.
 * @s: a #GtsSurface.
 * @distance: a #GtsBBoxDistFunc.
 * @delta: a sampling increment defined as the percentage of the diagonal
 * of the root bounding box of @tree.
 * @range: a #GtsRange to be filled with the results.
 *
 * Calls gts_bb_tree_triangle_distance() for each face of @s. The
 * fields of @range are filled with the minimum, maximum and average
 * distance. The average distance is defined as the sum of the average
 * distances for each triangle weighthed by their area and divided by
 * the total area of the surface. The standard deviation is defined
 * accordingly. The @n field of @range is filled with the number of
 * sampled points used.  
 */
void gts_bb_tree_surface_distance (GNode * tree,
				   GtsSurface * s,
				   GtsBBoxDistFunc distance,
				   gdouble delta,
				   GtsRange * range)
{
  gpointer data[5];
  gdouble total_area = 0.;

  g_return_if_fail (tree != NULL);
  g_return_if_fail (s != NULL);
  g_return_if_fail (delta > 0. && delta < 1.);
  g_return_if_fail (range != NULL);

  gts_range_init (range);
  delta *= sqrt (gts_bbox_diagonal2 (tree->data));
  data[0] = tree;
  data[1] = &delta;
  data[2] = range;
  data[3] = &total_area;
  data[4] = distance;

  gts_surface_foreach_face (s, 
			    (GtsFunc) surface_distance_foreach_triangle, 
			    data);

  if (total_area > 0.) {
    if (range->sum2 - range->sum*range->sum/total_area >= 0.)
      range->stddev = sqrt ((range->sum2 - range->sum*range->sum/total_area)
			    /total_area);
    else
      range->stddev = 0.;
    range->mean = range->sum/total_area;
  }
  else
    range->min = range->max = range->mean = range->stddev = 0.;
}
Beispiel #10
0
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;
}
Beispiel #11
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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 */
}
Beispiel #14
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
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;
}