예제 #1
0
/*     ^ e1
 *    /
 *   /_ e1.Tri (e2.Mirror.Tri)
 *  /  |
 * *---------> e2
 *
 * Check if the angle marked is a part of the triangulation
 * domain
 */
static gboolean
p2tr_cluster_cw_tri_between_is_in_domain (P2trEdge *e1, P2trEdge *e2)
{
  if (P2TR_EDGE_START(e1) != P2TR_EDGE_START(e2) || e1->tri != e2->mirror->tri)
    p2tr_exception_programmatic ("Non clockwise adjacent edges!");
  return e1->tri != NULL;
}
예제 #2
0
void
p2tr_plot_svg_plot_edge (P2trEdge *self, const gchar* color, FILE* outfile)
{
  gdouble x1 = P2TR_EDGE_START (self)->c.x;
  gdouble y1 = P2TR_EDGE_START (self)->c.y;
  gdouble x2 = self->end->c.x;
  gdouble y2 = self->end->c.y;

  p2tr_plot_svg_plot_line (x1, y1, x2, y2, color, outfile);

//  if (p2tr_edge_is_encroached (self))
//    p2tr_plot_svg_plot_circle ((x1 + x2) / 2, (y1 + y2) / 2, R, "red", outfile);
}
예제 #3
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;
}
예제 #4
0
/**
 * Return the edge cluster of the specified edge from the specified end
 * point. THE EDGES IN THE CLUSTER MUST BE UNREFFED!
 * @param[in] P The point which is shared between all edges of the cluster
 * @param[in] E The edge whose cluster should be returned
 * @return The cluster of @ref E from the point @ref P
 */
