/** * gts_edge_belongs_to_tetrahedron: * @e: a #GtsEdge. * * Returns: %TRUE if @e is used by faces forming a tetrahedron, %FALSE * otherwise. */ gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e) { GSList * i; GtsVertex * v1, * v2; g_return_val_if_fail (e != NULL, FALSE); v1 = GTS_SEGMENT (e)->v1; v2 = GTS_SEGMENT (e)->v2; i = e->triangles; while (i) { GtsEdge * e1, * e2; GtsVertex * vt1; GSList * j = i->next; triangle_vertices_edges (i->data, e, &vt1, &e1, &e2); while (j) { GtsSegment * s5; GtsEdge * e3, * e4; GtsVertex * vt2; triangle_vertices_edges (j->data, e, &vt2, &e3, &e4); s5 = gts_vertices_are_connected (vt1, vt2); if (GTS_IS_EDGE (s5) && gts_triangle_use_edges (e1, e3, GTS_EDGE (s5)) && gts_triangle_use_edges (e2, e4, GTS_EDGE (s5))) return TRUE; j = j->next; } i = i->next; } return FALSE; }
static GtsVertex * triangle_use_vertices (GtsTriangle * t, GtsVertex * A, GtsVertex * B) { GtsVertex * v1 = GTS_SEGMENT (t->e1)->v1, * v2 = GTS_SEGMENT (t->e1)->v2, * v3 = gts_triangle_vertex (t); if (v1 == A) { if (v2 == B) return v3; g_assert (v3 == B); return v2; } if (v2 == A) { if (v1 == B) return v3; g_assert (v3 == B); return v1; } if (v3 == A) { if (v1 == B) return v2; g_assert (v2 == B); return v1; } g_assert_not_reached (); return NULL; }
/** * gts_edge_is_contact: * @e: a #GtsEdge. * * Returns: the number of sets of connected triangles sharing @e as a * contact edge. */ guint gts_edge_is_contact (GtsEdge * e) { GSList * i, * triangles; guint ncomponent = 0; g_return_val_if_fail (e != NULL, 0); triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL); i = triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles); while (i) { GTS_OBJECT (i->data)->reserved = i; i = i->next; } i = e->triangles; while (i) { GtsTriangle * t = i->data; if (GTS_OBJECT (t)->reserved) { GtsEdge * e1; GTS_OBJECT (t)->reserved = NULL; e1 = next_edge (t, NULL, e); triangle_next (e1, e); triangle_next (next_edge (t, e1, e), e); ncomponent++; } i = i->next; } g_slist_foreach (triangles, (GFunc) gts_object_reset_reserved, NULL); g_slist_free (triangles); return ncomponent; }
/** * gts_edge_is_duplicate: * @e: a #GtsEdge. * * Returns: the first #GtsEdge different from @e which shares the * same endpoints or %NULL if there is none. */ GtsEdge * gts_edge_is_duplicate (GtsEdge * e) { GSList * i; GtsVertex * v2; g_return_val_if_fail (e != NULL, NULL); v2 = GTS_SEGMENT (e)->v2; i = GTS_SEGMENT (e)->v1->segments; if (GTS_SEGMENT (e)->v1 == v2) /* e is degenerate: special treatment */ while (i) { GtsSegment * s = i->data; if (s != GTS_SEGMENT (e) && GTS_IS_EDGE (s) && s->v1 == v2 && s->v2 == v2) return GTS_EDGE (s); i = i->next; } else /* e is not degenerate */ while (i) { GtsSegment * s = i->data; if (s != GTS_SEGMENT (e) && GTS_IS_EDGE (s) && (s->v1 == v2 || s->v2 == v2)) return GTS_EDGE (s); i = i->next; } return NULL; }
/** * gts_triangle_interpolate_height: * @t: a #GtsTriangle. * @p: a #GtsPoint. * * Fills the z-coordinate of point @p belonging to the plane * projection of triangle @t with the linearly interpolated value of * the z-coordinates of the vertices of @t. */ void gts_triangle_interpolate_height (GtsTriangle * t, GtsPoint * p) { GtsPoint * p1, * p2, * p3; gdouble x1, x2, y1, y2, det; g_return_if_fail (t != NULL); g_return_if_fail (p != NULL); p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); p3 = GTS_POINT (gts_triangle_vertex (t)); x1 = p2->x - p1->x; y1 = p2->y - p1->y; x2 = p3->x - p1->x; y2 = p3->y - p1->y; det = x1*y2 - x2*y1; if (det == 0.) p->z = (p1->z + p2->z + p3->z)/3.; else { gdouble x = p->x - p1->x; gdouble y = p->y - p1->y; gdouble a = (x*y2 - y*x2)/det; gdouble b = (y*x1 - x*y1)/det; p->z = (1. - a - b)*p1->z + a*p2->z + b*p3->z; } }
/** * gts_bbox_triangle: * @klass: a #GtsBBoxClass. * @t: a #GtsTriangle. * * Returns: a new #GtsBBox bounding box of @t. */ GtsBBox * gts_bbox_triangle (GtsBBoxClass * klass, GtsTriangle * t) { GtsBBox * bbox; GtsPoint * p; g_return_val_if_fail (t != NULL, NULL); g_return_val_if_fail (klass != NULL, NULL); p = GTS_POINT (GTS_SEGMENT (t->e1)->v1); bbox = gts_bbox_new (klass, t, p->x, p->y, p->z, p->x, p->y, p->z); p = GTS_POINT (GTS_SEGMENT (t->e1)->v2); if (p->x > bbox->x2) bbox->x2 = p->x; if (p->x < bbox->x1) bbox->x1 = p->x; if (p->y > bbox->y2) bbox->y2 = p->y; if (p->y < bbox->y1) bbox->y1 = p->y; if (p->z > bbox->z2) bbox->z2 = p->z; if (p->z < bbox->z1) bbox->z1 = p->z; p = GTS_POINT (gts_triangle_vertex (t)); if (p->x > bbox->x2) bbox->x2 = p->x; if (p->x < bbox->x1) bbox->x1 = p->x; if (p->y > bbox->y2) bbox->y2 = p->y; if (p->y < bbox->y1) bbox->y1 = p->y; if (p->z > bbox->z2) bbox->z2 = p->z; if (p->z < bbox->z1) bbox->z1 = p->z; return bbox; }
static void edge_clone (GtsObject * clone, GtsObject * object) { (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->clone) (clone, object); GTS_SEGMENT (clone)->v1 = GTS_SEGMENT (clone)->v2 = NULL; GTS_EDGE (clone)->triangles = NULL; }
static gboolean triangle_obtuse (GtsVertex * v, GtsFace * f) { GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); return (angle_obtuse (v, f) || angle_obtuse (GTS_SEGMENT (e)->v1, f) || angle_obtuse (GTS_SEGMENT (e)->v2, f)); }
static gboolean angle_obtuse (GtsVertex * v, GtsFace * f) { GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); GtsVector vec1, vec2; gts_vector_init (vec1, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v1)); gts_vector_init (vec2, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v2)); return (gts_vector_scalar (vec1, vec2) < 0.0); }
static gboolean triangle_is_hole (GtsTriangle * t) { GtsEdge * e1, * e2, * e3; GtsVertex * v1, * v2, * v3; gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3); if ((GTS_IS_CONSTRAINT (e1) && GTS_SEGMENT (e1)->v2 != v1) || (GTS_IS_CONSTRAINT (e2) && GTS_SEGMENT (e2)->v2 != v2) || (GTS_IS_CONSTRAINT (e3) && GTS_SEGMENT (e3)->v2 != v3)) return TRUE; return FALSE; }
/** * gts_triangles_are_compatible: * @t1: a #GtsTriangle. * @t2: a #GtsTriangle. * @e: a #GtsEdge used by both @t1 and @t2. * * Checks if @t1 and @t2 have compatible orientations i.e. if @t1 and * @t2 can be part of the same surface without conflict in the surface * normal orientation. * * Returns: %TRUE if @t1 and @t2 are compatible, %FALSE otherwise. */ gboolean gts_triangles_are_compatible (GtsTriangle * t1, GtsTriangle * t2, GtsEdge * e) { GtsEdge * e1 = NULL, * e2 = NULL; g_return_val_if_fail (t1 != NULL, FALSE); g_return_val_if_fail (t2 != NULL, FALSE); g_return_val_if_fail (e != NULL, FALSE); if (t1->e1 == e) e1 = t1->e2; else if (t1->e2 == e) e1 = t1->e3; else if (t1->e3 == e) e1 = t1->e1; else g_assert_not_reached (); if (t2->e1 == e) e2 = t2->e2; else if (t2->e2 == e) e2 = t2->e3; else if (t2->e3 == e) e2 = t2->e1; else g_assert_not_reached (); if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1 || GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2 || GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1 || GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) return FALSE; return TRUE; }
/** * gts_triangle_perimeter: * @t: a #GtsTriangle. * * Returns: the perimeter of the triangle @t. */ gdouble gts_triangle_perimeter (GtsTriangle * t) { GtsVertex * v; g_return_val_if_fail (t != NULL, 0.0); v = gts_triangle_vertex (t); return gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), GTS_POINT (GTS_SEGMENT (t->e1)->v2)) + gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), GTS_POINT (v)) + gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v2), GTS_POINT (v)); }
static void surface_distance_foreach_boundary (GtsEdge * e, gpointer * data) { gdouble * delta = data[1]; GtsRange * range = data[2]; gdouble * total_length = data[3], length; GtsRange range_edge; if (gts_edge_is_boundary (e, NULL)) { GtsSegment * s = GTS_SEGMENT (e); gts_bb_tree_segment_distance (data[0], s, data[4], *delta, &range_edge); if (range_edge.min < range->min) range->min = range_edge.min; if (range_edge.max > range->max) range->max = range_edge.max; range->n += range_edge.n; length = gts_point_distance (GTS_POINT (s->v1), GTS_POINT (s->v2)); *total_length += length; range->sum += length*range_edge.mean; range->sum2 += length*range_edge.mean*range_edge.mean; } }
/** * gts_vertex_gaussian_curvature: * @v: a #GtsVertex. * @s: a #GtsSurface. * @Kg: the Discrete Gaussian Curvature approximation at @v. * * Computes the Discrete Gaussian Curvature approximation at @v. * * This approximation is from the paper: * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr * VisMath '02, Berlin (Germany) * http://www-grail.usc.edu/pubs.html * * Returns: %TRUE if the operator could be evaluated, %FALSE if the * evaluation failed for some reason (@v is boundary or is the * endpoint of a non-manifold edge.) */ gboolean gts_vertex_gaussian_curvature (GtsVertex * v, GtsSurface * s, gdouble * Kg) { GSList * faces, * edges, * i; gdouble area = 0.0; gdouble angle_sum = 0.0; g_return_val_if_fail (v != NULL, FALSE); g_return_val_if_fail (s != NULL, FALSE); g_return_val_if_fail (Kg != NULL, FALSE); /* this operator is not defined for boundary edges */ if (gts_vertex_is_boundary (v, s)) return (FALSE); faces = gts_vertex_faces (v, s, NULL); g_return_val_if_fail (faces != NULL, FALSE); edges = gts_vertex_fan_oriented (v, s); if (edges == NULL) { g_slist_free (faces); return (FALSE); } i = faces; while (i) { GtsFace * f = i->data; area += region_area (v, f); i = i->next; } g_slist_free (faces); i = edges; while (i) { GtsEdge * e = i->data; GtsVertex * v1 = GTS_SEGMENT (e)->v1; GtsVertex * v2 = GTS_SEGMENT (e)->v2; angle_sum += angle_from_cotan (v, v1, v2); i = i->next; } g_slist_free (edges); *Kg = (2.0*M_PI - angle_sum)/area; return TRUE; }
static GtsEdge * next_edge (GtsTriangle * t, GtsEdge * e1, GtsEdge * e) { GtsVertex * v1 = GTS_SEGMENT (e)->v1; GtsVertex * v2 = GTS_SEGMENT (e)->v2; if (t->e1 != e1 && t->e1 != e && (edge_use_vertex (t->e1, v1) || edge_use_vertex (t->e1, v2))) return t->e1; else if (t->e2 != e1 && t->e2 != e && (edge_use_vertex (t->e2, v1) || edge_use_vertex (t->e2, v2))) return t->e2; else if (t->e3 != e1 && t->e3 != e && (edge_use_vertex (t->e3, v1) || edge_use_vertex (t->e3, v2))) return t->e3; g_assert_not_reached (); return NULL; }
static void triangle_plane (GtsTriangle * f, GtsVector p) { GtsPoint * v1, * v2, * v3; gdouble x1, x2, y1, y2, det; v1 = GTS_POINT (GTS_SEGMENT (f->e1)->v1); v2 = GTS_POINT (GTS_SEGMENT (f->e1)->v2); v3 = GTS_POINT (gts_triangle_vertex (f)); x1 = v2->x - v1->x; y1 = v2->y - v1->y; x2 = v3->x - v1->x; y2 = v3->y - v1->y; det = x1*y2 - x2*y1; g_assert (det != 0.); p[0] = (y2*(v2->z - v1->z) - y1*(v3->z - v1->z))/det; p[1] = (-x2*(v2->z - v1->z) + x1*(v3->z - v1->z))/det; p[2] = ((- v1->x*y2 + v1->y*x2)*(v2->z - v1->z) + (- v1->y*x1 + v1->x*y1)*(v3->z - v1->z))/det + v1->z; }
/** * gts_triangle_edge_opposite: * @t: a #GtsTriangle. * @v: a #GtsVertex of @t. * * Returns: the edge of @t opposite @v or %NULL if @v is not a vertice of @t. */ GtsEdge * gts_triangle_edge_opposite (GtsTriangle * t, GtsVertex * v) { GtsSegment * s1, * s2, * s3; g_return_val_if_fail (t != NULL, NULL); g_return_val_if_fail (v != NULL, NULL); s1 = GTS_SEGMENT (t->e1); s2 = GTS_SEGMENT (t->e2); if (s1->v1 != v && s1->v2 != v) { if (s2->v1 != v && s2->v2 != v) return NULL; return t->e1; } if (s2->v1 != v && s2->v2 != v) return t->e2; s3 = GTS_SEGMENT (t->e3); g_assert (s3->v1 != v && s3->v2 != v); return t->e3; }
static void triangle_vertices_edges (GtsTriangle * t, GtsEdge * e, GtsVertex ** v, GtsEdge ** ee1, GtsEdge ** ee2) { GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; GtsVertex * v1 = GTS_SEGMENT (e)->v1; if (e1 == e) e1 = e3; else if (e2 == e) e2 = e3; else g_assert (e3 == e); if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v2 == v1) { e3 = e1; e1 = e2; e2 = e3; } if (GTS_SEGMENT (e1)->v1 == v1) *v = GTS_SEGMENT (e1)->v2; else *v = GTS_SEGMENT (e1)->v1; *ee1 = e1; *ee2 = e2; }
void gts_write_triangle (GtsTriangle * t, GtsPoint * o, FILE * fptr) { gdouble xo = o ? o->x : 0.0; gdouble yo = o ? o->y : 0.0; gdouble zo = o ? o->z : 0.0; g_return_if_fail (t != NULL && fptr != NULL); fprintf (fptr, "(hdefine geometry \"t%d\" { =\n", id (t)); fprintf (fptr, "OFF 3 1 0\n" "%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2\n})\n" "(geometry \"t%d\" { : \"t%d\"})\n" "(normalization \"t%d\" none)\n", GTS_POINT (GTS_SEGMENT (t->e1)->v1)->x - xo, GTS_POINT (GTS_SEGMENT (t->e1)->v1)->y - yo, GTS_POINT (GTS_SEGMENT (t->e1)->v1)->z - zo, GTS_POINT (GTS_SEGMENT (t->e1)->v2)->x - xo, GTS_POINT (GTS_SEGMENT (t->e1)->v2)->y - yo, GTS_POINT (GTS_SEGMENT (t->e1)->v2)->z - zo, GTS_POINT (gts_triangle_vertex (t))->x - xo, GTS_POINT (gts_triangle_vertex (t))->y - yo, GTS_POINT (gts_triangle_vertex (t))->z - zo, id (t), id (t), id (t)); }
/** * gts_edge_swap: * @e: a #GtsEdge. * @s: a #GtsSurface. * * Performs an "edge swap" on the two triangles sharing @e and * belonging to @s. */ void gts_edge_swap (GtsEdge * e, GtsSurface * s) { GtsTriangle * t1 = NULL, * t2 = NULL, * t; GtsFace * f; GSList * i; GtsVertex * v1, * v2, * v3, * v4, * v5, * v6; GtsEdge * e1, * e2, * e3, * e4; GtsSegment * v3v6; g_return_if_fail (e != NULL); g_return_if_fail (s != NULL); i = e->triangles; while (i) { if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) { if (!t1) t1 = i->data; else if (!t2) t2 = i->data; else g_return_if_fail (gts_edge_face_number (e, s) == 2); } i = i->next; } g_assert (t1 && t2); gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e1, &e2); gts_triangle_vertices_edges (t2, e, &v4, &v5, &v6, &e, &e3, &e4); g_assert (v2 == v4 && v1 == v5); v3v6 = gts_vertices_are_connected (v3, v6); if (!GTS_IS_EDGE (v3v6)) v3v6 = GTS_SEGMENT (gts_edge_new (s->edge_class, v3, v6)); f = gts_face_new (s->face_class, e1, GTS_EDGE (v3v6), e4); if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) && GTS_IS_FACE (t)) { gts_object_destroy (GTS_OBJECT (f)); f = GTS_FACE (t); } gts_surface_add_face (s, f); f = gts_face_new (s->face_class, GTS_EDGE (v3v6), e2, e3); if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) && GTS_IS_FACE (t)) { gts_object_destroy (GTS_OBJECT (f)); f = GTS_FACE (t); } gts_surface_add_face (s, f); gts_surface_remove_face (s, GTS_FACE (t1)); gts_surface_remove_face (s, GTS_FACE (t2)); }
/** * gts_bbox_overlaps_triangle: * @bb: a #GtsBBox. * @t: a #GtsTriangle. * * This is a wrapper around the fast overlap test of Tomas * Akenine-Moller (http://www.cs.lth.se/home/Tomas_Akenine_Moller/). * * Returns: %TRUE if @bb overlaps with @t, %FALSE otherwise. */ gboolean gts_bbox_overlaps_triangle (GtsBBox * bb, GtsTriangle * t) { double bc[3], bh[3], tv[3][3]; GtsPoint * p1, * p2, * p3; g_return_val_if_fail (bb != NULL, FALSE); g_return_val_if_fail (t != NULL, FALSE); bc[0] = (bb->x2 + bb->x1)/2.; bh[0] = (bb->x2 - bb->x1)/2.; bc[1] = (bb->y2 + bb->y1)/2.; bh[1] = (bb->y2 - bb->y1)/2.; bc[2] = (bb->z2 + bb->z1)/2.; bh[2] = (bb->z2 - bb->z1)/2.; p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); p3 = GTS_POINT (gts_triangle_vertex (t)); tv[0][0] = p1->x; tv[0][1] = p1->y; tv[0][2] = p1->z; tv[1][0] = p2->x; tv[1][1] = p2->y; tv[1][2] = p2->z; tv[2][0] = p3->x; tv[2][1] = p3->y; tv[2][2] = p3->z; return triBoxOverlap (bc, bh, tv); }
static void smooth_fold (GtsVertex * v, gpointer * data) { gdouble * maxcosine2 = data[2]; GSList * i = v->segments; gboolean folded = FALSE; guint * nfold = data[3]; while (i && !folded) { if (GTS_IS_EDGE (i->data)) { GtsEdge * e = i->data; if (gts_triangles_are_folded (e->triangles, GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2, *maxcosine2)) folded = TRUE; } i = i->next; } if (folded) { (*nfold)++; smooth_vertex (v, data); } }
/** * gts_segment_new: * @klass: a #GtsSegmentClass. * @v1: a #GtsVertex. * @v2: another #GtsVertex different from @v1. * * Returns: a new #GtsSegment linking @v1 and @v2. */ GtsSegment * gts_segment_new (GtsSegmentClass * klass, GtsVertex * v1, GtsVertex * v2) { GtsSegment * s; g_return_val_if_fail (v1 != NULL, NULL); g_return_val_if_fail (v2 != NULL, NULL); g_return_val_if_fail (v1 != v2, NULL); s = GTS_SEGMENT (gts_object_new (GTS_OBJECT_CLASS (klass))); s->v1 = v1; s->v2 = v2; v1->segments = g_slist_prepend (v1->segments, s); v2->segments = g_slist_prepend (v2->segments, s); return s; }
static void segment_destroy (GtsObject * object) { GtsSegment * segment = GTS_SEGMENT (object); GtsVertex * v1 = segment->v1; GtsVertex * v2 = segment->v2; v1->segments = g_slist_remove (v1->segments, segment); if (!GTS_OBJECT_DESTROYED (v1) && !gts_allow_floating_vertices && v1->segments == NULL) gts_object_destroy (GTS_OBJECT (v1)); v2->segments = g_slist_remove (v2->segments, segment); if (!GTS_OBJECT_DESTROYED (v2) && !gts_allow_floating_vertices && v2->segments == NULL) gts_object_destroy (GTS_OBJECT (v2)); (* GTS_OBJECT_CLASS (gts_segment_class ())->parent_class->destroy) (object); }
static gdouble region_area (GtsVertex * v, GtsFace * f) { /* cf. Section 3.3 of [Meyer et al 2002] */ if (gts_triangle_area (GTS_TRIANGLE (f)) == 0.0) return (0.0); if (triangle_obtuse (v, f)) { if (angle_obtuse (v, f)) return (gts_triangle_area (GTS_TRIANGLE (f))/2.0); else return (gts_triangle_area (GTS_TRIANGLE (f))/4.0); } else { GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); return ((cotan (GTS_SEGMENT (e)->v1, v, GTS_SEGMENT (e)->v2)* gts_point_distance2 (GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v2)) + cotan (GTS_SEGMENT (e)->v2, v, GTS_SEGMENT (e)->v1)* gts_point_distance2 (GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v1))) /8.0); } }
void pygts_edge_cleanup(GtsSurface *s) { GSList *edges = NULL; GSList *i, *ii, *cur, *parents=NULL; PygtsEdge *edge; GtsEdge *e, *duplicate; g_return_if_fail(s != NULL); /* build list of edges */ gts_surface_foreach_edge(s, (GtsFunc)build_list, &edges); /* remove degenerate and duplicate edges. Note: we could use gts_edges_merge() to remove the duplicates and then remove the degenerate edges but it is more efficient to do everything at once (and it's more pedagogical too ...) */ /* We want to control manually the destruction of edges */ gts_allow_floating_edges = TRUE; i = edges; while(i) { e = (GtsEdge*)i->data; if(GTS_SEGMENT(e)->v1 == GTS_SEGMENT(e)->v2) { /* edge is degenerate */ if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) { /* destroy e */ gts_object_destroy(GTS_OBJECT(e)); } } else { if((duplicate = gts_edge_is_duplicate(e))) { /* Detach and save any parent triangles */ if( (edge = PYGTS_EDGE(g_hash_table_lookup(obj_table,GTS_OBJECT(e)))) !=NULL ) { ii = e->triangles; while(ii!=NULL) { cur = ii; ii = g_slist_next(ii); if(PYGTS_IS_PARENT_TRIANGLE(cur->data)) { e->triangles = g_slist_remove_link(e->triangles, cur); parents = g_slist_prepend(parents,cur->data); g_slist_free_1(cur); } } } /* replace e with its duplicate */ gts_edge_replace(e, duplicate); /* Reattach the parent segments */ if( edge != NULL ) { ii = parents; while(ii!=NULL) { e->triangles = g_slist_prepend(e->triangles, ii->data); ii = g_slist_next(ii); } g_slist_free(parents); parents = NULL; } if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) { /* destroy e */ gts_object_destroy(GTS_OBJECT (e)); } } } i = g_slist_next(i); } /* don't forget to reset to default */ gts_allow_floating_edges = FALSE; /* free list of edges */ g_slist_free (edges); }
/** * gts_triangle_set: * @triangle: a #GtsTriangle. * @e1: a #GtsEdge. * @e2: another #GtsEdge touching @e1. * @e3: another #GtsEdge touching both @e1 and @e2. * * Sets the edge of @triangle to @e1, @e2 and @e3 while checking that they * define a valid triangle. */ void gts_triangle_set (GtsTriangle * triangle, GtsEdge * e1, GtsEdge * e2, GtsEdge * e3) { g_return_if_fail (e1 != NULL); g_return_if_fail (e2 != NULL); g_return_if_fail (e3 != NULL); g_return_if_fail (e1 != e2 && e1 != e3 && e2 != e3); triangle->e1 = e1; triangle->e2 = e2; triangle->e3 = e3; if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), GTS_SEGMENT (e1)->v2, GTS_SEGMENT (e2)->v2)); else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), GTS_SEGMENT (e1)->v1, GTS_SEGMENT (e2)->v2)); else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), GTS_SEGMENT (e1)->v1, GTS_SEGMENT (e2)->v1)); else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2) g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), GTS_SEGMENT (e1)->v2, GTS_SEGMENT (e2)->v1)); else return; //finetjul: g_assert_not_reached (); e1->triangles = g_slist_prepend (e1->triangles, triangle); e2->triangles = g_slist_prepend (e2->triangles, triangle); e3->triangles = g_slist_prepend (e3->triangles, triangle); }
static PyObject * new_(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *o; PygtsObject *obj; GtsSegment *tmp; GtsObject *segment=NULL; PyObject *v1_=NULL,*v2_=NULL; PygtsVertex *v1,*v2; guint alloc_gtsobj = TRUE; guint N; /* Parse the args */ if(kwds) { o = PyDict_GetItemString(kwds,"alloc_gtsobj"); if(o==Py_False) { alloc_gtsobj = FALSE; } if(o!=NULL) { PyDict_DelItemString(kwds, "alloc_gtsobj"); } } if(kwds) { Py_INCREF(Py_False); PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False); } /* Allocate the gtsobj (if needed) */ if( alloc_gtsobj ) { /* Parse the args */ if( (N = PyTuple_Size(args)) < 2 ) { PyErr_SetString(PyExc_TypeError,"expected two Vertices"); return NULL; } v1_ = PyTuple_GET_ITEM(args,0); v2_ = PyTuple_GET_ITEM(args,1); /* Convert to PygtsObjects */ if(!pygts_vertex_check(v1_)) { PyErr_SetString(PyExc_TypeError,"expected two Vertices"); return NULL; } if(!pygts_vertex_check(v2_)) { PyErr_SetString(PyExc_TypeError,"expected two Vertices"); return NULL; } v1 = PYGTS_VERTEX(v1_); v2 = PYGTS_VERTEX(v2_); /* Error check */ if(PYGTS_OBJECT(v1)->gtsobj == PYGTS_OBJECT(v2)->gtsobj) { PyErr_SetString(PyExc_ValueError,"Vertices are identical"); return NULL; } /* Create the GtsSegment */ segment = GTS_OBJECT(gts_segment_new(gts_segment_class(), GTS_VERTEX(v1->gtsobj), GTS_VERTEX(v2->gtsobj))); if( segment == NULL ) { PyErr_SetString(PyExc_MemoryError, "could not create Segment"); return NULL; } /* Check for duplicate */ tmp = gts_segment_is_duplicate(GTS_SEGMENT(segment)); if( tmp != NULL ) { gts_object_destroy(segment); segment = GTS_OBJECT(tmp); } /* If corresponding PyObject found in object table, we are done */ if( (obj=(PygtsObject*)g_hash_table_lookup(obj_table,segment)) != NULL ) { Py_INCREF(obj); return (PyObject*)obj; } } /* Chain up */ obj = PYGTS_OBJECT(PygtsObjectType.tp_new(type,args,kwds)); if( alloc_gtsobj ) { obj->gtsobj = segment; pygts_object_register(PYGTS_OBJECT(obj)); } return (PyObject*)obj; }
/* stripe - Turns the input surface into triangle strips and outputs a Geomview representation of the result. */ int main (int argc, char * argv[]) { GtsSurface * s; GSList * strips = NULL, * i; gboolean verbose = FALSE; int c = 0; GtsFile * fp; /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hv", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hv"))) { #endif /* not HAVE_GETOPT_LONG */ case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: stripe [OPTION] < FILE\n" "Turns the input surface into triangle strips and outputs a\n" "Geomview representation of the result.\n" "\n" " -v --verbose print statistics about the surface and strips\n" " -h --help display this help and exit\n" "\n" "Report bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `stripe --help' for more information.\n"); return 1; /* failure */ } } /* read surface in */ s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("stripe: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } gts_file_destroy (fp); if (verbose) gts_surface_print_stats (s, stderr); strips = gts_surface_strip (s); /* if verbose on print stats */ if (verbose) { GtsRange l; gts_range_init (&l); i = strips; while (i) { gts_range_add_value (&l, g_slist_length (i->data)); i = i->next; } gts_range_update (&l); fprintf (stderr, "# Strips: %d\n# length : ", l.n); gts_range_print (&l, stderr); fputc ('\n', stderr); } puts ("LIST {\n"); i = strips; while (i) { GList * j = i->data; GtsTriangle * oldt = NULL; GtsColor c; c.r = rand ()/(gdouble) RAND_MAX; c.g = rand ()/(gdouble) RAND_MAX; c.b = rand ()/(gdouble) RAND_MAX; while (j) { GtsTriangle * t = j->data; GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1), * p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2), * p3 = GTS_POINT (gts_triangle_vertex (t)); printf ("OFF 3 1 3\n%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2 %g %g %g\n", p1->x, p1->y, p1->z, p2->x, p2->y, p2->z, p3->x, p3->y, p3->z, c.r, c.g, c.b); if (oldt) { GtsSegment * cs = GTS_SEGMENT (gts_triangles_common_edge (t, oldt)); GtsPoint * op1 = GTS_POINT (GTS_SEGMENT (oldt->e1)->v1), * op2 = GTS_POINT (GTS_SEGMENT (oldt->e1)->v2), * op3 = GTS_POINT (gts_triangle_vertex (oldt)); printf ("VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n", (op1->x + op2->x + op3->x)/3., (op1->y + op2->y + op3->y)/3., (op1->z + op2->z + op3->z)/3., (GTS_POINT (cs->v1)->x + GTS_POINT (cs->v2)->x)/2., (GTS_POINT (cs->v1)->y + GTS_POINT (cs->v2)->y)/2., (GTS_POINT (cs->v1)->z + GTS_POINT (cs->v2)->z)/2., (p1->x + p2->x + p3->x)/3., (p1->y + p2->y + p3->y)/3., (p1->z + p2->z + p3->z)/3.); } oldt = t; j = j->next; } i = i->next; } puts ("}\n"); return 0; /* success */ }
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; } }