From: Barak Itkin Date: Thu, 26 Apr 2012 13:09:52 +0000 (+0300) Subject: More work on P2trEdge, implement P2trTriangle X-Git-Tag: p2tc-0.1.0~99 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3cfdea92b6b7f25a99d58b2b08b1617b94a29411;p=poly2tri-c More work on P2trEdge, implement P2trTriangle --- diff --git a/refine/edge.c b/refine/edge.c index 9e394f1..b517e12 100644 --- a/refine/edge.c +++ b/refine/edge.c @@ -135,6 +135,15 @@ p2tr_edge_get_diametral_circle (P2trEdge *self, // this.mirror._p2tr_edge_remove(t, true); //} +P2trMesh* +p2tr_edge_get_mesh (P2trEdge *self) +{ + if (self->end != NULL) + return self->end->mesh; + else + return NULL; +} + gdouble p2tr_edge_get_length(P2trEdge* self) { diff --git a/refine/edge.h b/refine/edge.h index c820e8b..392483f 100644 --- a/refine/edge.h +++ b/refine/edge.h @@ -58,4 +58,12 @@ void p2tr_edge_remove (P2trEdge *self); P2trMesh* p2tr_edge_get_mesh (P2trEdge *self); gboolean p2tr_edge_is_removed (P2trEdge *self); + +gdouble p2tr_edge_get_length (P2trEdge* self); + +gdouble p2tr_edge_get_length_squared (P2trEdge* self); + +gdouble p2tr_edge_angle_between (P2trEdge *e1, + P2trEdge *e2); + #endif \ No newline at end of file diff --git a/refine/triangle.c b/refine/triangle.c new file mode 100644 index 0000000..ae5ae02 --- /dev/null +++ b/refine/triangle.c @@ -0,0 +1,200 @@ +#include +#include "point.h" +#include "edge.h" +#include "triangle.h" +#include "utils.h" +#include "math.h" + +P2trTriangle* +p2tr_triangle_new (P2trEdge *AB, + P2trEdge *BC, + P2trEdge *CA) +{ + gint i; + P2trTriangle *self = g_slice_new (P2trTriangle); + +#ifndef P2TC_NO_LOGIC_CHECKS + if (AB->end != P2TR_EDGE_START(BC) + || BC->end != P2TR_EDGE_START(CA) + || CA->end != P2TR_EDGE_START(AB)) + { + p2tr_exception_programmatic ("Unexpected edge sequence for a triangle!"); + } + + if (AB == BC->mirror || BC == CA->mirror || CA == AB->mirror) + { + p2tr_exception_programmatic ("Repeated edge in a triangle!"); + } +#endif + + switch (p2tr_math_orient2d(&CA->end->c, &AB->end->c, &BC->end->c)) + { + case P2TR_ORIENTATION_CCW: + self->edges[0] = CA->mirror; + self->edges[1] = BC->mirror; + self->edges[2] = AB->mirror; + break; + + case P2TR_ORIENTATION_CW: + self->edges[0] = AB; + self->edges[1] = BC; + self->edges[2] = CA; + break; + + case P2TR_ORIENTATION_LINEAR: + p2tr_exception_geometric ("Can't make a triangle of linear points!"); + } + +#ifdef P2TC_DEBUG_CHECKS + if (p2tr_math_orient2d (&self->edges[0]->end.c, + &self->edges[1]->end.c, + &self->edges[2]->end.c) != P2TR_ORIENTATION_CW) + { + p2tr_exception_programmatic ("Bad ordering!"); + } +#endif + + for (i = 0; i < 3; i++) + { +#ifdef P2TC_DEBUG_CHECKS + if (self->edges[i]->tri != NULL) + p2tr_exception_programmatic ("This edge is already in use by " + "another triangle!"); +#endif + self->edges[i]->tri = self; + p2tr_edge_ref (self->edges[i]); + } + + /* Reference by 3 edges, and another for the return of this pointer */ + self->refcount = 4; + + return self; +} + +void +p2tr_triangle_ref (P2trTriangle *self) +{ + ++self->refcount; +} + +void +p2tr_triangle_unref (P2trTriangle *self) +{ + if (--self->refcount == 0) + p2tr_triangle_free (self); +} + +void +p2tr_triangle_free (P2trTriangle *self) +{ + p2tr_triangle_remove (self); + g_slice_free (P2trTriangle, self); +} + +void +p2tr_triangle_remove (P2trTriangle *self) +{ + gint i; + P2trMesh *mesh; + + if (p2tr_triangle_is_removed (self)) + return; + + mesh = p2tr_triangle_get_mesh (self); + + for (i = 0; i < 3; i++) + { + self->edges[i]->tri = NULL; + p2tr_triangle_unref (self); + + p2tr_edge_unref (self->edges[i]); + self->edges[i] = NULL; + } + + if (mesh != NULL) + p2tr_mesh_on_triangle_removed (mesh, self); +} + +P2trMesh* +p2tr_triangle_get_mesh (P2trTriangle *self) +{ + if (self->edges[0] != NULL) + return p2tr_edge_get_mesh (self->edges[0]); + else + return NULL; +} + +gboolean +p2tr_triangle_is_removed (P2trTriangle *self) +{ + return self->edges[0] == NULL; +} + +P2trPoint* +p2tr_triangle_get_opposite_point (P2trTriangle *self, + P2trEdge *e) +{ + if (self->edges[0] == e || self->edges[0]->mirror == e) + return self->edges[1]->end; + if (self->edges[1] == e || self->edges[1]->mirror == e) + return self->edges[2]->end; + if (self->edges[2] == e || self->edges[2]->mirror == e) + return self->edges[0]->end; + + p2tr_exception_programmatic ("The edge is not in the triangle!"); +} + +P2trEdge* +p2tr_triangle_get_opposite_edge (P2trTriangle *self, + P2trPoint *p) +{ + if (self->edges[0]->end == p) + return self->edges[2]; + if (self->edges[1]->end == p) + return self->edges[0]; + if (self->edges[2]->end == p) + return self->edges[1]; + + p2tr_exception_programmatic ("The point is not in the triangle!"); +} + +gdouble +p2tr_triangle_get_angle_at (P2trTriangle *self, + P2trPoint *p) +{ + if (p == self->edges[0]->end) + return p2tr_edge_angle_between (self->edges[0], self->edges[1]); + else if (p == self->edges[1]->end) + return p2tr_edge_angle_between (self->edges[1], self->edges[2]); + else if (p == self->edges[2]->end) + return p2tr_edge_angle_between (self->edges[2], self->edges[0]); + + p2tr_exception_programmatic ("Can't find the point!"); +} + +gdouble +p2tr_triangle_smallest_non_constrained_angle (P2trTriangle *self) +{ + gdouble result = G_MAXDOUBLE, angle; + gint i; + + if (! self->edges[0]->constrained || !self->edges[1]->constrained) + { + angle = p2tr_edge_angle_between(self->edges[0], self->edges[1]); + result = MIN(result, angle); + } + + if (!self->edges[1]->constrained || !self->edges[2]->constrained) + { + angle = p2tr_edge_angle_between(self->edges[1], self->edges[2]); + result = MIN(result, angle); + } + + if (!self->edges[2]->constrained || !self->edges[0]->constrained) + { + angle = p2tr_edge_angle_between(self->edges[2], self->edges[0]); + result = MIN(result, angle); + } + + return result; +} diff --git a/refine/triangle.h b/refine/triangle.h index 62ea2bd..65ad46f 100644 --- a/refine/triangle.h +++ b/refine/triangle.h @@ -10,46 +10,36 @@ */ 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; + P2trEdge* edges[3]; - /** - * Is this edge still present in the triangulation? Or maybe it is - * just pending for the last unref? - */ - gboolean removed; + guint refcount; }; -#define P2TR_EDGE_START(E) ((E)->mirror->end) +P2trTriangle* p2tr_triangle_new (P2trEdge *AB, + P2trEdge *BC, + P2trEdge *CA); + +void p2tr_triangle_ref (P2trTriangle *self); + +void p2tr_triangle_unref (P2trTriangle *self); + +void p2tr_triangle_free (P2trTriangle *self); + +void p2tr_triangle_remove (P2trTriangle *self); + +P2trMesh* p2tr_triangle_get_mesh (P2trTriangle *self); + +gboolean p2tr_triangle_is_removed (P2trTriangle *self); + +P2trPoint* p2tr_triangle_get_opposite_point (P2trTriangle *self, + P2trEdge *e); + +P2trEdge* p2tr_triangle_get_opposite_edge (P2trTriangle *self, + P2trPoint *p); + +gdouble p2tr_triangle_get_angle_at (P2trTriangle *self, + P2trPoint *p); -void p2tr_edge_ref (P2trEdge *self); -void p2tr_edge_unref (P2trEdge *self); +gdouble p2tr_triangle_smallest_non_constrained_angle (P2trTriangle *self); -void p2tr_edge_remove (P2trEdge *self); #endif \ No newline at end of file