P2trCluster*
p2tr_cluster_get_for (P2trPoint   *P,
                      P2trEdge    *E)
{
  P2trCluster *cluster = g_slice_new (P2trCluster);
  gdouble temp_angle;
  P2trEdge *current, *next;
  
  cluster->min_angle = G_MAXDOUBLE;
  g_queue_init (&cluster->edges);

  if (P == E->end)
    P = P2TR_EDGE_START (E);
  else if (P != P2TR_EDGE_START (E))
    p2tr_exception_programmatic ("Unexpected point for the edge!");

  g_queue_push_head (&cluster->edges, E);

  current = E;
  next = p2tr_point_edge_cw (P, current);
  
  while (next != g_queue_peek_head (&cluster->edges)
      && (temp_angle = p2tr_edge_angle_between (current->mirror, next)) <= P2TR_CLUSTER_LIMIT_ANGLE
      && p2tr_cluster_cw_tri_between_is_in_domain (current, next))
    {
      g_queue_push_tail (&cluster->edges, next);
      p2tr_edge_ref (next);
      current = next;
      next = p2tr_point_edge_cw (P, current);
      cluster->min_angle = MIN (cluster->min_angle, temp_angle);
    }

  current = E;
  next = p2tr_point_edge_ccw(P, current);
  while (next != g_queue_peek_tail (&cluster->edges)
      && (temp_angle = p2tr_edge_angle_between (current->mirror, next)) <= P2TR_CLUSTER_LIMIT_ANGLE
      && p2tr_cluster_cw_tri_between_is_in_domain (next, current))
    {
      g_queue_push_head (&cluster->edges, next);
      p2tr_edge_ref (next);
      current = next;
      next = p2tr_point_edge_ccw (P, current);
      cluster->min_angle = MIN(cluster->min_angle, temp_angle);
    }

  return cluster;
}
예제 #5
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;
}
예제 #6
0
gboolean
p2tr_cdt_visible_from_edge (P2trCDT     *self,
                            P2trEdge    *e,
                            P2trVector2 *p)
{
    P2trBoundedLine line;

    p2tr_bounded_line_init (&line, &P2TR_EDGE_START(e)->c, &e->end->c);

    return p2tr_visibility_is_visible_from_edges (self->outline, p, &line, 1);
}
예제 #7
0
void
p2tr_edge_get_diametral_circle (P2trEdge   *self,
                                P2trCircle *circle)
{
  P2trVector2 radius;
  
  p2tr_vector2_center (&self->end->c, &P2TR_EDGE_START(self)->c, &circle->center);
  p2tr_vector2_sub (&self->end->c, &circle->center, &radius);

  circle->radius = p2tr_vector2_norm (&radius);
}
예제 #8
0
static void
p2tr_edge_remove_one_side (P2trEdge *self)
{
  if (self->tri != NULL)
  {
    p2tr_triangle_remove (self->tri);
    p2tr_triangle_unref (self->tri);
    self->tri = NULL;
  }
  _p2tr_point_remove_edge(P2TR_EDGE_START(self), self);
  p2tr_point_unref (self->end);
  self->end = NULL;
}
예제 #9
0
파일: rcdt.c 프로젝트: KyleLink/poly2tri-c
P2trPoint*
p2tr_cdt_insert_point (P2trCDT           *self,
                       const P2trVector2 *pc,
                       P2trTriangle      *point_location_guess)
{
  P2trTriangle *tri;
  P2trPoint    *pt;
  gboolean      inserted = FALSE;
  gint          i;

  P2TR_CDT_VALIDATE_UNUSED (self);

  if (point_location_guess == NULL)
    tri = p2tr_mesh_find_point (self->mesh, pc);
  else
    tri = p2tr_mesh_find_point_local (self->mesh, pc, point_location_guess);

  if (tri == NULL)
    p2tr_exception_geometric ("Tried to add point outside of domain!");

  pt = p2tr_mesh_new_point (self->mesh, pc);

  /* If the point falls on a line, we should split the line */
  for (i = 0; i < 3; i++)
    {
      P2trEdge *edge = tri->edges[i];
      if (p2tr_math_orient2d (& P2TR_EDGE_START(edge)->c,
              &edge->end->c, pc) == P2TR_ORIENTATION_LINEAR)
        {
          GList *parts = p2tr_cdt_split_edge (self, edge, pt), *eIter;
          for (eIter = parts; eIter != NULL; eIter = eIter->next)
            p2tr_edge_unref ((P2trEdge*)eIter->data);
          g_list_free(parts);

          inserted = TRUE;
          break;
        }
    }

  if (! inserted)
    /* If we reached this line, then the point is inside the triangle */
    p2tr_cdt_insert_point_into_triangle (self, pt, tri);

  /* We no longer need the triangle */
  p2tr_triangle_unref (tri);

  P2TR_CDT_VALIDATE_UNUSED (self);
  return pt;
}
예제 #10
0
static gboolean
p2tr_cdt_visible_from_tri (P2trCDT      *self,
                           P2trTriangle *tri,
                           P2trVector2  *p)
{
    P2trBoundedLine lines[3];
    gint i;

    for (i = 0; i < 3; i++)
        p2tr_bounded_line_init (&lines[i],
                                &P2TR_EDGE_START(tri->edges[i])->c,
                                &tri->edges[i]->end->c);

    return p2tr_visibility_is_visible_from_edges (self->outline, p, lines, 3);
}
예제 #11
0
P2trEdge*
p2tr_point_edge_cw (P2trPoint* self,
                    P2trEdge *e)
{
  GList *node;

  if (P2TR_EDGE_START(e) != self)
      p2tr_exception_programmatic ("Not an edge of this point!");

  node = g_list_find (self->outgoing_edges, e);
  if (node == NULL)
    p2tr_exception_programmatic ("Could not find the CW sibling edge"
        "because the edge is not present in the outgoing-edges list!");

    return (P2trEdge*) g_list_cyclic_prev (self->outgoing_edges, node);
}
예제 #12
0
gdouble
p2tr_edge_angle_between(P2trEdge *e1, P2trEdge *e2)
{
  /* A = E1.angle, a = abs (A)
   * B = E1.angle, b = abs (B)
   *
   * W is the angle we wish to find. Note the fact that we want
   * to find the angle so that the edges go CLOCKWISE around it.
   *
   * Case 1: Signs of A and B agree | Case 2: Signs of A and B disagree
   *         and A > 0              |         and A > 0
   *                                |
   * a = A, b = B                   | a = A, b = -B
   *             ^^                 |
   *         E2 //                  |           /
   *           //\                  |          /
   *          //b|                  |         /a
   * - - - - * - |W- - - - - - - -  | - - - - * - - - - 
   *         ^^a'|                  |       ^^ \\b
   *         ||_/                   |      // W \\
   *      E1 ||\                    |  E1 // \_/ \\ E2
   *        '||a\                   |    //       \\
   *     - - - - - -                |   //         vv
   *                                |
   * W = A' + B = (180 - A) + B     | W = 180 - (a + b) = 180 - (A - B) 
   * W = 180 - A + B                | W = 180 - A + B
   * 
   * By the illustration above, we can see that in general the angle W
   * can be computed by W = 180 - A + B in every case. The only thing to
   * note is that the range of the result of the computation is
   * [180 - 360, 180 + 360] = [-180, +540] so we may need to subtract
   * 360 to put it back in the range [-180, +180].
   */
  gdouble result;
  
  if (e1->end != P2TR_EDGE_START(e2))
    p2tr_exception_programmatic ("The end-point of the first edge isn't"
        " the end-point of the second edge!");

  result = G_PI - e1->angle + e2->angle;
  if (result > 2 * G_PI)
      result -= 2 * G_PI;

  return result;
}
예제 #13
0
void
_p2tr_point_remove_edge (P2trPoint *self, P2trEdge* e)
{
  GList *node;
  
  if (P2TR_EDGE_START(e) != self)
    p2tr_exception_programmatic ("Could not remove the given outgoing "
        "edge because doesn't start on this point!");

  node = g_list_find (self->outgoing_edges, e);
  if (node == NULL)
    p2tr_exception_programmatic ("Could not remove the given outgoing "
        "edge because it's not present in the outgoing-edges list!");

  self->outgoing_edges = g_list_delete_link (self->outgoing_edges, node);

  p2tr_edge_unref (e);
}
예제 #14
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;
}
예제 #15
0
P2trPoint*
p2tr_cdt_insert_point (P2trCDT           *self,
                       const P2trVector2 *pc,
                       P2trTriangle      *point_location_guess)
{
    P2trTriangle *tri;
    P2trPoint    *pt;
    gboolean      inserted = FALSE;
    gint          i;

    if (point_location_guess == NULL)
        tri = p2tr_mesh_find_point (self->mesh, pc);
    else
        tri = p2tr_mesh_find_point_local (self->mesh, pc, point_location_guess);

    if (tri == NULL)
        p2tr_exception_geometric ("Tried to add point outside of domain!");

    pt = p2tr_mesh_new_point (self->mesh, pc);

    /* If the point falls on a line, we should split the line */
    for (i = 0; i < 3; i++)
    {
        P2trEdge *edge = tri->edges[i];
        if (p2tr_math_orient2d (& P2TR_EDGE_START(edge)->c,
                                &edge->end->c, pc) == P2TR_ORIENTATION_LINEAR)
        {
            p2tr_cdt_split_edge (self, edge, pt);
            inserted = TRUE;
            break;
        }
    }

    if (! inserted)
        /* If we reached this line, then the point is inside the triangle */
        p2tr_cdt_insert_point_into_triangle (self, pt, tri);

    p2tr_cdt_on_new_point (self, pt);

    return pt;
}
예제 #16
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);
    }
}
예제 #17
0
gdouble
p2tr_edge_get_length_squared(P2trEdge* self)
{
  return p2tr_math_length_sq2 (&self->end->c, &P2TR_EDGE_START(self)->c);
}