Ejemplo n.º 1
0
static void bb_tree_free (GNode * tree, gboolean free_leaves)
{
  GNode * i;

  g_return_if_fail (tree != NULL);

  if (!free_leaves && tree->children == NULL) /* leaf node */
    return;

  gts_object_destroy (tree->data);

  i = tree->children;
  while (i) {
    bb_tree_free (i, free_leaves);
    i = i->next;
  }
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
static gboolean gfs_init_stokes_wave_event (GfsEvent * event, GfsSimulation * sim)
{
  if ((* GFS_EVENT_CLASS (GTS_OBJECT_CLASS (gfs_init_stokes_wave_class ())->parent_class)->event) 
      (event, sim)) {
    GfsVariable ** velocity = gfs_domain_velocity (GFS_DOMAIN (sim));
    GfsVariable * t = gfs_variable_from_name (GFS_DOMAIN (sim)->variables, "T");
    g_assert (velocity);
    g_assert (t);
    gfs_domain_cell_traverse (GFS_DOMAIN (sim), FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
			      (FttCellTraverseFunc) init_velocity, velocity);
    GfsSurface * surface = GFS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gfs_surface_class ())));
    surface->f = gfs_function_spatial_new (gfs_function_spatial_class (), stokes_height);
    gfs_object_simulation_set (surface->f, sim);
    gfs_domain_init_fraction (GFS_DOMAIN (sim), GFS_GENERIC_SURFACE (surface), t);
    gts_object_destroy (GTS_OBJECT (surface));
    return TRUE;
  }
  return FALSE;
}
Ejemplo n.º 4
0
static void cartesian_grid_destroy (CartesianGrid * g,
				    gboolean destroy_vertices)
{
  g_return_if_fail (g != NULL);

  if (destroy_vertices) {
    guint i, j;

    gts_allow_floating_vertices = TRUE;
    for (i = 0; i < g->nx; i++)
      for (j = 0; j < g->ny; j++)
	if (g->vertices[i][j])
	  gts_object_destroy (GTS_OBJECT (g->vertices[i][j]));
    gts_allow_floating_vertices = FALSE;
  }

  free2D ((void **) g->vertices, g->nx);
  g_free (g);
}
Ejemplo n.º 5
0
/**
 * gts_bb_tree_segment_distance:
 * @tree: a bounding box tree.
 * @s: a #GtsSegment.
 * @distance: a #GtsBBoxDistFunc.
 * @delta: spatial scale of the sampling to be used.
 * @range: a #GtsRange to be filled with the results.
 * 
 * Given a segment @s, points are sampled regularly on its length
 * using @delta as increment. The distance from each of these points
 * to the closest object of @tree is computed using @distance and the
 * gts_bb_tree_point_distance() function. The fields of @range are
 * filled with the number of points sampled, the minimum, average and
 * maximum value and the standard deviation.  
 */
void gts_bb_tree_segment_distance (GNode * tree,
				   GtsSegment * s,
				   gdouble (*distance) (GtsPoint *, 
							gpointer),
				   gdouble delta,
				   GtsRange * range)
{
  GtsPoint * p1, * p2, * p;
  GtsVector p1p2;
  gdouble l, t, dt;
  guint i, n;

  g_return_if_fail (tree != NULL);
  g_return_if_fail (s != NULL);
  g_return_if_fail (distance != NULL);
  g_return_if_fail (delta > 0.);
  g_return_if_fail (range != NULL);

  p1 = GTS_POINT (s->v1);
  p2 = GTS_POINT (s->v2);

  gts_vector_init (p1p2, p1, p2);
  gts_range_init (range);
  p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class())));

  l = sqrt (gts_vector_scalar (p1p2, p1p2));
  n = (guint) (l/delta + 1);
  dt = 1.0/(gdouble) n;
  t = 0.0;
  for (i = 0; i <= n; i++, t += dt) {
    p->x = p1->x + t*p1p2[0];
    p->y = p1->y + t*p1p2[1];
    p->z = p1->z + t*p1p2[2];
    
    gts_range_add_value (range,
			 gts_bb_tree_point_distance (tree, p, distance, NULL));
  }

  gts_object_destroy (GTS_OBJECT (p));
  gts_range_update (range);
}
Ejemplo n.º 6
0
Archivo: optimize.c Proyecto: bert/gts
static void edge_swap (GtsEdge * e, GtsSurface * s, GtsEHeap * heap)
{
    GSList * i;
    GtsTriangle * t1 = NULL, * t2 = NULL;
    GtsVertex * v1, * v2, * v3, * v4;
    GtsEdge * e1, * e2, * e3, * e4;

    i = e->triangles;
    while (i) {
        if (GTS_IS_FACE (i->data)) {
            if (!t1) t1 = i->data;
            else if (!t2) t2 = i->data;
            else g_assert_not_reached ();
        }
        i = i->next;
    }
    g_assert (t1 && t2);

    gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e3, &e4);
    gts_triangle_vertices_edges (t2, e, &v2, &v1, &v4, &e, &e1, &e2);

    gts_object_destroy (GTS_OBJECT (e));
    e = gts_edge_new (s->edge_class, v3, v4);
    gts_surface_add_face (s, gts_face_new (s->face_class, e, e4, e1));
    gts_surface_add_face (s, gts_face_new (s->face_class, e, e2, e3));

    HEAP_INSERT_EDGE (heap, e);
    HEAP_REMOVE_EDGE (heap, e1);
    HEAP_INSERT_EDGE (heap, e1);
    HEAP_REMOVE_EDGE (heap, e2);
    HEAP_INSERT_EDGE (heap, e2);
    HEAP_REMOVE_EDGE (heap, e3);
    HEAP_INSERT_EDGE (heap, e3);
    HEAP_REMOVE_EDGE (heap, e4);
    HEAP_INSERT_EDGE (heap, e4);
}
Ejemplo n.º 7
0
static void recursive_bisection (GtsWGraph * wg,
				 guint np,
				 guint ntry,
				 guint mmax,
				 guint nmin,
				 gfloat imbalance,
				 GSList ** list)
{
  if (np == 0)
    *list = g_slist_prepend (*list, wg);
  else {
    GtsGraphBisection * bg = 
      gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance);
    GtsGraph * g1 = bg->g1;
    GtsGraph * g2 = bg->g2;

    gts_object_destroy (GTS_OBJECT (wg));
    gts_graph_bisection_destroy (bg, FALSE);
    recursive_bisection (GTS_WGRAPH (g1), np - 1, ntry, mmax, nmin, imbalance,
			 list);
    recursive_bisection (GTS_WGRAPH (g2), np - 1, ntry, mmax, nmin, imbalance,
			 list);
  }
}
Ejemplo n.º 8
0
Archivo: edge.c Proyecto: MicBosi/GTS
/**
 * gts_edges_merge:
 * @edges: a list of #GtsEdge.
 *
 * For each edge in @edges check if it is duplicated (as
 * returned by gts_edge_is_duplicate()). If it is replace it by its
 * duplicate, destroy it and remove it from the list.
 *
 * Returns: the updated @edges list.
 */
