Example #1
0
static void gts_triangulate_test_stuff()
{
	gdouble v[4][3] = {
		{0.0, 0.0, 0.0},
		{0.0, 3.0, 0.0},
		{3.0, 3.0, 0.0},
		{1.0, 1.0, 0.0}
	};
	
	int i; 
	GtsVertex *vtx[4];
	GCList *polygon = NULL;
	GtsVector orient; 
	GCList *p; 
	
	for (i = 0; i < 4; ++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]); 
	}
	g_assert(g_clist_length(polygon));
	g_assert(gts_polygon_orientation(polygon, orient));	

	g_assert(orient[0] == 0 && orient[1] == 0 && orient[2] < 0); 

	p = g_clist_next(polygon); 
	g_assert(is_convex(GTS_POINT(p->prev->data), GTS_POINT(p->data),GTS_POINT(p->next->data), orient));
	g_assert(is_inside(GTS_POINT(vtx[0]), GTS_POINT(vtx[1]), GTS_POINT(vtx[2]), GTS_POINT(vtx[3])));
	g_assert(!is_inside(GTS_POINT(vtx[0]), GTS_POINT(vtx[1]), GTS_POINT(vtx[3]), GTS_POINT(vtx[2])));

	g_clist_free(p); 
	for (i = 0; i < 4; ++i) 
		gts_object_destroy(GTS_OBJECT(vtx[i])); 
		
}
Example #2
0
static void prepend (GtsListFace * f, 
		     gray ** g, guint i, guint j)
{
  f->points = g_slist_prepend (f->points, 
			       gts_vertex_new (gts_vertex_class (), 
					       i, j, g[j][i]));
}
Example #3
0
void ofxGtsSurface::addFace(ofPoint &p1, ofPoint &p2, ofPoint &p3) {
	
	if(!loaded) {
		setup();
	}
	
	GtsVertex *v1 = gts_vertex_new(surface->vertex_class, p1.x, p1.y, p1.z);
	GtsVertex *v2 = gts_vertex_new(surface->vertex_class, p2.x, p2.y, p2.z);
	GtsVertex *v3 = gts_vertex_new(surface->vertex_class, p3.x, p3.y, p3.z);	
	
	GtsEdge *e1 = gts_edge_new(surface->edge_class, v1, v2);
	GtsEdge *e2 = gts_edge_new(surface->edge_class, v2, v3);
	GtsEdge *e3 = gts_edge_new(surface->edge_class, v3, v1);	
	
	gts_surface_add_face(surface, gts_face_new(surface->face_class, e1, e2, e3));
	
}
Example #4
0
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)); 
}
Example #5
0
    GtsVertex* get_vertex(const k3d::uint_t Vertex)
    {
        if(!gts_vertices[Vertex])
        {
            const k3d::point3 mesh_point = (*mesh_points)[Vertex];
            gts_vertices[Vertex] = gts_vertex_new(gts_vertex_class(), mesh_point[0], mesh_point[1], mesh_point[2]);
        }

        return gts_vertices[Vertex];
    }
Example #6
0
/**
 * gts_segment_midvertex:
 * @s: a #GtsSegment.
 * @klass: a #GtsVertexClass to be used for the new vertex.
 *
 * Returns: a new #GtsVertex, midvertex of @s.
 */
GtsVertex * gts_segment_midvertex (GtsSegment * s, GtsVertexClass * klass)
{
  GtsPoint * p1, * p2;

  g_return_val_if_fail (s != NULL, NULL);
  g_return_val_if_fail (klass != NULL, NULL);

  p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2);
  return gts_vertex_new (klass,
			 (p1->x + p2->x)/2., 
			 (p1->y + p2->y)/2.,
			 (p1->z + p2->z)/2.);
}
Example #7
0
/**
 * gts_triangle_enclosing:
 * @klass: the class of the new triangle.
 * @points: a list of #GtsPoint.
 * @scale: a scaling factor (must be larger than one).
 *
 * Builds a new triangle (including new vertices and edges) enclosing
 * the plane projection of all the points in @points. This triangle is
 * equilateral and encloses a rectangle defined by the maximum and
 * minimum x and y coordinates of the points. @scale is an homothetic
 * scaling factor. If equal to one, the triangle encloses exactly the
 * enclosing rectangle.
 *
 * Returns: a new #GtsTriangle.
 */
GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass,
                                      GSList * points, gdouble scale)
{
    gdouble xmax, xmin, ymax, ymin;
    gdouble xo, yo, r;
    GtsVertex * v1, * v2, * v3;
    GtsEdge * e1, * e2, * e3;

    if (points == NULL)
        return NULL;

    xmax = xmin = GTS_POINT (points->data)->x;
    ymax = ymin = GTS_POINT (points->data)->y;
    points = points->next;
    while (points) {
        GtsPoint * p = points->data;
        if (p->x > xmax) xmax = p->x;
        else if (p->x < xmin) xmin = p->x;
        if (p->y > ymax) ymax = p->y;
        else if (p->y < ymin) ymin = p->y;
        points = points->next;
    }
    xo = (xmax + xmin)/2.;
    yo = (ymax + ymin)/2.;
    r = scale*sqrt((xmax - xo)*(xmax - xo) + (ymax - yo)*(ymax - yo));
    if (r == 0.0) r = scale;
    v1 = gts_vertex_new (gts_vertex_class (),
                         xo + r*SQRT3, yo - r, 0.0);
    v2 = gts_vertex_new (gts_vertex_class (),
                         xo, yo + 2.*r, 0.0);
    v3 = gts_vertex_new (gts_vertex_class (),
                         xo - r*SQRT3, yo - r, 0.0);
    e1 = gts_edge_new (gts_edge_class (), v1, v2);
    e2 = gts_edge_new (gts_edge_class (), v2, v3);
    e3 = gts_edge_new (gts_edge_class (), v3, v1);
    return gts_triangle_new (gts_triangle_class (), e1, e2, e3);
}
Example #8
0
/* the file format is the classic GTS file format but only the vertex and 
 * edge sections are read. */
