Beispiel #1
0
 def __new__(clas,data,mass,ctr):
     """Create a new Tensor instance"""
     ar = Tensor.__new__(clas,data)
     # We need mass and ctr!
     ar.mass = float(mass)
     ar.ctr = Coords(at.checkArray(ctr,shape=(3,),kind='f'))
     return ar
Beispiel #2
0
def read_stl_bin(fn):
    """Read a binary stl.

    Returns a Coords with shape (ntri,4,3). The first item of each
    triangle is the normal, the other three are the vertices.
    """
    def addTriangle(i):
        x[i] = np.fromfile(file=fil, dtype=at.Float, count=12).reshape(4, 3)
        fil.read(2)

    print("Reading binary .STL %s" % fn)
    fil = open(fn, 'rb')
    head = fil.read(80)
    if head[:5] == 'solid':
        raise ValueError("%s looks like an ASCII STL file!" % fn)
    i = head.find('COLOR=')
    if i >= 0 and i <= 70:
        color = np.fromstring(head[i + 6:i + 10], dtype=np.uint8, count=4)
    else:
        color = None

    ntri = np.fromfile(file=fil, dtype=at.Int, count=1)[0]
    print("Number of triangles: %s" % ntri)
    x = np.zeros((ntri, 4, 3), dtype=np.Float)
    #nbytes = 12*4 + 2
    [addTriangle(it) for it in range(ntri)]
    print("Finished reading binary stl")
    x = Coords(x)
    if color is not None:
        from pyformex.opengl.colors import GLcolor
        color = GLcolor(color[:3])
    return x, color
Beispiel #3
0
    def toNDC(self, x, rect=None):
        """Convert world coordinates to normalized device coordinates.

        The normalized device coordinates (NDC) have x and y values
        in the range -1 to +1 for points that are falling within the
        visible region of the camera.

        Parameters:

        - `x`: Coords with the world coordinates to be converted
        - `rect`: optional, a tuple of 4 values (x,y,w,h) specifying
          a rectangular subregion of the camera's viewport. The default
          is the full camera viewport.

        The return value is a Coords. The z-coordinate provides
        depth information.
        """
        m = self.modelview * self.projection
        if rect is not None:
            m = m * self.pickMatrix(rect)
        x = Coords4(x)
        x = Coords4(np.dot(x, m))
        if self._perspective:
            x = x.toCoords()  # This performs the perspective divide
        else:
            # Orthogonal projection
            # This is not tested yet!!!
            x = Coords(x[..., :3])
        return x
Beispiel #4
0
    def transform(self, X):
        """Apply isoparametric transform to a set of coordinates.

        Returns a Coords array with same shape as X
        """
        if not isinstance(X, Coords):
            try:
                X = Coords(X)
            except:
                raise ValueError("Expected a Coords object as argument")

        poly = Isopar.isodata[self.eltype]
        ndim = poly.ndim
        aa = poly.evalAtoms(X.reshape(-1, 3)[:, :ndim])
        xx = np.dot(aa, self.trf).reshape(X.shape)
        if ndim < 3:
            xx[..., ndim:] += X[..., ndim:]
        return X.__class__(xx)
Beispiel #5
0
    def _set_coords_inplace(self, coords):
        """Replace the current coords with new ones.

        """
        coords = Coords(coords)
        if coords.shape == self.coords.shape:
            self.coords = coords
            return self
        else:
            raise ValueError("Invalid reinitialization of Geometry coords")
Beispiel #6
0
 def unproject(self, x):
     """Map the window coordinates x to object coordinates."""
     m = self.modelview * self.projection
     #print("M*P",m)
     m1 = np.linalg.inv(m)
     #print("M*P -1",m1)
     x = self.fromWindow(x)
     #print("NORMALIZED DEVICE COORDINATES:",x)
     x = Vector4(x) * m1
     return Coords(x[:, :3] / x[:, 3])
