Esempio n. 1
0
    def set_size(self, axis_length, axis_radius):
        from chimerax.surface.shapes import cylinder_geometry, cone_geometry
        vaz, naz, taz = cylinder_geometry(radius=axis_radius,
                                          height=axis_length)
        vcz, ncz, tcz = cone_geometry(radius=axis_radius * 2,
                                      height=axis_length * 0.2,
                                      caps=True)
        from chimerax.geometry import Place
        vct = Place(origin=(0, 0, axis_length / 2))
        vcz = vct.transform_points(vcz)
        nv = len(vaz)
        tcz = tcz + nv
        from numpy import concatenate
        vaz = concatenate((vaz, vcz))
        naz = concatenate((naz, ncz))
        taz = concatenate((taz, tcz))
        nv = len(vaz)
        tx = Place(axes=[[0, 0, 1], [0, -1, 0], [1, 0, 0]])
        vax, nax, tax = tx.transform_points(vaz), tx.transform_vectors(
            naz), taz.copy() + nv
        ty = Place(axes=[[1, 0, 0], [0, 0, -1], [0, 1, 0]])
        vay, nay, tay = ty.transform_points(vaz), ty.transform_vectors(
            naz), taz.copy() + 2 * nv

        vc = self.vertex_colors
        self.set_geometry(concatenate((vax, vay, vaz)),
                          concatenate((nax, nay, naz)),
                          concatenate((tax, tay, taz)))
        self.vertex_colors = vc  # Setting geometry clears vertex colors
Esempio n. 2
0
def ellipsoid_geometry(center, axes, axis_lengths, num_triangles = 1000):

  from chimerax.surface import sphere_geometry
  varray, narray, tarray = sphere_geometry(num_triangles)
  narray = narray.copy()        # Is same as varray for sphere.
  from chimerax.geometry import Place, scale, normalize_vectors
  ptf = Place(axes = axes, origin = center) * scale(axis_lengths)
  ptf.transform_points(varray, in_place = True)
  ntf = Place(axes = axes) * scale([1/l for l in axis_lengths])
  ntf.transform_vectors(narray, in_place = True)
  normalize_vectors(narray)

  return varray, narray, tarray
Esempio n. 3
0
def _show_surface(session, varray, tarray, color, mesh,
                  center, rotation, qrotation, coordinate_system,
                  slab, model_id, shape_name, edge_mask = None, sharp_slab = False):
        
    if center is not None or rotation is not None or qrotation is not None:
        from chimerax.geometry import Place, translation
        tf = Place()
        if rotation is not None:
            tf = rotation * tf
        if qrotation is not None:
            tf = qrotation * tf
        if center is not None:
            from chimerax.core.commands import Center
            if isinstance(center, Center):
                center = center.scene_coordinates()
            tf = translation(center) * tf
        varray = tf.transform_points(varray)
        
    from chimerax.surface import calculate_vertex_normals
    narray = calculate_vertex_normals(varray, tarray)
    
    if slab is not None:
        from chimerax.mask.depthmask import slab_surface
        varray, narray, tarray = slab_surface(varray, tarray, narray, slab,
                                              sharp_edges = sharp_slab)

    s = _surface_model(session, model_id, shape_name, coordinate_system)
    s.set_geometry(varray, narray, tarray)
    if color is not None:
        s.color = color
    if mesh:
        s.display_style = s.Mesh
    if edge_mask is not None:
        s.edge_mask = edge_mask    # Hide spokes of hexagons.
    _add_surface(s)

    return s
