예제 #1
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
예제 #2
0
 def scale_command(self, tokens):
     if len(tokens) not in (2, 3, 4):
         raise ValueError("Expected 'x [y [z]]' after %s" % tokens[0])
     data = [self.parse_float(x) for x in tokens[1:]]
     if len(data) == 1:
         data.extend([data[0], data[0]])
     elif len(data) == 2:
         data.append(data[0])
     xform = scale(data)
     self.transforms.append(self.transforms[-1] * xform)
     self.pure.append(False)
예제 #3
0
def surface_projection_coordinates(surfaces, projection_axis, volume):

    g = volume.data

    # Scale rotated surface coordinates to grid index units.
    axis_aligned = (tuple(projection_axis) in ((1, 0, 0), (0, 1, 0), (0, 0, 1))
                    and tuple(g.cell_angles) == (90, 90, 90)
                    and g.rotation == ((1, 0, 0), (0, 1, 0), (0, 0, 1)))
    if axis_aligned:
        grid_spacing = g.step
    else:
        s = min(g.plane_spacings())
        grid_spacing = (s, s, s)

    # Determine transform from vertex coordinates to depth array indices
    # Rotate projection axis to z.
    from chimerax.geometry import orthonormal_frame, scale, translation
    tfrs = orthonormal_frame(projection_axis).inverse() * scale(
        [1 / s for s in grid_spacing])

    # Transform vertices to depth array coordinates.
    zsurf = []
    tcount = 0
    for vertices, triangles in surfaces:
        varray = tfrs.transform_points(vertices)
        zsurf.append((varray, triangles))
        tcount += len(triangles)
    if tcount == 0:
        return None

    # Compute origin for depth grid
    vmin, vmax = bounding_box(zsurf)
    if axis_aligned:
        o = tfrs * g.origin
        offset = [(vmin[a] - o[a]) for a in (0, 1, 2)]
        from math import floor
        align_frac = [offset[a] - floor(offset[a]) for a in (0, 1, 2)]
        vmin -= align_frac
    else:
        vmin -= 0.5

    tf = translation(-vmin) * tfrs

    # Shift surface vertices by depth grid origin
    for varray, triangles in zsurf:
        varray -= vmin

    # Compute size of depth grid
    from math import ceil
    size = tuple(int(ceil(vmax[a] - vmin[a] + 1)) for a in (0, 1))

    return zsurf, size, tf
예제 #4
0
def arrow_along_force_vector(arrow, xyz0, force, scale=1.0):
    '''
    Takes an arrow drawn by simple_arrow and rotates, translates and scales
    it to point from xyz0 along a force vector, with length scaled according
    to the magnitude of the force.
    '''
    from chimerax.geometry.place import translation, vector_rotation, scale, Place, product
    import numpy

    # Original arrow points along the z axis
    u = numpy.array((0, 0, 1), dtype='float32')
    # Get vector length
    l = numpy.linalg.norm(force)
    rot = vector_rotation(u, force / l)
    trans = translation(xyz0)
    sc = scale(l)
    arrow.position = product((trans, rot, sc))
예제 #5
0
def arrow_between_points(arrow, xyz0, xyz1):
    '''
    Takes an arrow drawn by simple_arrow and rotates, translates and scales
    it to point from xyz0 to xyz1 (or vice versa, if it's an inward-pointing
    arrow). In either case the arrow will have one end on xyz0. The other end
    will be on xyz1 if the height of the original arrow was 1 unit.
    '''
    from chimerax.geometry.place import translation, vector_rotation, scale, Place, product
    import numpy

    # Original arrow points along the z axis
    u = numpy.array((0, 0, 1), dtype='float32')
    # Get vector from xyz0 to xyz1
    v = xyz1 - xyz0
    # Get vector length
    l = numpy.linalg.norm(v)
    rot = vector_rotation(u, v / l)
    trans = translation(xyz0)
    sc = scale(l)
    arrow.position = product((trans, rot, sc))
