def gridNode(center, radius, dynamic=None, fixed=False, wire=False, color=None, highlight=False, material=-1): """ Create a :yref:`GridNode` which is needed to set up :yref:`GridConnections<GridConnection>`. See documentation of :yref:`yade.utils.sphere` for meaning of parameters. :return: Body object with the :yref:`gridNode` :yref:`shape<Body.shape>`. """ b = Body() b.shape = GridNode(radius=radius, color=color if color else utils.randomColor(), wire=wire, highlight=highlight) #V=(4./3)*math.pi*radius**3 # will be overwritten by the connection V = 0. geomInert = (2. / 5.) * V * radius**2 # will be overwritten by the connection utils._commonBodySetup(b, V, Vector3(geomInert, geomInert, geomInert), material, pos=center, dynamic=dynamic, fixed=fixed) b.aspherical = False b.bounded = False b.mask = 0 # avoid contact detection with the nodes. Manual interaction will be set for them in "gridConnection" below. return b
def chainedCylinder(begin=Vector3(0,0,0),end=Vector3(1.,0.,0.),radius=0.2,dynamic=None,fixed=False,wire=False,color=None,highlight=False,material=-1,mask=1): """ Create and connect a chainedCylinder with given parameters. The shape generated by repeted calls of this function is the Minkowski sum of polyline and sphere. :param Real radius: radius of sphere in the Minkowski sum. :param Vector3 begin: first point positioning the line in the Minkowski sum :param Vector3 last: last point positioning the line in the Minkowski sum In order to build a correct chain, last point of element of rank N must correspond to first point of element of rank N+1 in the same chain (with some tolerance, since bounding boxes will be used to create connections. :return: Body object with the :yref:`ChainedCylinder` :yref:`shape<Body.shape>`. .. note:: :yref:`ChainedCylinder` is deprecated and will be removed in the future, use :yref:`GridConnection` instead. See :yref:`yade.gridpfacet.cylinder` and :yref:`yade.gridpfacet.cylinderConnection`. """ import warnings warnings.warn('\033[1;31mchainedCylinder is deprecated and will be removed in the future, use GridConnection instead. See examples/grids/CohesiveGridConnectionSphere.py.\033[1;0m',category=UserWarning) segment=end-begin b=Body() b.shape=ChainedCylinder(radius=radius,length=segment.norm(),color=color if color else utils.randomColor(),wire=wire,highlight=highlight) b.shape.segment=segment V=2*(4./3)*math.pi*radius**3 geomInert=(2./5.)*V*radius**2+b.shape.length*b.shape.length*2*(4./3)*math.pi*radius**3 b.state=ChainedState() b.state.addToChain(O.bodies.append(b)) utils._commonBodySetup(b,V,Vector3(geomInert,geomInert,geomInert),material,pos=begin,resetState=False,dynamic=dynamic,fixed=fixed) b.mask=mask b.bound=Aabb(color=[0,1,0]) b.state.ori.setFromTwoVectors(Vector3(0.,0.,1.),segment) if (end == begin): b.state.ori = Quaternion((1,0,0),0) return b
def stl(file, dynamic=None, fixed=True, wire=True, color=None, highlight=False, noBound=False, material=-1): """ Import geometry from stl file, return list of created facets.""" imp = STLImporter() facets = imp.ymport(file) for b in facets: b.shape.color = color if color else utils.randomColor() b.shape.wire = wire b.shape.highlight = highlight pos, ori = b.state.pos, b.state.ori utils._commonBodySetup(b, 0, Vector3(0, 0, 0), material=material, pos=pos, noBound=noBound, dynamic=dynamic, fixed=fixed) #b.state.pos,b.state.ori=pos,ori b.state.ori = ori b.aspherical = False #b.dynamic=dynamic return facets
def stl(file, dynamic=None, fixed=True, wire=True, color=None, highlight=False, noBound=False, material=-1, scale=1.0, shift=Vector3.Zero): """ Import geometry from stl file, return list of created facets.""" imp = STLImporter() facets = imp.ymport(file) for b in facets: b.shape.setVertices(b.shape.vertices[0] * scale, b.shape.vertices[1] * scale, b.shape.vertices[2] * scale) b.shape.color = color if color else utils.randomColor() b.shape.wire = wire b.shape.highlight = highlight pos = b.state.pos * scale + shift utils._commonBodySetup(b, 0, Vector3(0, 0, 0), material=material, pos=pos, noBound=noBound, dynamic=dynamic, fixed=fixed) b.aspherical = False return facets
def chainedCylinder( begin=Vector3(0, 0, 0), end=Vector3(1.0, 0.0, 0.0), radius=0.2, dynamic=None, fixed=False, wire=False, color=None, highlight=False, material=-1, mask=1, ): """ Create and connect a chainedCylinder with given parameters. The shape generated by repeted calls of this function is the Minkowski sum of polyline and sphere. :param Real radius: radius of sphere in the Minkowski sum. :param Vector3 begin: first point positioning the line in the Minkowski sum :param Vector3 last: last point positioning the line in the Minkowski sum In order to build a correct chain, last point of element of rank N must correspond to first point of element of rank N+1 in the same chain (with some tolerance, since bounding boxes will be used to create connections. :return: Body object with the :yref:`ChainedCylinder` :yref:`shape<Body.shape>`. """ segment = end - begin b = Body() b.shape = ChainedCylinder( radius=radius, length=segment.norm(), color=color if color else utils.randomColor(), wire=wire, highlight=highlight, ) b.shape.segment = segment V = 2 * (4.0 / 3) * math.pi * radius ** 3 geomInert = (2.0 / 5.0) * V * radius ** 2 + b.shape.length * b.shape.length * 2 * (4.0 / 3) * math.pi * radius ** 3 b.state = ChainedState() b.state.addToChain(O.bodies.append(b)) utils._commonBodySetup( b, V, Vector3(geomInert, geomInert, geomInert), material, pos=begin, resetState=False, dynamic=dynamic, fixed=fixed, ) b.mask = mask b.bound = Aabb(color=[0, 1, 0]) b.state.ori.setFromTwoVectors(Vector3(0.0, 0.0, 1.0), segment) if end == begin: b.state.ori = Quaternion((1, 0, 0), 0) return b
def stl(file, dynamic=None,fixed=True,wire=True,color=None,highlight=False,noBound=False,material=-1): """ Import geometry from stl file, return list of created facets.""" imp = STLImporter() facets=imp.ymport(file) for b in facets: b.shape.color=color if color else utils.randomColor() b.shape.wire=wire b.shape.highlight=highlight pos=b.state.pos utils._commonBodySetup(b,0,Vector3(0,0,0),material=material,pos=pos,noBound=noBound,dynamic=dynamic,fixed=fixed) b.aspherical=False return facets
def gridConnection(id1,id2,radius,wire=False,color=None,highlight=False,material=-1,mask=1,cellDist=None): """ Create a :yref:`GridConnection` by connecting two :yref:`GridNodes<GridNode>`. :param id1,id2: the two :yref:`GridNodes<GridNode>` forming the cylinder. :param float radius: radius of the cylinder. Note that the radius needs to be the same as the one for the :yref:`GridNodes<GridNode>`. :param Vector3 cellDist: for periodic boundary conditions, see :yref:`Interaction.cellDist`. Note: periodic boundary conditions for gridConnections are not yet implemented! See documentation of :yref:`yade.utils.sphere` for meaning of other parameters. :return: Body object with the :yref:`GridConnection` :yref:`shape<Body.shape>`. .. note:: The material of the :yref:`GridNodes<GridNode>` will be used to set the constitutive behaviour of the internal connection, i.e., the constitutive behaviour of the cylinder. The material of the :yref:`GridConnection` is used for interactions with other (external) bodies. """ b=Body() b.shape=GridConnection(radius=radius,color=color if color else utils.randomColor(),wire=wire,highlight=highlight) sph1=O.bodies[id1] ; sph2=O.bodies[id2] i=createInteraction(id1,id2) nodeMat=sph1.material b.shape.node1=sph1 ; b.shape.node2=sph2 sph1.shape.addConnection(b) ; sph2.shape.addConnection(b) if(O.periodic): if(cellDist!=None): i.cellDist=cellDist segt=sph2.state.pos + O.cell.hSize*i.cellDist - sph1.state.pos else: segt=sph2.state.pos - sph1.state.pos L=segt.norm() V=0.5*L*math.pi*radius**2 geomInert=(2./5.)*V*radius**2 utils._commonBodySetup(b,V,Vector3(geomInert,geomInert,geomInert),material,pos=sph1.state.pos,dynamic=False,fixed=True) sph1.state.mass = sph1.state.mass + V*nodeMat.density sph2.state.mass = sph2.state.mass + V*nodeMat.density for k in [0,1,2]: sph1.state.inertia[k] = sph1.state.inertia[k] + geomInert*nodeMat.density sph2.state.inertia[k] = sph2.state.inertia[k] + geomInert*nodeMat.density b.aspherical=False if O.periodic: i.phys.unp= -(sph2.state.pos + O.cell.hSize*i.cellDist - sph1.state.pos).norm() + sph1.shape.radius + sph2.shape.radius b.shape.periodic=True b.shape.cellDist=i.cellDist else: i.phys.unp= -(sph2.state.pos - sph1.state.pos).norm() + sph1.shape.radius + sph2.shape.radius i.geom.connectionBody=b I=math.pi*(2.*radius)**4/64. E=nodeMat.young i.phys.kn=E*math.pi*(radius**2)/L i.phys.kr=E*I/L i.phys.ks=12.*E*I/(L**3) G=E/(2.*(1+nodeMat.poisson)) i.phys.ktw=2.*I*G/L b.mask=mask return b
def gridNode(center,radius,dynamic=None,fixed=False,wire=False,color=None,highlight=False,material=-1): """ Create a :yref:`GridNode` which is needed to set up :yref:`GridConnections<GridConnection>`. See documentation of :yref:`yade.utils.sphere` for meaning of parameters. :return: Body object with the :yref:`gridNode` :yref:`shape<Body.shape>`. """ b=Body() b.shape=GridNode(radius=radius,color=color if color else utils.randomColor(),wire=wire,highlight=highlight) #V=(4./3)*math.pi*radius**3 # will be overwritten by the connection V=0. geomInert=(2./5.)*V*radius**2 # will be overwritten by the connection utils._commonBodySetup(b,V,Vector3(geomInert,geomInert,geomInert),material,pos=center,dynamic=dynamic,fixed=fixed) b.aspherical=False b.bounded=False b.mask=0 # avoid contact detection with the nodes. Manual interaction will be set for them in "gridConnection" below. return b
def pfacet(id1,id2,id3,wire=True,color=None,highlight=False,material=-1,mask=1,cellDist=None): """ Create a :yref:`PFacet<PFacet>` element from 3 :yref:`GridNodes<GridNode>` which are already connected via 3 :yref:`GridConnections<GridConnection>`: :param id1,id2,id3: already with :yref:`GridConnections<GridConnection>` connected :yref:`GridNodes<GridNode>` :param bool wire: if ``True``, top and bottom facet are shown as skeleton; otherwise facets are filled. :param Vector3-or-None color: color of the PFacet; random color will be assigned if ``None``. :param Vector3 cellDist: for periodic boundary conditions, see :yref:`Interaction.cellDist`. Note: periodic boundary conditions are not yet implemented for PFacets! See documentation of :yref:`yade.utils.sphere` for meaning of other parameters. :return: Body object with the :yref:`PFacet<PFacet>` :yref:`shape<Body.shape>`. .. note:: :yref:`GridNodes<GridNode>` and :yref:`GridConnections<GridConnection>` need to have the same radius. This is also the radius used to create the :yref:`PFacet<PFacet>` """ b=Body() GridN1=O.bodies[id1]; GridN2=O.bodies[id2]; GridN3=O.bodies[id3] b.shape=PFacet(color=color if color else randomColor(),wire=wire,highlight=highlight,node1=GridN1,node2=GridN2,node3=GridN3) GridN1.bounded=False; GridN2.bounded=False; GridN3.bounded=False GridC1=O.bodies[O.interactions[id1,id2].geom.connectionBody.id] GridC2=O.bodies[O.interactions[id2,id3].geom.connectionBody.id] GridC3=O.bodies[O.interactions[id1,id3].geom.connectionBody.id] GridC1.bounded=False GridC2.bounded=False GridC3.bounded=False b.shape.conn1=GridC1 b.shape.conn2=GridC2 b.shape.conn3=GridC3 b.shape.radius=GridN1.shape.radius GridC1.shape.addPFacet(b) GridC2.shape.addPFacet(b) GridC3.shape.addPFacet(b) GridN1.shape.addPFacet(b); GridN2.shape.addPFacet(b); GridN3.shape.addPFacet(b) V=0 utils._commonBodySetup(b,V,Vector3(0,0,0),material,pos=GridN1.state.pos,dynamic=False,fixed=True) b.aspherical=False # mass and inertia are lumped into the GridNodes b.mask=mask return b
def finite_element(material,shape,nodes,faces,radius,dynamic=None,fixed=True,wire=False,Color=None,highlight=False,mask=1,interface=False): """Create sphere with given parameters; mass and inertia computed automatically. Last assigned material is used by default (*material* = -1), and utils.defaultMaterial() will be used if no material is defined at all. :param Vector3 center: center :param float radius: radius :param float dynamic: deprecated, see "fixed" :param float fixed: generate the body with all DOFs blocked? :param material: specify :yref:`Body.material`; different types are accepted: * int: O.materials[material] will be used; as a special case, if material==-1 and there is no shared materials defined, utils.defaultMaterial() will be assigned to O.materials[0] * string: label of an existing material that will be used * :yref:`Material` instance: this instance will be used * callable: will be called without arguments; returned Material value will be used (Material factory object, if you like) :param int mask: :yref:`Body.mask` for the body :param wire: display as wire sphere? :param highlight: highlight this body in the viewer? :param Vector3-or-None: body's color, as normalized RGB; random color will be assigned if ``None``. :return: A Body instance with desired characteristics. Creating default shared material if none exists neither is given:: >>> O.reset() >>> from yade import utils >>> len(O.materials) 0 >>> s0=utils.sphere([2,0,0],1) >>> len(O.materials) 1 Instance of material can be given:: >>> s1=utils.sphere([0,0,0],1,wire=False,color=(0,1,0),material=ElastMat(young=30e9,density=2e3)) >>> s1.shape.wire False >>> s1.shape.color Vector3(0,1,0) >>> s1.mat.density 2000.0 Material can be given by label:: >>> O.materials.append(FrictMat(young=10e9,poisson=.11,label='myMaterial')) 1 >>> s2=utils.sphere([0,0,2],1,material='myMaterial') >>> s2.mat.label 'myMaterial' >>> s2.mat.poisson 0.11 Finally, material can be a callable object (taking no arguments), which returns a Material instance. Use this if you don't call this function directly (for instance, through yade.pack.randomDensePack), passing only 1 *material* parameter, but you don't want material to be shared. For instance, randomized material properties can be created like this: >>> import random >>> def matFactory(): return ElastMat(young=1e10*random.random(),density=1e3+1e3*random.random()) ... >>> s3=utils.sphere([0,2,0],1,material=matFactory) >>> s4=utils.sphere([1,2,0],1,material=matFactory) """ b=Body(); b.shape=shape; O.bodies.append(b) nodes_ret=[]; #b.shape.color=Color; #add nodes to the scene and keep them in the nodes list if(interface==False): #Deformable Element for vec in nodes: # Second Example nod=node(vec,radius) O.bodies.append(nod) b.shape.addNode(nod) nodes_ret.append(nod) #add faces for drawing purposes for face in faces: b.shape.addFace(face) else: #Deformable Cohesive Element for nodepair in nodes: # Second Example b.shape.addPair(nodepair[0],nodepair[1]) #add faces for drawing purposes for face in faces: b.shape.addFace(face) V=1;#For symbolical geomInert=Vector3(1,1,1)#For symbolical #Only add body to draw it not for integration, therefore block all dof _commonBodySetup(b,V,geomInert,material,pos=Vector3(0,0,0),dynamic=False,fixed=True,blockedDOFs='xyzXYZ') b.aspherical=False b.mask=mask b.bounded=False return [b,nodes_ret]
def node(center,radius,dynamic=None,fixed=True,wire=False,color=None,highlight=False,material=-1,mask=1): """Create sphere with given parameters; mass and inertia computed automatically. Last assigned material is used by default (*material* = -1), and utils.defaultMaterial() will be used if no material is defined at all. :param Vector3 center: center :param float radius: radius :param float dynamic: deprecated, see "fixed" :param float fixed: generate the body with all DOFs blocked? :param material: specify :yref:`Body.material`; different types are accepted: * int: O.materials[material] will be used; as a special case, if material==-1 and there is no shared materials defined, utils.defaultMaterial() will be assigned to O.materials[0] * string: label of an existing material that will be used * :yref:`Material` instance: this instance will be used * callable: will be called without arguments; returned Material value will be used (Material factory object, if you like) :param int mask: :yref:`Body.mask` for the body :param wire: display as wire sphere? :param highlight: highlight this body in the viewer? :param Vector3-or-None: body's color, as normalized RGB; random color will be assigned if ``None``. :return: A Body instance with desired characteristics. Creating default shared material if none exists neither is given:: >>> O.reset() >>> from yade import utils >>> len(O.materials) 0 >>> s0=utils.sphere([2,0,0],1) >>> len(O.materials) 1 Instance of material can be given:: >>> s1=utils.sphere([0,0,0],1,wire=False,color=(0,1,0),material=ElastMat(young=30e9,density=2e3)) >>> s1.shape.wire False >>> s1.shape.color Vector3(0,1,0) >>> s1.mat.density 2000.0 Material can be given by label:: >>> O.materials.append(FrictMat(young=10e9,poisson=.11,label='myMaterial')) 1 >>> s2=utils.sphere([0,0,2],1,material='myMaterial') >>> s2.mat.label 'myMaterial' >>> s2.mat.poisson 0.11 Finally, material can be a callable object (taking no arguments), which returns a Material instance. Use this if you don't call this function directly (for instance, through yade.pack.randomDensePack), passing only 1 *material* parameter, but you don't want material to be shared. For instance, randomized material properties can be created like this: >>> import random >>> def matFactory(): return ElastMat(young=1e10*random.random(),density=1e3+1e3*random.random()) ... >>> s3=utils.sphere([0,2,0],1,material=matFactory) >>> s4=utils.sphere([1,2,0],1,material=matFactory) """ b=Body() b.shape=Node(radius=radius,color=color if color else randomColor(),wire=wire,highlight=highlight) V=(4./3)*math.pi*radius**3 geomInert=(2./5.)*V*radius**2 _commonBodySetup(b,V,Vector3(geomInert,geomInert,geomInert),material,pos=center,dynamic=dynamic,fixed=fixed,blockedDOFs='XYZ') b.aspherical=False b.mask=mask b.bounded=True return b
def finite_element(material, shape, nodes, faces, radius, dynamic=None, fixed=True, wire=False, Color=None, highlight=False, mask=1, interface=False): """Create sphere with given parameters; mass and inertia computed automatically. Last assigned material is used by default (*material* = -1), and utils.defaultMaterial() will be used if no material is defined at all. :param Vector3 center: center :param float radius: radius :param float dynamic: deprecated, see "fixed" :param float fixed: generate the body with all DOFs blocked? :param material: specify :yref:`Body.material`; different types are accepted: * int: O.materials[material] will be used; as a special case, if material==-1 and there is no shared materials defined, utils.defaultMaterial() will be assigned to O.materials[0] * string: label of an existing material that will be used * :yref:`Material` instance: this instance will be used * callable: will be called without arguments; returned Material value will be used (Material factory object, if you like) :param int mask: :yref:`Body.mask` for the body :param wire: display as wire sphere? :param highlight: highlight this body in the viewer? :param Vector3-or-None: body's color, as normalized RGB; random color will be assigned if ``None``. :return: A Body instance with desired characteristics. Creating default shared material if none exists neither is given:: >>> O.reset() >>> from yade import utils >>> len(O.materials) 0 >>> s0=utils.sphere([2,0,0],1) >>> len(O.materials) 1 Instance of material can be given:: >>> s1=utils.sphere([0,0,0],1,wire=False,color=(0,1,0),material=ElastMat(young=30e9,density=2e3)) >>> s1.shape.wire False >>> s1.shape.color Vector3(0,1,0) >>> s1.mat.density 2000.0 Material can be given by label:: >>> O.materials.append(FrictMat(young=10e9,poisson=.11,label='myMaterial')) 1 >>> s2=utils.sphere([0,0,2],1,material='myMaterial') >>> s2.mat.label 'myMaterial' >>> s2.mat.poisson 0.11 Finally, material can be a callable object (taking no arguments), which returns a Material instance. Use this if you don't call this function directly (for instance, through yade.pack.randomDensePack), passing only 1 *material* parameter, but you don't want material to be shared. For instance, randomized material properties can be created like this: >>> import random >>> def matFactory(): return ElastMat(young=1e10*random.random(),density=1e3+1e3*random.random()) ... >>> s3=utils.sphere([0,2,0],1,material=matFactory) >>> s4=utils.sphere([1,2,0],1,material=matFactory) """ b = Body() b.shape = shape O.bodies.append(b) nodes_ret = [] #b.shape.color=Color; #add nodes to the scene and keep them in the nodes list if (interface == False): #Deformable Element for vec in nodes: # Second Example nod = node(vec, radius) O.bodies.append(nod) b.shape.addNode(nod) nodes_ret.append(nod) #add faces for drawing purposes for face in faces: b.shape.addFace(face) else: #Deformable Cohesive Element for nodepair in nodes: # Second Example b.shape.addPair(nodepair[0], nodepair[1]) #add faces for drawing purposes for face in faces: b.shape.addFace(face) V = 1 #For symbolical geomInert = Vector3(1, 1, 1) #For symbolical #Only add body to draw it not for integration, therefore block all dof _commonBodySetup(b, V, geomInert, material, pos=Vector3(0, 0, 0), dynamic=False, fixed=True, blockedDOFs='xyzXYZ') b.aspherical = False b.mask = mask b.bounded = False return [b, nodes_ret]
def node(center, radius, dynamic=None, fixed=True, wire=False, color=None, highlight=False, material=-1, mask=1): """Create sphere with given parameters; mass and inertia computed automatically. Last assigned material is used by default (*material* = -1), and utils.defaultMaterial() will be used if no material is defined at all. :param Vector3 center: center :param float radius: radius :param float dynamic: deprecated, see "fixed" :param float fixed: generate the body with all DOFs blocked? :param material: specify :yref:`Body.material`; different types are accepted: * int: O.materials[material] will be used; as a special case, if material==-1 and there is no shared materials defined, utils.defaultMaterial() will be assigned to O.materials[0] * string: label of an existing material that will be used * :yref:`Material` instance: this instance will be used * callable: will be called without arguments; returned Material value will be used (Material factory object, if you like) :param int mask: :yref:`Body.mask` for the body :param wire: display as wire sphere? :param highlight: highlight this body in the viewer? :param Vector3-or-None: body's color, as normalized RGB; random color will be assigned if ``None``. :return: A Body instance with desired characteristics. Creating default shared material if none exists neither is given:: >>> O.reset() >>> from yade import utils >>> len(O.materials) 0 >>> s0=utils.sphere([2,0,0],1) >>> len(O.materials) 1 Instance of material can be given:: >>> s1=utils.sphere([0,0,0],1,wire=False,color=(0,1,0),material=ElastMat(young=30e9,density=2e3)) >>> s1.shape.wire False >>> s1.shape.color Vector3(0,1,0) >>> s1.mat.density 2000.0 Material can be given by label:: >>> O.materials.append(FrictMat(young=10e9,poisson=.11,label='myMaterial')) 1 >>> s2=utils.sphere([0,0,2],1,material='myMaterial') >>> s2.mat.label 'myMaterial' >>> s2.mat.poisson 0.11 Finally, material can be a callable object (taking no arguments), which returns a Material instance. Use this if you don't call this function directly (for instance, through yade.pack.randomDensePack), passing only 1 *material* parameter, but you don't want material to be shared. For instance, randomized material properties can be created like this: >>> import random >>> def matFactory(): return ElastMat(young=1e10*random.random(),density=1e3+1e3*random.random()) ... >>> s3=utils.sphere([0,2,0],1,material=matFactory) >>> s4=utils.sphere([1,2,0],1,material=matFactory) """ b = Body() b.shape = Node(radius=radius, color=color if color else randomColor(), wire=wire, highlight=highlight) V = (4. / 3) * math.pi * radius**3 geomInert = (2. / 5.) * V * radius**2 _commonBodySetup(b, V, Vector3(geomInert, geomInert, geomInert), material, pos=center, dynamic=dynamic, fixed=fixed, blockedDOFs='XYZ') b.aspherical = False b.mask = mask b.bounded = True return b
def gridConnection(id1, id2, radius, wire=False, color=None, highlight=False, material=-1, mask=1, cellDist=None): """ Create a :yref:`GridConnection` by connecting two :yref:`GridNodes<GridNode>`. :param id1,id2: already with :yref:`GridConnections<GridConnection>` connected :yref:`GridNodes<GridNode>` :param bool wire: if ``True``, top and bottom facet are shown as skeleton; otherwise facets are filled. :param Vector3-or-None color: color of the PFacet; random color will be assigned if ``None``. :param Vector3 cellDist: for periodic boundary conditions, see :yref:`Interaction.cellDist`. Note: periodic boundary conditions are not yet implemented! See documentation of :yref:`yade.utils.sphere` for meaning of other parameters. :return: Body object with the :yref:`PFacet<PFacet>` :yref:`shape<Body.shape>`. .. note:: :yref:`GridNodes<GridNode>` and :yref:`GridConnections<GridConnection>` need to have the same radius. This is also the radius used to create the :yref:`PFacet<PFacet>` """ b = Body() b.shape = GridConnection( radius=radius, color=color if color else utils.randomColor(), wire=wire, highlight=highlight ) sph1 = O.bodies[id1] sph2 = O.bodies[id2] i = createInteraction(id1, id2) nodeMat = sph1.material b.shape.node1 = sph1 b.shape.node2 = sph2 sph1.shape.addConnection(b) sph2.shape.addConnection(b) if O.periodic: if cellDist != None: i.cellDist = cellDist segt = sph2.state.pos + O.cell.hSize * i.cellDist - sph1.state.pos else: segt = sph2.state.pos - sph1.state.pos L = segt.norm() V = 0.5 * L * math.pi * radius ** 2 geomInert = (2.0 / 5.0) * V * radius ** 2 utils._commonBodySetup( b, V, Vector3(geomInert, geomInert, geomInert), material, pos=sph1.state.pos, dynamic=False, fixed=True ) sph1.state.mass = sph1.state.mass + V * nodeMat.density sph2.state.mass = sph2.state.mass + V * nodeMat.density for k in [0, 1, 2]: sph1.state.inertia[k] = sph1.state.inertia[k] + geomInert * nodeMat.density sph2.state.inertia[k] = sph2.state.inertia[k] + geomInert * nodeMat.density b.aspherical = False if O.periodic: i.phys.unp = ( -(sph2.state.pos + O.cell.hSize * i.cellDist - sph1.state.pos).norm() + sph1.shape.radius + sph2.shape.radius ) b.shape.periodic = True b.shape.cellDist = i.cellDist else: i.phys.unp = -(sph2.state.pos - sph1.state.pos).norm() + sph1.shape.radius + sph2.shape.radius i.geom.connectionBody = b I = math.pi * (2.0 * radius) ** 4 / 64.0 E = nodeMat.young i.phys.kn = E * math.pi * (radius ** 2) / L i.phys.kr = E * I / L i.phys.ks = 12.0 * E * I / (L ** 3) G = E / (2.0 * (1 + nodeMat.poisson)) i.phys.ktw = 2.0 * I * G / L b.mask = mask return b