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_bbox_segment: * @klass: a #GtsBBoxClass. * @s: a #GtsSegment. * * Returns: a new #GtsBBox bounding box of @s. */ GtsBBox * gts_bbox_segment (GtsBBoxClass * klass, GtsSegment * s) { GtsBBox * bbox; GtsPoint * p1, * p2; g_return_val_if_fail (s != NULL, NULL); g_return_val_if_fail (klass != NULL, NULL); bbox = gts_bbox_new (klass, s, 0., 0., 0., 0., 0., 0.); p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2); if (p1->x > p2->x) { bbox->x2 = p1->x; bbox->x1 = p2->x; } else { bbox->x1 = p1->x; bbox->x2 = p2->x; } if (p1->y > p2->y) { bbox->y2 = p1->y; bbox->y1 = p2->y; } else { bbox->y1 = p1->y; bbox->y2 = p2->y; } if (p1->z > p2->z) { bbox->z2 = p1->z; bbox->z1 = p2->z; } else { bbox->z1 = p1->z; bbox->z2 = p2->z; } return bbox; }
/** * gts_triangles_are_folded: * @triangles: a list of #GtsTriangle. * @A: a #GtsVertex. * @B: another #GtsVertex. * @max: the maximum value of the square of the cosine of the angle between * two triangles. * * Given a list of triangles sharing @A and @B as vertices, checks if any * two triangles in the list make an angle larger than a given value defined * by @max. * * Returns: %TRUE if any pair of triangles in @triangles makes an angle larger * than the maximum value, %FALSE otherwise. */ gboolean gts_triangles_are_folded (GSList * triangles, GtsVertex * A, GtsVertex * B, gdouble max) { GSList * i; g_return_val_if_fail (A != NULL, TRUE); g_return_val_if_fail (B != NULL, TRUE); i = triangles; while (i) { GtsVertex * C = triangle_use_vertices (i->data, A, B); GSList * j = i->next; while (j) { GtsVertex * D = triangle_use_vertices (j->data, A, B); if (points_are_folded (GTS_POINT (A), GTS_POINT (B), GTS_POINT (C), GTS_POINT (D), max)) return TRUE; j = j->next; } i = i->next; } return FALSE; }
/** * 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; }
/** * 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)); }
static GtsSurface * happrox_list (GSList * points, gboolean keep_enclosing, gboolean closed, CostFunc cost_func, gpointer cost_data, GtsStopFunc stop_func, gpointer stop_data) { GtsSurface * s = gts_surface_new (gts_surface_class (), GTS_FACE_CLASS (list_face_class ()), gts_edge_class (), gts_vertex_class ()); GtsTriangle * t; GtsVertex * w1, * w2, * w3; GtsListFace * f; /* creates enclosing triangle */ t = gts_triangle_enclosing (gts_triangle_class (), points, 10.); gts_triangle_vertices (t, &w1, &w2, &w3); GTS_POINT (w1)->z = GTS_POINT (w2)->z = GTS_POINT (w3)->z = keep_enclosing ? -10. : -1e30; f = GTS_LIST_FACE (gts_face_new (s->face_class, t->e1, t->e2, t->e3)); gts_surface_add_face (s, GTS_FACE (f)); f->points = points; /* refine surface */ surface_hf_refine (s, cost_func, cost_data, stop_func, stop_data); /* destroy unused vertices */ gts_surface_foreach_face (s, (GtsFunc) destroy_unused, NULL); /* destroy enclosing triangle */ if (!keep_enclosing) { gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (w1)); gts_object_destroy (GTS_OBJECT (w2)); gts_object_destroy (GTS_OBJECT (w3)); gts_allow_floating_vertices = FALSE; } else if (closed) { GSList * l = gts_surface_boundary (s); GtsFace * f; g_assert (g_slist_length (l) == 3); f = gts_face_new (s->face_class, l->data, l->next->data, l->next->next->data); gts_surface_add_face (s, f); if (!gts_face_is_compatible (f, s)) gts_triangle_revert (GTS_TRIANGLE (f)); g_slist_free (l); gts_object_destroy (GTS_OBJECT (t)); } else gts_object_destroy (GTS_OBJECT (t)); return s; }
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); }
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)); }
void gts_triangulate_convex_polygon(GtsSurface *s, GtsEdgePool *pool, GCList *p) { guint poly_length = g_clist_length(p); while (poly_length > 2) { while (poly_length > 3) { GtsVector e1, e2; GtsPoint *v1 = GTS_POINT(p->prev->data); GtsPoint *v2 = GTS_POINT(p->data); GtsPoint *v3 = GTS_POINT(p->next->data); GtsPoint *v4 = GTS_POINT(p->next->next->data); if (v1 == v3 || v2 == v4) { g_debug("kill degenerated triangle"); GCList *p1 = p; GCList *p2 = p->next; p=g_clist_delete_link(p,p1); p=g_clist_delete_link(p,p2); poly_length -= 2; continue; } gts_vector_init(e1, v1, v3); gts_vector_init(e2, v2, v4); if (gts_vector_scalar(e1, e1) < gts_vector_scalar(e2, e2)) { add_face_from_polygon_corner(s, pool, GTS_VERTEX(v1), GTS_VERTEX(v2), GTS_VERTEX(v3)); p = g_clist_delete_link(p, p); } else { add_face_from_polygon_corner(s, pool, GTS_VERTEX(v2), GTS_VERTEX(v3), GTS_VERTEX(v4)); p = g_clist_delete_link(p, p->next); } --poly_length; } if (g_clist_length(p) > 2) { add_face_from_polygon_corner(s, pool, GTS_VERTEX(p->prev->data), GTS_VERTEX(p->data), GTS_VERTEX(p->next->data)); p = g_clist_delete_link(p, p); --poly_length; } } g_clist_free(p); }
/** * gts_triangle_normal: * @t: a #GtsTriangle. * @x: the x coordinate of the normal. * @y: the y coordinate of the normal. * @z: the z coordinate of the normal. * * Computes the coordinates of the oriented normal of @t as the * cross-product of two edges, using the left-hand rule. The normal is * not normalized. If this triangle is part of a closed and oriented * surface, the normal points to the outside of the surface. */ void gts_triangle_normal (GtsTriangle * t, gdouble * x, gdouble * y, gdouble * z) { GtsVertex * v1, * v2 = NULL, * v3 = NULL; GtsPoint * p1, * p2, * p3; gdouble x1, y1, z1, x2, y2, z2; g_return_if_fail (t != NULL); 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 { fprintf (stderr, "t: %p t->e1: %p t->e2: %p t->e3: %p t->e1->v1: %p t->e1->v2: %p t->e2->v1: %p t->e2->v2: %p t->e3->v1: %p t->e3->v2: %p\n", t, t->e1, t->e2, t->e3, GTS_SEGMENT (t->e1)->v1, GTS_SEGMENT (t->e1)->v2, GTS_SEGMENT (t->e2)->v1, GTS_SEGMENT (t->e2)->v2, GTS_SEGMENT (t->e3)->v1, GTS_SEGMENT (t->e3)->v2); g_assert_not_reached (); } p1 = GTS_POINT (v1); p2 = GTS_POINT (v2); p3 = GTS_POINT (v3); x1 = p2->x - p1->x; y1 = p2->y - p1->y; z1 = p2->z - p1->z; x2 = p3->x - p1->x; y2 = p3->y - p1->y; z2 = p3->z - p1->z; *x = y1*z2 - z1*y2; *y = z1*x2 - x1*z2; *z = x1*y2 - y1*x2; }
/** * gts_segment_midvertex: * @s: a #GtsSegment. * @klass: a #GtsVertexClass to be used for the new vertex. * * Returns: a new #GtsVertex, midvertex of @s. */ GtsVertex * gts_segment_midvertex (GtsSegment * s, GtsVertexClass * klass) { GtsPoint * p1, * p2; g_return_val_if_fail (s != NULL, NULL); g_return_val_if_fail (klass != NULL, NULL); p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2); return gts_vertex_new (klass, (p1->x + p2->x)/2., (p1->y + p2->y)/2., (p1->z + p2->z)/2.); }
static gdouble edge_swap_cost (GtsEdge * e) { GSList * i; GtsTriangle * t1 = NULL, * t2 = NULL; GtsVertex * v1, * v2, * v3, * v4; GtsEdge * e1, * e2, * e3, * e4; gdouble ab, aa; i = e->triangles; while (i) { if (GTS_IS_FACE (i->data)) { if (!t1) t1 = i->data; else if (!t2) t2 = i->data; else return G_MAXDOUBLE; } i = i->next; } if (!t1 || !t2) return G_MAXDOUBLE; gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e3, &e4); gts_triangle_vertices_edges (t2, e, &v2, &v1, &v4, &e, &e1, &e2); ab = triangles_angle (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3), GTS_POINT (v4)); aa = triangles_angle (GTS_POINT (v3), GTS_POINT (v4), GTS_POINT (v2), GTS_POINT (v1)); return fabs (ab) - fabs (aa); }
/* Helper function for inGtsSurface::aabb() */ static void vertex_aabb(GtsVertex *vertex, std::pair<Vector3r,Vector3r> *bb) { GtsPoint *_p=GTS_POINT(vertex); Vector3r p(_p->x,_p->y,_p->z); bb->first=bb->first.cwiseMin(p); bb->second=bb->second.cwiseMax(p); }
gint gts_polygon_orientation(GCList *polygon, GtsVector retval) { GtsVector a,b; retval[0] = retval[1] = retval[2] = 0.0; if (polygon->next == polygon->prev) /* only two points */ return 0; gts_vector_init(a, GTS_POINT(polygon->data), GTS_POINT(polygon->prev->data)); gts_vector_init(b, GTS_POINT(polygon->data), GTS_POINT(polygon->next->data)); gts_vector_cross(retval, a, b); gts_vector_normalize(retval); return 1; }
/** * gts_bb_tree_triangle_distance: * @tree: a bounding box tree. * @t: a #GtsTriangle. * @distance: a #GtsBBoxDistFunc. * @delta: spatial scale of the sampling to be used. * @range: a #GtsRange to be filled with the results. * * Given a triangle @t, points are sampled regularly on its surface * using @delta as increment. The distance from each of these points * to the closest object of @tree is computed using @distance and the * gts_bb_tree_point_distance() function. The fields of @range are * filled with the number of points sampled, the minimum, average and * maximum value and the standard deviation. */ void gts_bb_tree_triangle_distance (GNode * tree, GtsTriangle * t, GtsBBoxDistFunc distance, gdouble delta, GtsRange * range) { GtsPoint * p1, * p2, * p3, * p; GtsVector p1p2, p1p3; gdouble l1, t1, dt1; guint i, n1; g_return_if_fail (tree != NULL); g_return_if_fail (t != NULL); g_return_if_fail (distance != NULL); g_return_if_fail (delta > 0.); g_return_if_fail (range != NULL); gts_triangle_vertices (t, (GtsVertex **) &p1, (GtsVertex **) &p2, (GtsVertex **) &p3); gts_vector_init (p1p2, p1, p2); gts_vector_init (p1p3, p1, p3); gts_range_init (range); p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ()))); l1 = sqrt (gts_vector_scalar (p1p2, p1p2)); n1 = l1/delta + 1; dt1 = 1.0/(gdouble) n1; t1 = 0.0; for (i = 0; i <= n1; i++, t1 += dt1) { gdouble t2 = 1. - t1; gdouble x = t2*p1p3[0]; gdouble y = t2*p1p3[1]; gdouble z = t2*p1p3[2]; gdouble l2 = sqrt (x*x + y*y + z*z); guint j, n2 = (guint) (l2/delta + 1); gdouble dt2 = t2/(gdouble) n2; x = t2*p1->x + t1*p2->x; y = t2*p1->y + t1*p2->y; z = t2*p1->z + t1*p2->z; t2 = 0.0; for (j = 0; j <= n2; j++, t2 += dt2) { p->x = x + t2*p1p3[0]; p->y = y + t2*p1p3[1]; p->z = z + t2*p1p3[2]; gts_range_add_value (range, gts_bb_tree_point_distance (tree, p, distance, NULL)); } } gts_object_destroy (GTS_OBJECT (p)); gts_range_update (range); }
int pygts_segment_compare(GtsSegment* s1,GtsSegment* s2) { if( (pygts_point_compare(GTS_POINT(s1->v1),GTS_POINT(s2->v1))==0 && pygts_point_compare(GTS_POINT(s1->v2),GTS_POINT(s2->v2))==0) || (pygts_point_compare(GTS_POINT(s1->v1),GTS_POINT(s2->v2))==0 && pygts_point_compare(GTS_POINT(s1->v2),GTS_POINT(s2->v1))==0) ) { return 0; } return -1; }
static gdouble angle_from_cotan (GtsVertex * vo, GtsVertex * v1, GtsVertex * v2) { /* cf. Appendix B and the caption of Table 1 from [Meyer et al 2002] */ GtsVector u, v; gdouble udotv, denom; gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1)); gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2)); udotv = gts_vector_scalar (u, v); denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) - udotv*udotv); /* Note: I assume this is what they mean by using atan2 (). -Ray Jones */ /* tan = denom/udotv = y/x (see man page for atan2) */ return (fabs (atan2 (denom, udotv))); }
static gdouble cotan (GtsVertex * vo, GtsVertex * v1, GtsVertex * v2) { /* cf. Appendix B of [Meyer et al 2002] */ GtsVector u, v; gdouble udotv, denom; gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1)); gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2)); udotv = gts_vector_scalar (u, v); denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) - udotv*udotv); /* denom can be zero if u==v. Returning 0 is acceptable, based on * the callers of this function below. */ if (denom == 0.0) return (0.0); return (udotv/denom); }
/** * gts_bb_tree_segment_distance: * @tree: a bounding box tree. * @s: a #GtsSegment. * @distance: a #GtsBBoxDistFunc. * @delta: spatial scale of the sampling to be used. * @range: a #GtsRange to be filled with the results. * * Given a segment @s, points are sampled regularly on its length * using @delta as increment. The distance from each of these points * to the closest object of @tree is computed using @distance and the * gts_bb_tree_point_distance() function. The fields of @range are * filled with the number of points sampled, the minimum, average and * maximum value and the standard deviation. */ void gts_bb_tree_segment_distance (GNode * tree, GtsSegment * s, gdouble (*distance) (GtsPoint *, gpointer), gdouble delta, GtsRange * range) { GtsPoint * p1, * p2, * p; GtsVector p1p2; gdouble l, t, dt; guint i, n; g_return_if_fail (tree != NULL); g_return_if_fail (s != NULL); g_return_if_fail (distance != NULL); g_return_if_fail (delta > 0.); g_return_if_fail (range != NULL); p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2); gts_vector_init (p1p2, p1, p2); gts_range_init (range); p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class()))); l = sqrt (gts_vector_scalar (p1p2, p1p2)); n = (guint) (l/delta + 1); dt = 1.0/(gdouble) n; t = 0.0; for (i = 0; i <= n; i++, t += dt) { p->x = p1->x + t*p1p2[0]; p->y = p1->y + t*p1p2[1]; p->z = p1->z + t*p1p2[2]; gts_range_add_value (range, gts_bb_tree_point_distance (tree, p, distance, NULL)); } gts_object_destroy (GTS_OBJECT (p)); gts_range_update (range); }
static void write_face (GtsTriangle * t) { GtsVertex * v1, * v2, * v3; GtsVector n; gts_triangle_vertices (t, &v1, &v2, &v3); gts_triangle_normal (t, &n[0], &n[1], &n[2]); gts_vector_normalize (n); printf ("facet normal %g %g %g\nouter loop\n", n[0], n[1], n[2]); printf ("vertex %g %g %g\n", GTS_POINT (v1)->x, GTS_POINT (v1)->y, GTS_POINT (v1)->z); printf ("vertex %g %g %g\n", GTS_POINT (v2)->x, GTS_POINT (v2)->y, GTS_POINT (v2)->z); printf ("vertex %g %g %g\n", GTS_POINT (v3)->x, GTS_POINT (v3)->y, GTS_POINT (v3)->z); puts ("endloop\nendfacet"); }
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; }
static void smooth_vertex (GtsVertex * v, gpointer * data) { GtsSurface * s = data[0]; if (!gts_vertex_is_boundary (v, s)) { gdouble * lambda = data[1]; GSList * vertices = gts_vertex_neighbors (v, NULL, s); GSList * i; GtsVector U0 = { 0., 0., 0.}; guint n = 0; i = vertices; while (i) { GtsPoint * p = i->data; U0[0] += p->x; U0[1] += p->y; U0[2] += p->z; n++; i = i->next; } g_slist_free (vertices); if (n > 0) { GTS_POINT (v)->x += (*lambda)*(U0[0]/n - GTS_POINT (v)->x); GTS_POINT (v)->y += (*lambda)*(U0[1]/n - GTS_POINT (v)->y); GTS_POINT (v)->z += (*lambda)*(U0[2]/n - GTS_POINT (v)->z); } } }
/** * 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); }
/** * gts_bbox_overlaps_segment: * @bb: a #GtsBBox. * @s: a #GtsSegment. * * This functions uses gts_bbox_overlaps_triangle() with a degenerate * triangle. * * Returns: %TRUE if @bb overlaps with @s, %FALSE otherwise. */ gboolean gts_bbox_overlaps_segment (GtsBBox * bb, GtsSegment * s) { 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 (s != 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 (s->v1); p2 = GTS_POINT (s->v2); p3 = p1; 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 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); } }
/** * 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; }
/** * gts_triangle_enclosing: * @klass: the class of the new triangle. * @points: a list of #GtsPoint. * @scale: a scaling factor (must be larger than one). * * Builds a new triangle (including new vertices and edges) enclosing * the plane projection of all the points in @points. This triangle is * equilateral and encloses a rectangle defined by the maximum and * minimum x and y coordinates of the points. @scale is an homothetic * scaling factor. If equal to one, the triangle encloses exactly the * enclosing rectangle. * * Returns: a new #GtsTriangle. */ GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass, GSList * points, gdouble scale) { gdouble xmax, xmin, ymax, ymin; gdouble xo, yo, r; GtsVertex * v1, * v2, * v3; GtsEdge * e1, * e2, * e3; if (points == NULL) return NULL; xmax = xmin = GTS_POINT (points->data)->x; ymax = ymin = GTS_POINT (points->data)->y; points = points->next; while (points) { GtsPoint * p = points->data; if (p->x > xmax) xmax = p->x; else if (p->x < xmin) xmin = p->x; if (p->y > ymax) ymax = p->y; else if (p->y < ymin) ymin = p->y; points = points->next; } xo = (xmax + xmin)/2.; yo = (ymax + ymin)/2.; r = scale*sqrt((xmax - xo)*(xmax - xo) + (ymax - yo)*(ymax - yo)); if (r == 0.0) r = scale; v1 = gts_vertex_new (gts_vertex_class (), xo + r*SQRT3, yo - r, 0.0); v2 = gts_vertex_new (gts_vertex_class (), xo, yo + 2.*r, 0.0); v3 = gts_vertex_new (gts_vertex_class (), xo - r*SQRT3, yo - r, 0.0); e1 = gts_edge_new (gts_edge_class (), v1, v2); e2 = gts_edge_new (gts_edge_class (), v2, v3); e3 = gts_edge_new (gts_edge_class (), v3, v1); return gts_triangle_new (gts_triangle_class (), e1, e2, e3); }
static void write_edge (GtsSegment * s, FILE * fp) { fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n", GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z, GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z); }
/** * 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)); }