예제 #1
0
파일: Polygon3.cpp 프로젝트: sidch/Thea
// Original comment:
//   Triangulation happens in 2d. We could inverse transform the polygon around the normal direction, or we just use the two
//   most signficant axes. Here we find the two longest axes and use them to triangulate.  Inverse transforming them would
//   introduce more doubling point error and isn't worth it.
//
// SC says:
//   This doesn't work: the vertices can be collinear when projected onto the plane of the two longest axes of the bounding box.
//   Example (from real data):
//
//     v[0] = (-13.7199, 4.45725, -8.00059)
//     v[1] = (-0.115787, 12.3116, -4.96109)
//     v[2] = (0.88992, 12.8922, -3.80342)
//     v[3] = (-0.115787, 12.3116, -2.64576)
//     v[4] = (-13.7199, 4.45725, 0.393742)
//     v[5] = (-13.7199, 4.45725, -0.856258)
//     v[6] = (-12.5335, 5.14221, -3.80342)
//     v[7] = (-13.7199, 4.45725, -6.75059)
//
//   Instead, we will project onto the plane of the polygon.
long
Polygon3::triangulate(Array<long> & tri_indices, Real epsilon) const
{
  if (epsilon < 0)
    epsilon = Math::eps<Real>();

  if (vertices.size() < 3)
  {
    tri_indices.clear();
  }
  else if (vertices.size() == 3)
  {
    tri_indices.resize(3);
    tri_indices[0] = vertices[0].index;
    tri_indices[1] = vertices[1].index;
    tri_indices[2] = vertices[2].index;
  }
  else if (vertices.size() > 3)
  {
    tri_indices.clear();

    size_t n = vertices.size();
    proj_vertices.resize(n);

    Vector3 normal = computeNormal();
    Matrix3 basis = Math::orthonormalBasis(normal);
    Vector3 axis0 = basis.col(0);
    Vector3 axis1 = basis.col(1);

    Vector3 v0 = vertices[0].position;  // a reference point for the plane of the polygon
    for (size_t i = 0; i < n; ++i)
    {
      Vector3 v = vertices[i].position - v0;
      proj_vertices[i] = Vector2(v.dot(axis0), v.dot(axis1));
    }

    Array<size_t> indices(n);
    bool flipped = false;
    if (projArea() > 0)
    {
      for (size_t v = 0; v < n; ++v)
        indices[v] = v;
    }
    else
    {
      for (size_t v = 0; v < n; ++v)
        indices[v] = (n - 1) - v;

      flipped = true;
    }

    size_t nv = n;
    size_t count = 2 * nv;
    for (size_t v = nv - 1; nv > 2; )
    {
      if ((count--) <= 0)
        break;

      size_t u = v;
      if (nv <= u) u = 0;

      v = u + 1;
      if (nv <= v) v = 0;

      size_t w = v + 1;
      if (nv <= w) w = 0;

      if (snip(u, v, w, nv, indices, epsilon))
      {
        size_t a = indices[u];
        size_t b = indices[v];
        size_t c = indices[w];
        if (flipped)
        {
          tri_indices.push_back(vertices[c].index);
          tri_indices.push_back(vertices[b].index);
          tri_indices.push_back(vertices[a].index);
        }
        else
        {
          tri_indices.push_back(vertices[a].index);
          tri_indices.push_back(vertices[b].index);
          tri_indices.push_back(vertices[c].index);
        }

        size_t s = v, t = v + 1;
        for ( ; t < nv; ++s, ++t)
          indices[s] = indices[t];

        nv--;
        count = 2 * nv;
      }
    }
  }

  return (long)tri_indices.size() / 3;
}
예제 #2
0
// Original comment:
//   Triangulation happens in 2d. We could inverse transform the polygon around the normal direction, or we just use the two
//   most signficant axes. Here we find the two longest axes and use them to triangulate.  Inverse transforming them would
//   introduce more doubling point error and isn't worth it.
//
// SC says:
//   This doesn't work: the vertices can be collinear when projected onto the plane of the two longest axes of the bounding box.
//   Example (from real data):
//
//     v[0] = (-13.7199, 4.45725, -8.00059)
//     v[1] = (-0.115787, 12.3116, -4.96109)
//     v[2] = (0.88992, 12.8922, -3.80342)
//     v[3] = (-0.115787, 12.3116, -2.64576)
//     v[4] = (-13.7199, 4.45725, 0.393742)
//     v[5] = (-13.7199, 4.45725, -0.856258)
//     v[6] = (-12.5335, 5.14221, -3.80342)
//     v[7] = (-13.7199, 4.45725, -6.75059)
//
//   Instead, we will project onto the plane of the polygon.
long
Polygon3::triangulate(TheaArray<long> & tri_indices) const
{
  if (vertices.size() < 3)
  {
    tri_indices.clear();
  }
  else if (vertices.size() == 3)
  {
    tri_indices.resize(3);
    tri_indices[0] = vertices[0].index;
    tri_indices[1] = vertices[1].index;
    tri_indices[2] = vertices[2].index;
  }
  else if (vertices.size() > 3)
  {
    tri_indices.clear();

    array_size_t n = vertices.size();
    proj_vertices.resize(n);

    Vector3 normal = getNormal();
    Vector3 axis0, axis1;
    normal.createOrthonormalBasis(axis0, axis1);

    Vector3 v0 = vertices[0].position;  // a reference point for the plane of the polygon
    for (array_size_t i = 0; i < n; ++i)
    {
      Vector3 v = vertices[i].position - v0;
      proj_vertices[i] = Vector2(v.dot(axis0), v.dot(axis1));
    }

    TheaArray<array_size_t> indices(n);
    bool flipped = false;
    if (projArea() > 0)
    {
      for (array_size_t v = 0; v < n; ++v)
        indices[v] = v;
    }
    else
    {
      for (array_size_t v = 0; v < n; ++v)
        indices[v] = (n - 1) - v;

      flipped = true;
    }

    array_size_t nv = n;
    array_size_t count = 2 * nv;
    for (array_size_t v = nv - 1; nv > 2; )
    {
      if ((count--) <= 0)
        break;

      array_size_t u = v;
      if (nv <= u) u = 0;

      v = u + 1;
      if (nv <= v) v = 0;

      array_size_t w = v + 1;
      if (nv <= w) w = 0;

      if (snip(u, v, w, nv, indices))
      {
        array_size_t a = indices[u];
        array_size_t b = indices[v];
        array_size_t c = indices[w];
        if (flipped)
        {
          tri_indices.push_back(vertices[c].index);
          tri_indices.push_back(vertices[b].index);
          tri_indices.push_back(vertices[a].index);
        }
        else
        {
          tri_indices.push_back(vertices[a].index);
          tri_indices.push_back(vertices[b].index);
          tri_indices.push_back(vertices[c].index);
        }

        array_size_t s = v, t = v + 1;
        for ( ; t < nv; ++s, ++t)
          indices[s] = indices[t];

        nv--;
        count = 2 * nv;
      }
    }
  }

  return (long)tri_indices.size() / 3;
}