Esempio n. 4
0
def mesh_geometry(mesh, seg):
    # TODO: SFF format data structure mix vertices and normals, calling both vertices -- a nightmare.
    #   Semantics of which normal belong with which vertices unclear (consecutive in polygon?).
    #   Efficiency reading is horrible.  Ask Paul K to make separate vertex and normal lists.
    nv = mesh.num_vertices // 2
    from numpy import empty, float32
    va = empty((nv, 3), float32)
    na = empty((nv, 3), float32)
    for i, v in enumerate(mesh.vertices):
        vid = v.id
        if vid != i:
            raise ValueError(
                'Require mesh vertices be numbers consecutively from 0, got vertex id %d in position %d'
                % (vid, i))
        d = v.designation  # 'surface' or 'normal'
        if d == 'surface':
            if vid % 2 == 1:
                raise ValueError(
                    'Require odd mesh indices to be normals, got a vertex at position %d'
                    % vid)
            va[vid // 2] = v.point
        elif d == 'normal':
            if vid % 2 == 0:
                raise ValueError(
                    'Require even mesh indices to be vertices, got a normal at position %d'
                    % vid)
            na[vid // 2] = v.point
        else:
            raise ValueError(
                'Vertex %d designation "%s" is not "surface" or "normal"' %
                (v.id, d))
    '''
    vids = list(set(v.id for v in mesh.vertices if v.designation == 'surface'))
    vids.sort()
    print ('vertex ids', vids[:3], 'num', len(vids), 'last', vids[-1])
    '''

    if mesh.transform_id is None:
        from chimerax.geometry import Place, scale
        #        transform = scale((160,160,160)) * Place(seg.transforms[0].data_array)
        transform = Place(seg.transforms[0].data_array) * scale(
            (160, 160, 160))
    else:
        transform = transform_by_id(seg, mesh.transform_id)
    transform.transform_points(va, in_place=True)
    transform.transform_normals(na, in_place=True)

    tri = []
    for p in mesh.polygons:
        #        print ('poly', len(p.vertex_ids), p.vertex_ids[:6])
        t = tuple(vid // 2 for vid in p.vertices if vid % 2 == 0)
        if len(t) != 3:
            raise ValueError(
                'Require polygons to be single triangles, got polygon with %d vertices'
                % len(t))
        tri.append(t)
        '''
        last_vid = None
        for vid in p.vertex_ids:
            if vid % 2 == 0:
                if last_vid is not None:
#                    tri.append((vid//2,last_vid//2))
                    tri.append((vid//2,last_vid//2,vid//2))
                last_vid = vid
        first_vid = p.vertex_ids[0]
        tri.append((last_vid//2,first_vid//2,last_vid//2))
        '''
    from numpy import array, int32
    ta = array(tri, int32)

    return va, na, ta
Esempio n. 5
0
def ses_surface_geometry(xyz,
                         radii,
                         probe_radius=1.4,
                         grid_spacing=0.5,
                         sas=False):
    '''
    Calculate a solvent excluded molecular surface using a distance grid
    contouring method.  Vertex, normal and triangle arrays are returned.
    If sas is true then the solvent accessible surface is returned instead.
    '''

    # Compute bounding box for atoms
    xyz_min, xyz_max = xyz.min(axis=0), xyz.max(axis=0)
    pad = 2 * probe_radius + radii.max() + grid_spacing
    origin = [x - pad for x in xyz_min]

    # Create 3d grid for computing distance map
    from math import ceil
    s = grid_spacing
    shape = [
        int(ceil((xyz_max[a] - xyz_min[a] + 2 * pad) / s)) for a in (2, 1, 0)
    ]
    #    print('ses surface grid size', shape, 'spheres', len(xyz))
    from numpy import empty, float32, sqrt
    try:
        matrix = empty(shape, float32)
    except (MemoryError, ValueError):
        raise MemoryError(
            'Surface calculation out of memory trying to allocate a grid %d x %d x %d '
            % (shape[2], shape[1], shape[0]) +
            'to cover xyz bounds %.3g,%.3g,%.3g ' % tuple(xyz_min) +
            'to %.3g,%.3g,%.3g ' % tuple(xyz_max) +
            'with grid size %.3g' % grid_spacing)

    max_index_range = 2
    matrix[:, :, :] = max_index_range

    # Transform centers and radii to grid index coordinates
    from chimerax.geometry import Place
    xyz_to_ijk_tf = Place(
        ((1.0 / s, 0, 0, -origin[0] / s), (0, 1.0 / s, 0, -origin[1] / s),
         (0, 0, 1.0 / s, -origin[2] / s)))
    from numpy import float32
    ijk = xyz.astype(float32)
    xyz_to_ijk_tf.transform_points(ijk, in_place=True)
    ri = radii.astype(float32)
    ri += probe_radius
    ri /= s

    # Compute distance map from surface of spheres, positive outside.
    from chimerax.map import sphere_surface_distance
    sphere_surface_distance(ijk, ri, max_index_range, matrix)

    # Get the SAS surface as a contour surface of the distance map
    from chimerax.map import contour_surface
    level = 0
    sas_va, sas_ta, sas_na = contour_surface(matrix,
                                             level,
                                             cap_faces=False,
                                             calculate_normals=True)
    if sas:
        xyz_to_ijk_tf.inverse().transform_points(sas_va, in_place=True)
        return sas_va, sas_na, sas_ta

    # Compute SES surface distance map using SAS surface vertex
    # points as probe sphere centers.
    matrix[:, :, :] = max_index_range
    rp = empty((len(sas_va), ), float32)
    rp[:] = float(probe_radius) / s
    sphere_surface_distance(sas_va, rp, max_index_range, matrix)
    ses_va, ses_ta, ses_na = contour_surface(matrix,
                                             level,
                                             cap_faces=False,
                                             calculate_normals=True)

    # Transform surface from grid index coordinates to atom coordinates
    xyz_to_ijk_tf.inverse().transform_points(ses_va, in_place=True)

    # Delete connected components more than 1.5 probe radius from atom spheres.
    kvi = []
    kti = []
    from ._surface import connected_pieces
    vtilist = connected_pieces(ses_ta)
    for vi, ti in vtilist:
        v0 = ses_va[vi[0], :]
        d = xyz - v0
        d2 = (d * d).sum(axis=1)
        adist = (sqrt(d2) - radii).min()
        if adist < 1.5 * probe_radius:
            kvi.append(vi)
            kti.append(ti)
    from .split import reduce_geometry
    from numpy import concatenate
    keepv = concatenate(kvi) if kvi else []
    keept = concatenate(kti) if kti else []
    va, na, ta = reduce_geometry(ses_va, ses_na, ses_ta, keepv, keept)

    return va, na, ta
Esempio n. 6
0
def draw_slab(nd, residue, name, params):
    shapes = []
    standard = standard_bases[name]
    ring_atom_names = standard["ring atom names"]
    atoms = get_ring(residue, ring_atom_names)
    if not atoms:
        return shapes
    plane = Plane([a.coord for a in atoms])
    info = find_dimensions(params.dimensions)
    tag = standard['tag']
    slab_corners = info[tag]
    origin = residue.find_atom(anchor(info[ANCHOR], tag)).coord
    origin = plane.nearest(origin)

    pts = [plane.nearest(a.coord) for a in atoms[0:2]]
    y_axis = pts[0] - pts[1]
    normalize_vector(y_axis)
    x_axis = numpy.cross(y_axis, plane.normal)
    xf = Place(matrix=((x_axis[0], y_axis[0], plane.normal[0], origin[0]),
                       (x_axis[1], y_axis[1], plane.normal[1], origin[1]),
                       (x_axis[2], y_axis[2], plane.normal[2], origin[2])))
    xf = xf * standard["correction factor"]

    color = residue.ring_color
    half_thickness = params.thickness / 2

    llx, lly = slab_corners[0]
    llz = -half_thickness
    urx, ury = slab_corners[1]
    urz = half_thickness
    center = (llx + urx) / 2, (lly + ury) / 2, 0
    if params.shape == 'box':
        llb = (llx, lly, llz)
        urf = (urx, ury, urz)
        xf2 = xf
        va, na, ta = box_geometry(llb, urf)
        pure_rotation = True
    elif params.shape == 'muffler':
        radius = (urx - llx) / 2 * _SQRT2
        xf2 = xf * translation(center)
        xf2 = xf2 * scale((1, 1, half_thickness * _SQRT2 / radius))
        height = ury - lly
        va, na, ta = get_cylinder(radius, numpy.array((0, -height / 2, 0)),
                                  numpy.array((0, height / 2, 0)))
        pure_rotation = False
    elif params.shape == 'ellipsoid':
        # need to reach anchor atom
        xf2 = xf * translation(center)
        sr = (ury - lly) / 2 * _SQRT3
        xf2 = xf2 * scale(
            ((urx - llx) / 2 * _SQRT3 / sr, 1, half_thickness * _SQRT3 / sr))
        va, na, ta = get_sphere(sr, (0, 0, 0))
        pure_rotation = False
    else:
        raise RuntimeError('unknown base shape')

    description = '%s %s' % (residue, tag)
    xf2.transform_points(va, in_place=True)
    xf2.transform_normals(na, in_place=True, is_rotation=pure_rotation)
    shapes.append(AtomicShapeInfo(va, na, ta, color, atoms, description))

    if not params.orient:
        return shapes

    # show slab orientation by putting "bumps" on surface
    if tag == PYRIMIDINE:
        center = (llx + urx) / 2.0, (lly + ury) / 2, half_thickness
        va, na, ta = get_sphere(half_thickness, center)
        xf.transform_points(va, in_place=True)
        xf.transform_normals(na, in_place=True, is_rotation=True)
        shapes.append(AtomicShapeInfo(va, na, ta, color, atoms, description))
    else:
        # purine
        center = (llx + urx) / 2.0, lly + (ury - lly) / 3, half_thickness
        va, na, ta = get_sphere(half_thickness, center)
        xf.transform_points(va, in_place=True)
        xf.transform_normals(na, in_place=True, is_rotation=True)
        shapes.append(AtomicShapeInfo(va, na, ta, color, atoms, description))
        center = (llx + urx) / 2.0, lly + (ury - lly) * 2 / 3, half_thickness
        va, na, ta = get_sphere(half_thickness, center)
        xf.transform_points(va, in_place=True)
        xf.transform_normals(na, in_place=True, is_rotation=True)
        shapes.append(AtomicShapeInfo(va, na, ta, color, atoms, description))
    return shapes