Ejemplo n.º 1
0
// Compute the OBB for a set of points relative to a transform matrix and see if it is smaller than the current best value. If
// so, return it.
static void
computeOBB(TheaArray<Vector3> const & points, CoordinateFrame3 const & cframe, OBB & current_best_result, bool overwrite)
{
  if (points.empty())
    return;

  Vector3 lo, hi;
  lo = hi = cframe.pointToObjectSpace(points[0]);

  Vector3 p;
  for (array_size_t i = 1; i < points.size(); ++i)
  {
    p = cframe.pointToObjectSpace(points[i]);
    lo = lo.min(p);
    hi = hi.max(p);
  }

  Vector3 e = hi - lo;
  double volume = e.x() * e.y() * e.z();
  if (overwrite || volume < current_best_result.volume)
  {
    Vector3 c  = 0.5f * (lo + hi);
    Vector3 he = 0.5f * e;
    current_best_result = OBB(c - he, c + he, cframe, volume);
  }
}
Ejemplo n.º 2
0
// A rather hacky way of forming a joint descriptor, suitable only for exact matches like we want here
void
accumGroupFeatures(MeshGroup const & mg, TheaArray<double> & features)
{
  for (MeshGroup::MeshConstIterator mi = mg.meshesBegin(); mi != mg.meshesEnd(); ++mi)
  {
    TheaArray<double> const & mf = (*mi)->getFeatures();
    if (features.empty())
      features.resize(mf.size());

    alwaysAssertM(mf.size() == features.size(), "Feature vectors have different sizes");

    for (array_size_t j = 0; j < features.size(); ++j)
      features[j] += mf[j];
  }

  for (MeshGroup::GroupConstIterator ci = mg.childrenBegin(); ci != mg.childrenEnd(); ++ci)
    accumGroupFeatures(**ci, features);
}
Ejemplo n.º 3
0
bool
sampleMesh(string const & mesh_path, TheaArray<DVector3> & samples)
{
  typedef DisplayMesh Mesh;
  typedef MeshGroup<Mesh> MG;

  try
  {
    MG mg("MeshGroup");
    mg.load(mesh_path);

    MeshSampler<Mesh> sampler(mg);
    TheaArray<Vector3> pts;
    sampler.sampleEvenlyByArea(num_mesh_samples, pts);

    samples.resize(pts.size());
    for (array_size_t i = 0; i < samples.size(); ++i)
      samples[i] = DVector3(pts[i]);
  }
  THEA_STANDARD_CATCH_BLOCKS(return false;, ERROR, "%s", "An error occurred")
Ejemplo n.º 4
0
    static long findEdgeConnected(MeshT & mesh, TheaArray< TheaArray<FaceHandleT> > & components,
                                  typename boost::enable_if< Graphics::IsCGALMesh<MeshT> >::type * dummy = NULL)
    {
      // Begin with all faces as separate components
      TheaArray<typename MeshT::Facet *> facets;
      for (typename MeshT::Facet_iterator fi = mesh.facets_begin(); fi != mesh.facets_end(); fi++)
        facets.push_back(&(*fi));

      typedef UnionFind<typename MeshT::Facet *> FacetUnionFind;
      FacetUnionFind uf(facets.begin(), facets.end());

      // Now go over all edges, connecting the faces on either side
      for (typename MeshT::Edge_iterator ei = mesh.edges_begin(); ei != mesh.edges_end(); ei++)
      {
        if (!ei->is_border_edge())
        {
          long handle1 = uf.getObjectID(&(*ei->facet()));
          long handle2 = uf.getObjectID(&(*ei->opposite()->facet()));
          uf.merge(handle1, handle2);
        }
      }

      // Reserve space for the result
      components.resize((array_size_t)uf.numSets());

      typedef TheaUnorderedMap<long, array_size_t> ComponentIndexMap;
      ComponentIndexMap component_indices;

      // Loop over facets, adding each to the appropriate result subarray
      array_size_t component_index;
      for (typename MeshT::Facet_iterator fi = mesh.facets_begin(); fi != mesh.facets_end(); fi++)
      {
        long rep = uf.find(uf.getObjectID(&(*fi)));
        typename ComponentIndexMap::const_iterator existing = component_indices.find(rep);
        if (existing == component_indices.end())
        {
          component_index = component_indices.size();
          component_indices[rep] = component_index;
          components[component_index].clear();
          components[component_index].reserve(uf.sizeOfSet(rep));
        }
        else
          component_index = existing->second;

        components[component_index].push_back(fi);
      }

      return (long)components.size();
    }
Ejemplo n.º 5
0
static void
computeBestFitOBB(TheaArray<Vector3> const & points, Box3 & result, bool has_up, Vector3 const & up)
{
  if (points.empty())
  {
    result = Box3();
    return;
  }
  else if (points.size() == 1)
  {
    result = Box3(AxisAlignedBox3(points[0]));
    return;
  }

  Vector3 centroid;
  CoordinateFrame3 cframe;

  if (has_up)
  {
    centroid = CentroidN<Vector3, 3>::compute(points.begin(), points.end());
    Vector3 u, v;
    up.createOrthonormalBasis(u, v);
    cframe = CoordinateFrame3::_fromAffine(AffineTransform3(basisMatrix(u, v, up), centroid));
  }
  else
  {
    Plane3 plane;
    LinearLeastSquares3<Vector3>::fitPlane(points.begin(), points.end(), plane, &centroid);
    planeToCFrame(plane, centroid, cframe);
  }

  OBB best_obb;
  computeOBB(points, cframe, best_obb, true);

  Matrix3 rot = Matrix3::rotationAxisAngle((has_up ? up : Vector3::unitY()), Math::degreesToRadians(10));
  for (int a = 10;  a < 180; a += 10)
  {
    cframe._setRotation(cframe.getRotation() * rot);
    computeOBB(points, cframe, best_obb, false);
  }

  result = Box3(AxisAlignedBox3(best_obb.lo, best_obb.hi), best_obb.cframe);
}
Ejemplo n.º 6
0
bool
areSimilarFeatureVectors(TheaArray<double> const & f0, long nv0, TheaArray<double> const & f1, long nv1)
{
  if (nv0 != nv1)
    return false;

  alwaysAssertM(f0.size() == f1.size(), "Feature vectors have different sizes");

  // Compare histograms
  double diff = 0;
  for (array_size_t i = 0; i + 1 < f0.size(); ++i)
    diff += std::fabs(f0[i] - f1[i]);

  static double const HIST_THRESHOLD = 1e-2;
  if (diff > HIST_THRESHOLD * nv0)
    return false;

  // Compare scales
  static double const SCALE_THRESHOLD = 1e-2;
  if (!Math::fuzzyEq(f0.back(), f1.back(), SCALE_THRESHOLD * (std::fabs(f0.back()) + 1)))
    return false;

  return true;
}
Ejemplo n.º 7
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, 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();

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

    Vector3 normal = computeNormal();
    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, epsilon))
      {
        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;
}
Ejemplo n.º 8
0
    static bool makeManifold(TheaArray<FaceT> & faces, long num_vertices, TheaArray<long> & vertex_map)
    {
      if (num_vertices <= 0 || faces.size() <= 0)
        return false;

      array_size_t nf = (array_size_t)faces.size();
      array_size_t nv = (array_size_t)num_vertices;

      // Initialize every vertex to map to itself
      vertex_map.resize(nv);
      for (array_size_t i = 0; i < nv; ++i)
        vertex_map[i] = (long)i;

      // Associate each vertex with its incident faces
      TheaArray< TheaArray<array_size_t> > v2f(nv);
      for (array_size_t i = 0; i < nf; ++i)
        for (typename FaceT::const_iterator vi = faces[i].begin(); vi != faces[i].end(); ++vi)
        {
          debugAssertM(*vi >= 0 && (long)*vi < num_vertices,
                      format("Manifold: Vertex index %ld out of range [0, %ld)", (long)*vi, num_vertices));
          v2f[(array_size_t)*vi].push_back(i);
        }

      // Queue the set of vertices
      TheaStack<array_size_t> vertex_stack;
      for (long i = (long)nv - 1; i >= 0; --i)
        vertex_stack.push((array_size_t)i);

      // Split the faces at each vertex into manifold groups
      while (!vertex_stack.empty())
      {
        array_size_t i = vertex_stack.top();
        vertex_stack.pop();

        // Set of edges (represented by their further vertices) incident at this vertex that have already been observed to be
        // shared by two faces
        TheaSet<array_size_t> shared_edges;

        // Group the faces into maximal edge-connected components
        typedef UnionFind<array_size_t> UnionFind;
        UnionFind uf(v2f[i].begin(), v2f[i].end());

        for (array_size_t j = 0; j < v2f[i].size(); ++j)
          for (array_size_t k = j + 1; k < v2f[i].size(); ++k)
            if (shareEdgeAtVertex(faces[v2f[i][j]], faces[v2f[i][k]], i, shared_edges))
              uf.merge((long)j, (long)k);

        // Retain only the faces edge-connected to the first one, assigning the rest to a copy of the vertex
        bool created_new_vertex = false;
        for (array_size_t j = 1; j < v2f[i].size(); ++j)
        {
          if (!uf.sameSet(0, j))
          {
            array_size_t face = v2f[i][j];
            array_size_t copy_index = v2f.size() - 1;

            if (!created_new_vertex) // create a copy of the vertex
            {
              copy_index++;
              v2f.push_back(TheaArray<array_size_t>());
              vertex_map.push_back(vertex_map[i]);
              vertex_stack.push(copy_index);

              created_new_vertex = true;
            }

            v2f[copy_index].push_back(face);

            // Update the vertex index of this face to point to the copy
            for (typename FaceT::iterator vi = faces[face].begin(); vi != faces[face].end(); ++vi)
              if (*vi == (typename FaceT::value_type)i)
              {
                *vi = (typename FaceT::value_type)copy_index;
                break;
              }
          }
        }

        // If we made a copy of this vertex, we can get rid of faces reassigned to the copy
        if (created_new_vertex)
        {
          TheaArray<array_size_t> nbd;
          for (array_size_t j = 0; j < v2f[i].size(); ++j)
            if (uf.sameSet(0, j))
              nbd.push_back(v2f[i][j]);

          v2f[i] = nbd;
        }
      }

      if ((long)vertex_map.size() > num_vertices)
      {
        THEA_DEBUG << "Manifold: Non-manifold vertices found and fixed";
        return true;
      }
      else
        return false;
    }