Beispiel #7
0
def point_inertia(X,mass=None,center_only=False):
    """Compute the total mass, center of mass and inertia tensor mass points.

    Parameters:

    - `X`: a Coords with shape (npoints,3). Shapes (...,3) are accepted
      but will be reshaped to (npoints,3).
    - `mass`: optional, (npoints,) float array with the mass of the points.
      If omitted, all points have mass 1.
    - `center_only`: bool: if True, only returns the total mass and center
      of mass.

    Returns a tuple (M,C,I) where M is the total mass of all points, C is
    the center of mass, and I is the inertia tensor in the central coordinate
    system, i.e. a coordinate system with axes paralle to the global axes
    but origin at the (computed) center of mass. If `center_only` is True,
    returns the tuple (M,C) only. On large models this is more effective
    in case you do not need the inertia tensor.

    """
    X = Coords(X).reshape(-1, 3)
    npoints = X.shape[0]
    if mass is not None:
        mass = at.checkArray(mass,shape=(npoints,),kind='f')
        mass = mass.reshape(-1,1)
        M = mass.sum()
        C = (X*mass).sum(axis=0) / M
    else:
        M = float(npoints)
        C = X.mean(axis=0)
    if center_only:
        return M,C

    Xc = X - C
    x, y, z = Xc[:, 0], Xc[:, 1], Xc[:, 2]
    xx, yy, zz, yz, zx, xy = x*x, y*y, z*z, y*z, z*x, x*y
    I = np.column_stack([ yy+zz, zz+xx, xx+yy, -yz, -zx, -xy ])
    if mass is not None:
        I *= mass
    I = I.sum(axis=0)
    return M,C,I
Beispiel #8
0
 def __new__(clas, coords=None, origins=None, vectors=None):
     """Initialize the BoundVectors."""
     if coords is None:
         coords = eye(2, 3, -1)
         if vectors is not None:
             coords = np.resize(coords, vectors.shape[:-1] + (2, 3))
             coords[..., 1, :] = vectors
         if origins is not None:
             coords += origins[..., np.newaxis, :]
     elif coords.shape[-2:] != (2, 3):
         raise ValueError("Expected shape (2,3) for last two array axes.")
     return Coords.__new__(clas, coords)
Beispiel #9
0
    def toNDC1(self, x, rect=None):
        """This is like toNDC without the perspective divide

        This function is useful to compute the vertex position of a
        3D point as computed by the vertex shader.

        """
        m = self.modelview * self.projection
        if rect is not None:
            m = m * self.pickMatrix(rect)
        x = Coords4(x)
        x = Coords4(np.dot(x, m))
        x = Coords(x[..., :3])
        return x
Beispiel #10
0
    def resized(self, size=1., tol=1.e-5):
        """Return a copy of the Geometry scaled to the given size.

        size can be a single value or a list of three values for the
        three coordinate directions. If it is a single value, all directions
        are scaled to the same size.
        Directions for which the geometry has a size smaller than tol times
        the maximum size are not rescaled.
        """
        from numpy import resize
        s = self.sizes()
        size = Coords(resize(size, (3, )))
        ignore = s < tol * s.max()
        s[ignore] = size[ignore]
        return self.scale(size / s)
Beispiel #11
0
    def __init__(self,coords=None,elems=None,meshes=None,fuse=True):
        """Create new model data.

        coords is an array with nodal coordinates
        elems is either a single element connectivity array, or a list of such.
        In a simple case, coords and elems can be the arrays obtained by
        ``coords, elems = F.feModel()``.
        This is however limited to a model where all elements have the same
        number of nodes. Then you can use the list of elems arrays. The 'fe'
        plugin has a helper function to create this list. E.g., if ``FL`` is a
        list of Formices (possibly with different plexitude), then
        ``fe.mergeModels([Fi.feModel() for Fi in FL])``
        will return the (coords,elems) tuple to create the Model.

        The model can have node and element property numbers.
        """
        Geometry.__init__(self)
        if meshes is not None:
            if coords is not None or elems is not None:
                raise ValueError("You can not use nodes/elems together with meshes")
            for M in meshes:
                if M.prop is None:
                    M.setProp(0)
            self.coords, self.elems = mergeMeshes(meshes, fuse=fuse)
            self.prop = np.concatenate([M.prop for M in meshes])
        else:
            if not isinstance(elems, list):
                elems = [ elems ]
            self.coords = Coords(coords)
            self.elems = [ Connectivity(e) for e in elems ]
            self.prop = None
            meshes = self.meshes()
        nnodes = [ m.nnodes() for m in meshes ]
        nelems = [ m.nelems() for m in meshes ]
        nplex = [ m.nplex() for m in meshes ]
        self.cnodes = np.cumsum([0]+nnodes)
        self.celems = np.cumsum([0]+nelems)
        print("Finite Element Model")
        print("Number of nodes: %s" % self.coords.shape[0])
        print("Number of elements: %s" % self.celems[-1])
        print("Number of element groups: %s" % len(nelems))
        #print("Number of nodes per group: %s" % nnodes)
        print("Number of elements per group: %s" % nelems)
        print("Plexitude of each group: %s" % nplex)