GList * gts_edges_merge (GList * edges)
{
    GList * i = edges;

    /* we want to control edge destruction */
    gts_allow_floating_edges = TRUE;
    while (i) {
        GtsEdge * e = i->data;
        GtsEdge * de = gts_edge_is_duplicate (e);
        if (de) {
            GList * next = i->next;
            edges = g_list_remove_link (edges, i);
            g_list_free_1 (i);
            i = next;
            gts_edge_replace (e, de);
            gts_object_destroy (GTS_OBJECT (e));
        }
        else
            i = i->next;
    }
    gts_allow_floating_edges = FALSE;;

    return edges;
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
/**
 * gts_graph_bisection_new:
 * @wg: a #GtsWGraph.
 * @ntry: the number of tries for the graph growing algorithm.
 * @mmax: the number of unsucessful moves for the refinement algorithm.
 * @nmin: the minimum number of nodes of the coarsest graph.
 * @imbalance: the maximum relative imbalance allowed between the
 * weights of both halves of the partition.
 *
 * An implementation of a multilevel bisection algorithm as presented
 * in Karypis and Kumar (1997). A multilevel hierarchy of graphs is
 * created using the #GtsPGraph object. The bisection of the coarsest
 * graph is created using the gts_graph_ggg_bisection() function. The
 * graph is then uncoarsened using gts_pgraph_down() and at each level
 * the bisection is refined using gts_graph_bisection_bkl_refine().
 *
 * Returns: a new #GtsGraphBisection of @wg.  
 */
GtsGraphBisection * gts_graph_bisection_new (GtsWGraph * wg,
					     guint ntry,
					     guint mmax,
					     guint nmin,
					     gfloat imbalance)
{
  GtsGraph * g;
  GtsPGraph * pg;
  GtsGraphBisection * bg;
  gdouble cost;

  g_return_val_if_fail (wg != NULL, NULL);

  g = GTS_GRAPH (wg);
  pg = gts_pgraph_new (gts_pgraph_class (), g, 
		       gts_gnode_split_class (),
		       gts_wgnode_class (),
		       gts_wgedge_class (),
		       nmin);

  bg = gts_graph_ggg_bisection (g, ntry);
#ifdef DEBUG
  fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n",
	   gts_container_size (GTS_CONTAINER (bg->g1)),
	   gts_graph_weight (bg->g1),
	   gts_graph_edges_cut (bg->g1),
	   gts_graph_edges_cut_weight (bg->g1));
  g_assert (gts_graph_bisection_check (bg));
#endif
  while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) {
#ifdef DEBUG
    fprintf (stderr, "  cost: %g\n", cost);
    g_assert (gts_graph_bisection_check (bg));
#endif
  }
#ifdef DEBUG
  fprintf (stderr, "after  size: %5d weight: %5g cuts: %5d cweight: %5g\n",
	   gts_container_size (GTS_CONTAINER (bg->g1)),
	   gts_graph_weight (bg->g1),
	   gts_graph_edges_cut (bg->g1),
	   gts_graph_edges_cut_weight (bg->g1));
#endif
  while (gts_pgraph_down (pg, (GtsFunc) bisection_children, bg)) {
#ifdef DEBUG
    fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n",
	     gts_container_size (GTS_CONTAINER (bg->g1)),
	     gts_graph_weight (bg->g1),
	     gts_graph_edges_cut (bg->g1),
	     gts_graph_edges_cut_weight (bg->g1));	   
#endif
    while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) {
#ifdef DEBUG
      fprintf (stderr, "  cost: %g\n", cost);
      g_assert (gts_graph_bisection_check (bg));
#endif
    }
#ifdef DEBUG
    fprintf (stderr, "after  size: %5d weight: %5g cuts: %5d cweight: %5g\n",
	     gts_container_size (GTS_CONTAINER (bg->g1)),
	     gts_graph_weight (bg->g1),
	     gts_graph_edges_cut (bg->g1),
	     gts_graph_edges_cut_weight (bg->g1));
