/** * gts_triangle_is_stabbed: * @t: a #GtsTriangle. * @p: a #GtsPoint. * @orientation: a pointer or %NULL. * * Returns: one of the vertices of @t, one of the edges of @t or @t if * any of these are stabbed by the ray starting at @p (included) and * ending at (@p->x, @p->y, +infty), %NULL otherwise. If the ray is * contained in the plane of the triangle %NULL is also returned. If * @orientation is not %NULL, it is set to the value of the * orientation of @p relative to @t (as given by * gts_point_orientation_3d()). */ GtsObject * gts_triangle_is_stabbed (GtsTriangle * t, GtsPoint * p, gdouble * orientation) { GtsVertex * v1, * v2, * v3, * inverted = NULL; GtsEdge * e1, * e2, * e3, * tmp; gdouble o, o1, o2, o3; g_return_val_if_fail (t != NULL, NULL); g_return_val_if_fail (p != NULL, NULL); gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3); o = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3)); if (o == 0.) return NULL; if (o < 0.) { inverted = v1; v1 = v2; v2 = inverted; tmp = e2; e2 = e3; e3 = tmp; } o = gts_point_orientation_3d (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3), p); if (o < 0.) return NULL; o1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p); if (o1 < 0.) return NULL; o2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p); if (o2 < 0.) return NULL; o3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p); if (o3 < 0.) return NULL; if (orientation) *orientation = inverted ? -o : o; if (o1 == 0.) { if (o2 == 0.) return GTS_OBJECT (v2); if (o3 == 0.) return GTS_OBJECT (v1); return GTS_OBJECT (e1); } if (o2 == 0.) { if (o3 == 0.) return GTS_OBJECT (v3); return GTS_OBJECT (e2); } if (o3 == 0.) return GTS_OBJECT (e3); return GTS_OBJECT (t); }
/** * gts_triangle_orientation: * @t: a #GtsTriangle. * * Checks for the orientation of the plane (x,y) projection of a * triangle. See gts_point_orientation() for details. This function * is geometrically robust. * * Returns: a number depending on the orientation of the vertices of @t. */ gdouble gts_triangle_orientation (GtsTriangle * t) { GtsVertex * v1, * v2 = NULL, * v3 = NULL; g_return_val_if_fail (t != NULL, 0.0); v1 = GTS_SEGMENT (t->e1)->v1; if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { v2 = GTS_SEGMENT (t->e2)->v2; v3 = GTS_SEGMENT (t->e1)->v2; } else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { v2 = GTS_SEGMENT (t->e1)->v2; v3 = GTS_SEGMENT (t->e2)->v1; } else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { v2 = GTS_SEGMENT (t->e2)->v1; v3 = GTS_SEGMENT (t->e1)->v2; } else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { v2 = GTS_SEGMENT (t->e1)->v2; v3 = GTS_SEGMENT (t->e2)->v2; } else g_assert_not_reached (); return gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3)); }
/** * gts_segments_are_intersecting: * @s1: a #GtsSegment. * @s2: a #GtsSegment. * * Returns: %GTS_IN if @s1 and @s2 are intersecting, %GTS_ON if one of the * endpoints of @s1 (resp. @s2) lies on @s2 (resp. @s1), %GTS_OUT otherwise. */ GtsIntersect gts_segments_are_intersecting (GtsSegment * s1, GtsSegment * s2) { GtsPoint * p1, * p2, * p3, * p4; gdouble d1, d2, d3, d4; g_return_val_if_fail (s1 != NULL && s2 != NULL, FALSE); p1 = GTS_POINT (s1->v1); p2 = GTS_POINT (s1->v2); p3 = GTS_POINT (s2->v1); p4 = GTS_POINT (s2->v2); d1 = gts_point_orientation (p1, p2, p3); d2 = gts_point_orientation (p1, p2, p4); if ((d1 > 0.0 && d2 > 0.0) || (d1 < 0.0 && d2 < 0.0)) return GTS_OUT; d3 = gts_point_orientation (p3, p4, p1); d4 = gts_point_orientation (p3, p4, p2); if ((d3 > 0.0 && d4 > 0.0) || (d3 < 0.0 && d4 < 0.0)) return GTS_OUT; if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0 || d4 == 0.0) return GTS_ON; return GTS_IN; }
static void gts_constraint_split (GtsConstraint * c, GtsSurface * s, GtsFifo * fifo) { GSList * i; GtsVertex * v1, * v2; GtsEdge * e; g_return_if_fail (c != NULL); g_return_if_fail (s != NULL); v1 = GTS_SEGMENT (c)->v1; v2 = GTS_SEGMENT (c)->v2; e = GTS_EDGE (c); i = e->triangles; while (i) { GtsFace * f = i->data; if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) { GtsVertex * v = gts_triangle_vertex_opposite (GTS_TRIANGLE (f), e); if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v)) == 0.) { GSList * j = e->triangles; GtsFace * f1 = NULL; GtsEdge * e1, * e2; /* replaces edges with constraints */ gts_triangle_vertices_edges (GTS_TRIANGLE (f), e, &v1, &v2, &v, &e, &e1, &e2); if (!GTS_IS_CONSTRAINT (e1)) { GtsEdge * ne1 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v2, v); gts_edge_replace (e1, ne1); gts_object_destroy (GTS_OBJECT (e1)); e1 = ne1; if (fifo) gts_fifo_push (fifo, e1); } if (!GTS_IS_CONSTRAINT (e2)) { GtsEdge * ne2 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v, v1); gts_edge_replace (e2, ne2); gts_object_destroy (GTS_OBJECT (e2)); e2 = ne2; if (fifo) gts_fifo_push (fifo, e2); } /* look for face opposite */ while (j && !f1) { if (GTS_IS_FACE (j->data) && gts_face_has_parent_surface (j->data, s)) f1 = j->data; j = j->next; } if (f1) { /* c is not a boundary of s */ GtsEdge * e3, * e4, * e5; GtsVertex * v3; gts_triangle_vertices_edges (GTS_TRIANGLE (f1), e, &v1, &v2, &v3, &e, &e3, &e4); e5 = gts_edge_new (s->edge_class, v, v3); gts_surface_add_face (s, gts_face_new (s->face_class, e5, e2, e3)); gts_surface_add_face (s, gts_face_new (s->face_class, e5, e4, e1)); gts_object_destroy (GTS_OBJECT (f1)); } gts_object_destroy (GTS_OBJECT (f)); return; } } i = i->next; } }