Exemple #1
0
/**
 * Try to flip a given edge. If successfull, return the new edge on
 * @ref new_edge, append the new triangles to @ref new_tris and return
 * TRUE.
 * THE NEW TRIANGLES MUST BE UNREFFED!
 * THE NEW EDGE MUST BE UNREFFED!
 */
static gboolean
p2tr_cdt_try_flip (P2trCDT   *self,
                   P2trEdge  *to_flip,
                   GQueue    *new_tris,
                   P2trEdge **new_edge)
{
    /*    C
     *  / | \
     * B-----A    to_flip: A->B
     *  \ | /     to_flip.Tri: ABC
     *    D
     */
    P2trPoint *A, *B, *C, *D;
    P2trTriangle *ABC, *ADB;
    P2trEdge *DC;

    new_edge = NULL;

    if (to_flip->constrained || to_flip->delaunay)
    {
        return FALSE;
    }

    A = P2TR_EDGE_START (to_flip);
    B = to_flip->end;
    C = p2tr_triangle_get_opposite_point (to_flip->tri, to_flip);
    D = p2tr_triangle_get_opposite_point (to_flip->mirror->tri, to_flip->mirror);

    ABC = to_flip->tri;
    ADB = to_flip->mirror->tri;

    /* Check if the quadriliteral ADBC is concave (because if it is, we
     * can't flip the edge) */
    if (p2tr_triangle_get_angle_at(ABC, A) + p2tr_triangle_get_angle_at(ADB, A) >= G_PI)
        return FALSE;
    if (p2tr_triangle_get_angle_at(ABC, B) + p2tr_triangle_get_angle_at(ADB, B) >= G_PI)
        return FALSE;

    p2tr_edge_remove (to_flip);

    DC = p2tr_mesh_new_edge (self->mesh, D, C, FALSE);
    DC->delaunay = DC->mirror->delaunay = TRUE;

    g_queue_push_tail (new_tris, p2tr_mesh_new_triangle (self->mesh,
                       p2tr_point_get_edge_to (C, A),
                       p2tr_point_get_edge_to (A, D),
                       DC));

    g_queue_push_tail (new_tris, p2tr_mesh_new_triangle (self->mesh,
                       p2tr_point_get_edge_to (D, B),
                       p2tr_point_get_edge_to (B, C),
                       DC->mirror));

    *new_edge = DC;

    return TRUE;
}
Exemple #2
0
/**
 * Try to flip a given edge, If successfull, return the new edge (reffed!),
 * otherwise return NULL
 */
P2trEdge*
p2tr_cdt_try_flip (P2trCDT   *self,
                   P2trEdge  *to_flip)
{
  /*    C
   *  / | \
   * B-----A    to_flip: A->B
   *  \ | /     to_flip.Tri: ABC
   *    D
   */
  P2trPoint *A, *B, *C, *D;
  P2trEdge *AB, *CA, *AD, *DB, *BC, *DC;

  g_assert (! to_flip->constrained && ! to_flip->delaunay);

  A = P2TR_EDGE_START (to_flip);
  B = to_flip->end;
  C = p2tr_triangle_get_opposite_point (to_flip->tri, to_flip, FALSE);
  D = p2tr_triangle_get_opposite_point (to_flip->mirror->tri, to_flip->mirror, FALSE);

  AB = to_flip;

  /* Check if the quadriliteral ADBC is concave (because if it is, we
   * can't flip the edge) */
  if (p2tr_triangle_circumcircle_contains_point (AB->tri, &D->c) != P2TR_INCIRCLE_IN)
    return NULL;

  CA = p2tr_point_get_edge_to (C, A, FALSE);
  AD = p2tr_point_get_edge_to (A, D, FALSE);
  DB = p2tr_point_get_edge_to (D, B, FALSE);
  BC = p2tr_point_get_edge_to (B, C, FALSE);

  p2tr_edge_remove (AB);

  DC = p2tr_mesh_new_edge (self->mesh, D, C, FALSE);

  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh,
      CA, AD, DC));

  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh,
      DB, BC, DC->mirror));

  return DC;
}
Exemple #3
0
/** Insert a point into a triangle. This function assumes the point is
 * inside the triangle - not on one of its edges and not outside of it.
 */