#endif
  }
  gts_object_destroy (GTS_OBJECT (pg));

  return bg;
}
Ejemplo n.º 11
0
static PyObject *
new_(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
  PyObject *o;
  PygtsObject *obj;
  GtsSegment *tmp;
  GtsObject *segment=NULL;
  PyObject *v1_=NULL,*v2_=NULL;
  PygtsVertex *v1,*v2;
  guint alloc_gtsobj = TRUE;
  guint N;

  /* 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);
  }

  /* Allocate the gtsobj (if needed) */
  if( alloc_gtsobj ) {

    /* Parse the args */
    if( (N = PyTuple_Size(args)) < 2 ) {
      PyErr_SetString(PyExc_TypeError,"expected two Vertices");
      return NULL;
    }
    v1_ = PyTuple_GET_ITEM(args,0);
    v2_ = PyTuple_GET_ITEM(args,1);

    /* Convert to PygtsObjects */
    if(!pygts_vertex_check(v1_)) {
      PyErr_SetString(PyExc_TypeError,"expected two Vertices");
      return NULL;
    }
    if(!pygts_vertex_check(v2_)) {
      PyErr_SetString(PyExc_TypeError,"expected two Vertices");
      return NULL;
    }
    v1 = PYGTS_VERTEX(v1_);
    v2 = PYGTS_VERTEX(v2_);

    /* Error check */
    if(PYGTS_OBJECT(v1)->gtsobj == PYGTS_OBJECT(v2)->gtsobj) {
      PyErr_SetString(PyExc_ValueError,"Vertices are identical");
      return NULL;
    }

    /* Create the GtsSegment */
    segment = GTS_OBJECT(gts_segment_new(gts_segment_class(),
					 GTS_VERTEX(v1->gtsobj),
					 GTS_VERTEX(v2->gtsobj)));
    if( segment == NULL )  {
      PyErr_SetString(PyExc_MemoryError, "could not create Segment");
      return NULL;
    }

    /* Check for duplicate */
    tmp = gts_segment_is_duplicate(GTS_SEGMENT(segment));
    if( tmp != NULL ) {
      gts_object_destroy(segment);
      segment = GTS_OBJECT(tmp);
    }

    /* If corresponding PyObject found in object table, we are done */
    if( (obj=(PygtsObject*)g_hash_table_lookup(obj_table,segment)) != NULL ) {
      Py_INCREF(obj);
      return (PyObject*)obj;
    }
  }  

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

  if( alloc_gtsobj ) {
    obj->gtsobj = segment;
    pygts_object_register(PYGTS_OBJECT(obj));
  }

  return (PyObject*)obj;
}
Ejemplo n.º 12
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;
}
Ejemplo n.º 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 */
}
Ejemplo n.º 14
0
int main (int argc, char * argv[])
{
  gboolean verbose = FALSE;
  gboolean triangulate_holes = TRUE;
  gboolean write_holes = FALSE;
  int c = 0;
  CartesianGrid * grid;
  guint line = 0;
  GtsSurface * s;
  GTimer * timer;

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

  /* parse options using getopt */
  while (c != EOF) {
#ifdef HAVE_GETOPT_LONG
    static struct option long_options[] = {
      {"holes", no_argument, NULL, 'H'},
      {"keep", no_argument, NULL, 'k'},
      {"help", no_argument, NULL, 'h'},
      {"verbose", no_argument, NULL, 'v'},
      { NULL }
    };
    int option_index = 0;
    switch ((c = getopt_long (argc, argv, "hvHk", 
			      long_options, &option_index))) {
#else /* not HAVE_GETOPT_LONG */
    switch ((c = getopt (argc, argv, "hvHk"))) {
#endif /* not HAVE_GETOPT_LONG */
    case 'H': /* holes */
      write_holes = TRUE;
      break;
    case 'k': /* keep */
      triangulate_holes = FALSE;
      break;
    case 'v': /* verbose */
      verbose = TRUE;
      break;
    case 'h': /* help */
      fprintf (stderr,
             "Usage: cartesian [OPTION] < FILE\n"
	     "Triangulates vertices of a regular cartesian mesh\n"
	     "(possibly containing holes)\n"
	     "\n"
	     "  -k    --keep     keep holes\n"
	     "  -H    --holes    write holes only\n"
	     "  -v    --verbose  print statistics about the surface\n"
	     "  -h    --help     display this help and exit\n"
	       "\n"
	     "Reports bugs to %s\n",
	       GTS_MAINTAINER);
      return 0; /* success */
      break;
    case '?': /* wrong options */
      fprintf (stderr, "Try `cartesian --help' for more information.\n");
      return 1; /* failure */
    }
  }
  
  grid = cartesian_grid_read (gts_vertex_class (), &line);
  if (grid == NULL) {
    fprintf (stderr, 
	   "cartesian: file on standard input is not a valid cartesian grid\n"
	   "error at line %u\n", line);
    return 1;
  }

  timer = g_timer_new ();
  g_timer_start (timer);
  s = gts_surface_new (gts_surface_class (), 
		       gts_face_class (), 
		       gts_edge_class (), 
		       gts_vertex_class ());
  cartesian_grid_triangulate (grid, s);
  if (triangulate_holes) {    
    GtsSurface * holes = cartesian_grid_triangulate_holes (grid, s);
    if (write_holes) {
      gts_object_destroy (GTS_OBJECT (s));
      s = holes;
    }
    else
      gts_surface_merge (s, holes);
  }
  g_timer_stop (timer);
  
  if (verbose) {
    gts_surface_print_stats (s, stderr);
    fprintf (stderr, "# Triangulation time: %g s speed: %.0f vertex/s\n", 
	     g_timer_elapsed (timer, NULL),
	     gts_surface_vertex_number (s)/g_timer_elapsed (timer, NULL));
  }

  gts_surface_write (s, stdout);

  return 0; /* success */
}
Ejemplo n.º 15
0
/**
 * gts_graph_bfgg_bisection:
 * @g: a #GtsGraph.
 * @ntry: the number of randomly selected initial seeds.
 *
 * An implementation of a "Breadth-First Graph Growing" algorithm.
 *
 * @ntry randomly chosen seeds are used and the best partition is retained.
 *
 * Returns: a new #GtsGraphBisection of @g.
 */
GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, guint ntry)
{
  gfloat size, bestcost = G_MAXFLOAT, smin;
  GtsGraph * bestg1 = NULL, * bestg2 = NULL;
  GtsEHeap * degree_heap;
  GtsGNode * seed;
  GtsGraphBisection * bg;

  g_return_val_if_fail (g != NULL, NULL);

  bg = g_malloc (sizeof (GtsGraphBisection));
  bg->g = g;

  size = gts_graph_weight (g)/2.;
  smin = 0.9*size;

  degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g);
  gts_eheap_freeze (degree_heap);
  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap);
  gts_eheap_thaw (degree_heap);

  while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) {
    GtsGraph * g1, * g2;
    GtsGNode * n;
    gdouble cost;
    GtsGraphTraverse * t = gts_graph_traverse_new (g, seed, 
						   GTS_BREADTH_FIRST, TRUE);
    
    g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
			g->node_class, g->edge_class);
    g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
			g->node_class, g->edge_class);

    while ((n = gts_graph_traverse_next (t)))
      if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) {
	gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
	GTS_OBJECT (n)->reserved = n;
      }
    gts_graph_traverse_destroy (t);
    
    gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2);

    cost = gts_graph_edges_cut_weight (g1);
    if (!bestg1 || (cost < bestcost && gts_graph_weight (g1) >= smin)) {
      if (bestg1)
	bestcost = cost;
      if (bestg1)
	gts_object_destroy (GTS_OBJECT (bestg1));
      if (bestg2)
	gts_object_destroy (GTS_OBJECT (bestg2));
      bestg1 = g1;
      bestg2 = g2;
    }
    else {
      gts_object_destroy (GTS_OBJECT (g1));
      gts_object_destroy (GTS_OBJECT (g2));
    }

    ntry--;
  }
  gts_eheap_destroy (degree_heap);

#ifdef DEBUG
  fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n",
	   bestcost, 
	   gts_graph_weight (bestg1), 
	   gts_container_size (GTS_CONTAINER (bestg1)),
	   gts_graph_weight (bestg2), 
	   gts_container_size (GTS_CONTAINER (bestg2)));
#endif

  bg->g1 = bestg1;
  bg->g2 = bestg2;
  
  /* boundary nodes */
  bg->bg1 = g_hash_table_new (NULL, NULL);
  gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg);
  bg->bg2 = g_hash_table_new (NULL, NULL);
  gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg);

  return bg;
}
Ejemplo n.º 16
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"); 
}
Ejemplo n.º 17
0
/**
 * gts_hsurface_new:
 * @klass: a #GtsHSurfaceClass.
 * @hsplit_class: a #GtsHSplitClass.
 * @psurface: a #GtsPSurface.
 * @expand_key: a #GtsKeyFunc used to order the priority heap of expandable 
 * #GtsHSplit.
 * @expand_data: data to be passed to @expand_key.
 * @collapse_key: a #GtsKeyFunc used to order the priority heap of collapsable
 * #GtsHSplit.
 * @collapse_data: data to be passed to @collapsed_key.
 *
 * Returns: a new #GtsHSurface, hierarchical extension of @psurface
 * and using #GtsHSplit of class @hsplit_class. Note that @psurface is
 * destroyed in the process.
 */
