From: Barak Itkin Date: Thu, 26 Apr 2012 10:54:21 +0000 (+0300) Subject: More work on P2trPoint, and implement P2trEdge X-Git-Tag: p2tc-0.1.0~101 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=da04653342b7a6bc9c764f08dcb2b24b5f964621;p=poly2tri-c More work on P2trPoint, and implement P2trEdge --- diff --git a/refine/edge.c b/refine/edge.c new file mode 100644 index 0000000..141a930 --- /dev/null +++ b/refine/edge.c @@ -0,0 +1,191 @@ +#include +#include +#include "point.h" +#include "edge.h" + +static void +p2tr_edge_init (P2trEdge *self, + P2trPoint *start, + P2trPoint *end, + gboolean constrained, + P2trEdge *mirror) +{ + self->angle = atan2 (end->y - start->y, end->x - start->x); + self->constrained = constrained; + self->delaunay = FALSE; + self->end = end; + self->mirror = mirror; + self->refcount = 0; + self->removed = FALSE; + self->tri = NULL; +} + +P2trEdge* +p2tr_edge_new (P2trPoint *start, + P2trPoint *end, + gboolean constrained) +{ + P2trEdge *self = g_slice_new (P2trEdge); + P2trEdge *mirror = g_slice_new (P2trEdge); + + p2tr_edge_init (self, start, end, constrained, mirror); + p2tr_edge_init (mirror, end, start, constrained, self); + + p2tr_point_ref (start); + p2tr_point_ref (end); + + _p2tr_point_insert_edge (start, self); + _p2tr_point_insert_edge (end, mirror); + + ++self->refcount; + return self; +} + +void +p2tr_edge_ref (P2trEdge *self) +{ + ++self->refcount; +} + +void +p2tr_edge_unref (P2trEdge *self) +{ + if (--self->refcount == 0 && self->mirror->refcount == 0) + p2tr_edge_free (self); +} + +gboolean +p2tr_edge_is_removed (P2trEdge *self) +{ + return self->end == NULL; +} + +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; +} + +void +p2tr_edge_remove (P2trEdge *self) +{ + P2trMesh *mesh; + + if (self->end == NULL) /* This is only true if the edge was removed */ + return; + + mesh = p2tr_edge_get_mesh (self); + p2tr_edge_remove_one_side (self); + p2tr_edge_remove_one_side (self->mirror); + + if (mesh != NULL) + { + p2tr_mesh_on_edge_removed (self); + p2tr_mesh_on_edge_removed (self->mirror); + } +} + +void +p2tr_edge_free (P2trEdge *self) +{ + p2tr_edge_remove (self); + g_slice_free (P2trEdge, self); + g_slice_free (P2trEdge, self->mirror); +} + +void +p2tr_edge_get_diametral_circle (P2trEdge *self, + P2trCircle *circle) +{ + P2trVector2 radius; + + p2tr_vector2_center (self->end, P2TR_EDGE_START(self), &circle->center); + p2tr_vector2_sub (self->end, &circle->center, &radius); + + circle->radius = p2tr_vector2_norm (&radius); +} + +//public void p2tr_edge_remove(P2trTriangulation t) +//{ +// _p2tr_edge_remove(T, false); +//} + +//private void _p2tr_edge_remove(P2trTriangulation t, bool is_mirror) +//{ +// if (this.removed) +// return; +// +// t.edges.Remove(this); +// this.removed = true; +// +// this.start.p2tr_point_remove_edge(this); +// +// if (this.tri != null) +// this.tri.p2tr_triangle_remove(t); +// +// if (! is_mirror) +// this.mirror._p2tr_edge_remove(t, true); +//} + +gdouble +p2tr_edge_get_length(P2trEdge* self) +{ + return sqrt (p2tr_math_length_sq2 (&self->end, &P2TR_EDGE_START(self))); +} + +gdouble +p2tr_edge_get_length_squared(P2trEdge* self) +{ + return p2tr_math_length_sq2 (&self->end, &P2TR_EDGE_START(self)); +} + +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]. + */ + 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!"); + + gdouble result = G_PI - e1->angle + e2->angle; + if (result > 2 * G_PI) + result -= 2 * G_PI; + return result; +} \ No newline at end of file diff --git a/refine/edge.h b/refine/edge.h index b3709c1..b007035 100644 --- a/refine/edge.h +++ b/refine/edge.h @@ -25,7 +25,8 @@ struct P2trEdge_ /** * The angle of the direction of this edge. Although it can be * computed anytime using atan2 on the vector of this edge, we cache - * it here since it's heavily used and the computation is expensive + * it here since it's heavily used and the computation is expensive. + * The angle increases as we go CCW, and it's in the range [-PI,+PI] */ gdouble angle; @@ -41,7 +42,19 @@ struct P2trEdge_ #define P2TR_EDGE_START(E) ((E)->mirror->end) -void p2tr_edge_ref (P2trEdge *self); -void p2tr_edge_unref (P2trEdge *self); +void p2tr_edge_new (P2trPoint *start, + P2trPoint *end, + gboolean constrained); +void p2tr_edge_ref (P2trEdge *self); + +void p2tr_edge_unref (P2trEdge *self); + +void p2tr_edge_free (P2trEdge *self); + +void p2tr_edge_remove (P2trEdge *self); + +void p2tr_edge_get_mesh (P2trEdge *self); + +gboolean p2tr_edge_is_removed (P2trEdge *self); #endif \ No newline at end of file diff --git a/refine/mesh.h b/refine/mesh.h index db5217d..1041f46 100644 --- a/refine/mesh.h +++ b/refine/mesh.h @@ -32,17 +32,21 @@ P2trTriangle* p2tr_mesh_new_triangle2 (P2trMesh *mesh, P2trEdge *BC, P2trEdge *CA); -gboolean p2tr_mesh_remove_point (P2trMesh *mesh, - P2trEdge *edge); +gboolean p2tr_mesh_on_point_removed (P2trMesh *mesh, + P2trPoint *point); -gboolean p2tr_mesh_remove_edge (P2trMesh *mesh, - P2trEdge *edge); +gboolean p2tr_mesh_on_edge_removed (P2trMesh *mesh, + P2trEdge *edge); -gboolean p2tr_mesh_remove_triangle (P2trMesh *mesh, - P2trTriangle *triangle); +gboolean p2tr_mesh_on_triangle_removed (P2trMesh *mesh, + P2trTriangle *triangle); void p2tr_mesh_clear (P2trMesh *mesh); void p2tr_mesh_destroy (P2trMesh *mesh); +void p2tr_mesh_unref (P2trMesh *mesh); + +void p2tr_mesh_ref (P2trMesh *mesh); + #endif \ No newline at end of file diff --git a/refine/point.c b/refine/point.c index 5b72ed2..7d92065 100644 --- a/refine/point.c +++ b/refine/point.c @@ -8,19 +8,34 @@ p2tr_point_new (const P2trVector2 *c) P2trPoint *self = g_slice_new (P2trPoint); p2tr_vector2_copy (&self->c, c); + self->mesh = NULL; self->outgoing_edges = NULL; - + self->refcount = 1; + return self; } -static void -p2tr_point_delete (P2trPoint *self) +void +p2tr_point_remove (P2trPoint *self) { - GList *iter; - for (iter = self->outgoing_edges; iter != NULL; iter = iter->next) - p2tr_edge_unref ((P2trEdge*) iter->data); + /* We can not iterate over the list of edges while removing the edges, + * because the removal action will modify the list. Instead we will + * simply look at the first edge untill the list is emptied. */ + while (self->outgoing_edges != NULL) + p2tr_edge_remove ((P2trEdge*) self->outgoing_edges->data); + + if (self->mesh != NULL) + { + p2tr_mesh_on_point_removed (self->mesh, self); + p2tr_mesh_unref (self->mesh); + self->mesh = NULL; + } +} - g_list_free (self->outgoing_edges); +void +p2tr_point_free (P2trPoint *self) +{ + p2tr_point_remove (self); g_slice_free (P2trPoint, self); } @@ -150,5 +165,11 @@ void p2tr_point_unref (P2trPoint *self) { if (--self->refcount == 0) - p2tr_point_delete (self); + p2tr_point_free (self); +} + +P2trMesh* +p2tr_point_get_mesh (P2trPoint *self) +{ + return self->mesh; } \ No newline at end of file diff --git a/refine/point.h b/refine/point.h index b975f52..81d513a 100644 --- a/refine/point.h +++ b/refine/point.h @@ -22,10 +22,21 @@ struct P2trPoint_ /** A count of references to the point */ guint refcount; + + /** The triangular mesh containing this point */ + P2trMesh *mesh; }; P2trPoint* p2tr_point_new (const P2trVector2 *c); +void p2tr_point_ref (P2trPoint *self); + +void p2tr_point_unref (P2trPoint *self); + +void p2tr_point_free (P2trPoint *self); + +void p2tr_point_remove (P2trPoint *self); + P2trEdge* p2tr_point_get_edge_to (P2trPoint *start, P2trPoint *end); @@ -45,8 +56,6 @@ gboolean p2tr_point_is_fully_in_domain (P2trPoint *self); gboolean p2tr_point_has_constrained_edge (P2trPoint *self); -void p2tr_point_ref (P2trPoint *self); - -void p2tr_point_unref (P2trPoint *self); +P2trMesh* p2tr_point_get_mesh (P2trPoint *self); #endif \ No newline at end of file diff --git a/refine/triangle.h b/refine/triangle.h new file mode 100644 index 0000000..62ea2bd --- /dev/null +++ b/refine/triangle.h @@ -0,0 +1,55 @@ +#ifndef __P2TC_REFINE_TRIANGLE_H__ +#define __P2TC_REFINE_TRIANGLE_H__ + +#include +#include "triangulation.h" + +/** + * @struct P2trTriangle_ + * A struct for a triangle in a triangular mesh + */ +struct P2trTriangle_ +{ + /** The end point of this mesh */ + P2trPoint *end; + + /** The edge going in the opposite direction from this edge */ + P2trEdge *mirror; + + /** Is this a constrained edge? */ + gboolean constrained; + + /** The triangle where this edge goes clockwise along its outline */ + P2trTriangle *tri; + + /** + * The angle of the direction of this edge. Although it can be + * computed anytime using atan2 on the vector of this edge, we cache + * it here since it's heavily used and the computation is expensive. + * The angle increases as we go CCW, and it's in the range [-PI, +PI] + */ + gdouble angle; + + /** + * Is this edge a delaunay edge? This field is used by the refinement + * algorithm and should not be used elsewhere! + */ + gboolean delaunay; + + /** A count of references to the edge */ + guint refcount; + + /** + * Is this edge still present in the triangulation? Or maybe it is + * just pending for the last unref? + */ + gboolean removed; +}; + +#define P2TR_EDGE_START(E) ((E)->mirror->end) + +void p2tr_edge_ref (P2trEdge *self); +void p2tr_edge_unref (P2trEdge *self); + +void p2tr_edge_remove (P2trEdge *self); +#endif \ No newline at end of file diff --git a/refine/vector2.c b/refine/vector2.c index fde20b6..4853567 100644 --- a/refine/vector2.c +++ b/refine/vector2.c @@ -28,6 +28,15 @@ p2tr_vector2_sub (const P2trVector2 *a, dest->y = a->y - b->y; } +void +p2tr_vector2_center (const P2trVector2 *a, + const P2trVector2 *b, + P2trVector2 *dest) +{ + dest->x = (a->x + b->x) * 0.5; + dest->y = (a->y + b->y) * 0.5; +} + gdouble p2tr_vector2_norm (const P2trVector2 *v) { diff --git a/refine/vector2.h b/refine/vector2.h index 92381a0..8fe7a61 100644 --- a/refine/vector2.h +++ b/refine/vector2.h @@ -28,6 +28,14 @@ gboolean p2tr_vector2_is_same (const P2trVector2 *a, const P2trVector2 *b */ void p2tr_vector2_sub (const P2trVector2 *a, const P2trVector2 *b, P2trVector2 *dest); +/** + * Compute the center point of the edge defined between two points + * @param[in] a The first side of the edge + * @param[in] b The second side of the edge + * @param[out] dest The vector in which the result should be stored + */ +void p2tr_vector2_center (const P2trVector2 *a, const P2trVector2 *b, P2trVector2 *dest); + /** * Compute the norm of a vector (the length of the line from the origin * to the 2D point it represents)