void
p2tr_cdt_insert_point_into_triangle (P2trCDT      *self,
                                     P2trPoint    *P,
                                     P2trTriangle *tri)
{
  P2trVEdgeSet *flip_candidates = p2tr_vedge_set_new ();

  P2trPoint *A = tri->edges[0]->end;
  P2trPoint *B = tri->edges[1]->end;
  P2trPoint *C = tri->edges[2]->end;

  P2trEdge *CA = tri->edges[0];
  P2trEdge *AB = tri->edges[1];
  P2trEdge *BC = tri->edges[2];

  P2trEdge *AP, *BP, *CP;

  p2tr_triangle_remove (tri);

  AP = p2tr_mesh_new_edge (self->mesh, A, P, FALSE);
  BP = p2tr_mesh_new_edge (self->mesh, B, P, FALSE);
  CP = p2tr_mesh_new_edge (self->mesh, C, P, FALSE);

  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, AB, BP, AP->mirror));
  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, BC, CP, BP->mirror));
  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, CA, AP, CP->mirror));

  p2tr_vedge_set_add (flip_candidates, CP);
  p2tr_vedge_set_add (flip_candidates, AP);
  p2tr_vedge_set_add (flip_candidates, BP);

  p2tr_vedge_set_add (flip_candidates, p2tr_edge_ref (CA));
  p2tr_vedge_set_add (flip_candidates, p2tr_edge_ref (AB));
  p2tr_vedge_set_add (flip_candidates, p2tr_edge_ref (BC));

  /* Flip fix the newly created triangles to preserve the the
   * constrained delaunay property. The flip-fix function will unref the
   * new triangles for us! */
  p2tr_cdt_flip_fix (self, flip_candidates);

  p2tr_vedge_set_free (flip_candidates);
}
Exemple #4
0
/** Insert a point into a triangle. This function assumes the point is
 * inside the triangle - not on one of its edges and not outside of it.
 */
void
p2tr_cdt_insert_point_into_triangle (P2trCDT      *self,
                                     P2trPoint    *P,
                                     P2trTriangle *tri)
{
    GList *new_tris;

    P2trPoint *A = tri->edges[0]->end;
    P2trPoint *B = tri->edges[1]->end;
    P2trPoint *C = tri->edges[2]->end;

    P2trEdge *CA = tri->edges[1];
    P2trEdge *AB = tri->edges[2];
    P2trEdge *BC = tri->edges[0];

    P2trEdge *AP, *BP, *CP;

    p2tr_triangle_remove (tri);

    AP = p2tr_mesh_new_edge (self->mesh, A, P, FALSE);
    BP = p2tr_mesh_new_edge (self->mesh, B, P, FALSE);
    CP = p2tr_mesh_new_edge (self->mesh, C, P, FALSE);

    new_tris = p2tr_utils_new_reversed_pointer_list (3,
               p2tr_mesh_new_triangle (self->mesh, AB, BP, AP->mirror),
               p2tr_mesh_new_triangle (self->mesh, BC, CP, BP->mirror),
               p2tr_mesh_new_triangle (self->mesh, CA, AP, CP->mirror));

    p2tr_edge_unref (CP);
    p2tr_edge_unref (BP);
    p2tr_edge_unref (AP);

    /* Flip fix the newly created triangles to preserve the the
     * constrained delaunay property. The flip-fix function will unref the
     * new triangles for us! */
    p2tr_cdt_flip_fix (self, new_tris);

    g_list_free (new_tris);
}
Exemple #5
0
/**
 * Triangulate a polygon by creating edges to a center point.
 * 1. If there is a NULL point in the polygon, two triangles are not
 *    created (these are the two that would have used it)
 * 2. THE RETURNED TRIANGLES MUST BE UNREFFED!
 */
static GList*
p2tr_cdt_triangulate_fan (P2trCDT   *self,
                          P2trPoint *center,
                          GList     *edge_pts)
{
    GList *new_tris = NULL;
    GList *iter;

    /* We can not triangulate unless at least two points are given */
    if (edge_pts == NULL || edge_pts->next == NULL)
    {
        p2tr_exception_programmatic ("Not enough points to triangulate as"
                                     " a star!");
    }

    for (iter = edge_pts; iter != NULL; iter = iter->next)
    {
        P2trPoint *A = (P2trPoint*) iter->data;
        P2trPoint *B = (P2trPoint*) g_list_cyclic_next (edge_pts, iter)->data;
        P2trEdge *AB, *BC, *CA;
        P2trTriangle *tri;

        if (A == NULL || B == NULL)
            continue;

        AB = p2tr_point_get_edge_to (A, B);
        BC = p2tr_mesh_new_or_existing_edge (self->mesh, B, center, FALSE);
        CA = p2tr_mesh_new_or_existing_edge (self->mesh, center, A, FALSE);

        tri = p2tr_mesh_new_triangle (self->mesh, AB, BC, CA);
        new_tris = g_list_prepend (new_tris, tri);

        p2tr_edge_unref (BC);
        p2tr_edge_unref (CA);
    }

    return new_tris;
}
Exemple #6
0
/**
 * Triangulate a polygon by creating edges to a center point.
 * 1. If there is a NULL point in the polygon, two triangles are not
 *    created (these are the two that would have used it)
 * 2. THE RETURNED EDGES MUST BE UNREFFED!
 */