GtsHSurface * gts_hsurface_new (GtsHSurfaceClass * klass,
				GtsHSplitClass * hsplit_class,
				GtsPSurface * psurface,
				GtsKeyFunc expand_key,
				gpointer expand_data,
				GtsKeyFunc collapse_key,
				gpointer collapse_data)
{
  GtsHSurface * hsurface;

  g_return_val_if_fail (klass != NULL, NULL);
  g_return_val_if_fail (hsplit_class != NULL, NULL);
  g_return_val_if_fail (psurface != NULL, NULL);
  g_return_val_if_fail (expand_key != NULL, NULL);
  g_return_val_if_fail (collapse_key != NULL, NULL);

  hsurface = GTS_HSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass)));
  hsurface->s = psurface->s;
  hsurface->expandable = gts_eheap_new (expand_key, expand_data);
  hsurface->collapsable = gts_eheap_new (collapse_key, collapse_data);
  g_ptr_array_set_size (hsurface->split, psurface->split->len);

  while (gts_psurface_remove_vertex (psurface))
    ;
  while (psurface->pos) {
    GtsSplit * vs = g_ptr_array_index (psurface->split, psurface->pos - 1);
    GtsHSplit * hs = gts_hsplit_new (hsplit_class, vs);

    g_ptr_array_index (hsurface->split, psurface->pos - 1) = hs;
    psurface->pos--;

    hs->parent = GTS_OBJECT (vs)->reserved;
    if (hs->parent) {
      GtsSplit * vsp = GTS_SPLIT (hs->parent);

      if (vsp->v1 == GTS_OBJECT (vs)) {
	g_assert (vsp->v2 != GTS_OBJECT (vs));
	vsp->v1 = GTS_OBJECT (hs);
      }
      else {
	g_assert (vsp->v2 == GTS_OBJECT (vs));
	vsp->v2 = GTS_OBJECT (hs);
      }
    }
    else
      hsurface->roots = g_slist_prepend (hsurface->roots, hs);

    hs->nchild = 0;
    if (GTS_IS_SPLIT (vs->v1))
      GTS_OBJECT (vs->v1)->reserved = hs;
    else
      hs->nchild++;
    if (GTS_IS_SPLIT (vs->v2))
      GTS_OBJECT (vs->v2)->reserved = hs;
    else
      hs->nchild++;
    
    gts_split_expand (vs, psurface->s, psurface->s->edge_class);

    if (hs->nchild == 2)
      HEAP_INSERT_HSPLIT (hsurface->collapsable, hs);
  }

  hsurface->nvertex = gts_surface_vertex_number (hsurface->s);
  gts_object_destroy (GTS_OBJECT (psurface));

  return hsurface;
}
Ejemplo n.º 18
0
/* inside - check if points are inside a surface */
int main (int argc, char * argv[])
{
  GtsSurface * s1;
  GNode * tree1;
  GtsPoint P;
  FILE * fptr;
  GtsFile * fp;
  int c = 0, cnt = 0;
  double x,y,z;
  gboolean verbose = FALSE;
  gchar * file1, * file2;
  gboolean is_open1, is_inside;

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

  /* parse options using getopt */
  while (c != EOF) {
#ifdef HAVE_GETOPT_LONG
    static struct option long_options[] = {
      {"help", no_argument, NULL, 'h'},
      {"verbose", no_argument, NULL, 'v'}
    };
    int option_index = 0;
    switch ((c = getopt_long (argc, argv, "shv", 
			      long_options, &option_index))) {
#else /* not HAVE_GETOPT_LONG */
    switch ((c = getopt (argc, argv, "shv"))) {
#endif /* not HAVE_GETOPT_LONG */
    case 'v': /* verbose */
      verbose = TRUE;
      break;
    case 'h': /* help */
      fprintf (stderr,
	"Usage: gtsinside [OPTION] FILE1 FILE2\n"
	"Test whether points are inside a closed surface.\n"
	"FILE1 is a surface file. FILE2 is a text file where each line\n"
	"contains the three coordinates of a point, separated with blanks.\n"
	"\n"
	"  -v      --verbose  print statistics about the surface\n"
	"  -h      --help     display this help and exit\n"
	"\n"
	"Reports bugs to %s\n",
	"https://savannah.nongnu.org/projects/pyformex/");
      return 0; /* success */
      break;
    case '?': /* wrong options */
      fprintf (stderr, "Try `gtsinside --help' for more information.\n");
      return 1; /* failure */
    }
  }

  if (optind >= argc) { /* missing FILE1 */
    fprintf (stderr, 
	     "gtsinside: missing FILE1\n"
	     "Try `inside --help' for more information.\n");
    return 1; /* failure */
  }
  file1 = argv[optind++];

  if (optind >= argc) { /* missing FILE2 */
    fprintf (stderr, 
	     "gtsinside: missing FILE2\n"
	     "Try `gtsinside --help' for more information.\n");
    return 1; /* failure */
  }
  file2 = argv[optind++];

  /* open first file */
  if ((fptr = fopen (file1, "rt")) == NULL) {
    fprintf (stderr, "gtsinside: can not open file `%s'\n", file1);
    return 1;
  }
  /* reads in first surface file */
  s1 = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ())));
  fp = gts_file_new (fptr);
  if (gts_surface_read (s1, fp)) {
    fprintf (stderr, "gtsinside: `%s' is not a valid GTS surface file\n", 
	     file1);
    fprintf (stderr, "%s:%d:%d: %s\n", file1, fp->line, fp->pos, fp->error);
    return 1;
  }
  gts_file_destroy (fp);
  fclose (fptr);

  /* open second file */
  if ((fptr = fopen (file2, "rt")) == NULL) {
    fprintf (stderr, "gtsinside: can not open file `%s'\n", file2);
    return 1;
  }

  /* display summary information about the surface */
  if (verbose) {
    gts_surface_print_stats (s1, stderr);
  }

  /* check that the surface is an orientable manifold */
  if (!gts_surface_is_orientable (s1)) {
    fprintf (stderr, "gtsinside: surface `%s' is not an orientable manifold\n",
  	     file1);
    return 1;
  }

  /* build bounding box tree for the surface */
  tree1 = gts_bb_tree_surface (s1);
  is_open1 = gts_surface_volume (s1) < 0. ? TRUE : FALSE;

  /* scan file 2 for points and determine if it they are inside surface */
  while ( fscanf(fptr, "%lg %lg %lg", &x, &y, &z) == 3 ) {
    P.x = x; P.y = y; P.z = z;
    is_inside = gts_point_is_inside_surface(&P,tree1,is_open1);
    if (is_inside) printf("%d\n",cnt);
    //printf("Point %d: %lf, %lf, %lf: %d\n",cnt,P.x,P.y,P.z,is_inside);
    cnt++;
  }
  if ( !feof(fptr) ) {
    fprintf (stderr, "gtsinside: error while reading points from file `%s'\n",
  	     file2);
    return 1;
  }
  fclose (fptr);

  /* destroy surface */
  gts_object_destroy (GTS_OBJECT (s1));

  /* destroy bounding box tree (including bounding boxes) */
  gts_bb_tree_destroy (tree1, TRUE);

  return 0;
}
Ejemplo n.º 19
0
static void gfs_refine_destroy (GtsObject * o)
{
  gts_object_destroy (GTS_OBJECT (GFS_REFINE (o)->maxlevel));
  (* GTS_OBJECT_CLASS (gfs_refine_class ())->parent_class->destroy) (o);
}
Ejemplo n.º 20
0
/**
 * gts_graph_bubble_partition:
 * @g: a #GtsGraph.
 * @np: number of partitions.
 * @niter: the maximum number of iterations.
 * @step_info: a #GtsFunc or %NULL.
 * @data: user data to pass to @step_info.
 *
 * An implementation of the "bubble partitioning algorithm" of
 * Diekmann, Preis, Schlimbach and Walshaw (2000). The maximum number
 * of iteration on the positions of the graph growing seeds is
 * controlled by @niter.
 *
 * If not %NULL @step_info is called after each iteration on the seeds
 * positions passing the partition (a GSList) as argument.
 *
 * Returns: a list of @np new #GtsGraph representing the partition.  
 */
