void dumpToMesh (OrientedBox &box, Mesh3D &mesh)
{
    mesh.setColor(RGBColor::Cyan());

    for (int i = 0; i < 200; i++)
        for (int j = 0; j < 200; j++)
            for (int k = 0; k < 200; k++)
            {
                Vector3dd T = Vector3dd(i - 100, j - 100, k - 100) / 10.0;
                T += box.position;
                if (box.isInside(T))
                {
                    mesh.addPoint(T);
                }
            }

    mesh.setColor(RGBColor::Yellow());
    for (Vector3dd &p : box.getPoints())
    {
        mesh.addPoint(p);
    }
    mesh.setColor(RGBColor::Green());
    mesh.addOOB(box, true);


}
Ejemplo n.º 2
0
bool TestYLineOBox ( Vector const & V, OrientedBox const & B )
{
	Vector point = B.transformToLocal(V);
	Vector normal = B.rotateToLocal(Vector::unitY);

	return TestLineABox( Line3d(point,normal), B.getLocalShape() );
}
Ejemplo n.º 3
0
 ErrorCode leaf( EntityHandle node ) {
   OrientedBox box;
   ErrorCode rval = mTool->box( node, box );
   if (MB_SUCCESS !=rval) return rval;
   EntityHandle h;
   rval = box.make_hex( h, mOut );
   if (MB_SUCCESS !=rval) return rval;
   int i = hash_handle( node );
   return mOut->tag_set_data( mTag, &h, 1, &i );
 }
