Example #1
0
/**
 * Insert a point so that is splits an existing edge. This function
 * assumes that the point is on the edge itself and between its
 * end-points.
 * If the edge being split is constrained, then the function returns a
 * list containing both parts resulted from the splitting. In that case,
 * THE RETURNED EDGES MUST BE UNREFERENCED!
 */
GList*
p2tr_cdt_split_edge (P2trCDT   *self,
                     P2trEdge  *e,
                     P2trPoint *C)
{
    /*      W
     *     /|\
     *    / | \
     *   /  |  \      E.Mirror.Tri: YXW
     * X*---*---*Y    E: X->Y
     *   \  |C /      E.Tri: XYV
     *    \ | /
     *     \|/
     *      V
     */
    P2trPoint *X = P2TR_EDGE_START (e), *Y = e->end;
    P2trPoint *V = (e->tri != NULL) ? p2tr_triangle_get_opposite_point(e->tri, e) : NULL;
    P2trPoint *W = (e->mirror->tri != NULL) ? p2tr_triangle_get_opposite_point (e->mirror->tri, e->mirror) : NULL;
    gboolean   constrained = e->constrained;
    P2trEdge  *XC, *CY;
    GList     *new_tris = NULL, *fan = NULL, *new_edges = NULL;

    p2tr_edge_remove (e);

    XC = p2tr_mesh_new_edge (self->mesh, X, C, constrained);
    CY = p2tr_mesh_new_edge (self->mesh, C, Y, constrained);

    fan = p2tr_utils_new_reversed_pointer_list (4, W, X, V, Y);
    new_tris = p2tr_cdt_triangulate_fan (self, C, fan);
    g_list_free (fan);

    /* Now make this a CDT again
     * The new triangles will be unreffed by the flip_fix function, which
     * is good since we receive them with an extra reference!
     */
    p2tr_cdt_flip_fix (self, new_tris);
    g_list_free (new_tris);

    if (constrained)
    {
        /* If this was a subsegment, then both parts of the subsegment
         * should exist */
        if (p2tr_edge_is_removed (XC) || p2tr_edge_is_removed (CY))
            p2tr_exception_geometric ("Subsegments gone!");
        else
        {
            new_edges = g_list_prepend (new_edges, CY);
            new_edges = g_list_prepend (new_edges, XC);
        }
    }
    else
    {
        p2tr_edge_unref (XC);
        p2tr_edge_unref (CY);
    }

    p2tr_cdt_on_new_point (self, C);

    return new_edges;
}
Example #2
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;
}
Example #3
0
/**
 * THE GIVEN INPUT TRIANGLES MUST BE GIVEN WITH AN EXTRA REFERENCE SINCE
 * THEY WILL BE UNREFFED!
 */
static void
p2tr_cdt_flip_fix (P2trCDT *self,
                   GList   *initial_triangles)
{
    GQueue flipped_edges, tris_to_fix;
    GList *iter;

    g_queue_init (&flipped_edges);
    g_queue_init (&tris_to_fix);

    for (iter = initial_triangles; iter != NULL; iter = iter->next)
        g_queue_push_tail (&tris_to_fix, iter->data);

    while (! g_queue_is_empty (&tris_to_fix))
    {
        P2trTriangle *tri = (P2trTriangle*)g_queue_pop_head (&tris_to_fix);
        P2trCircle   circum_circle;
        gint         i;

        if (p2tr_triangle_is_removed (tri))
        {
            p2tr_triangle_unref (tri);
            continue;
        }

        p2tr_triangle_get_circum_circle (tri, &circum_circle);

        for (i = 0; i < 3; i++)
        {
            P2trEdge  *e = tri->edges[i];
            P2trPoint *opposite;

            if (e->constrained || e->delaunay)
                continue;

            opposite = p2tr_triangle_get_opposite_point (e->mirror->tri, e->mirror);
            if (! p2tr_circle_test_point_outside(&circum_circle, &opposite->c))
            {
                P2trEdge *flipped;
                if (p2tr_cdt_try_flip (self, e, &tris_to_fix, &flipped))
                {
                    g_queue_push_tail (&flipped_edges, flipped);
                    /* Stop iterating this triangle since it doesn't exist
                     * any more */
                    break;
                }
            }
        }

        /* We are finished with the triangle, so unref it as promised */
        p2tr_triangle_unref (tri);
    }

    while (! g_queue_is_empty (&flipped_edges))
    {
        P2trEdge *e = (P2trEdge*) g_queue_pop_head (&flipped_edges);
        e->delaunay = e->mirror->delaunay = FALSE;
        p2tr_edge_unref (e);
    }
}
Example #4
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;
}
Example #5
0
void
p2tr_cdt_flip_fix (P2trCDT     *self,
                   P2trVEdgeSet *candidates)
{
  P2trEdge *edge;
  P2trVEdge *vedge;

  while (p2tr_vedge_set_pop (candidates, &vedge))
    {
      if (! p2tr_vedge_try_get_and_unref (vedge, &edge))
        continue;

      if (! edge->constrained
          /* TODO: we probably don't need this check... */
          && ! p2tr_edge_is_removed (edge))
        {
          /* If the edge is not constrained, then it should be
           * a part of two triangles */
          P2trPoint *A  = P2TR_EDGE_START(edge), *B = edge->end;
          P2trPoint *C1 = p2tr_triangle_get_opposite_point (edge->tri, edge, FALSE);
          P2trPoint *C2 = p2tr_triangle_get_opposite_point (edge->mirror->tri, edge->mirror, FALSE);

          P2trEdge *flipped = p2tr_cdt_try_flip (self, edge);
          if (flipped != NULL)
            {
              p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (A, C1, TRUE));
              p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (A, C2, TRUE));
              p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (B, C1, TRUE));
              p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (B, C2, TRUE));
              p2tr_edge_unref (flipped);
            }
        }

      p2tr_edge_unref (edge);
    }
}