示例#1
0
文件: triangle.c 项目: finetjul/gts
static gboolean points_are_folded (GtsPoint * A,
                                   GtsPoint * B,
                                   GtsPoint * C,
                                   GtsPoint * D,
                                   gdouble max)
{
    GtsVector AB, AC, AD;
    GtsVector n1, n2;
    gdouble nn1, nn2, n1n2;

    gts_vector_init (AB, A, B);
    gts_vector_init (AC, A, C);
    gts_vector_init (AD, A, D);
    gts_vector_cross (n1, AB, AC);
    gts_vector_cross (n2, AD, AB);

    nn1 = gts_vector_scalar (n1, n1);
    nn2 = gts_vector_scalar (n2, n2);
    if (nn1 >= AREA_RATIO_MAX2*nn2 || nn2 >= AREA_RATIO_MAX2*nn1)
        return TRUE;
    n1n2 = gts_vector_scalar (n1, n2);
    if (n1n2 > 0.)
        return FALSE;
    if (n1n2*n1n2/(nn1*nn2) > max)
        return TRUE;
    return FALSE;
}
示例#2
0
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);
}
示例#3
0
文件: bbtree.c 项目: ClavinSBU/gts
/**
 * 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);
}
示例#4
0
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)));
}
示例#5
0
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);
}
示例#6
0
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);
}
示例#7
0
static gboolean is_convex(GtsPoint *p0, GtsPoint *p1, GtsPoint *p2, GtsVector orientation)
{
	g_assert(GTS_IS_POINT(p0)); 
	g_assert(GTS_IS_POINT(p1)); 
	g_assert(GTS_IS_POINT(p2)); 
	
	GtsVector a; 
	GtsVector b;
	GtsVector c; 
	
	gts_vector_init(a, p1, p0); 
	gts_vector_init(b, p1, p2); 
	
	gts_vector_cross(c, a, b);
	
	return gts_vector_scalar(c, orientation) >= 0; 
	
}
示例#8
0
文件: bbtree.c 项目: ClavinSBU/gts
/**
 * 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);
}
示例#9
0
/** 
 * 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);
}