Beispiel #12
0
def createElementType(name,
                      doc,
                      ndim,
                      vertices,
                      edges=('', []),
                      faces=('', []),
                      **kargs):
    name = name.capitalize()
    if name in _registered_element_types:
        raise ValueError("Element type %s already exists" % name)

    #print "\n CREATING ELEMENT TYPE %s\n" % name

    D = dict(
        __doc__='_' + doc,  # block autodoc for generated classed
        ndim=ndim,
        vertices=Coords(vertices),
        edges=_sanitize(edges),
        faces=_sanitize(faces),
    )

    for a in [
            'drawedges', 'drawedges2', 'drawfaces', 'drawfaces2',
            'drawgl2edges', 'drawgl2faces'
    ]:
        if a in kargs:
            D[a] = [_sanitize(e) for e in kargs[a]]
            del kargs[a]

    # other args are added as-is
    D.update(kargs)
    #print "Final class dict:",D

    ## # add the element to the collection
    ## if self._name in Element.collection:
    ##     raise ValueError("Can not create duplicate element names"
    ## Element.collection[self._name] = self

    C = type(name, (ElementType, ), D)
    _registered_element_types[name] = C
    return C
Beispiel #13
0
def readInpFile(filename):
    """Read the geometry from an Abaqus/Calculix .inp file

    This is a replacement for the convertInp/readMeshFile combination.
    It uses the ccxinp plugin to provide a direct import of the Finite
    Element meshes from an Abaqus or Calculix input file.
    Currently still experimental and limited in functionality (aimed
    primarily at Calculix). But also many simple meshes from Abaqus can
    already be read.

    Returns an dict.
    """
    from pyformex.plugins import ccxinp, fe
    ccxinp.skip_unknown_eltype = True
    model = ccxinp.readInput(filename)
    print("Number of parts: %s" % len(model.parts))
    fem = {}
    for part in model.parts:
        try:
            coords = Coords(part['coords'])
            nodid = part['nodid']
            nodpos = at.inverseUniqueIndex(nodid)
            print("nnodes = %s" % coords.shape[0])
            print("nodid: %s" % nodid)
            print("nodpos: %s" % nodpos)
            for e in part['elems']:
                print("Orig els %s" % e[1])
                print("Trl els %s" % nodpos[e[1]])
            elems = [
                Connectivity(nodpos[e], eltype=t) for (t, e) in part['elems']
            ]
            print('ELEM TYPES: %s' % [e.eltype for e in elems])
            fem[part['name']] = fe.Model(coords, elems)
        except:
            print("Skipping part %s" % part['name'])
    return fem
Beispiel #14
0
def readNodes(fil):
    """Read a set of nodes from an open mesh file"""
    a = np.fromfile(fil, sep=" ").reshape(-1, 3)
    x = Coords(a)
    return x
