--- /dev/null
+#include <math.h>
+
+#include <glib.h>
+#include "utils.h"
+#include "point.h"
+#include "edge.h"
+
+#include "cluster.h"
+
+static gboolean p2tr_cluster_cw_tri_between_is_in_domain (P2trEdge *e1,
+ P2trEdge *e2);
+
+gdouble
+p2tr_cluster_shortest_edge_length (P2trCluster *self)
+{
+ gdouble min_length_sq = G_MAXDOUBLE, temp;
+ GList *iter;
+
+ for (iter = g_queue_peek_head(&self->edges); iter != NULL; iter = iter->next)
+ {
+ temp = p2tr_edge_get_length_squared ((P2trEdge*)iter->data);
+ min_length_sq = MIN(min_length_sq, temp);
+ }
+ return sqrt (min_length_sq);
+}
+
+/**
+ * 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;
+}
+
+/* ^ 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;
+}
+
+void
+p2tr_cluster_free (P2trCluster *self)
+{
+ GList *iter;
+
+ for (iter = g_queue_peek_head(&self->edges); iter != NULL; iter = iter->next)
+ p2tr_edge_unref ((P2trEdge*)iter->data);
+
+ g_queue_clear (&self->edges);
+ g_slice_free (P2trCluster, self);
+}
\ No newline at end of file