Ejemplo n.º 4
0
Sphere EncloseSphere ( OrientedBox const & shape )
{
	float x = shape.getExtentX();
	float y = shape.getExtentY();
	float z = shape.getExtentZ();

	float radius = sqrt( x*x + y*y + z*z );

	return Sphere( shape.getCenter(), radius );
}
Ejemplo n.º 5
0
Vector ClosestPointOBox ( Vector const & V, OrientedBox const & B )
{
	Vector lV = B.transformToLocal(V);

	AxialBox lB = B.getLocalShape();

	Vector lC = ClosestPointABox(lV,lB);

	Vector out = B.transformToWorld(lC);

	return out;
}
Ejemplo n.º 6
0
CkReductionMsg* boxGrowth(int nMsg, CkReductionMsg** msgs) {
	OrientedBox<T>* pbox = static_cast<OrientedBox<T> *>(msgs[0]->getData());
	OrientedBox<T>* msgpbox;
	for(int i = 1; i < nMsg; i++) {
		msgpbox = static_cast<OrientedBox<T> *>(msgs[i]->getData());
		if(msgpbox->initialized()) {
			pbox->grow(msgpbox->lesser_corner);
			pbox->grow(msgpbox->greater_corner);
		}
	}
	
	return CkReductionMsg::buildNew(sizeof(OrientedBox<T>), pbox);
}
Ejemplo n.º 7
0
// a visit to a node, will create an OrientedBox object for that node, get a hex from that box and tag it with 
// an integer tag representing it's depth in the tree, and add it to the list of *hexes* for this tree
ErrorCode OBBHexWriter::visit( EntityHandle node,
			   int depth, 
			   bool& descend)
{
  
 ErrorCode rval;
  
  //create a new tag for the tree depth of the obb
  std::string depth_tag_name = "TREE_DEPTH";
  rval = mbi2->tag_get_handle( depth_tag_name.c_str(),  1, MB_TYPE_INTEGER, depth_tag, 
			       MB_TAG_DENSE|MB_TAG_CREAT);
  assert( MB_SUCCESS == rval );
  if( MB_SUCCESS != rval ) return rval; 

  OrientedBox box;
  rval = tool->box( node, box );
  assert(MB_SUCCESS == rval );
  if ( MB_SUCCESS != rval ) return rval; 
  
  rval = box.make_hex( new_hex, mbi2 );
  assert( MB_SUCCESS == rval );
  if( MB_SUCCESS != rval ) return rval; 
  
  void *ptr = &depth;
  rval = mbi2-> tag_set_data( depth_tag, &new_hex, 1, ptr);
  assert( MB_SUCCESS == rval );
  if( MB_SUCCESS != rval ) return rval; 

  if(w_tris)
    {
    //get the triangles contained by this node
    std::vector<EntityHandle> tris; 
    
    rval = tool->get_moab_instance()->get_entities_by_type( node, MBTRI, tris);
    assert(MB_SUCCESS == rval );
    if ( MB_SUCCESS != rval ) return rval; 
    
    rval = transfer_tri_inst( tool->get_moab_instance(), mbi2, tris);
    assert( MB_SUCCESS == rval );
  
    //add the data to the class attributes
    tri_map[new_hex] = tris;
    }
  
  //add the hex and go to the next tree depth
  hexes.push_back(new_hex);
  descend = true;    
  
  return MB_SUCCESS;
}
// Compute the granular "stress"
Matrix3 
PeriodicBCComputeStressStrain::calcGranularStress(const DEMParticlePArray& particles,
                                                  const DEMContactArray& contacts,
                                                  const OrientedBox& spatialDomain)
{
  Matrix3 stress(0.0);

  // Basic component (Love-Weber)
  for (const auto& contact : contacts) {
    auto p1Center = contact.getP1()->currentPosition();
    auto p2Center = contact.getP2()->currentPosition();
    auto direction = -(p1Center - p2Center);
    auto force = contact.getNormalForce() + contact.getTangentForce();
    stress += Dyad(force, direction);
  }

  // Component needed if # of particles in RVE is small
  // **TODO**

  // Inertial component (Nicot, 2013)
  Matrix3 inertial(0.0);
  for (const auto& particle : particles) {
    Vec momentJ = particle->getMomentJ();
    Matrix3 localInertialTensor(momentJ.x(), 0.0, 0.0,
                               0.0, momentJ.y(), 0.0,
                               0.0, 0.0, momentJ.z());
    Vec ax_a = particle->currentAxisA();
    Vec ax_b = particle->currentAxisB();
    Vec ax_c = particle->currentAxisC();
    Matrix3 Q(ax_a.x(), ax_b.x(), ax_c.x(),
              ax_a.y(), ax_b.y(), ax_c.y(),
              ax_a.z(), ax_b.z(), ax_c.z());
    Matrix3 chi = Q.Transpose() * localInertialTensor * Q;

    Vec omega = particle->currentAngularVelocity();
    Vec localOmegaDot = particle->angularAcceleration();
    Vec omegaDot = Q.Transpose() * localOmegaDot;

    inertial -= (chi * dot(omega, omega));
    inertial += (Dyad(omega, omega) * chi);

    Matrix3 permu(0.0);
    for (int j = 0; j < 3; ++j) {
      permu(0,j) = omegaDot[1] * chi(j,2) - omega[2] * chi(j,1);
      permu(1,j) = omegaDot[2] * chi(j,0) - omega[0] * chi(j,2);
      permu(2,j) = omegaDot[0] * chi(j,1) - omega[1] * chi(j,0);
    }
    inertial += permu;
  }
  stress -= inertial;
  stress /= spatialDomain.volume();
  return stress;
}
Ejemplo n.º 9
0
Range ProjectAxis ( Line3d const & L, OrientedBox const & B )
{
	Vector const & N = L.getNormal();

	real x = std::abs( Collision3d::ComponentAlong( B.getAxisX(), N ) ) * B.getExtentX();
	real y = std::abs( Collision3d::ComponentAlong( B.getAxisY(), N ) ) * B.getExtentY();
	real z = std::abs( Collision3d::ComponentAlong( B.getAxisZ(), N ) ) * B.getExtentZ();

	real d = x + y + z;

	real c = ProjectAxis( L, B.getCenter() );

	return Range( c - d, c + d );
}
Ejemplo n.º 10
0
bool TestOBoxOBox ( OrientedBox const & boxA, OrientedBox const & boxB )
{
	// convenience variables
	const Vector* akA = boxA.getAxes();
	const Vector* akB = boxB.getAxes();
	const float* afEA = boxA.getExtents();
	const float* afEB = boxB.getExtents();

	// compute difference of box centers, D = C1-C0
	Vector kD = boxB.getCenter() - boxA.getCenter();

	float aafC[3][3];     // matrix C = A^T B, c_{ij} = Dot(A_i,B_j)
	float aafAbsC[3][3];  // |c_{ij}|
	float afAD[3];        // Dot(A_i,D)
	float fR0, fR1, fR;   // interval radii and distance between centers
	float fR01;           // = R0 + R1

	// axis C0+t*A0
	aafC[0][0] = akA[0].dot(akB[0]);
	aafC[0][1] = akA[0].dot(akB[1]);
	aafC[0][2] = akA[0].dot(akB[2]);
	afAD[0] = akA[0].dot(kD);
	aafAbsC[0][0] = static_cast<float>(fabs(aafC[0][0]));
	aafAbsC[0][1] = static_cast<float>(fabs(aafC[0][1]));
	aafAbsC[0][2] = static_cast<float>(fabs(aafC[0][2]));
	fR = static_cast<float>(fabs(afAD[0]));
	fR1 = afEB[0]*aafAbsC[0][0]+afEB[1]*aafAbsC[0][1]+afEB[2]*aafAbsC[0][2];
	fR01 = afEA[0] + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A1
	aafC[1][0] = akA[1].dot(akB[0]);
	aafC[1][1] = akA[1].dot(akB[1]);
	aafC[1][2] = akA[1].dot(akB[2]);
	afAD[1] = akA[1].dot(kD);
	aafAbsC[1][0] = static_cast<float>(fabs(aafC[1][0]));
	aafAbsC[1][1] = static_cast<float>(fabs(aafC[1][1]));
	aafAbsC[1][2] = static_cast<float>(fabs(aafC[1][2]));
	fR = static_cast<float>(fabs(afAD[1]));
	fR1 = afEB[0]*aafAbsC[1][0]+afEB[1]*aafAbsC[1][1]+afEB[2]*aafAbsC[1][2];
	fR01 = afEA[1] + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A2
	aafC[2][0] = akA[2].dot(akB[0]);
	aafC[2][1] = akA[2].dot(akB[1]);
	aafC[2][2] = akA[2].dot(akB[2]);
	afAD[2] = akA[2].dot(kD);
	aafAbsC[2][0] = static_cast<float>(fabs(aafC[2][0]));
	aafAbsC[2][1] = static_cast<float>(fabs(aafC[2][1]));
	aafAbsC[2][2] = static_cast<float>(fabs(aafC[2][2]));
	fR = static_cast<float>(fabs(afAD[2]));
	fR1 = afEB[0]*aafAbsC[2][0]+afEB[1]*aafAbsC[2][1]+afEB[2]*aafAbsC[2][2];
	fR01 = afEA[2] + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*B0
	fR = static_cast<float>(fabs(akB[0].dot(kD)));
	fR0 = afEA[0]*aafAbsC[0][0]+afEA[1]*aafAbsC[1][0]+afEA[2]*aafAbsC[2][0];
	fR01 = fR0 + afEB[0];
	if ( fR > fR01 )
		return false;

	// axis C0+t*B1
	fR = static_cast<float>(fabs(akB[1].dot(kD)));
	fR0 = afEA[0]*aafAbsC[0][1]+afEA[1]*aafAbsC[1][1]+afEA[2]*aafAbsC[2][1];
	fR01 = fR0 + afEB[1];
	if ( fR > fR01 )
		return false;

	// axis C0+t*B2
	fR = static_cast<float>(fabs(akB[2].dot(kD)));
	fR0 = afEA[0]*aafAbsC[0][2]+afEA[1]*aafAbsC[1][2]+afEA[2]*aafAbsC[2][2];
	fR01 = fR0 + afEB[2];
	if ( fR > fR01 )
		return false;

	// axis C0+t*A0xB0
	fR = static_cast<float>(fabs(afAD[2]*aafC[1][0]-afAD[1]*aafC[2][0]));
	fR0 = afEA[1]*aafAbsC[2][0] + afEA[2]*aafAbsC[1][0];
	fR1 = afEB[1]*aafAbsC[0][2] + afEB[2]*aafAbsC[0][1];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A0xB1
	fR = static_cast<float>(fabs(afAD[2]*aafC[1][1]-afAD[1]*aafC[2][1]));
	fR0 = afEA[1]*aafAbsC[2][1] + afEA[2]*aafAbsC[1][1];
	fR1 = afEB[0]*aafAbsC[0][2] + afEB[2]*aafAbsC[0][0];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A0xB2
	fR = static_cast<float>(fabs(afAD[2]*aafC[1][2]-afAD[1]*aafC[2][2]));
	fR0 = afEA[1]*aafAbsC[2][2] + afEA[2]*aafAbsC[1][2];
	fR1 = afEB[0]*aafAbsC[0][1] + afEB[1]*aafAbsC[0][0];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A1xB0
	fR = static_cast<float>(fabs(afAD[0]*aafC[2][0]-afAD[2]*aafC[0][0]));
	fR0 = afEA[0]*aafAbsC[2][0] + afEA[2]*aafAbsC[0][0];
	fR1 = afEB[1]*aafAbsC[1][2] + afEB[2]*aafAbsC[1][1];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A1xB1
	fR = static_cast<float>(fabs(afAD[0]*aafC[2][1]-afAD[2]*aafC[0][1]));
	fR0 = afEA[0]*aafAbsC[2][1] + afEA[2]*aafAbsC[0][1];
	fR1 = afEB[0]*aafAbsC[1][2] + afEB[2]*aafAbsC[1][0];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A1xB2
	fR = static_cast<float>(fabs(afAD[0]*aafC[2][2]-afAD[2]*aafC[0][2]));
	fR0 = afEA[0]*aafAbsC[2][2] + afEA[2]*aafAbsC[0][2];
	fR1 = afEB[0]*aafAbsC[1][1] + afEB[1]*aafAbsC[1][0];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A2xB0
	fR = static_cast<float>(fabs(afAD[1]*aafC[0][0]-afAD[0]*aafC[1][0]));
	fR0 = afEA[0]*aafAbsC[1][0] + afEA[1]*aafAbsC[0][0];
	fR1 = afEB[1]*aafAbsC[2][2] + afEB[2]*aafAbsC[2][1];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A2xB1
	fR = static_cast<float>(fabs(afAD[1]*aafC[0][1]-afAD[0]*aafC[1][1]));
	fR0 = afEA[0]*aafAbsC[1][1] + afEA[1]*aafAbsC[0][1];
	fR1 = afEB[0]*aafAbsC[2][2] + afEB[2]*aafAbsC[2][0];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	// axis C0+t*A2xB2
	fR = static_cast<float>(fabs(afAD[1]*aafC[0][2]-afAD[0]*aafC[1][2]));
	fR0 = afEA[0]*aafAbsC[1][2] + afEA[1]*aafAbsC[0][2];
	fR1 = afEB[0]*aafAbsC[2][1] + afEB[1]*aafAbsC[2][0];
	fR01 = fR0 + fR1;
	if ( fR > fR01 )
		return false;

	return true;
}
Ejemplo n.º 11
0
ContainmentResult   TestPointOBox ( Vector const & V, OrientedBox const & B )
{
	Vector localV = B.transformToLocal(V);

	return Test(localV,B.getLocalShape());
}
Ejemplo n.º 12
0
ErrorCode TreeValidator::visit( EntityHandle node,
                                  int depth,
                                  bool& descend )
{
  ErrorCode rval;
  descend = true;
  
  Range contents;
  rval = instance->get_entities_by_handle( node, contents );
  if (MB_SUCCESS != rval) 
    return error(node, "Error getting contents of tree node.  Corrupt tree?");
  entity_count += contents.size();
  
  if (surfaces) {
      // if no longer in subtree for previous surface, clear
    if (depth <= surface_depth) 
      surface_depth = -1;
      
    EntityHandle surface = 0;
    Range::iterator surf_iter = contents.lower_bound( MBENTITYSET );
    if (surf_iter != contents.end()) {
      surface = *surf_iter;
      contents.erase( surf_iter );
    }
    
    if (surface) {
      if (surface_depth >=0) {
        ++multiple_surface_count;
        print( node, "Multiple surfaces in encountered in same subtree." );
      }
      else {
        surface_depth = depth;
        surface_handle = surface;
      }
    }
  }
  
  std::vector<EntityHandle> children;
  rval = tool->get_moab_instance()->get_child_meshsets( node, children );
  if (MB_SUCCESS != rval || (!children.empty() && children.size() != 2)) 
    return error(node, "Error getting children.  Corrupt tree?");
  
  OrientedBox box;
  rval = tool->box( node, box );
  if (MB_SUCCESS != rval) 
    return error(node, "Error getting oriented box from tree node.  Corrupt tree?");
  
  if (children.empty() && contents.empty()) {
    ++empty_leaf_count;
    print( node, "Empty leaf node.\n" );
  }
  else if (!children.empty() && !contents.empty()) {
    ++non_empty_non_leaf_count;
    print( node, "Non-leaf node is not empty." );
  }
  
  if (surfaces && children.empty() && surface_depth < 0) {
    ++missing_surface_count;
    print( node, "Reached leaf node w/out encountering any surface set.");
  }
  
  double dot_epsilon = epsilon*(box.axis[0]+box.axis[1]+box.axis[2]).length();
  if (box.axis[0] % box.axis[1] > dot_epsilon ||
      box.axis[0] % box.axis[2] > dot_epsilon ||
      box.axis[1] % box.axis[2] > dot_epsilon ) {
    ++non_ortho_count;
    print (node, "Box axes are not orthogonal");
  }
  
  if (!children.empty()) {
    for (int i = 0; i < 2; ++i) {
      OrientedBox other_box;
      rval = tool->box( children[i], other_box );
      if (MB_SUCCESS != rval) 
        return error( children[i], " Error getting oriented box from tree node.  Corrupt tree?" );
//      else if (!box.contained( other_box, epsilon )) {
//        ++child_outside_count;
//        print( children[i], "Parent box does not contain child box." );
//        char string[64];
//        sprintf(string, "     Volume ratio is %f", other_box.volume()/box.volume() );
//        print( children [i], string );
//      }
        else {
          double vol_ratio = other_box.volume()/box.volume();
          if (vol_ratio > 2.0) {
            char string[64];
            sprintf(string, "child/parent volume ratio is %f", vol_ratio );
            print( children[i], string );
            sprintf(string, "   child/parent area ratio is %f", other_box.area()/box.area() );
            print( children[i], string );
          }
       }
    }
  }
  
  bool bad_element = false;
  bool bad_element_handle = false;
  bool bad_element_conn = false;
  bool duplicate_element = false;
  int num_outside = 0;
  bool boundary[6] = { false, false, false, false, false, false };
  for (Range::iterator it = contents.begin(); it != contents.end(); ++it) {
    EntityType type = instance->type_from_handle( *it );
    int dim = CN::Dimension( type );
    if (dim != 2) {
      bad_element = true;
      continue;
    }
    
    const EntityHandle* conn;
    int conn_len;
    rval = instance->get_connectivity( *it, conn, conn_len );
    if (MB_SUCCESS != rval) {
      bad_element_handle = true;
      continue;
    }
    
    std::vector<CartVect> coords(conn_len);
    rval = instance->get_coords( conn, conn_len, coords[0].array() );
    if (MB_SUCCESS != rval) {
      bad_element_conn = true;
      continue;
    }
    
    bool outside = false;
    for (std::vector<CartVect>::iterator j = coords.begin(); j != coords.end(); ++j) {
      if (!box.contained( *j, epsilon ))
        outside = true;
      else for (int d = 0; d < 3; ++d) {
#if MB_ORIENTED_BOX_UNIT_VECTORS
        double n = box.axis[d] % (*j - box.center);
        if (fabs(n - box.length[d]) <= epsilon)
          boundary[2*d] = true;
        if (fabs(n + box.length[d]) <= epsilon)
          boundary[2*d+1] = true;
#else
        double ln = box.axis[d].length();
        CartVect v1 = *j - box.center - box.axis[d];
        CartVect v2 = *j - box.center + box.axis[d];
        if (fabs(v1 % box.axis[d]) <= ln * epsilon)
          boundary[2*d] = true;
        if (fabs(v2 % box.axis[d]) <= ln * epsilon)
          boundary[2*d+1] = true;
#endif
      }
    }
    if (outside)
      ++num_outside;
      
    if (!seen.insert(*it).second) {
      duplicate_element = true;
      ++duplicate_entity_count;
    }
  }
  
  CartVect alength( box.axis[0].length(), box.axis[1].length(), box.axis[2].length() );
#if MB_ORIENTED_BOX_UNIT_VECTORS
  CartVect length = box.length;
#else
  CartVect length = alength;
#endif
  
  if (length[0] > length[1] || length[0] > length[2] || length[1] > length[2]) {
    ++unsorted_axis_count;
    print( node, "Box axes are not ordered from shortest to longest." );
  }
  
#if MB_ORIENTED_BOX_UNIT_VECTORS
  if (fabs(alength[0] - 1.0) > epsilon ||
      fabs(alength[1] - 1.0) > epsilon ||
      fabs(alength[2] - 1.0) > epsilon) {
    ++non_unit_count;
    print( node, "Box axes are not unit vectors.");
  }
#endif

#if MB_ORIENTED_BOX_OUTER_RADIUS
  if (fabs(length.length() - box.radius) > tolerance) {
    ++bad_outer_radius_count;
    print( node, "Box has incorrect outer radius.");
  }
#endif

  if (depth+1 < settings.max_depth 
      && contents.size() > (unsigned)(4*settings.max_leaf_entities))
  {
    char string[64];
    sprintf(string, "leaf at depth %d with %u entities", depth, (unsigned)contents.size() );
    print( node, string );
  }
    
      
  bool all_boundaries = true;
  for (int f = 0; f < 6; ++f)
    all_boundaries = all_boundaries && boundary[f];
  
  if (bad_element) {
    ++entity_invalid_count;
    print( node, "Set contained an entity with an inappropriate dimension." );
  }
  if (bad_element_handle) {
    ++error_count;
    print( node, "Error querying face contained in set.");
  }
  if (bad_element_conn) {
    ++error_count;
    print( node, "Error querying connectivity of element.");
  }
  if (duplicate_element) {
    print( node, "Elements occur in multiple leaves of tree.");
  }
  if (num_outside > 0) {
    ++entity_outside_count;
    num_entities_outside += num_outside;
    if (printing)
      stream << instance->id_from_handle( node ) << ": "
             << num_outside << " elements outside box." << std::endl;
  }
  else if (!all_boundaries && !contents.empty()) {
    ++loose_box_count;
    print( node, "Box does not fit contained elements tightly." );
  }

  return MB_SUCCESS;
}
Ejemplo n.º 13
0
DEMParticlePArray
DEMParticleCreator::updatePeriodicDEMParticles(const OrientedBox& periodicDomain, 
                                               DEMParticlePArray& particles)
{
  auto e0 = periodicDomain.axis(0) * (periodicDomain.extent(0) * 2);
  auto e1 = periodicDomain.axis(1) * (periodicDomain.extent(1) * 2);
  auto e2 = periodicDomain.axis(2) * (periodicDomain.extent(2) * 2);

  std::vector<Vec> vertices = periodicDomain.vertices();
  constexpr std::array<std::array<int, 4>, 6> faceIndices = {{
      {{0, 4, 7, 3}} // x-
    , {{1, 2, 6, 5}} // x+
    , {{0, 1, 5, 4}} // y-
    , {{2, 3, 7, 6}} // y+
    , {{0, 3, 2, 1}} // z-
    , {{4, 5, 6, 7}}  // z+

  }};
  std::vector<Face> faces;
  for (const auto& indices : faceIndices) {
    int i0 = indices[0]; int i1 = indices[1]; 
    int i2 = indices[2]; int i3 = indices[3];
    Face face(vertices[i0], vertices[i1], vertices[i2], vertices[i3]);
    faces.push_back(face);
  }

  // Check intersections
  DEMParticlePArray extraParticles;
  for (const auto& particle : particles) {

    if (particle->getType() != DEMParticle::DEMParticleType::FREE) {
      continue;
    }

    auto position = particle->currentPosition();

    auto axis_a = particle->currentAxisA();
    auto axis_b = particle->currentAxisB();
    auto axis_c = particle->currentAxisC();

    auto radius_a = particle->radiusA();
    auto radius_b = particle->radiusB();
    auto radius_c = particle->radiusC();

    auto id = particle->getId();

    // Create an ellipsoid object for ellipsoid-face intersection tests
    Ellipsoid ellipsoid(id, position, axis_a, axis_b, axis_c, 
                        radius_a, radius_b, radius_c);

    int faceID = 1;
    for (const auto& face : faces) {
      auto status = ellipsoid.intersects(face);
      // std::cout << "Face = " << face << "\n";
      // std::cout << "status = " << std::boolalpha << status.first
      //           << " face " << static_cast<int>(status.second.first)
      //           << " , " << status.second.second << "\n";
      if (status.first) {
        std::vector<Vec> translations;

        switch (static_cast<Boundary::BoundaryID>(faceID)) {
          case Boundary::BoundaryID::NONE:
            break;
          case Boundary::BoundaryID::XMINUS:
          {
            Vec shift = e0;
            //std::cout << " Loc: x-: " << shift << "\n";
            translations.push_back(shift);
            addExtraTranslations(shift, face, status, translations);
            break;
          }
          case Boundary::BoundaryID::XPLUS:
          {
            Vec shift = -e0;
            //std::cout << " Loc: x-: " << shift << "\n";
            translations.push_back(shift);
            addExtraTranslations(shift, face, status, translations);
            break;
          }
          case Boundary::BoundaryID::YMINUS:
          {
            Vec shift = e1;
            //std::cout << " Loc: y-: " << shift << "\n";
            translations.push_back(shift);
            addExtraTranslations(shift, face, status, translations);
            break;
          }
          case Boundary::BoundaryID::YPLUS:
          {
            Vec shift = -e1;
            //std::cout << " Loc: y-: " << shift << "\n";
            translations.push_back(shift);
            addExtraTranslations(shift, face, status, translations);
            break;
          }
          case Boundary::BoundaryID::ZMINUS:
          {
            Vec shift = e2;
            //std::cout << " Loc: z-: " << shift << "\n";
            translations.push_back(shift);
            addExtraTranslations(shift, face, status, translations);
            break;
          }
          case Boundary::BoundaryID::ZPLUS:
          {
            Vec shift = -e2;
            //std::cout << " Loc: z-: " << shift << "\n";
            translations.push_back(shift);
            addExtraTranslations(shift, face, status, translations);
            break;
          }
            break;
        }

        // Create copies
        particle->setType(DEMParticle::DEMParticleType::BOUNDARY_PERIODIC);
        for (const auto& translation : translations) {
          DEMParticleP newParticle = std::make_shared<DEMParticle>(*particle);
          newParticle->setCurrentPosition(particle->currentPosition() + 
                                          translation);
          newParticle->setPreviousPosition(particle->previousPosition() + 
                                           translation);
          newParticle->setId(particle->getId());
          newParticle->computeAndSetGlobalCoef();
          extraParticles.push_back(newParticle);
        }
      }
      faceID += 1;
    }
  }

  // Remove duplicates
  removeDuplicates(extraParticles);

  return extraParticles;
}