GSList * gts_graph_bubble_partition (GtsGraph * g, 
				     guint np, 
				     guint niter,
				     GtsFunc step_info,
				     gpointer data)
{
  GSList * list = NULL, * seeds = NULL;
  GtsGNode * seed = NULL;
  guint min = G_MAXINT/2 - 1;
  gpointer info[3];
  GtsGraph * g1;
  gboolean changed = TRUE;

  g_return_val_if_fail (g != NULL, NULL);
  g_return_val_if_fail (np > 0, NULL);

  info[0] = &seed;
  info[1] = g;
  info[2] = &min;
  gts_container_foreach (GTS_CONTAINER (g), 
			 (GtsFunc) find_smallest_degree,
			 info);
  if (seed == NULL)
    return NULL;

  g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
  gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
  list = g_slist_prepend (list, g1);
  GTS_OBJECT (g1)->reserved = seed;
  seeds = g_slist_prepend (seeds, seed);

  while (--np && seed)
    if ((seed = gts_graph_farthest (g, seeds))) {
      g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
      gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
      list = g_slist_prepend (list, g1);
      GTS_OBJECT (g1)->reserved = seed;
      seeds = g_slist_prepend (seeds, seed);
    }
  g_slist_free (seeds);
  
  partition_update (list, g);

  while (changed && niter--) {
    GSList * i;

    changed = FALSE;
    i = list;
    while (i) {
      GtsGraph * g1 = i->data;
      GtsGNode * seed = GTS_OBJECT (g1)->reserved;
      GtsGNode * new_seed = graph_new_seed (g1, seed);
      if (new_seed != seed) {
	changed = TRUE;
	GTS_OBJECT (g1)->reserved = new_seed;
      }
      i = i->next;
    }

    if (changed) {
      i = list;
      while (i) {
	GtsGraph * g1 = i->data;
	GtsGNode * seed = GTS_OBJECT (g1)->reserved;

	gts_object_destroy (GTS_OBJECT (g1));
	i->data = g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
	gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
	GTS_OBJECT (g1)->reserved = seed;
	i = i->next;
      }
      partition_update (list, g);
      if (step_info)
	(* step_info) (list, data);
    }
  }
  g_slist_foreach (list, (GFunc) gts_object_reset_reserved, NULL);
  return list;
}
Ejemplo n.º 21
0
/**
 * gts_graph_ggg_bisection:
 * @g: a #GtsGraph.
 * @ntry: the number of randomly selected initial seeds.
 *
 * An implementation of the "Greedy Graph Growing" algorithm of
 * Karypis and Kumar (1997).  
 *
 * @ntry randomly chosen seeds are used and the best partition is retained.
 *
 * Returns: a new #GtsGraphBisection of @g.
 */
GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, guint ntry)
{
  gfloat size, bestcost = G_MAXFLOAT, smin;
  GtsGraph * bestg1 = NULL, * bestg2 = NULL;
  gboolean balanced = FALSE;
  GtsEHeap * degree_heap;
  GtsGNode * seed;
  GtsGraphBisection * bg;

  g_return_val_if_fail (g != NULL, NULL);

  bg = g_malloc (sizeof (GtsGraphBisection));
  bg->g = g;

  size = gts_graph_weight (g)/2.;
  smin = 0.9*size;

  degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g);
  gts_eheap_freeze (degree_heap);
  gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap);
  gts_eheap_thaw (degree_heap);

  while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) {
    GtsGraph * g1, * g2;
    GtsGNode * n;
    gdouble cost;
    gpointer data[2];
    GtsEHeap * heap;
  
    g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
			g->node_class, g->edge_class);
    g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
			g->node_class, g->edge_class);
    
    data[0] = g;
    data[1] = g1;
    heap = gts_eheap_new ((GtsKeyFunc) node_cost, data);

    gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
    GTS_OBJECT (seed)->reserved = seed;
    gts_gnode_foreach_neighbor (seed, g, (GtsFunc) add_neighbor, heap);

    while ((n = gts_eheap_remove_top (heap, &cost)))
      if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) {
	gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
	GTS_OBJECT (n)->reserved = n;
	gts_gnode_foreach_neighbor (n, g, (GtsFunc) add_neighbor, heap);
      }
      else
	GTS_OBJECT (n)->reserved = NULL;
    gts_eheap_destroy (heap);
    
    gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2);

    cost = gts_graph_edges_cut_weight (g1);
    if (!bestg1 || 
	(!balanced && gts_graph_weight (g1) >= smin) ||
	(cost < bestcost && gts_graph_weight (g1) >= smin)) {
      if (bestg1)
	bestcost = cost;
      if (bestg1)
	gts_object_destroy (GTS_OBJECT (bestg1));
      if (bestg2)
	gts_object_destroy (GTS_OBJECT (bestg2));
      bestg1 = g1;
      bestg2 = g2;
      if (gts_graph_weight (g1) >= smin)
	balanced = TRUE;
    }
    else {
      gts_object_destroy (GTS_OBJECT (g1));
      gts_object_destroy (GTS_OBJECT (g2));
    }

    ntry--;
  }
  gts_eheap_destroy (degree_heap);

#ifdef DEBUG
  fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n",
	   bestcost, 
	   gts_graph_weight (bestg1), 
	   gts_container_size (GTS_CONTAINER (bestg1)),
	   gts_graph_weight (bestg2), 
	   gts_container_size (GTS_CONTAINER (bestg2)));