static guint read_list (GPtrArray * vertices,
			GtsFifo * constraints,
			GtsEdgeClass * edge_class,
			FILE * fptr)
{
  guint nv, ne, nt, i;
  guint line = 1;

  g_return_val_if_fail (vertices != NULL, 1);
  g_return_val_if_fail (constraints != NULL, 1);
  g_return_val_if_fail (edge_class != NULL, 1);
  g_return_val_if_fail (fptr != NULL, 1);

  if (fscanf (fptr, "%u %u %u", &nv, &ne, &nt) != 3)
    return line;
  line++;

  g_ptr_array_set_size (vertices, nv);
  i = 1;
  while (i <= nv) {
    gdouble x, y, z;

    if (fscanf (fptr, "%lf %lf %lf", &x, &y, &z) != 3)
      return line;
    line++;

    g_ptr_array_index (vertices, i++ - 1) = 
      gts_vertex_new (gts_vertex_class (), x, y, z);
  }
  
  i = 1;
  while (i <= ne) {
    guint iv1, iv2;

    if (fscanf (fptr, "%u %u", &iv1, &iv2) != 2 ||
	iv1 <= 0 || iv1 > nv || iv2 <= 0 || iv2 > nv)
      return line;
    line++;

    gts_fifo_push (constraints, 
		   gts_edge_new (edge_class,
				 g_ptr_array_index (vertices, iv1 - 1),
				 g_ptr_array_index (vertices, iv2 - 1)));
    i++;
  }

  return 0;
}
Example #9
0
static PyObject *
new_(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
  PyObject *o;
  PygtsObject *obj;
  guint alloc_gtsobj = TRUE;

  /* Parse the args */
  if(kwds) {
    o = PyDict_GetItemString(kwds,"alloc_gtsobj");
    if(o==Py_False) {
      alloc_gtsobj = FALSE;
    }
    if(o!=NULL) {
      PyDict_DelItemString(kwds, "alloc_gtsobj");
    }
  }
  if(kwds) {
    Py_INCREF(Py_False);
    PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
  }

  /* Chain up */
  obj = PYGTS_OBJECT(PygtsPointType.tp_new(type,args,kwds));

  /* Allocate the gtsobj (if needed) */
  if( alloc_gtsobj ) {
    obj->gtsobj = GTS_OBJECT(gts_vertex_new(gts_vertex_class(),0,0,0));
    if( obj->gtsobj == NULL )  {
      PyErr_SetString(PyExc_MemoryError, "could not create Vertex");
      return NULL;
    }

    /* Create the parent GtsSegment */
    if( (obj->gtsobj_parent=parent(GTS_VERTEX(obj->gtsobj))) == NULL ) {
      gts_object_destroy(obj->gtsobj);
      obj->gtsobj = NULL;
      return NULL;
    }

    pygts_object_register(obj);
  }

  return (PyObject*)obj;
}
Example #10
0
static CartesianGrid * cartesian_grid_read (GtsVertexClass * klass,
					    guint * line)
{
  CartesianGrid * grid;
  guint nx, ny, line_number = 1, i, j;

  g_return_val_if_fail (klass != NULL, NULL);
  
  if (scanf ("%u %u", &nx, &ny) != 2) {
    if (line)
      *line = line_number;
    return NULL;
  }
  line_number++;

  grid = cartesian_grid_new (nx, ny);
  for (i = 0; i < nx; i++)
    for (j = 0; j < ny; j++) {
      gdouble x, y, z;
      if (scanf ("%lf %lf %lf", &x, &y, &z) != 3) {
	cartesian_grid_destroy (grid, TRUE);
	if (line)
	  *line = line_number;
	return NULL;
      }
      if (z != 0.)
	grid->vertices[i][j] = gts_vertex_new (klass, x, y, z);
      if (x > grid->xmax) grid->xmax = x;
      if (x < grid->xmin) grid->xmin = x;
      if (y > grid->ymax) grid->ymax = y;
      if (y < grid->ymin) grid->ymin = y;
      line_number++;
    }

  return grid;
}
Example #11
0
static GtsObject *
parent(GtsVertex *v1) {
  GtsPoint *p1;
  GtsVertex *v2;
  GtsSegment *p;

  /* Create another Vertex */
  p1 = GTS_POINT(v1);
  if( (v2 = gts_vertex_new(pygts_parent_vertex_class(),p1->x,p1->y,p1->z+1)) 
    == NULL ) {
    PyErr_SetString(PyExc_MemoryError, "could not create parent");
    return NULL;
  }

  /* Create and return the parent */
  if( (p = gts_segment_new(pygts_parent_segment_class(),v1,v2))
      == NULL ) {
    PyErr_SetString(PyExc_MemoryError, "could not create parent");
    gts_object_destroy(GTS_OBJECT(v2));
    return NULL;
  }

  return GTS_OBJECT(p);
}
Example #12
0
static GtsSurface * cartesian_grid_triangulate_holes (CartesianGrid * grid,
						      GtsSurface * s)
{
  GtsVertex * v1, * v2, * v3, * v4;
  GtsEdge * e1, * e2, * e3, * e4, * e5;
  gdouble w, h;
  GtsSurface * box;
  GSList * constraints = NULL, * vertices = NULL, * i;
  gpointer data[2];

  g_return_val_if_fail (grid != NULL, NULL);
  g_return_val_if_fail (s != NULL, NULL);

  /* build enclosing box */
  w = grid->xmax - grid->xmin;
  h = grid->ymax - grid->ymin;
  v1 = gts_vertex_new (s->vertex_class, grid->xmin - w, grid->ymin - h, 0.);
  v2 = gts_vertex_new (s->vertex_class, grid->xmax + w, grid->ymin - h, 0.);
  v3 = gts_vertex_new (s->vertex_class, grid->xmax + w, grid->ymax + h, 0.);
  v4 = gts_vertex_new (s->vertex_class, grid->xmin - w, grid->ymax + h, 0.);

  e1 = gts_edge_new (s->edge_class, v1, v2);
  e2 = gts_edge_new (s->edge_class, v2, v3);
  e3 = gts_edge_new (s->edge_class, v3, v4);
  e4 = gts_edge_new (s->edge_class, v4, v1);
  e5 = gts_edge_new (s->edge_class, v1, v3);

  box = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass), 
			 s->face_class, 
			 s->edge_class, 
			 s->vertex_class);
  gts_surface_add_face (box, gts_face_new (s->face_class, e1, e2, e5));
  gts_surface_add_face (box, gts_face_new (s->face_class, e3, e4, e5));

  /* build vertex and constraint list from the boundaries of the input
     surface s */
  data[0] = s;
  data[1] = &constraints;
  gts_surface_foreach_edge (s, (GtsFunc) build_constraint_list, data);
  vertices = gts_vertices_from_segments (constraints);

  /* triangulate holes */
  i = vertices;
  while (i) {
    g_assert (!gts_delaunay_add_vertex (box, i->data, NULL));
    i = i->next;
  }
  g_slist_free (vertices);

  i = constraints;
  while (i) {
    g_assert (!gts_delaunay_add_constraint (box, i->data));
    i = i->next;
  }

  /* destroy corners of the enclosing box */
  gts_allow_floating_vertices = TRUE;
  gts_object_destroy (GTS_OBJECT (v1));
  gts_object_destroy (GTS_OBJECT (v2));
  gts_object_destroy (GTS_OBJECT (v3));
  gts_object_destroy (GTS_OBJECT (v4));
  gts_allow_floating_vertices = FALSE;

  /* remove parts of the mesh which are not holes */
  i = constraints;
  while (i) {
    edge_mark_as_hole (i->data, box);
    i = i->next;
  }
  g_slist_free (constraints);

  /* remove marked and duplicate faces */
  gts_surface_foreach_face_remove (box, (GtsFunc) face_is_marked, NULL);

  /* box now contains only the triangulated holes. */
  return box;
}
Example #13
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;
}
Example #14
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"); 
}
Example #15
0
PygtsVertex *
pygts_vertex_from_sequence(PyObject *tuple) {
  guint i,N;
  gdouble x=0,y=0,z=0;
  PyObject *obj;
  GtsVertex *v;
  PygtsVertex *vertex;

  /* Convert list into tuple */
  if(PyList_Check(tuple)) {
    tuple = PyList_AsTuple(tuple);
  }
  else {
    Py_INCREF(tuple);
  }
  if(!PyTuple_Check(tuple)) {
    Py_DECREF(tuple);
    PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
    return NULL;
  }

  /* Get the tuple size */
  if( (N = PyTuple_Size(tuple)) > 3 ) {
    PyErr_SetString(PyExc_RuntimeError,
		    "expected a list or tuple of up to three floats");
    Py_DECREF(tuple);
    return NULL;
  }

  /* Get the coordinates */
  for(i=0;i<N;i++) {
    obj = PyTuple_GET_ITEM(tuple,i);

    if(!PyFloat_Check(obj) && !PyLong_Check(obj)) {
      PyErr_SetString(PyExc_TypeError,"expected a list or tuple of floats");
      Py_DECREF(tuple);
      return NULL;
    }
    if(i==0) {
      if(PyFloat_Check(obj)) x = PyFloat_AsDouble(obj);
      else  x = (double)PyLong_AsLong(obj);
    }
    if(i==1) {
      if(PyFloat_Check(obj)) y = PyFloat_AsDouble(obj);
      else  y = (double)PyLong_AsLong(obj);
    }
    if(i==2) {
      if(PyFloat_Check(obj)) z = PyFloat_AsDouble(obj);
      else  z = (double)PyLong_AsLong(obj);
    }
  }
  Py_DECREF(tuple);

  /* Create the vertex */  
  if( (v = gts_vertex_new(gts_vertex_class(),x,y,z)) == NULL ) {
    PyErr_SetString(PyExc_MemoryError,"could not create Vertex");
  }
  if( (vertex = pygts_vertex_new(v)) == NULL ) {
    gts_object_destroy(GTS_OBJECT(v));
    return NULL;
  }

  return vertex;
}
Example #16
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;
}
Example #17
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 */
}
Example #18
0
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 (), &params);
  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;
}
Example #19
0
 void add_vertex(const k3d::point3& Coordinates, k3d::uint_t Vertices[4], k3d::uint_t Edges[4], double Weights[4], k3d::uint_t& NewVertex)
 {
     NewVertex = gts_vertices.size();
     gts_vertices.push_back(gts_vertex_new(gts_vertex_class(), Coordinates[0], Coordinates[1], Coordinates[2]));
 }
