static PyObject* is_on(PygtsFace *self, PyObject *args) { PyObject *s_=NULL; PygtsSurface *s=NULL; SELF_CHECK /* Parse the args */ if(! PyArg_ParseTuple(args, "O", &s_) ) return NULL; /* Convert to PygtsObjects */ if( pygts_surface_check(s_) ) { s = PYGTS_SURFACE(s_); } else { PyErr_SetString(PyExc_TypeError, "expected a Surface"); return NULL; } if( gts_face_has_parent_surface(PYGTS_FACE_AS_GTS_FACE(self), PYGTS_SURFACE_AS_GTS_SURFACE(s)) ) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } }
static void mark_as_hole (GtsFace * f, GtsSurface * s) { GtsEdge * e1, * e2, * e3; if (GTS_OBJECT (f)->reserved == f) return; GTS_OBJECT (f)->reserved = f; e1 = GTS_TRIANGLE (f)->e1; e2 = GTS_TRIANGLE (f)->e2; e3 = GTS_TRIANGLE (f)->e3; if (!GTS_IS_CONSTRAINT (e1)) { GSList * i = e1->triangles; while (i) { GtsFace * f1 = i->data; if (f1 != f && GTS_IS_FACE (f1) && gts_face_has_parent_surface (f1, s)) mark_as_hole (f1, s); i = i->next; } } if (!GTS_IS_CONSTRAINT (e2)) { GSList * i = e2->triangles; while (i) { GtsFace * f1 = i->data; if (f1 != f && GTS_IS_FACE (f1) && gts_face_has_parent_surface (f1, s)) mark_as_hole (f1, s); i = i->next; } } if (!GTS_IS_CONSTRAINT (e3)) { GSList * i = e3->triangles; while (i) { GtsFace * f1 = i->data; if (f1 != f && GTS_IS_FACE (f1) && gts_face_has_parent_surface (f1, s)) mark_as_hole (f1, s); i = i->next; } } }
/** * 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)); }
static void edge_mark_as_hole (GtsEdge * e, GtsSurface * s) { GSList * i = e->triangles; while (i) { GtsFace * f = i->data; if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s) && triangle_is_hole (GTS_TRIANGLE (f))) mark_as_hole (f, s); i = i->next; } }
/** * gts_edge_has_parent_surface: * @e: a #GtsEdge. * @surface: a #GtsSurface. * * Returns: a #GtsFace of @surface having @e as an edge, %NULL otherwise. */ GtsFace * gts_edge_has_parent_surface (GtsEdge * e, GtsSurface * surface) { GSList * i; g_return_val_if_fail (e != NULL, NULL); i = e->triangles; while (i) { if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, surface)) return i->data; i = i->next; } return NULL; }
/** * gts_edge_face_number: * @e: a #GtsEdge. * @s: a #GtsSurface. * * Returns: the number of faces using @e and belonging to @s. */ guint gts_edge_face_number (GtsEdge * e, GtsSurface * s) { GSList * i; guint nt = 0; g_return_val_if_fail (e != NULL, 0); g_return_val_if_fail (s != NULL, 0); i = e->triangles; while (i) { if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (GTS_FACE (i->data), s)) nt++; i = i->next; } return nt; }
/** * gts_edge_is_boundary: * @e: a #GtsEdge. * @surface: a #GtsSurface or %NULL. * * Returns: the unique #GtsFace (which belongs to @surface) and which * has @e as an edge (i.e. @e is a boundary edge (of @surface)) or %NULL * if there is more than one or no faces (belonging to @surface) and * with @e as an edge. */ GtsFace * gts_edge_is_boundary (GtsEdge * e, GtsSurface * surface) { GSList * i; GtsFace * f = NULL; g_return_val_if_fail (e != NULL, NULL); i = e->triangles; while (i) { if (GTS_IS_FACE (i->data)) { if (!surface || gts_face_has_parent_surface (i->data, surface)) { if (f != NULL) return NULL; f = i->data; } } i = i->next; } return f; }
/** * gts_edge_manifold_faces: * @e: a #GtsEdge. * @s: a #GtsSurface. * @f1: pointer for first face. * @f2: pointer for second face. * * If @e is a manifold edge of surface @s, fills @f1 and @f2 with the * faces belonging to @s and sharing @e. * * Returns: %TRUE if @e is a manifold edge, %FALSE otherwise. */ gboolean gts_edge_manifold_faces (GtsEdge * e, GtsSurface * s, GtsFace ** f1, GtsFace ** f2) { GSList * i; g_return_val_if_fail (e != NULL, FALSE); g_return_val_if_fail (s != NULL, FALSE); g_return_val_if_fail (f1 != NULL, FALSE); g_return_val_if_fail (f2 != NULL, FALSE); *f1 = *f2 = NULL; i = e->triangles; while (i) { if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) { if (!(*f1)) *f1 = i->data; else if (!(*f2)) *f2 = i->data; else return FALSE; } i = i->next; } return (*f1 && *f2); }
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; } }
GSList *gts_vertex_faces( GtsVertex *v, GtsSurface *surface, GSList *list ) { int eax; GSList *i; { /* phantom */ int _g_boolean_var_; if ( v == 0 ) { g_return_if_fail_warning( 0, __PRETTY_FUNCTION__, "v != NULL" ); list = 0; } i = &v->segments; if ( v->segments[4].next ) { { do { if ( gts_edge_class( ) == 0 ) { g_return_if_fail_warning( 0, __PRETTY_FUNCTION__, "klass != NULL" ); i = &i->next; if ( i->next == 0 ) break; } else { if ( i->data[0] ) { if ( *(int*)(i->data[0]) == 0 ) { g_return_if_fail_warning( 0, __PRETTY_FUNCTION__, "c != NULL" ); i = &i->next; if ( i->next == 0 ) break; } else do { if ( *(int*)(*(int*)(i->data[0]) + 64) == gts_edge_class( ) ) { GSList *j = j[2].next; if ( j[2].next ) { { do { if ( gts_face_class( ) == 0 ) g_return_if_fail_warning( 0, __PRETTY_FUNCTION__, "klass != NULL" ); else if ( j ) { if ( j->data[0] == 0 ) g_return_if_fail_warning( 0, __PRETTY_FUNCTION__, "c != NULL" ); else do { if ( j->_GSList == gts_face_class( ) ) { if ( ( !surface || gts_face_has_parent_surface( &j->data[0], surface ) ) && g_slist_find( list, &j ) == 0 ) { list = g_slist_prepend( list, &j ); break; } else break; } else } while ( j->_GSList ); } j = j->next; } while ( j->next ); break; } } else break; } else { } } while ( *(int*)(*(int*)(*(int*)(i->data[0]) + 64) + 64) ); } i = &i->next; } }
/** * gts_vertex_principal_directions: * @v: a #GtsVertex. * @s: a #GtsSurface. * @Kh: mean curvature normal (a #GtsVector). * @Kg: Gaussian curvature (a gdouble). * @e1: first principal curvature direction (direction of largest curvature). * @e2: second principal curvature direction. * * Computes the principal curvature directions at a point given @Kh * and @Kg, the mean curvature normal and Gaussian curvatures at that * point, computed with gts_vertex_mean_curvature_normal() and * gts_vertex_gaussian_curvature(), respectively. * * Note that this computation is very approximate and tends to be * unstable. Smoothing of the surface or the principal directions may * be necessary to achieve reasonable results. */ void gts_vertex_principal_directions (GtsVertex * v, GtsSurface * s, GtsVector Kh, gdouble Kg, GtsVector e1, GtsVector e2) { GtsVector N; gdouble normKh; GSList * i, * j; GtsVector basis1, basis2, d, eig; gdouble ve2, vdotN; gdouble aterm_da, bterm_da, cterm_da, const_da; gdouble aterm_db, bterm_db, cterm_db, const_db; gdouble a, b, c; gdouble K1, K2; gdouble *weights, *kappas, *d1s, *d2s; gint edge_count; gdouble err_e1, err_e2; int e; /* compute unit normal */ normKh = sqrt (gts_vector_scalar (Kh, Kh)); if (normKh > 0.0) { N[0] = Kh[0] / normKh; N[1] = Kh[1] / normKh; N[2] = Kh[2] / normKh; } else { /* This vertex is a point of zero mean curvature (flat or saddle * point). Compute a normal by averaging the adjacent triangles */ N[0] = N[1] = N[2] = 0.0; i = gts_vertex_faces (v, s, NULL); while (i) { gdouble x, y, z; gts_triangle_normal (GTS_TRIANGLE ((GtsFace *) i->data), &x, &y, &z); N[0] += x; N[1] += y; N[2] += z; i = i->next; } g_return_if_fail (gts_vector_norm (N) > 0.0); gts_vector_normalize (N); } /* construct a basis from N: */ /* set basis1 to any component not the largest of N */ basis1[0] = basis1[1] = basis1[2] = 0.0; if (fabs (N[0]) > fabs (N[1])) basis1[1] = 1.0; else basis1[0] = 1.0; /* make basis2 orthogonal to N */ gts_vector_cross (basis2, N, basis1); gts_vector_normalize (basis2); /* make basis1 orthogonal to N and basis2 */ gts_vector_cross (basis1, N, basis2); gts_vector_normalize (basis1); aterm_da = bterm_da = cterm_da = const_da = 0.0; aterm_db = bterm_db = cterm_db = const_db = 0.0; weights = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); kappas = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); d1s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); d2s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); edge_count = 0; i = v->segments; while (i) { GtsEdge * e; GtsFace * f1, * f2; gdouble weight, kappa, d1, d2; GtsVector vec_edge; if (! GTS_IS_EDGE (i->data)) { i = i->next; continue; } e = i->data; /* since this vertex passed the tests in * gts_vertex_mean_curvature_normal(), this should be true. */ g_assert (gts_edge_face_number (e, s) == 2); /* identify the two triangles bordering e in s */ f1 = f2 = NULL; j = e->triangles; while (j) { if ((! GTS_IS_FACE (j->data)) || (! gts_face_has_parent_surface (GTS_FACE (j->data), s))) { j = j->next; continue; } if (f1 == NULL) f1 = GTS_FACE (j->data); else { f2 = GTS_FACE (j->data); break; } j = j->next; } g_assert (f2 != NULL); /* We are solving for the values of the curvature tensor * B = [ a b ; b c ]. * The computations here are from section 5 of [Meyer et al 2002]. * * The first step is to calculate the linear equations governing * the values of (a,b,c). These can be computed by setting the * derivatives of the error E to zero (section 5.3). * * Since a + c = norm(Kh), we only compute the linear equations * for dE/da and dE/db. (NB: [Meyer et al 2002] has the * equation a + b = norm(Kh), but I'm almost positive this is * incorrect.) * * Note that the w_ij (defined in section 5.2) are all scaled by * (1/8*A_mixed). We drop this uniform scale factor because the * solution of the linear equations doesn't rely on it. * * The terms of the linear equations are xterm_dy with x in * {a,b,c} and y in {a,b}. There are also const_dy terms that are * the constant factors in the equations. */ /* find the vector from v along edge e */ gts_vector_init (vec_edge, GTS_POINT (v), GTS_POINT ((GTS_SEGMENT (e)->v1 == v) ? GTS_SEGMENT (e)->v2 : GTS_SEGMENT (e)->v1)); ve2 = gts_vector_scalar (vec_edge, vec_edge); vdotN = gts_vector_scalar (vec_edge, N); /* section 5.2 - There is a typo in the computation of kappa. The * edges should be x_j-x_i. */ kappa = 2.0 * vdotN / ve2; /* section 5.2 */ /* I don't like performing a minimization where some of the * weights can be negative (as can be the case if f1 or f2 are * obtuse). To ensure all-positive weights, we check for * obtuseness and use values similar to those in region_area(). */ weight = 0.0; if (! triangle_obtuse(v, f1)) { weight += ve2 * cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f1), e), GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0; } else { if (angle_obtuse (v, f1)) { weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 4.0; } else { weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 8.0; } } if (! triangle_obtuse(v, f2)) { weight += ve2 * cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f2), e), GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0; } else { if (angle_obtuse (v, f2)) { weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 4.0; } else { weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 8.0; } } /* projection of edge perpendicular to N (section 5.3) */ d[0] = vec_edge[0] - vdotN * N[0]; d[1] = vec_edge[1] - vdotN * N[1]; d[2] = vec_edge[2] - vdotN * N[2]; gts_vector_normalize (d); /* not explicit in the paper, but necessary. Move d to 2D basis. */ d1 = gts_vector_scalar (d, basis1); d2 = gts_vector_scalar (d, basis2); /* store off the curvature, direction of edge, and weights for later use */ weights[edge_count] = weight; kappas[edge_count] = kappa; d1s[edge_count] = d1; d2s[edge_count] = d2; edge_count++; /* Finally, update the linear equations */ aterm_da += weight * d1 * d1 * d1 * d1; bterm_da += weight * d1 * d1 * 2 * d1 * d2; cterm_da += weight * d1 * d1 * d2 * d2; const_da += weight * d1 * d1 * (- kappa); aterm_db += weight * d1 * d2 * d1 * d1; bterm_db += weight * d1 * d2 * 2 * d1 * d2; cterm_db += weight * d1 * d2 * d2 * d2; const_db += weight * d1 * d2 * (- kappa); i = i->next; } /* now use the identity (Section 5.3) a + c = |Kh| = 2 * kappa_h */ aterm_da -= cterm_da; const_da += cterm_da * normKh; aterm_db -= cterm_db; const_db += cterm_db * normKh; /* check for solvability of the linear system */ if (((aterm_da * bterm_db - aterm_db * bterm_da) != 0.0) && ((const_da != 0.0) || (const_db != 0.0))) { linsolve (aterm_da, bterm_da, -const_da, aterm_db, bterm_db, -const_db, &a, &b); c = normKh - a; eigenvector (a, b, c, eig); } else { /* region of v is planar */ eig[0] = 1.0; eig[1] = 0.0; } /* Although the eigenvectors of B are good estimates of the * principal directions, it seems that which one is attached to * which curvature direction is a bit arbitrary. This may be a bug * in my implementation, or just a side-effect of the inaccuracy of * B due to the discrete nature of the sampling. * * To overcome this behavior, we'll evaluate which assignment best * matches the given eigenvectors by comparing the curvature * estimates computed above and the curvatures calculated from the * discrete differential operators. */ gts_vertex_principal_curvatures (0.5 * normKh, Kg, &K1, &K2); err_e1 = err_e2 = 0.0; /* loop through the values previously saved */ for (e = 0; e < edge_count; e++) { gdouble weight, kappa, d1, d2; gdouble temp1, temp2; gdouble delta; weight = weights[e]; kappa = kappas[e]; d1 = d1s[e]; d2 = d2s[e]; temp1 = fabs (eig[0] * d1 + eig[1] * d2); temp1 = temp1 * temp1; temp2 = fabs (eig[1] * d1 - eig[0] * d2); temp2 = temp2 * temp2; /* err_e1 is for K1 associated with e1 */ delta = K1 * temp1 + K2 * temp2 - kappa; err_e1 += weight * delta * delta; /* err_e2 is for K1 associated with e2 */ delta = K2 * temp1 + K1 * temp2 - kappa; err_e2 += weight * delta * delta; } g_free (weights); g_free (kappas); g_free (d1s); g_free (d2s); /* rotate eig by a right angle if that would decrease the error */ if (err_e2 < err_e1) { gdouble temp = eig[0]; eig[0] = eig[1]; eig[1] = -temp; } e1[0] = eig[0] * basis1[0] + eig[1] * basis2[0]; e1[1] = eig[0] * basis1[1] + eig[1] * basis2[1]; e1[2] = eig[0] * basis1[2] + eig[1] * basis2[2]; gts_vector_normalize (e1); /* make N,e1,e2 a right handed coordinate sytem */ gts_vector_cross (e2, N, e1); gts_vector_normalize (e2); }