static P2trVEdgeSet*
p2tr_cdt_triangulate_fan (P2trCDT   *self,
                          P2trPoint *center,
                          GList     *edge_pts)
{
  P2trVEdgeSet* fan_edges = p2tr_vedge_set_new ();
  GList *iter;

  /* We can not triangulate unless at least two points are given */
  if (edge_pts == NULL || edge_pts->next == NULL)
    {
      p2tr_exception_programmatic ("Not enough points to triangulate as"
          " a star!");
    }

  for (iter = edge_pts; iter != NULL; iter = iter->next)
    {
      P2trPoint *A = (P2trPoint*) iter->data;
      P2trPoint *B = (P2trPoint*) g_list_cyclic_next (edge_pts, iter)->data;
      P2trEdge *AB, *BC, *CA;

      if (A == NULL || B == NULL)
        continue;

      AB = p2tr_point_get_edge_to (A, B, TRUE);
      BC = p2tr_mesh_new_or_existing_edge (self->mesh, B, center, FALSE);
      CA = p2tr_mesh_new_or_existing_edge (self->mesh, center, A, FALSE);

      p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, AB, BC, CA));

      p2tr_vedge_set_add (fan_edges, CA);
      p2tr_vedge_set_add (fan_edges, BC);
      p2tr_vedge_set_add (fan_edges, AB);
    }

  return fan_edges;
}
Exemple #7
0
P2trCDT* p2tr_cdt_new (P2tCDT *cdt)
{
    P2tTrianglePtrArray cdt_tris = p2t_cdt_get_triangles (cdt);
    GHashTable *point_map = g_hash_table_new (g_direct_hash, g_direct_equal);
    P2trCDT *rmesh = g_slice_new (P2trCDT);

    gint i, j;

    rmesh->mesh = p2tr_mesh_new ();
    rmesh->outline = p2tr_pslg_new ();

    /* First iteration over the CDT - create all the points */
    for (i = 0; i < cdt_tris->len; i++)
    {
        P2tTriangle *cdt_tri = triangle_index (cdt_tris, i);
        for (j = 0; j < 3; j++)
        {
            P2tPoint *cdt_pt = p2t_triangle_get_point(cdt_tri, j);
            P2trPoint *new_pt = g_hash_table_lookup (point_map, cdt_pt);

            if (new_pt == NULL)
            {
                new_pt = p2tr_point_new2 (cdt_pt->x, cdt_pt->y);
                g_hash_table_insert (point_map, cdt_pt, new_pt);
            }
        }
    }

    /* Second iteration over the CDT - create all the edges and find the
     * outline */
    for (i = 0; i < cdt_tris->len; i++)
    {
        P2tTriangle *cdt_tri = triangle_index (cdt_tris, i);

        for (j = 0; j < 3; j++)
        {
            P2tPoint *start = p2t_triangle_get_point (cdt_tri, j);
            P2tPoint *end = p2t_triangle_get_point (cdt_tri, (j + 1) % 3);
            int edge_index = p2t_triangle_edge_index (cdt_tri, start, end);

            P2trPoint *start_new = g_hash_table_lookup (point_map, start);
            P2trPoint *end_new = g_hash_table_lookup (point_map, end);

            if (! p2tr_point_has_edge_to (start_new, end_new))
            {
                gboolean constrained = cdt_tri->constrained_edge[edge_index];
                P2trEdge *edge = p2tr_mesh_new_edge (rmesh->mesh, start_new, end_new, constrained);

                /* If the edge is constrained, we should add it to the
                 * outline */
                if (constrained)
                    p2tr_pslg_add_new_line(rmesh->outline, &start_new->c,
                                           &end_new->c);

                /* We only wanted to create the edge now. We will use it
                 * later */
                p2tr_edge_unref (edge);
            }
        }
    }

    /* Third iteration over the CDT - create all the triangles */
    for (i = 0; i < cdt_tris->len; i++)
    {
        P2tTriangle *cdt_tri = triangle_index (cdt_tris, i);

        P2trPoint *pt1 = g_hash_table_lookup (point_map, p2t_triangle_get_point (cdt_tri, 0));
        P2trPoint *pt2 = g_hash_table_lookup (point_map, p2t_triangle_get_point (cdt_tri, 1));
        P2trPoint *pt3 = g_hash_table_lookup (point_map, p2t_triangle_get_point (cdt_tri, 2));

        P2trTriangle *new_tri = p2tr_mesh_new_triangle (rmesh->mesh,
                                p2tr_point_get_edge_to(pt1, pt2),
                                p2tr_point_get_edge_to(pt2, pt3),
                                p2tr_point_get_edge_to(pt3, pt1));

        /* We won't do any usage of the triangle, so just unref it */
        p2tr_triangle_unref (new_tri);
    }

    return rmesh;
}
Exemple #8
0
P2trCDT*
p2tr_cdt_new (P2tCDT *cdt)
{
  P2tTrianglePtrArray cdt_tris = p2t_cdt_get_triangles (cdt);
  GHashTable *point_map = g_hash_table_new (g_direct_hash, g_direct_equal);
  P2trCDT *rmesh = g_slice_new (P2trCDT);
  GHashTableIter iter;
  P2trPoint *pt_iter = NULL;

  P2trVEdgeSet *new_edges = p2tr_vedge_set_new ();

  guint i, j;

  rmesh->mesh = p2tr_mesh_new ();
  rmesh->outline = p2tr_pslg_new ();

  /* First iteration over the CDT - create all the points */
  for (i = 0; i < cdt_tris->len; i++)
  {
    P2tTriangle *cdt_tri = triangle_index (cdt_tris, i);
    for (j = 0; j < 3; j++)
      {
        P2tPoint *cdt_pt = p2t_triangle_get_point(cdt_tri, j);
        P2trPoint *new_pt = (P2trPoint*) g_hash_table_lookup (point_map, cdt_pt);

        if (new_pt == NULL)
          {
            new_pt = p2tr_mesh_new_point2 (rmesh->mesh, cdt_pt->x, cdt_pt->y);
            g_hash_table_insert (point_map, cdt_pt, new_pt);
          }
      }
  }

  /* Second iteration over the CDT - create all the edges and find the
   * outline */
  for (i = 0; i < cdt_tris->len; i++)
  {
    P2tTriangle *cdt_tri = triangle_index (cdt_tris, i);

    for (j = 0; j < 3; j++)
      {
        P2tPoint *start = p2t_triangle_get_point (cdt_tri, j);
        P2tPoint *end = p2t_triangle_get_point (cdt_tri, (j + 1) % 3);
        int edge_index = p2t_triangle_edge_index (cdt_tri, start, end);

        P2trPoint *start_new = (P2trPoint*) g_hash_table_lookup (point_map, start);
        P2trPoint *end_new = (P2trPoint*) g_hash_table_lookup (point_map, end);

        if (! p2tr_point_has_edge_to (start_new, end_new))
          {
            gboolean constrained = cdt_tri->constrained_edge[edge_index]
            || cdt_tri->neighbors_[edge_index] == NULL;
            P2trEdge *edge = p2tr_mesh_new_edge (rmesh->mesh, start_new, end_new, constrained);

            /* If the edge is constrained, we should add it to the
             * outline */
            if (constrained)
              p2tr_pslg_add_new_line(rmesh->outline, &start_new->c,
                  &end_new->c);

            /* We only wanted to create the edge now. We will use it
             * later */
            p2tr_vedge_set_add (new_edges, edge);
          }
      }
  }

  /* Third iteration over the CDT - create all the triangles */
  for (i = 0; i < cdt_tris->len; i++)
  {
    P2tTriangle *cdt_tri = triangle_index (cdt_tris, i);

    P2trPoint *pt1 = (P2trPoint*) g_hash_table_lookup (point_map, p2t_triangle_get_point (cdt_tri, 0));
    P2trPoint *pt2 = (P2trPoint*) g_hash_table_lookup (point_map, p2t_triangle_get_point (cdt_tri, 1));
    P2trPoint *pt3 = (P2trPoint*) g_hash_table_lookup (point_map, p2t_triangle_get_point (cdt_tri, 2));

    P2trTriangle *new_tri = p2tr_mesh_new_triangle (rmesh->mesh,
        p2tr_point_get_edge_to(pt1, pt2, FALSE),
        p2tr_point_get_edge_to(pt2, pt3, FALSE),
        p2tr_point_get_edge_to(pt3, pt1, FALSE));

    /* We won't do any usage of the triangle, so just unref it */
    p2tr_triangle_unref (new_tri);
  }

  /* And do an extra flip fix */
  p2tr_cdt_flip_fix (rmesh, new_edges);

  p2tr_vedge_set_free (new_edges);

  /* Now finally unref the points we added into the map */
  g_hash_table_iter_init (&iter, point_map);
  while (g_hash_table_iter_next (&iter, NULL, (gpointer*)&pt_iter))
    p2tr_point_unref (pt_iter);
  g_hash_table_destroy (point_map);

  return rmesh;
}