Example #20
0
int main (int argc, char * argv[])
{
  int c = 0;
  gboolean verbose = FALSE;
  GtsSurface * s;
  CostFunc cost_func = (CostFunc) height_cost;
  gpointer cost_data = NULL;
  GtsStopFunc stop_func = NULL;
  gpointer stop_data = NULL;
  StopOptions stop = NUMBER;
  guint number = 0;
  gdouble cmin = 0.0;
  gboolean logcost = FALSE;
  gboolean flat = FALSE;
  gdouble relative = 0.;
  gboolean keep_enclosing = FALSE;
  gboolean closed = FALSE;

  if (!setlocale (LC_ALL, "POSIX"))
    g_warning ("cannot set locale to POSIX");

  while (c != EOF) {
#ifdef HAVE_GETOPT_LONG
    static struct option long_options[] = {
      {"closed", no_argument, NULL, 'C'},
      {"keep", no_argument, NULL, 'k'},
      {"relative", required_argument, NULL, 'r'},
      {"flat", no_argument, NULL, 'f'},
      {"log", no_argument, NULL, 'l'},
      {"number", required_argument, NULL, 'n'},
      {"cost", 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, "hvn:c:lfr:kC",
			      long_options, &option_index))) {
#else /* not HAVE_GETOPT_LONG */
    switch ((c = getopt (argc, argv, "hvn:c:lfr:kC"))) {
#endif /* not HAVE_GETOPT_LONG */
    case 'C': /* closed */
      closed = TRUE;
      keep_enclosing = TRUE;
      break;
    case 'k': /* keep */
      keep_enclosing = TRUE;
      break;
    case 'r': /* relative */
      cost_func = (CostFunc) relative_height_cost;
      relative = strtod (optarg, NULL);
      cost_data = &relative;
      if (relative <= 0.) {
	fprintf (stderr, "happrox: argument for -r option must be strictly positive\n");
	return 1;
      }
      break;
    case 'f': /* flat file */
      flat = TRUE;
      break;
    case 'l': /* log cost */
      logcost = TRUE;
      break;
    case 'n': /* stop by number */
      stop = NUMBER;
      number = strtol (optarg, NULL, 0);
      break;
    case 'c': /* stop by cost */
      stop = COST;
      cmin = strtod (optarg, NULL);
      break;
    case 'h': /* help */
      fprintf (stderr,
	       "Usage: happrox [OPTION]... < [input.pgm|input] > output.gts\n"
	       "Returns a simplified triangulation of a set of points using\n"
	       "algorithm III of Garland and Heckbert (1995).\n"
	       "\n"
	       "  -n N, --number=N    stop the refinement process if the number of\n"
	       "                      vertices is larger than N\n"
	       "  -c C, --cost=C      stop the refinement process if the cost of insertion\n"
	       "                      of a vertex is smaller than C\n"
	       "  -f    --flat        input is a flat file with three x,y,z columns\n"
	       "                        (default is PGM file)\n"
               "  -r Z  --relative=Z  use relative height cost for all heights larger than Z\n"
	       "  -k    --keep        keep enclosing triangle\n"
	       "  -C    --closed      close the surface\n"
	       "  -l    --log         log evolution of cost\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 `happrox --help' for more information.\n");
      return 1;
    }
  }

  switch (stop) {
  case NUMBER:
    if (verbose)
      stop_func = (GtsStopFunc) stop_number_verbose;
    else
      stop_func = (GtsStopFunc) stop_number;
    if (logcost)
      stop_func = (GtsStopFunc) stop_number_log_cost;
    stop_data = &number;
    break;
  case COST:
    if (verbose)
      stop_func = (GtsStopFunc) stop_cost_verbose;
    else
      stop_func = (GtsStopFunc) stop_cost; 
    stop_data = &cmin;
    break;
  default:
    g_assert_not_reached ();
  }

  if (flat) {
    GSList * points = NULL;
    guint n = 0;
    gdouble x, y, z;

    while (scanf ("%lf %lf %lf", &x, &y, &z) == 3) {
      points = g_slist_prepend (points, gts_vertex_new (gts_vertex_class (), x, y, z));
      n++;
    }
    if (verbose)
      fprintf (stderr, "happrox: %d vertices\n", n);

    s = happrox_list (points, keep_enclosing, closed, cost_func, cost_data, stop_func, stop_data);
  }
  else {
    gint width, height;
    gray ** g, maxgray;

    g = pgm_readpgm (stdin, &width, &height, &maxgray);
    if (verbose)
      fprintf (stderr, "happrox: width: %d height: %d maxgray: %d\n",
	       width, height, maxgray);
    
    s = happrox (g, width, height, cost_func, cost_data, stop_func, stop_data);
  }

  if (verbose) {
    fputc ('\n', stderr);
    gts_surface_print_stats (s, stderr);
  }
  gts_surface_write (s, stdout);

  return 0;
}
Example #21
0
/* 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;
}