예제 #6
0
def exclamation_mark(radius=0.1, height=2, nc=8, color=[255, 0, 0, 255]):
    '''
    An exclamation mark for annotating rotamer outliers
    '''
    from chimerax.surface.shapes import cone_geometry, sphere_geometry2
    from chimerax.geometry import translation, scale
    import numpy
    stem = cone_geometry(radius=radius, height=height, nc=nc, caps=True)
    spheres = list(sphere_geometry2(nc * 4))
    spheres[0] = scale(radius * 0.7).transform_points(spheres[0])

    v, n, t = stem

    vbottom = translation(
        (0, 0, height / 2 + radius * 1.5)).transform_points(spheres[0])
    t = numpy.concatenate((t, spheres[2] + len(v)))
    v = numpy.concatenate((v, vbottom))
    n = numpy.concatenate((n, spheres[1]))

    return v, n, t
예제 #7
0
def transform_by_id(seg, tf_id):
    from chimerax.geometry import Place, scale
    for tf in seg.transforms:
        if tf.id == tf_id:
            return scale((160, 160, 160)) * Place(tf.data_array)
    return Place()
예제 #8
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
예제 #9
0
 def _head_position(self, vr_camera):
     from chimerax.geometry import scale
     return _place_matrix(vr_camera.room_position *
                          scale(1 / vr_camera.scene_scale))
예제 #10
0
def imod_models(session, chunk_list, name, mesh, contours):

    # Get coordinate transform before mesh and contour chunks
    tf = None

    use_minx = False
    if use_minx:
        for c in chunk_list:
            if c['id'] == b'MINX':
                # MINX chunk comes after mesh and contours.
                print('MINX cscale', c['cscale'], 'ctrans', c['ctrans'],
                      'otrans', c['otrans'], 'crot', c['crot'])
                #                t = [xo-xc for xo,xc in zip(c['otrans'], c['ctrans'])]
                t = [-xc for xc in c['ctrans']]
                rx, ry, rz = c['crot']
                rx = ry = rz = 0
                from chimerax.geometry import rotation, translation, scale
                tf = (rotation((0, 0, 1), rz) * rotation(
                    (0, 1, 0), ry) * rotation(
                        (1, 0, 0), rx) * translation(t) * scale(c['cscale']))

    surfaces = []
    msets = []
    pixel_size = None
    for c in chunk_list:
        cid = c['id']
        if cid == b'IMOD':
            xyz_scale = c['xscale'], c['yscale'], c['zscale']
            pixel_size = c['pixsize']
            units = c['units']
            # Units: 0 = pixels, 3 = km, 1 = m, -2 = cm, -3 = mm,
            #        -6 = microns, -9 = nm, -10 = Angstroms, -12 = pm
            #            print ('IMOD pixel size =', pixel_size, 'units', units, ' scale', xyz_scale)
            #            print 'IMOD flags', bin(c['flags'])
            u = -10 if units == 0 else (0 if units == 1 else units)
            import math
            pixel_size_angstroms = pixel_size * math.pow(10, 10 + u)
            if tf is None:
                xs, ys, zs = [s * pixel_size_angstroms for s in xyz_scale]
                from chimerax.geometry import scale
                tf = scale((xs, ys, zs))
        elif cid == b'OBJT':
            alpha = 1.0 - 0.01 * c['trans']
            object_rgba = (c['red'], c['green'], c['blue'], alpha)
            obj_name = c['name'].decode('ascii')
            pds = c['pdrawsize']
            radius = pds * pixel_size_angstroms if pds > 0 else pixel_size_angstroms
            fill = c['flags'] & (1 << 8)
            lines = not (c['flags'] & (1 << 11))
            only_points = (not lines and not fill)
            link = not only_points
            open_contours = c['flags'] & (1 << 3)
            mset = None
        elif cid == b'MESH':
            if mesh:
                surf = create_mesh(session, c, tf, object_rgba, obj_name)
                surfaces.append(surf)
        elif cid == b'CONT':
            if contours:
                if mset is None:
                    from chimerax.markers import MarkerSet
                    mname = '%s %s contours' % (name, obj_name)
                    mset = MarkerSet(session, mname)
                    msets.append(mset)
                create_contour(c, tf, radius, object_rgba, link, open_contours,
                               mset)

    return surfaces, msets, pixel_size
예제 #11
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