#endif

  g_assert (bestg1 != NULL);
  bg->g1 = bestg1;
  g_assert (bestg2 != NULL);
  bg->g2 = bestg2;
  
  /* boundary nodes */
  bg->bg1 = g_hash_table_new (NULL, NULL);
  gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg);
  bg->bg2 = g_hash_table_new (NULL, NULL);
  gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg);

  return bg;
}
Ejemplo n.º 22
0
extern field_t* field_read_gfs(const char* file)
{
  int argc = 0;
  gfs_init(&argc,NULL);

  FILE *st = fopen(file,"r");

  if (!st)
    {
      fprintf(stderr,"failed to open %s\n",file);
      return NULL;
    }

  GtsFile *fp = gts_file_new(st);
  GfsSimulation *sim = gfs_simulation_read(fp);

  if (!sim) 
    {
      fprintf(stderr,
              "file %s not a valid simulation file\n"
              "line %d:%d: %s\n",
              file,
              fp->line, 
              fp->pos, 
              fp->error);
      return NULL;
    }

  gts_file_destroy(fp);
  fclose(st);

  GfsDomain *gdom = GFS_DOMAIN(sim);

  /* find the bounding box */

  bbox_t *bb = NULL;

  gfs_domain_cell_traverse(gdom,
			   FTT_PRE_ORDER,
			   FTT_TRAVERSE_NON_LEAFS, 
			   0,
			   (FttCellTraverseFunc)ftt_bbox, 
			   &bb);

  if (!bb)
    {
      fprintf(stderr,"failed to determine bounding box\n");
      return NULL;
    }

#ifdef FRG_DEBUG

  fprintf(stdout, 
	  "%g %g %g %g\n",
	  bb->x.min,
	  bb->x.max,
	  bb->y.min,
	  bb->y.max);

#endif

  /* tree depth and discretisation size */

  int 
    depth = gfs_domain_depth(gdom),
    nw = (int)(POW2(depth)*bbox_width(*bb)),
    nh = (int)(POW2(depth)*bbox_height(*bb));

  /* shave bbox for node-aligned rather than pixel */

  double shave = bbox_width(*bb)/(2.0*nw);

  bb->x.min += shave;
  bb->x.max -= shave;
  bb->y.min += shave;
  bb->y.max -= shave;

  /* create & intialise meshes */

  bilinear_t* B[2];
  int i;

  for (i=0 ; i<2 ; i++)
    {
      if ((B[i] = bilinear_new()) == NULL) return NULL;
      if (bilinear_dimension(nw,nh,*bb,B[i]) != ERROR_OK) return NULL;
    }

  ftts_t ftts;

  ftts.B     = B;
  ftts.depth = depth;

  if ((ftts.u = gfs_variable_from_name(gdom->variables,"U")) == NULL)
    {
      fprintf(stderr,"no variable U\n");
      return NULL;
    }

  if ((ftts.v = gfs_variable_from_name(gdom->variables,"V")) == NULL)
    {
      fprintf(stderr,"no variable V\n");
      return NULL;
    }

  gfs_domain_cell_traverse(gdom,
			   FTT_PRE_ORDER,
			   FTT_TRAVERSE_LEAFS, 
			   -1,
			   (FttCellTraverseFunc)ftt_sample, 
			   &ftts);

  /* clean up */

  free(bb);
  gts_object_destroy(GTS_OBJECT(sim)); 

  /* results */

  field_t* F = malloc(sizeof(field_t));

  if (!F) return NULL;

  F->u = B[0];
  F->v = B[1];
  F->k = NULL;

  return F;
}
Ejemplo n.º 23
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;
}
Ejemplo n.º 24
0
void 
pygts_edge_cleanup(GtsSurface *s)
{
  GSList *edges = NULL;
  GSList *i, *ii, *cur, *parents=NULL;
  PygtsEdge *edge;
  GtsEdge *e, *duplicate;

  g_return_if_fail(s != NULL);

  /* build list of edges */
  gts_surface_foreach_edge(s, (GtsFunc)build_list, &edges);

  /* remove degenerate and duplicate edges.
     Note: we could use gts_edges_merge() to remove the duplicates and then
     remove the degenerate edges but it is more efficient to do everything 
     at once (and it's more pedagogical too ...) */

  /* We want to control manually the destruction of edges */
  gts_allow_floating_edges = TRUE;

  i = edges;
  while(i) {
    e = (GtsEdge*)i->data;
    if(GTS_SEGMENT(e)->v1 == GTS_SEGMENT(e)->v2) {
      /* edge is degenerate */
      if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) {
	/* destroy e */
	gts_object_destroy(GTS_OBJECT(e));
      }
    }
    else {
      if((duplicate = gts_edge_is_duplicate(e))) {

	/* Detach and save any parent triangles */
	if( (edge = PYGTS_EDGE(g_hash_table_lookup(obj_table,GTS_OBJECT(e))))
	    !=NULL ) {
	  ii = e->triangles;
	  while(ii!=NULL) {
	    cur = ii;
	    ii = g_slist_next(ii);
	    if(PYGTS_IS_PARENT_TRIANGLE(cur->data)) {
	      e->triangles = g_slist_remove_link(e->triangles, cur);
	      parents = g_slist_prepend(parents,cur->data);
	      g_slist_free_1(cur);
	    }
	  } 
	}

	/* replace e with its duplicate */
	gts_edge_replace(e, duplicate);

	/* Reattach the parent segments */
	if( edge != NULL ) {
	  ii = parents;
	  while(ii!=NULL) {
	    e->triangles = g_slist_prepend(e->triangles, ii->data);
	    ii = g_slist_next(ii);
	  }
	  g_slist_free(parents);
	  parents = NULL;
	}

	if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) {
	  /* destroy e */
	  gts_object_destroy(GTS_OBJECT (e));
	}
      }
    }
    i = g_slist_next(i);
  }
  
  /* don't forget to reset to default */
  gts_allow_floating_edges = FALSE;

  /* free list of edges */
  g_slist_free (edges);
}
Ejemplo n.º 25
0
static void gts_constraint_split (GtsConstraint * c, 
				  GtsSurface * s,
				  GtsFifo * fifo)
{
  GSList * i;
  GtsVertex * v1, * v2;
  GtsEdge * e;

  g_return_if_fail (c != NULL);
  g_return_if_fail (s != NULL);

  v1 = GTS_SEGMENT (c)->v1;
  v2 = GTS_SEGMENT (c)->v2;
  e = GTS_EDGE (c);

  i = e->triangles;
  while (i) {
    GtsFace * f = i->data;
    if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) {
      GtsVertex * v = gts_triangle_vertex_opposite (GTS_TRIANGLE (f), e);
      if (gts_point_orientation (GTS_POINT (v1), 
				 GTS_POINT (v2), 
				 GTS_POINT (v)) == 0.) {
	GSList * j = e->triangles;
	GtsFace * f1 = NULL;
	GtsEdge * e1, * e2;

	/* replaces edges with constraints */
	gts_triangle_vertices_edges (GTS_TRIANGLE (f), e,
				     &v1, &v2, &v, &e, &e1, &e2);
	if (!GTS_IS_CONSTRAINT (e1)) {
	  GtsEdge * ne1 = 
	    gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v2, v);
	  gts_edge_replace (e1, ne1);
	  gts_object_destroy (GTS_OBJECT (e1));
	  e1 = ne1;
	  if (fifo) gts_fifo_push (fifo, e1);
	}
	if (!GTS_IS_CONSTRAINT (e2)) {
	  GtsEdge * ne2 = 
	    gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v, v1);
	  gts_edge_replace (e2, ne2);
	  gts_object_destroy (GTS_OBJECT (e2));
	  e2 = ne2;
	  if (fifo) gts_fifo_push (fifo, e2);
	}

	/* look for face opposite */
	while (j && !f1) {
	  if (GTS_IS_FACE (j->data) && 
	      gts_face_has_parent_surface (j->data, s))
	    f1 = j->data;
	  j = j->next;
	}
	if (f1) { /* c is not a boundary of s */
	  GtsEdge * e3, * e4, * e5;
	  GtsVertex * v3;
	  gts_triangle_vertices_edges (GTS_TRIANGLE (f1), e,
				       &v1, &v2, &v3, &e, &e3, &e4);
	  e5 = gts_edge_new (s->edge_class, v, v3);
	  gts_surface_add_face (s, gts_face_new (s->face_class, e5, e2, e3));
	  gts_surface_add_face (s, gts_face_new (s->face_class, e5, e4, e1));
	  gts_object_destroy (GTS_OBJECT (f1));
	}
	gts_object_destroy (GTS_OBJECT (f));
	return;
      }
    }
    i = i->next;
  }
}
Ejemplo n.º 26
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;
}
Ejemplo n.º 27
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;
}
Ejemplo n.º 28
0
int main (int argc, char * argv[])
{
  GPtrArray * vertices;
  GtsFifo * edges;
  guint i, line;
  GtsTriangle * t;
  GtsVertex * v1, * v2, * v3;
  GtsSurface * surface;
  gboolean keep_hull = TRUE;
  gboolean verbose = FALSE;
  gboolean add_constraints = TRUE;
  gboolean remove_holes = FALSE;
  gboolean check_delaunay = FALSE;
  gboolean conform = FALSE;
  gboolean refine = FALSE;
  gboolean split_constraints = FALSE;
  gboolean randomize = FALSE;
  gboolean remove_duplicates = FALSE;
  gint steiner_max = -1;
  gdouble quality = 0., area = G_MAXDOUBLE;
  int c = 0, status = 0;
  const char * fname = NULL;
  GTimer * timer;

  /* parse options using getopt */
  while (c != EOF) {
#ifdef HAVE_GETOPT_LONG
    static struct option long_options[] = {
      {"duplicates", no_argument, NULL, 'd'},
      {"help", no_argument, NULL, 'h'},
      {"verbose", no_argument, NULL, 'v'},
      {"randomize", no_argument, NULL, 'r'},
      {"hull", no_argument, NULL, 'b'},
      {"noconst", no_argument, NULL, 'e'},
      {"holes", no_argument, NULL, 'H'},
      {"split", no_argument, NULL, 'S'},
      {"check", no_argument, NULL, 'c'},
      {"files", required_argument, NULL, 'f'},
      {"conform", no_argument, NULL, 'o'},
      {"steiner", required_argument, NULL, 's'},
      {"quality", required_argument, NULL, 'q'},
      {"area", required_argument, NULL, 'a'}
    };
    int option_index = 0;
    switch ((c = getopt_long (argc, argv, "hvbecf:os:q:a:HSrd",
			      long_options, &option_index))) {
#else /* not HAVE_GETOPT_LONG */
    switch ((c = getopt (argc, argv, "hvbecf:os:q:a:HSrd"))) {
#endif /* not HAVE_GETOPT_LONG */
    case 'd': /* duplicates */
      remove_duplicates = TRUE;
      break;
    case 'b': /* do not keep convex hull */
      keep_hull = FALSE;
      break;
    case 'e': /* do not add constrained edges */
      add_constraints = FALSE;
      break;
    case 'H': /* remove holes */
      remove_holes = TRUE;
      break;
    case 'S': /* split constraints */
      split_constraints = TRUE;
      break;
    case 'r': /* randomize */
      randomize = TRUE;
      break;
    case 'c': /* check Delaunay property */
      check_delaunay = TRUE;
      break;
    case 'f': /* generates files */
      fname = optarg;
      break;      
    case 'v': /* verbose */
      verbose = TRUE;
      break;
    case 'o': /* conform */
      conform = TRUE;
      break;
    case 's': /* steiner */
      steiner_max = atoi (optarg);
      break;
    case 'q': /* quality */
      conform = TRUE;
      refine = TRUE;
      quality = atof (optarg);
      break;
    case 'a': /* area */
      conform = TRUE;
      refine = TRUE;
      area = atof (optarg);
      break;
    case 'h': /* help */
      fprintf (stderr,
             "Usage: delaunay [OPTION] < file.gts\n"
	     "Construct the constrained Delaunay triangulation of the input\n"
	     "\n"
	     "  -b       --hull         do not keep convex hull\n"
	     "  -e       --noconst      do not add constrained edges\n"
	     "  -S       --split        split constraints (experimental)\n"
	     "  -H       --holes        remove holes from the triangulation\n"
	     "  -d       --duplicates   remove duplicate vertices\n"
	     "  -r       --randomize    shuffle input vertex list\n"
	     "  -c       --check        check Delaunay property\n"
	     "  -f FNAME --files=FNAME  generate evolution files\n"
	     "  -o       --conform      generate conforming triangulation\n"
	     "  -s N     --steiner=N    maximum number of Steiner points for\n"
	     "                          conforming triangulation (default is no limit)\n"
	     "  -q Q     --quality=Q    Set the minimum acceptable face quality\n"
	     "  -a A     --area=A       Set the maximum acceptable face area\n"
	     "  -v       --verbose      print statistics about the triangulation\n"
	     "  -h       --help         display this help and exit\n"
	     "\n"
	     "Reports bugs to %s\n",
	     GTS_MAINTAINER);
      return 0; /* success */
      break;
    case '?': /* wrong options */
      fprintf (stderr, "Try `delaunay --help' for more information.\n");
      return 1; /* failure */
    }
  }

  /* read file => two lists: vertices and constraints */

  edges = gts_fifo_new ();
  vertices = g_ptr_array_new ();
  if (add_constraints) /* the edge class is a GtsConstraintClass */
    line = read_list (vertices, edges, 
		      GTS_EDGE_CLASS (gts_constraint_class ()),
		      stdin);
  else /* the edge class is a "normal" edge: GtsEdgeClass */
    line = read_list (vertices, edges, 
		      gts_edge_class (), 
		      stdin);

  if (line > 0) {
    fprintf (stderr, "delaunay: error in input file at line %u\n", line);
    return 1;
  }

  timer = g_timer_new ();
  g_timer_start (timer);

  if (randomize)
    shuffle_array (vertices);

  /* create triangle enclosing all the vertices */
  {
    GSList * list = NULL;
    for (i = 0; i < vertices->len; i++)
      list = g_slist_prepend (list, g_ptr_array_index (vertices, i));
    t = gts_triangle_enclosing (gts_triangle_class (), list, 100.);
    g_slist_free (list);
  }
  gts_triangle_vertices (t, &v1, &v2, &v3);

  /* create surface with one face: the enclosing triangle */
  surface = gts_surface_new (gts_surface_class (),
			     gts_face_class (),
			     gts_edge_class (),
			     gts_vertex_class ());
  gts_surface_add_face (surface, gts_face_new (gts_face_class (),
					       t->e1, t->e2, t->e3));

  /* add vertices */
  for (i = 0; i < vertices->len; i++) {
    GtsVertex * v1 = g_ptr_array_index (vertices, i);
    GtsVertex * v = gts_delaunay_add_vertex (surface, v1, NULL);

    g_assert (v != v1);
    if (v != NULL) {
      if (!remove_duplicates) {
	fprintf (stderr, "delaunay: duplicate vertex (%g,%g) in input file\n",
		 GTS_POINT (v)->x, GTS_POINT (v)->y);
	return 1; /* Failure */
      }
      else
	gts_vertex_replace (v1, v);
    }
    if (fname) {
      static guint nf = 1;
      char s[80];
      FILE * fp;

      g_snprintf (s, 80, "%s.%u", fname, nf++);
      fp = fopen (s, "wt");
      gts_surface_write_oogl (surface, fp);
      fclose (fp);

      if (check_delaunay && gts_delaunay_check (surface)) {
	fprintf (stderr, "delaunay: triangulation is not Delaunay\n");
	return 1;
      }
    }
  }
  g_ptr_array_free (vertices, TRUE);

  /* add remaining constraints */
  if (add_constraints)
    gts_fifo_foreach (edges, (GtsFunc) add_constraint, surface);

  /* destroy enclosing triangle */
  gts_allow_floating_vertices = TRUE;
  gts_object_destroy (GTS_OBJECT (v1));
  gts_object_destroy (GTS_OBJECT (v2));
  gts_object_destroy (GTS_OBJECT (v3));
  gts_allow_floating_vertices = FALSE;

  if (!keep_hull)
    gts_delaunay_remove_hull (surface);

  if (remove_holes)
    delaunay_remove_holes (surface);

  if (split_constraints) {
    gpointer data[2];

    data[0] = surface;
    data[1] = edges;
    gts_fifo_foreach (edges, (GtsFunc) split_constraint, data);
  }

  if (conform) {
    guint encroached_number = 
      gts_delaunay_conform (surface, 
			    steiner_max,
			    (GtsEncroachFunc) gts_vertex_encroaches_edge,
			    NULL);
    if (encroached_number == 0 && refine) {
      guint unrefined_number;
      gpointer data[2];
      
      data[0] = &quality;
      data[1] = &area;
      unrefined_number = 
	gts_delaunay_refine (surface, 
			     steiner_max,
			     (GtsEncroachFunc) gts_vertex_encroaches_edge,
			     NULL,
			     (GtsKeyFunc) triangle_cost,
			     data);
      if (verbose && unrefined_number > 0)
	fprintf (stderr, 
		 "delaunay: ran out of Steiner points (max: %d) during refinement\n"
		 "%d unrefined faces left\n",
		 steiner_max, unrefined_number);
    }
    else if (verbose && encroached_number > 0)
      fprintf (stderr, 
	       "delaunay: ran out of Steiner points (max: %d) during conforming\n"
	       "Delaunay triangulation: %d encroached constraints left\n",
	       steiner_max, encroached_number);
  }
  g_timer_stop (timer);

  if (verbose) {
    gts_surface_print_stats (surface, stderr);
    fprintf (stderr, "# Triangulation time: %g s speed: %.0f vertex/s\n", 
	  g_timer_elapsed (timer, NULL),
	  gts_surface_vertex_number (surface)/g_timer_elapsed (timer, NULL));
  }

  if (check_delaunay && gts_delaunay_check (surface)) {
    fprintf (stderr, "delaunay: triangulation is not Delaunay\n");
    status = 1; /* failure */
  }

  /* write triangulation */
  gts_surface_write (surface, stdout);

  return status;
}
Ejemplo n.º 29
0
/* This function is modified from the original in GTS in order to avoid 
 * deallocating any objects referenced by the live-objects table.  The 
 * approach is similar to what is used for replace() in vertex.c.
 */
GList*
pygts_vertices_merge(GList* vertices, gdouble epsilon,
		     gboolean (* check) (GtsVertex *, GtsVertex *))
{
  GPtrArray *array;
  GList *i, *next;
  GNode *kdtree;
  GtsVertex *v;
  GtsBBox *bbox;
  GSList *selected, *j;
  GtsVertex *sv;
  PygtsObject *obj;
  PygtsVertex *vertex=NULL;
  GSList *parents=NULL, *ii,*cur;

  g_return_val_if_fail(vertices != NULL, 0);

  array = g_ptr_array_new();
  i = vertices;
  while (i) {
    g_ptr_array_add(array, i->data);
    i = g_list_next(i);
  }
  kdtree = gts_kdtree_new(array, NULL);
  g_ptr_array_free(array, TRUE);

  i = vertices;
  while(i) {
    v = (GtsVertex*)i->data;
    if (!GTS_OBJECT(v)->reserved) { /* Do something only if v is active */

      /* build bounding box */
      bbox = gts_bbox_new(gts_bbox_class(), v, 
			  GTS_POINT(v)->x - epsilon,
			  GTS_POINT(v)->y - epsilon,
			  GTS_POINT(v)->z - epsilon,
			  GTS_POINT(v)->x + epsilon,
			  GTS_POINT(v)->y + epsilon,
			  GTS_POINT(v)->z + epsilon);

      /* select vertices which are inside bbox using kdtree */
      j = selected = gts_kdtree_range(kdtree, bbox, NULL);
      while(j) {
        sv = (GtsVertex*)j->data;
        if( sv!=v && !GTS_OBJECT(sv)->reserved && (!check||(*check)(sv, v)) ) {
          /* sv is not v and is active */
	  if( (obj = (PygtsObject*)g_hash_table_lookup(obj_table,GTS_OBJECT(sv))) !=NULL ) {
	    vertex = PYGTS_VERTEX(obj);
	    /* Detach and save any parent segments */
	    ii = sv->segments;
	    while(ii!=NULL) {
	      cur = ii;
	      ii = g_slist_next(ii);
	      if(PYGTS_IS_PARENT_SEGMENT(cur->data)) {
		sv->segments = g_slist_remove_link(sv->segments, cur);
		parents = g_slist_prepend(parents,cur->data);
		g_slist_free_1(cur);
	      }
	    } 
	  }

          gts_vertex_replace(sv, v);
          GTS_OBJECT(sv)->reserved = sv; /* mark sv as inactive */

	  /* Reattach the parent segments */
	  if( vertex != NULL ) {
	    ii = parents;
	    while(ii!=NULL) {
	      sv->segments = g_slist_prepend(sv->segments, ii->data);
	      ii = g_slist_next(ii);
	    }
	    g_slist_free(parents);
	    parents = NULL;
	  }
	  vertex = NULL;
        }
        j = g_slist_next(j);
      }
      g_slist_free(selected);
      gts_object_destroy(GTS_OBJECT(bbox));
    }
    i = g_list_next(i);
  }
  gts_kdtree_destroy(kdtree);


  /* destroy inactive vertices and removes them from list */

  /* we want to control vertex destruction */
  gts_allow_floating_vertices = TRUE;

  i = vertices;
  while (i) {
    v = (GtsVertex*)i->data;
    next = g_list_next(i);
    if(GTS_OBJECT(v)->reserved) { /* v is inactive */
      if( g_hash_table_lookup(obj_table,GTS_OBJECT(v))==NULL ) {
	gts_object_destroy(GTS_OBJECT(v));
      }
      else {
	GTS_OBJECT(v)->reserved = 0;
      }
      vertices = g_list_remove_link(vertices, i);
      g_list_free_1(i);
    }
    i = next;
  }
  gts_allow_floating_vertices = FALSE; 

  return vertices;
}
Ejemplo n.º 30
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;
}