Beispiel #15
0
    def __init__(self,text,pos,gravity=None,size=18,width=None,font=None,lineskip=1.0,grid=None,texmode=4,**kargs):
        """Initialize the Text actor."""

        # split the string on newlines
        text = str(text).split('\n')

        # set pos and offset3d depending on pos type (2D vs 3D rendering)
        pos = at.checkArray(pos)
        if pos.shape[-1] == 2:
            rendertype = 2
            pos = [pos[0],pos[1],0.]
            offset3d = None
        else:
            rendertype = 1
            offset3d = Coords(pos)
            pos = [0.,0.,0.]
            if offset3d.ndim > 1:
                if offset3d.shape[0] != len(text[0]):
                    raise ValueError("Length of text(%s) and pos(%s) should match!" % (len(text),len(pos)))
                # Flag vertex offset to shader
                rendertype = -1

        # set the font characteristics
        if font is None:
            font = FontTexture.default(size)
        if isinstance(font,(str,unicode)):
            font = FontTexture(font,size)
        if width is None:
            #print("Font %s / %s" % (font.height,font.width))
            aspect = float(font.width) / font.height
            width = size * aspect
        self.width = width

        # set the alignment
        if gravity is None:
            gravity = 'E'
        alignment = ['0','0','0']
        if 'W' in gravity:
            alignment[0] = '+'
        elif 'E' in gravity:
            alignment[0] = '-'
        if 'S' in gravity:
            alignment[1] = '+'
        elif 'N' in gravity:
            alignment[1] = '-'
        alignment = ''.join(alignment)

        # record the lengths of the lines, join all characters
        # together, create texture coordinates for all characters
        # create a geometry grid for the longest line
        lt = [ len(t) for t in text ]
        text = ''.join(text)
        texcoords = font.texCoords(text)
        if grid is None:
            grid = Formex('4:0123').replic(max(lt))
        grid = grid.scale([width,size,0.])

        # create the actor for the first line
        l = lt[0]
        g = grid.select(range(l)).align(alignment,pos)
        Actor.__init__(self,g,rendertype=rendertype,texture=font,texmode=texmode,texcoords=texcoords[:l],opak=False,ontop=True,offset3d=offset3d,**kargs)

        for k in lt[1:]:
            # lower the canvas y-value
            pos[1] -= font.height * lineskip
            g = grid.select(range(k)).align(alignment,pos)
            C = Actor(g,rendertype=rendertype,texture=font,texmode=texmode,texcoords=texcoords[l:l+k],opak=False,ontop=True,offset3d=offset3d,**kargs)
            self.children.append(C)
            # do next line
            l += k
Beispiel #16
0
 def points(self):
     """Return origin and endpoints of unit vectors along axes."""
     return Coords.concatenate([self.axes+self.trl, self.trl])
Beispiel #17
0
 def origins(self):
     """Return the initial points of the BoundVectors."""
     return Coords(self[..., 0, :])
Beispiel #18
0
        (0.0, 1.0, 0.0),
    ],
    edges=(
        'line2',
        [(0, 1), (1, 2), (2, 3), (3, 0)],
    ),
    drawgl2faces=[('tri3', [(0, 1, 3), (1, 2, 3)])],
)

Quad6 = createElementType(
    'quad6',
    "A 6-node quadrilateral",
    ndim=2,
    vertices=Coords.concatenate(
        [Quad4.vertices, [
            (0.5, 0.0, 0.0),
            (0.5, 1.0, 0.0),
        ]]),
    edges=('line3', [(0, 4, 1), (1, 1, 2), (2, 5, 3), (3, 3, 0)]),
    reversed=(3, 2, 1, 0, 5, 4),
    drawedges=[('line2', [(1, 2), (3, 0)]), ('line3', [(0, 4, 1), (2, 5, 3)])],
    drawfaces=[(
        'quad4',
        [(0, 4, 5, 3), (2, 5, 4, 1)],
    )],
    drawgl2edges=[('line2', [(1, 2), (3, 0), (0, 4), (4, 1), (2, 5), (5, 3)])],
    drawgl2faces=[('tri3', [(0, 4, 3), (4, 5, 3), (4, 1, 5), (1, 2, 5)])],
)

Quad8 = createElementType(
    'quad8',
Beispiel #19
0
 def heads(self):
     """Return the endpoints of the BoundVectors."""
     return Coords(self[..., 1, :])
Beispiel #20
0
 def vectors(self):
     """Return the vectors of the BoundVectors."""
     return Coords(self.heads() - self.origins())