Ejemplo n.º 1
0
def segment_surface(v, sindex, descrip, color):
    from chimerax.core.models import Surface
    s = Surface('segment %d %s' % (sindex, descrip), v.session)
    va, na, ta = segment_surface_geometry(v, sindex)
    s.set_geometry(va, na, ta)
    s.color = segment_color(color)
    return s
Ejemplo n.º 2
0
def _transform_schematic(session, transform, center, from_rgba, to_rgba,
                         length, width, thickness):

    axis, rot_center, angle_deg, shift = transform.axis_center_angle_shift()

    # Align rot_center at same position along axis as center.
    from chimerax.geometry import inner_product
    rot_center += inner_product(center - rot_center, axis) * axis
    width_axis = center - rot_center
    varray, narray, tarray = _axis_square(axis, rot_center, width_axis, length,
                                          width, thickness)

    from chimerax.core.models import Model, Surface

    s1 = Surface('slab 1', session)
    s1.set_geometry(varray, narray, tarray)
    s1.color = from_rgba

    s2 = Surface('slab 2', session)
    from chimerax.geometry import rotation, translation
    rot2 = translation(shift * axis) * rotation(
        axis, angle_deg, center=rot_center)
    varray2 = rot2 * varray
    narray2 = rot2.transform_vectors(narray)
    s2.set_geometry(varray2, narray2, tarray)
    s2.color = to_rgba

    m = Model('transform schematic', session)
    m.add([s1, s2])

    return m
Ejemplo n.º 3
0
def surfaces_from_nodes(nodes, color, place, instances, session):

    from collada.scene import GeometryNode, Node
    from chimerax.geometry import Place
    from chimerax.core.models import Surface
    splist = []
    for n in nodes:
        if isinstance(n, GeometryNode):
            materials = dict((m.symbol, m.target) for m in n.materials)
            g = n.geometry
            colors = g.sourceById
            if g.id in instances:
                add_geometry_instance(g.primitives, instances[g.id], place,
                                      color, materials)
            else:
                instances[g.id] = spieces = geometry_node_surfaces(
                    g.primitives, place, color, materials, colors, session)
                splist.extend(spieces)
        elif isinstance(n, Node):
            pl = place * Place(n.matrix[:3, :])
            spieces = surfaces_from_nodes(n.children, color, pl, instances,
                                          session)
            name = n.xmlnode.get('name')
            if len(spieces) > 1:
                m = Surface(name, session)
                m.add(spieces)
                splist.append(m)
            elif len(spieces) == 1:
                s = spieces[0]
                s.name = name
                splist.append(s)
    return splist
Ejemplo n.º 4
0
 def update_selection(self, *, fire_trigger=True):
     asel = self.atoms.selected
     tmask = self._atom_triangle_mask(asel)
     if tmask is None:
         sel_val = False
     else:
         sel_val = (tmask.sum() > 0)
     Surface.set_selected(self, sel_val, fire_trigger=fire_trigger)
     self.highlighted_triangles_mask = tmask
Ejemplo n.º 5
0
def spherical_surface(
    session,
    radius_function,
    move=None,  # a Place instance to rotate and translate surface
    theta_steps=100,
    phi_steps=50,
    positive_color=(255, 100, 100, 255),  # red, green, blue, alpha, 0-255 
    negative_color=(100, 100, 255, 255)):

    # Compute vertices and vertex colors
    vertices = []
    colors = []
    for t in range(theta_steps):
        theta = (t / theta_steps) * 2 * pi
        ct, st = cos(theta), sin(theta)
        for p in range(phi_steps):
            phi = (p / (phi_steps - 1)) * pi
            cp, sp = cos(phi), sin(phi)
            r = radius_function(theta, phi)
            xyz = (r * sp * ct, r * sp * st, r * cp)
            vertices.append(xyz)
            color = positive_color if r >= 0 else negative_color
            colors.append(color)

    # Compute triangles, triples of vertex indices
    triangles = []
    for t in range(theta_steps):
        for p in range(phi_steps - 1):
            i = t * phi_steps + p
            t1 = (t + 1) % theta_steps
            i1 = t1 * phi_steps + p
            triangles.append((i, i + 1, i1 + 1))
            triangles.append((i, i1 + 1, i1))

    # Create numpy arrays
    from numpy import array, float32, uint8, int32
    va = array(vertices, float32)
    ca = array(colors, uint8)
    ta = array(triangles, int32)

    # Rotate and translate vertices to a new location.
    if move is not None:
        move.transform_points(va, in_place=True)

    # Compute average vertex normal vectors
    from chimerax.surface import calculate_vertex_normals
    na = calculate_vertex_normals(va, ta)

    # Create ChimeraX surface model
    from chimerax.core.models import Surface
    s = Surface('surface', session)
    s.set_geometry(va, na, ta)
    s.vertex_colors = ca
    session.models.add([s])

    return s
Ejemplo n.º 6
0
def triangles_model(session,
                    points,
                    triangles,
                    name='vtk polygons',
                    color=(180, 180, 180, 255)):
    from chimerax.core.models import Surface
    m = Surface(name, session)
    from chimerax import surface
    normals = surface.calculate_vertex_normals(points, triangles)
    m.set_geometry(points, normals, triangles)
    m.color = color
    return m
Ejemplo n.º 7
0
def new_cap(drawing, cap_name):
    from chimerax.core.models import Model, Surface
    if isinstance(drawing, Model):
        # Make cap a model when capping a model so color can be set by command.
        c = Surface(cap_name, drawing.session)
        c.display_style = drawing.display_style
        c.SESSION_SAVE = False
        drawing.add([c])
    else:
        # Cap is on a Drawing that is not a Model
        c = drawing.new_drawing(cap_name)
    c.is_clip_cap = True
    return c
Ejemplo n.º 8
0
def _cage_surface(session, name, replace):
    # Make new surface model or find an existing one.
    sm = None
    from chimerax.core.models import Surface
    if replace:
        mlist = [m for m in session.models.list(type=Surface)
                 if hasattr(m, 'hkcage')]
        if mlist:
            sm = mlist[0]
            sm.name = name
    if sm is None:
        sm = Surface(name, session)
    sm.hkcage = True
    return sm
Ejemplo n.º 9
0
 def restore_snapshot(session, data):
     d = data
     s = MolecularSurface(session, d['atoms'], d['show_atoms'],
                          d['probe_radius'], d['grid_spacing'],
                          d['resolution'], d['level'], d['name'],
                          d['color'], d['visible_patches'],
                          d['sharp_boundaries'])
     Surface.set_state_from_snapshot(s, session, d['model state'])
     geom_attrs = ('vertices', 'normals', 'triangles')
     s.set_geometry(d['vertices'], d['normals'], d['triangles'])
     for attr in MolecularSurface._save_attrs:
         if attr in d and attr not in geom_attrs:
             setattr(s, attr, d[attr])
     return s
Ejemplo n.º 10
0
def ellipsoid_surface(axes, lengths, center, color, surface, submodel_name = None,
                      num_triangles = 1000):

  xf = surface.position.inverse()
  sa, sc = transform_ellipsoid(axes, center, xf)
  varray, narray, tarray = ellipsoid_geometry(sc, sa, lengths, num_triangles = num_triangles)
  if submodel_name is None:
      s = surface
  else:
      from chimerax.core.models import Surface
      s = Surface(submodel_name, surface.session)
      surface.add([s])
  s.set_geometry(varray, narray, tarray)
  s.color = color
  return s
Ejemplo n.º 11
0
def _surface_model(name, place, model_id, replace, session):

    from chimerax.core.models import Surface
    if not model_id is None:
        slist = session.models.list(model_id = model_id, type = Surface)
        if slist:
            s = slist[0]
            if replace:
                session.models.close([s])
            else:
                return s

    s = Surface(name, session)
    s.id = model_id
    s.position = place
    session.models.add([s])
    return s
Ejemplo n.º 12
0
def load_surface(session,
                 tensor_file,
                 sc=2.09,
                 theta_steps=100,
                 phi_steps=50,
                 positive_color=(255, 100, 100, 255),
                 negative_color=(100, 100, 255, 255),
                 marker_pos_color=(100, 255, 100, 255),
                 marker_neg_color=(255, 255, 100, 255)):

    Delta, Eta, Euler, Pos, Marker = load_tensor(tensor_file)

    from chimerax.core.models import Surface
    from chimerax.surface import calculate_vertex_normals, combine_geometry_vntc

    geom = list()

    for k, (delta, eta, euler, pos,
            marker) in enumerate(zip(Delta, Eta, Euler, Pos, Marker)):
        if marker == 1:
            pc = marker_pos_color
            nc = marker_neg_color
        else:
            pc = positive_color
            nc = negative_color
        xyz,tri,colors=spherical_surface(\
                                         delta=delta,eta=eta,euler=euler,pos=pos,\
                                         sc=sc,theta_steps=theta_steps,\
                                         phi_steps=phi_steps,\
                                         positive_color=pc,\
                                         negative_color=nc)

        norm_vecs = calculate_vertex_normals(xyz, tri)

        geom.append((xyz, norm_vecs, tri, colors))

    xyz, norm_vecs, tri, colors = combine_geometry_vntc(geom)
    s = Surface('surface', session)
    s.set_geometry(xyz, norm_vecs, tri)
    s.vertex_colors = colors
    session.models.add([s])

    return s
Ejemplo n.º 13
0
def mesh_models(session, seg):
    surfs = []
    from chimerax.core.models import Surface
    from chimerax.surface import combine_geometry_vnt
    for segment in seg.segments:
        if segment.mesh_list is None:
            continue
        geoms = [mesh_geometry(mesh, seg) for mesh in segment.mesh_list]
        if len(geoms) == 0:
            continue
        va, na, ta = combine_geometry_vnt(geoms)
        s = Surface('mesh %d' % segment.id, session)
        s.set_geometry(va, na, ta)
        #        s.display_style = s.Mesh
        #        s.use_lighting = False
        s.color = segment_color(segment.colour)

        surfs.append(s)
    return surfs
Ejemplo n.º 14
0
 def take_snapshot(self, session, flags):
     init_attrs = ('atoms', 'show_atoms', 'probe_radius', 'grid_spacing',
                   'resolution', 'level', 'name', 'color',
                   'visible_patches', 'sharp_boundaries')
     data = {attr: getattr(self, attr) for attr in init_attrs}
     data['model state'] = Surface.take_snapshot(self, session, flags)
     data.update({
         attr: getattr(self, attr)
         for attr in self._save_attrs if hasattr(self, attr)
     })
     data['version'] = MOLSURF_STATE_VERSION
     return data
Ejemplo n.º 15
0
    def __init__(self,
                 session,
                 enclose_atoms,
                 show_atoms,
                 probe_radius,
                 grid_spacing,
                 resolution,
                 level,
                 name,
                 color,
                 visible_patches,
                 sharp_boundaries,
                 update=True):

        Surface.__init__(self, name, session)
        self.selection_coupled = enclose_atoms.unique_structures

        self.atoms = enclose_atoms
        self._atom_count = len(
            self.atoms)  # Used to determine when atoms deleted.
        self.show_atoms = show_atoms  # Atoms for surface patch to show
        self.probe_radius = probe_radius  # Only used for solvent excluded surface
        self.grid_spacing = grid_spacing
        self.resolution = resolution  # Only used for Gaussian surface
        self.level = level  # Contour level for Gaussian surface, atomic number units
        self.color = color
        self._atom_patch_colors = None
        self._atom_patch_color_mask = None
        self.visible_patches = visible_patches
        self.sharp_boundaries = sharp_boundaries
        self._joined_triangles = None
        self._refinement_steps = 1  # Used for fixing sharp edge problems near 3 atom junctions.

        self._auto_update_handler = None
        self.auto_update = update

        self._vertex_to_atom = None
        self._vertex_to_atom_count = None  # Used to check if atoms deleted
        self._max_radius = None
        self.clip_cap = True
Ejemplo n.º 16
0
def _surface_model(session, model_id, shape_name, position = None):

    s = None if model_id is None else _find_surface_model(session, model_id)
    if s is None:
        from chimerax.core.models import Surface
        s = Surface(shape_name, session)
        if model_id is not None:
            s.id = model_id
        if position is not None:
            s.position = position
        s.SESSION_SAVE_DRAWING = True
        s.clip_cap = True			# Cap surface when clipped
    return s
Ejemplo n.º 17
0
def meshes_as_models(session, meshes, buf_arrays):

    mesh_models = []
    ba = buf_arrays
    from numpy import int32
    from chimerax.core.models import Surface
    for m in meshes:
        if 'primitives' not in m:
            raise glTFError('glTF mesh has no "primitives": %s' % str(j))
        pdlist = []
        for pi, p in enumerate(m['primitives']):
            if 'mode' in p and p['mode'] != GLTF_TRIANGLES:
                raise glTFError(
                    'glTF reader only handles triangles, got mode %d' %
                    p['mode'])
            if 'indices' not in p:
                raise glTFError('glTF missing "indices" in primitive %s' %
                                str(p))
            ta = ba[p['indices']]
            if len(ta.shape) == 1:
                ta = ta.reshape((len(ta) // 3, 3))
            ta = ta.astype(int32, copy=False)
            if 'attributes' not in p:
                raise glTFError('glTF missing "attributes" in primitive %s' %
                                str(p))
            pa = p['attributes']
            if 'POSITION' not in pa:
                raise glTFError(
                    'glTF missing "POSITION" attribute in primitive %s' %
                    str(p))
            va = ba[pa['POSITION']]
            if 'NORMAL' in pa:
                na = ba[pa['NORMAL']]
            else:
                from chimerax import surface
                na = surface.calculate_vertex_normals(va, ta)
            if 'COLOR_0' in pa:
                vc = ba[pa['COLOR_0']]
            else:
                vc = None
            pd = Surface('p%d' % pi, session)
            set_geometry(pd, va, na, vc, ta)
            pdlist.append(pd)
        mesh_models.append(pdlist)

    return mesh_models
Ejemplo n.º 18
0
def geometry_node_surfaces(primitives, place, color, materials, colors,
                           session):

    from collada import polylist, triangleset

    splist = []
    for p in primitives:
        if isinstance(p, polylist.Polylist):
            p = p.triangleset()
        if not isinstance(p, triangleset.TriangleSet):
            continue  # Skip line sets.

        t = p.vertex_index  # N by 3 array of vertex indices for triangles
        t = t.copy()  # array from pycollada is not contiguous.
        v = p.vertex  # M by 3 array of floats for vertex positions
        ni = p.normal_index  # N by 3 array of normal indices for triangles
        n = p.normal  # M by 3 array of floats for vertex normals

        # Collada allows different normals on the same vertex in different triangles,
        # but Hydra only allows one normal per vertex.
        if n is None:
            vn = None
        else:
            from numpy import empty
            vn = empty(v.shape, n.dtype)
            vn[t.ravel(), :] = n[ni.ravel(), :]

        vcolors = vertex_colors(p, t, len(v), colors)
        c = material_color(materials.get(p.material), color)

        name = '%d' % (len(splist) + 1)
        from chimerax.core.models import Surface
        sp = Surface(name, session)
        sp.set_geometry(v, vn, t)
        sp.color_list = [c]
        sp.position_list = [place]
        if not vcolors is None:
            sp.vertex_colors = vcolors
        sp.clip_cap = True

        splist.append(sp)

    return splist
Ejemplo n.º 19
0
def show_hk_lattice(session,
                    h,
                    k,
                    radius,
                    orientation='222',
                    color=(255, 255, 255, 255),
                    sphere_factor=0,
                    edge_radius=None,
                    mesh=False,
                    replace=True):

    varray, tarray, hex_edges = hk_icosahedron_lattice(h, k, radius,
                                                       orientation)
    interpolate_with_sphere(varray, radius, sphere_factor)

    name = 'Icosahedron h = %d, k = %d' % (h, k)

    if mesh:
        model = sm = _cage_surface(session, name, replace)
        sm.set_geometry(varray, None, tarray)
        sm.color = color
        sm.display_style = sm.Mesh
        sm.edge_mask = hex_edges  # Hide spokes of hexagons.
        if sm.id is None:
            session.models.add([sm])
    else:
        # Make cage from markers.
        from chimerax.core.models import Surface
        sm = Surface(name, session)
        sm.set_geometry(varray, None, tarray)
        sm.color = color
        sm.display_style = sm.Mesh
        sm.edge_mask = hex_edges  # Hide spokes of hexagons.
        if edge_radius is None:
            edge_radius = .01 * radius
        mset = _cage_markers(session, name) if replace else None
        from chimerax.markers.cmd import markers_from_mesh
        model = markers_from_mesh(session, [sm],
                                  color=color,
                                  edge_radius=edge_radius,
                                  markers=mset)
        model.name = name
        if mset:
            mset._prev_markers.delete()

    model.hkcage = True

    return model
Ejemplo n.º 20
0
def create_mesh(session, c, transform, rgba, name):

    varray, tarray = mesh_geometry(c)
    if len(tarray) == 0:
        return None

    transform.transform_points(varray, in_place=True)

    from chimerax.core.models import Surface
    s = Surface(name, session)
    s.SESSION_SAVE_DRAWING = True
    s.clip_cap = True  # Cap surface when clipped
    from chimerax.surface import calculate_vertex_normals
    narray = calculate_vertex_normals(varray, tarray)
    s.set_geometry(varray, narray, tarray)
    rgba8 = [int(r * 255) for r in rgba]
    s.color = rgba8

    return s
Ejemplo n.º 21
0
def ellipsoid_mesh(session, name, center, radii, rotation, divisions, color,
                   opacity):
    vertices, edges = lattitude_longtitude_circles(divisions)

    # Stretch, rotate and center
    vertices *= radii
    rotation.transform_points(vertices, in_place=True)
    vertices += center

    # Create ellipsoid model
    from chimerax.core.models import Surface
    s = Surface(name, session)
    normals = None
    s.set_geometry(vertices, normals, edges)
    s.color = [int(255 * r) for r in color + [opacity]]
    s.display_style = s.Mesh
    session.models.add([s])
Ejemplo n.º 22
0
def vbur_vis(
    session,
    geom,
    targets,
    radii,
    scale,
    radius,
    center,
    point_spacing,
    intersection_scale,
    volume_type,
    vbur,
    labels,
    basis=None,
    key_atoms=None,
):
    # from cProfile import Profile
    #
    # profile = Profile()
    # profile.enable()

    # number of points is based on surface area
    n_grid = int(4 * np.pi * radius**2 / point_spacing)
    if volume_type == "buried":
        model = Surface("%%Vbur for %s" % geom.name, session)
    else:
        model = Surface("%%Vfree for %s" % geom.name, session)
    # verts, norms, and triangles for the drawing
    vertices = []
    normals = []
    triangles = []

    if isinstance(center, np.ndarray):
        center_coords = center
    else:
        center_coords = geom.COM(center)

    if isinstance(radii, dict):
        radii_dict = radii
    elif radii.lower() == "umn":
        radii_dict = VDW_RADII
    elif radii.lower() == "bondi":
        radii_dict = BONDI_RADII
    else:
        raise RuntimeError("received %s for radii, must be umn or bondi" %
                           radii)

    if not hasattr(center, "__iter__"):
        center = [center]

    if targets is None:
        if len(center) == 1:
            atoms = [atom for atom in geom.atoms if atom not in center]
        else:
            atoms = geom.atoms
    else:
        atoms = geom.find(targets)

    atoms_within_radius = []
    for atom in atoms:
        # determine which atom's radii extend within the sphere
        # reduces the number of distances we need to calculate
        d = np.linalg.norm(center_coords - atom.coords)
        inner_edge = d - scale * radii_dict[atom.element]
        if inner_edge < radius:
            atoms_within_radius.append(atom)

    # sort atoms based on their distance to the center
    # this makes is so we usually break out of looping over the atoms faster
    atoms_within_radius.sort(
        key=lambda a, c=center_coords: np.linalg.norm(a.coords - c))

    radius_list = []
    for atom in atoms_within_radius:
        radius_list.append(scale * radii_dict[atom.element])

    coords = geom.coordinates(atoms_within_radius)

    atom_dist = distance_matrix(coords, coords)

    sphere = fibonacci_sphere(num=n_grid, radius=radius)

    # add points right where spheres intersect
    # this makes the intersections look less pokey
    d_ac = distance_matrix(coords, [center_coords])
    center_added_points = []
    atom_added_points = [[] for atom in atoms_within_radius]
    for i in range(0, len(coords)):
        r1 = radius_list[i]
        v_n = coords[i] - center_coords
        v_n /= np.linalg.norm(v_n)
        d = d_ac[i, 0]
        # intersection with big sphere
        if d + r1 > radius:
            theta = np.arccos((r1**2 - radius**2 - d**2) / (-2 * d * radius))
            h = radius * np.sin(theta)
            b = radius * np.cos(theta)
            p = b * v_n

            circ = 2 * np.pi * h
            n_added = int(np.ceil(intersection_scale * circ / point_spacing))
            r_t = perp_vector(v_n)

            r0 = np.cross(r_t, v_n)
            r0 *= h / np.linalg.norm(r0)

            rot_angle = 2 * np.pi / n_added
            R = rotation_matrix(rot_angle, v_n)
            prev_r = r0
            prev_r_list = []
            for x in np.linspace(0, 2 * np.pi, num=n_added):
                prev_r = np.dot(R, prev_r)
                prev_r_list.append(prev_r)
            prev_r_list = np.array(prev_r_list)
            d_ep = distance_matrix(prev_r_list + p + center_coords, coords)
            # if the point is obscured by another atom, don't bother adding it
            # this saves time on triangulation
            diff_mat = d_ep - radius_list
            diff_mat[:, i] = 1
            mask = np.invert(np.any(diff_mat < 0, axis=1))
            center_added_points.extend(prev_r_list[mask] + p)
            atom_added_points[i].extend(prev_r_list[mask] + p + center_coords)

        for j in range(0, i):
            d = atom_dist[i, j]
            r2 = radius_list[j]
            if d < r1 + r2 and d > abs(r1 - r2):
                v_n = coords[j] - coords[i]
                v_n /= np.linalg.norm(v_n)
                theta = np.arccos((r2**2 - r1**2 - d**2) / (-2 * r1 * d))
                h = r1 * np.sin(theta)
                b = r1 * np.cos(theta)
                p = b * v_n

                circ = 2 * np.pi * h
                n_added = int(
                    np.ceil(intersection_scale * circ / point_spacing))
                r_t = perp_vector(v_n)

                r0 = np.cross(r_t, v_n)
                r0 *= h / np.linalg.norm(r0)

                rot_angle = 2 * np.pi / n_added
                R = rotation_matrix(rot_angle, v_n)
                prev_r = r0
                prev_r_list = []
                for x in np.linspace(0, 2 * np.pi, num=n_added):
                    prev_r = np.dot(R, prev_r)
                    prev_r_list.append(prev_r)
                prev_r_list = np.array(prev_r_list)
                norm_mask = np.linalg.norm(center_coords -
                                           (prev_r_list + p + coords[i]),
                                           axis=1) < radius
                prev_r_list = prev_r_list[norm_mask]

                if not len(prev_r_list):
                    continue
                d_ep = distance_matrix(prev_r_list + p + coords[i], coords)
                diff_mat = d_ep - radius_list
                diff_mat[:, i] = 1
                diff_mat[:, j] = 1
                mask = np.invert(np.any(diff_mat < 0, axis=1))
                if any(mask):
                    atom_added_points[i].extend(prev_r_list[mask] + p +
                                                coords[i])
                    atom_added_points[j].extend(prev_r_list[mask] + p +
                                                coords[i])

    tol = 0.3 * point_spacing
    for i in range(0, len(coords)):
        # get a grid of points around each atom
        # remove any points that are close to an intersection
        # this makes it less likely for the triangulation to choose
        # one of these points instead of one that we already added
        # then, if we have to remove a triangle involving one of these points later,
        # it won't leave a gap
        n_atom_grid = int(radius_list[i]**2 * n_grid / radius**2)
        atom_sphere = fibonacci_sphere(radius=radius_list[i], num=n_atom_grid)
        mask = np.ones(len(atom_sphere), dtype=bool)
        n_atom_grid = len(atom_sphere)
        if len(atom_added_points[i]) > 0:
            remove_ndx = []
            dist_mat = distance_matrix(
                atom_sphere,
                np.array(atom_added_points[i]) - coords[i])
            mask *= np.any((dist_mat - tol) < 0)

            atom_sphere = atom_sphere[mask]

            atom_sphere = np.array(atom_sphere)
            n_atom_grid = len(atom_sphere)
            atom_sphere = np.concatenate(
                (atom_sphere, np.array(atom_added_points[i]) - coords[i]))

        if len(atom_sphere) < 4:
            continue
        atom_hull = ConvexHull(atom_sphere / radius_list[i])
        tri = atom_hull.simplices

        atom_sphere += coords[i]

        remove_v = []
        new_ndx = np.zeros(len(atom_sphere), dtype=int)

        # remove any points that are covered by another atom
        # only loop over n_atom_grid points so we don't remove
        # any points right on the intersection b/c of
        # numerical issues
        del_count = 0
        atom_grid_dist = distance_matrix(atom_sphere, coords)
        center_atom_grid_dist = distance_matrix(atom_sphere,
                                                [center_coords])[:, 0]
        for j in range(0, n_atom_grid):
            if center_atom_grid_dist[j] > radius:
                remove_v.append(j)
                del_count += 1
                continue
            for k in range(0, len(coords)):
                if i == k:
                    continue
                if atom_grid_dist[j, k] < radius_list[k]:
                    remove_v.append(j)
                    del_count += 1
                    break

            new_ndx[j] = j - del_count

        for j in range(n_atom_grid, len(atom_sphere)):
            new_ndx[j] = j - del_count

        if len(remove_v) == len(atom_sphere):
            continue

        atom_sphere = atom_sphere.tolist()
        for vi in remove_v[::-1]:
            atom_sphere.pop(vi)
            tri = tri[np.all(tri != vi, axis=1)]

        for j, ti in enumerate(tri):
            for k, v in enumerate(ti):
                tri[j][k] = new_ndx[v]

        atom_sphere = np.array(atom_sphere)
        norms = -(atom_sphere - coords[i]) / radius_list[i]

        triangles.extend(tri + len(vertices))
        vertices.extend(atom_sphere)
        normals.extend(norms)

    remove_ndx = []
    if len(center_added_points) > 0:
        dist_mat = distance_matrix(sphere, center_added_points)
        for i in range(0, len(sphere)):
            for j in range(0, len(center_added_points)):
                if dist_mat[i, j] < tol:
                    remove_ndx.append(i)
                    break

        sphere = sphere.tolist()
        for ndx in remove_ndx[::-1]:
            sphere.pop(ndx)

        sphere = np.array(sphere)

    n_sphere = len(sphere)
    if center_added_points:
        sphere = np.concatenate((sphere, np.array(center_added_points)))

    center_hull = ConvexHull(sphere / radius)
    sphere += center_coords
    tri = center_hull.simplices

    remove_v = []
    new_ndx = np.zeros(len(sphere), dtype=int)
    del_count = 0
    center_grid_dist = distance_matrix(sphere, coords)
    for i in range(0, n_sphere):
        if volume_type == "free":
            for j in range(0, len(coords)):
                if center_grid_dist[i, j] < radius_list[j]:
                    remove_v.append(i)
                    del_count += 1
                    break

        elif volume_type == "buried":
            if all(center_grid_dist[i, j] > radius_list[j]
                   for j in range(0, len(coords))):
                remove_v.append(i)
                del_count += 1

        new_ndx[i] = i - del_count

    for i in range(n_sphere, len(sphere)):
        new_ndx[i] = i - del_count

    sphere = sphere.tolist()
    mask = np.ones(len(tri), dtype=bool)
    for vi in remove_v[::-1]:
        sphere.pop(vi)
        mask *= np.invert(np.any(tri == vi, axis=1))
    tri = tri[mask]

    new_t = tri
    if volume_type == "buried":
        mask = np.invert(np.all(new_t >= n_sphere, axis=1))
        new_t = new_t[mask]

    new_t = np.array(new_t)

    for i, ti in enumerate(new_t):
        new_t[i] = new_ndx[ti]

    norms = []
    if sphere:
        sphere = np.array(sphere)
        norms = (sphere - center_coords) / radius

    triangles.extend(new_t + len(vertices))
    vertices.extend(sphere)
    normals.extend(norms)

    # the triangles need to be reordered so the points are
    # clockwise (or counterclockwise? i don't remember)
    vertices = np.array(vertices)
    normals = np.array(normals)
    triangles = np.array(triangles)
    v1 = vertices[triangles[:, 1]] - vertices[triangles[:, 0]]
    v2 = vertices[triangles[:, 2]] - vertices[triangles[:, 0]]
    c = np.cross(v1, v2)
    mask = np.sum(c * normals[triangles[:, 0]], axis=1) < 0
    triangles[mask] = triangles[mask, ::-1]

    model.set_geometry(vertices, normals, triangles)

    # profile.disable()
    # from TestManager.stream_holder import StreamHolder
    # import pstats
    # stream = StreamHolder(session)
    # pstats.Stats(profile, stream=stream).strip_dirs().sort_stats(-1).print_stats()
    # stream.flush()

    if labels != "none":
        d = model.new_drawing("octants")
        d.display_style = d.Mesh
        d.use_lighting = False
        d.casts_shadows = False
        d.pickable = False

        d_theta = np.pi / 180
        oct_radius = 1.01 * radius
        verts = [np.zeros(3)]
        triangles = []
        for k, v in enumerate(basis.T):
            if labels == "quadrants" and k == 2:
                continue

            start_ndx = len(verts)
            prev_vert = oct_radius * perp_vector(v)
            verts.append(prev_vert)
            R = rotation_matrix(d_theta, v)

            for i in range(1, 360):
                triangles.append([0, start_ndx + i - 1, start_ndx + i])
                prev_vert = np.dot(R, prev_vert)
                verts.append(prev_vert)

            triangles.append([0, start_ndx, start_ndx + i - 1])

            for v2 in basis.T[:k]:
                v3 = np.cross(v, v2)
                v3 /= np.linalg.norm(v3)
                v3 *= oct_radius
                ndx = len(verts)
                verts.append(v)
                verts.append(v3)
                triangles.append([ndx, 0, ndx + 1])
                ndx = len(verts)
                verts.append(v)
                verts.append(-v3)
                triangles.append([ndx, 0, ndx + 1])
                ndx = len(verts)
                verts.append(-v)
                verts.append(-v3)
                triangles.append([ndx, 0, ndx + 1])
                ndx = len(verts)
                verts.append(-v)
                verts.append(v3)
                triangles.append([ndx, 0, ndx + 1])

        norms = np.array(verts) / oct_radius
        verts = np.array(verts) + center_coords
        triangles = np.array(triangles)

        d.set_geometry(verts, norms, triangles)
        d.set_edge_mask(2 * np.ones(len(triangles), dtype=int))

        label_list = []
        x = basis.T[0]
        x = x / np.linalg.norm(x)
        y = basis.T[1]
        y = y / np.linalg.norm(y)
        z = basis.T[2]
        z = z / np.linalg.norm(z)
        if labels == "octants":
            for i, val in enumerate(vbur):
                coordinates = np.zeros(3)

                if any(i == n for n in [1, 2, 5, 6]):
                    coordinates -= x
                else:
                    coordinates += x
                if any(i == n for n in [2, 3, 4, 5]):
                    coordinates -= y
                else:
                    coordinates += y
                if i > 3:
                    coordinates -= z
                else:
                    coordinates += z
                if volume_type == "free":
                    l = "%.1f%%" % (100 / 8 - val)
                else:
                    l = "%.1f%%" % (val)
                coordinates /= np.linalg.norm(coordinates)
                coordinates *= radius
                coordinates += center_coords
                label_list.append(VoidLabel(l, coordinates, session.main_view))
        else:
            quad_vbur = [
                vbur[0] + vbur[7],
                vbur[1] + vbur[6],
                vbur[2] + vbur[5],
                vbur[3] + vbur[4],
            ]
            for i, val in enumerate(quad_vbur):
                coordinates = np.zeros(3)
                if any(i == n for n in [1, 2]):
                    coordinates -= x
                else:
                    coordinates += x
                if any(i == n for n in [2, 3]):
                    coordinates -= y
                else:
                    coordinates += y

                if volume_type == "free":
                    l = "%.1f%%" % (25 - val)
                else:
                    l = "%.1f%%" % (val)
                coordinates /= np.linalg.norm(coordinates)
                coordinates *= radius
                coordinates += center_coords
                label_list.append(VoidLabel(l, coordinates, session.main_view))
        label_object = VoidLabels(session)
        label_object.add_labels(label_list)
        model.add([label_object])
        return [model]

    return [model]
Ejemplo n.º 23
0
def calculate_segmentation_surfaces(seg,
                                    where=None,
                                    each=None,
                                    region='all',
                                    step=None,
                                    color=None):
    # Warn if number of surfaces is large.
    if where is None and each is None:
        max_seg_id = _maximum_segment_id(seg)
        if max_seg_id > 100:
            from chimerax.core.errors import UserError
            raise UserError(
                'Segmentation %s (#%s) has %d segments (> 100).'
                ' To create surface for each segment use "each segment" option.'
                % (seg.name, seg.id_string, max_seg_id))

    # Compute surfaces
    conditions = (where if where else []) + ([each] if each else [])
    group, attribute_name = _which_segments(seg, conditions)
    matrix = seg.matrix(step=step, subregion=region)
    from . import segmentation_surfaces
    surfs = segmentation_surfaces(matrix, group)

    # Transform vertices from index to scene units and compute normals.
    geom = []
    tf = seg.matrix_indices_to_xyz_transform(step=step, subregion=region)
    for region_id, va, ta in surfs:
        tf.transform_points(va, in_place=True)
        from chimerax.surface import calculate_vertex_normals
        na = calculate_vertex_normals(va, ta)
        geom.append((region_id, va, na, ta))

    # Determine surface coloring.
    if color is None:
        attr = None if attribute_name == 'segment' else attribute_name
        colors = _attribute_colors(seg, attr).attribute_rgba

    # Create one or more surface models
    from chimerax.core.models import Surface
    from chimerax.surface import combine_geometry_xvnt
    segsurfs = []
    if each is None and len(geom) > 1:
        # Combine multiple surfaces into one.
        va, na, ta = combine_geometry_xvnt(geom)
        name = '%s %d %ss' % (seg.name, len(geom), attribute_name)
        s = Surface(name, seg.session)
        s.clip_cap = True  # Cap surface when clipped
        s.set_geometry(va, na, ta)
        if color is None:
            color_counts = [(colors[region_id], len(sva))
                            for region_id, sva, sna, sta in geom]
            s.vertex_colors = _vertex_colors(len(va), color_counts)
        else:
            s.color = color
        segsurfs.append(s)
    else:
        # Create multiple surface models
        for region_id, va, na, ta in geom:
            name = '%s %s %d' % (seg.name, attribute_name, region_id)
            s = Surface(name, seg.session)
            s.clip_cap = True  # Cap surface when clipped
            s.set_geometry(va, na, ta)
            s.color = colors[region_id] if color is None else color
            segsurfs.append(s)

    return segsurfs
Ejemplo n.º 24
0
 def take_snapshot(self, session, flags):
     return Surface.save_geometry(self, session, flags)
Ejemplo n.º 25
0
 def __init__(self, session):
     Surface.__init__(self, 'blob outline box', session)
     self.pickable = False
Ejemplo n.º 26
0
def vbur_vis(
    session,
    geom,
    targets,
    radii,
    scale,
    radius,
    center,
    point_spacing,
    intersection_scale,
    volume_type,
):
    # number of points is based on surface area
    n_grid = int(4 * np.pi * radius**2 / point_spacing)
    if volume_type == "buried":
        model = Surface("%%Vbur for %s" % geom.name, session)
    else:
        model = Surface("%%Vfree for %s" % geom.name, session)
    # verts, norms, and triangles for the drawing
    vertices = []
    normals = []
    triangles = []

    if isinstance(center, np.ndarray):
        center_coords = center
    else:
        center_coords = geom.COM(center)

    if isinstance(radii, dict):
        radii_dict = radii
    elif radii.lower() == "umn":
        radii_dict = VDW_RADII
    elif radii.lower() == "bondi":
        radii_dict = BONDI_RADII
    else:
        raise RuntimeError("received %s for radii, must be umn or bondi" %
                           radii)

    if not hasattr(center, "__iter__"):
        center = [center]

    if targets is None:
        if len(center) == 1:
            atoms = [atom for atom in geom.atoms if atom not in center]
        else:
            atoms = geom.atoms
    else:
        atoms = geom.find(targets)

    atoms_within_radius = []
    for atom in atoms:
        # determine which atom's radii extend within the sphere
        # reduces the number of distances we need to calculate
        d = np.linalg.norm(center_coords - atom.coords)
        inner_edge = d - scale * radii_dict[atom.element]
        outer_edge = inner_edge + 2 * scale * radii_dict[atom.element]
        if inner_edge < radius:
            atoms_within_radius.append(atom)

    # sort atoms based on their distance to the center
    # this makes is so we usually break out of looping over the atoms faster
    atoms_within_radius.sort(
        key=lambda a, c=center_coords: np.linalg.norm(a.coords - c))

    radius_list = []
    for atom in atoms_within_radius:
        radius_list.append(scale * radii_dict[atom.element])

    coords = geom.coordinates(atoms_within_radius)

    atom_dist = distance_matrix(coords, coords)

    sphere = fibonacci_sphere(num=n_grid, radius=radius)

    # add points right where spheres intersect
    # this makes the intersections look less pokey
    d_ac = distance_matrix(coords, [center_coords])
    center_added_points = []
    atom_added_points = [[] for atom in atoms_within_radius]
    for i in range(0, len(coords)):
        r1 = radius_list[i]
        v_n = coords[i] - center_coords
        v_n /= np.linalg.norm(v_n)
        d = d_ac[i, 0]
        # intersection with big sphere
        if d + r1 > radius:
            theta = np.arccos((r1**2 - radius**2 - d**2) / (-2 * d * radius))
            h = radius * np.sin(theta)
            b = radius * np.cos(theta)
            p = b * v_n

            circ = 2 * np.pi * h
            n_added = int(np.ceil(intersection_scale * circ / point_spacing))
            r_t = np.zeros(3)
            for j in range(0, 3):
                if v_n[j] != 0:
                    if j == 0:
                        r_t[1] = v_n[j]
                        r_t[0] = v_n[1]
                    else:
                        r_t[0] = v_n[j]
                        r_t[1] = v_n[0]
                    break

            r0 = np.cross(r_t, v_n)
            r0 *= h / np.linalg.norm(r0)

            rot_angle = 2 * np.pi / n_added
            R = rotation_matrix(rot_angle, v_n)
            prev_r = r0
            for x in np.linspace(0, 2 * np.pi, num=n_added):
                prev_r = np.dot(R, prev_r)
                d_ep = distance_matrix(coords, [prev_r + p + center_coords])
                # if the point is obscured by another atom, don't bother adding it
                # this saves time on triangulation
                for j in range(0, len(coords)):
                    if i == j:
                        continue
                    if d_ep[j, 0] <= radius_list[j]:
                        break
                else:
                    center_added_points.append(prev_r + p)
                    atom_added_points[i].append(prev_r + p + center_coords)

        for j in range(0, i):
            d = atom_dist[i, j]
            r2 = radius_list[j]
            if d < r1 + r2 and d > abs(r1 - r2):
                v_n = coords[j] - coords[i]
                v_n /= np.linalg.norm(v_n)
                theta = np.arccos((r2**2 - r1**2 - d**2) / (-2 * r1 * d))
                h = r1 * np.sin(theta)
                b = r1 * np.cos(theta)
                p = b * v_n

                circ = 2 * np.pi * h
                n_added = int(
                    np.ceil(intersection_scale * circ / point_spacing))
                r_t = np.zeros(3)
                for k in range(0, 3):
                    if v_n[k] != 0:
                        if k == 0:
                            r_t[1] = v_n[k]
                            r_t[0] = v_n[1]
                        else:
                            r_t[0] = v_n[k]
                            r_t[1] = v_n[0]
                        break

                r0 = np.cross(r_t, v_n)
                r0 *= h / np.linalg.norm(r0)

                rot_angle = 2 * np.pi / n_added
                R = rotation_matrix(rot_angle, v_n)
                prev_r = r0
                for x in np.linspace(0, 2 * np.pi, num=n_added):
                    prev_r = np.dot(R, prev_r)
                    if np.linalg.norm(center_coords -
                                      (prev_r + p + coords[i])) > radius:
                        continue

                    d_ep = distance_matrix(coords, [prev_r + p + coords[i]])
                    for k in range(0, len(coords)):
                        if i == k or j == k:
                            continue

                        if d_ep[k, 0] <= radius_list[k]:
                            break
                    else:
                        atom_added_points[i].append(prev_r + p + coords[i])
                        atom_added_points[j].append(prev_r + p + coords[i])

    for i in range(0, len(coords)):
        # get a grid of points around each atom
        # remove any points that are close to an intersection
        # this makes it less likely for the triangulation to choose
        # one of these points instead of one that we already added
        # then, if we have to remove a triangle involving one of these points later,
        # it won't leave a gap
        n_atom_grid = int(radius_list[i]**2 * n_grid / radius**2)
        atom_sphere = fibonacci_sphere(radius=radius_list[i], num=n_atom_grid)
        n_atom_grid = len(atom_sphere)
        if len(atom_added_points[i]) > 0:
            remove_ndx = []
            dist_mat = distance_matrix(
                atom_sphere,
                np.array(atom_added_points[i]) - coords[i])
            for j in range(0, len(atom_sphere)):
                for k in range(0, len(atom_added_points[i])):
                    if dist_mat[j, k] < 0.3 * point_spacing:
                        remove_ndx.append(j)
                        break

            atom_sphere = atom_sphere.tolist()
            for ndx in remove_ndx[::-1]:
                atom_sphere.pop(ndx)

            atom_sphere = np.array(atom_sphere)
            n_atom_grid = len(atom_sphere)
            atom_sphere = np.concatenate(
                (atom_sphere, np.array(atom_added_points[i]) - coords[i]))

        atom_hull = ConvexHull(atom_sphere / radius_list[i])
        tri = atom_hull.simplices

        atom_sphere += coords[i]

        remove_v = []
        new_ndx = np.zeros(len(atom_sphere), dtype=int)

        # remove any points that are covered by another atom
        # only loop over n_atom_grid points so we don't remove
        # any points right on the intersection b/c of
        # numerical issues
        del_count = 0
        atom_grid_dist = distance_matrix(atom_sphere, coords)
        center_atom_grid_dist = distance_matrix(atom_sphere,
                                                [center_coords])[:, 0]
        for j in range(0, n_atom_grid):
            if center_atom_grid_dist[j] > radius:
                remove_v.append(j)
                del_count += 1
                continue
            for k in range(0, len(coords)):
                if i == k:
                    continue
                if atom_grid_dist[j, k] < radius_list[k]:
                    remove_v.append(j)
                    del_count += 1
                    break

            new_ndx[j] = j - del_count

        for j in range(n_atom_grid, len(atom_sphere)):
            new_ndx[j] = j - del_count

        if len(remove_v) == len(atom_sphere):
            continue

        atom_sphere = atom_sphere.tolist()
        for vi in remove_v[::-1]:
            atom_sphere.pop(vi)
            tri = tri[np.all(tri != vi, axis=1)]

        new_t = tri.tolist()
        # remove_t = []
        # for j, ti in enumerate(new_t):
        #     if all(t >= n_atom_grid for t in ti):
        #         remove_t.append(j)
        #
        # for vi in remove_t[::-1]:
        #     new_t.pop(vi)
        new_t = np.array(new_t)

        for j, ti in enumerate(new_t):
            for k, v in enumerate(ti):
                new_t[j][k] = new_ndx[v]

        atom_sphere = np.array(atom_sphere)
        norms = -(atom_sphere - coords[i]) / radius_list[i]

        triangles.extend(new_t + len(vertices))
        vertices.extend(atom_sphere)
        normals.extend(norms)

    remove_ndx = []
    if len(center_added_points) > 0:
        dist_mat = distance_matrix(sphere, center_added_points)
        for i in range(0, len(sphere)):
            for j in range(0, len(center_added_points)):
                if dist_mat[i, j] < 0.3 * point_spacing:
                    remove_ndx.append(i)
                    break

        sphere = sphere.tolist()
        for ndx in remove_ndx[::-1]:
            sphere.pop(ndx)

        sphere = np.array(sphere)

    n_sphere = len(sphere)
    sphere = np.concatenate((sphere, np.array(center_added_points)))

    center_hull = ConvexHull(sphere / radius)
    sphere += center_coords
    tri = center_hull.simplices

    remove_v = []
    new_ndx = np.zeros(len(sphere), dtype=int)
    del_count = 0
    center_grid_dist = distance_matrix(sphere, coords)
    for i in range(0, n_sphere):
        if volume_type == "free":
            for j in range(0, len(coords)):
                if center_grid_dist[i, j] < radius_list[j]:
                    remove_v.append(i)
                    del_count += 1
                    break

        elif volume_type == "buried":
            if all(center_grid_dist[i, j] > radius_list[j]
                   for j in range(0, len(coords))):
                remove_v.append(i)
                del_count += 1

        new_ndx[i] = i - del_count

    for i in range(n_sphere, len(sphere)):
        new_ndx[i] = i - del_count

    sphere = sphere.tolist()
    for vi in remove_v[::-1]:
        sphere.pop(vi)
        tri = tri[np.all(tri != vi, axis=1)]

    new_t = tri.tolist()
    if volume_type == "buried":
        remove_t = []
        for j, ti in enumerate(new_t):
            if all(t >= n_sphere for t in ti):
                remove_t.append(j)

        for vi in remove_t[::-1]:
            new_t.pop(vi)

    new_t = np.array(new_t)

    for i, ti in enumerate(new_t):
        for j, v in enumerate(ti):
            new_t[i][j] = new_ndx[v]

    sphere = np.array(sphere)
    norms = (sphere - center_coords) / radius

    triangles.extend(new_t + len(vertices))
    vertices.extend(sphere)
    normals.extend(norms)

    # the triangles need to be reordered so the points are
    # clockwise (or counterclockwise? i don't remember)
    for i in range(0, len(triangles)):
        t = triangles[i]
        v1 = vertices[t[1]] - vertices[t[0]]
        v2 = vertices[t[2]] - vertices[t[0]]
        c = np.cross(v1, v2)
        if np.dot(c, normals[t[0]]) < 0:
            triangles[i] = t[::-1]

    model.set_geometry(np.array(vertices), np.array(normals),
                       np.array(triangles))

    return model
Ejemplo n.º 27
0
 def delete(self):
     self.auto_update = False  # Remove auto update handler
     Surface.delete(self)
Ejemplo n.º 28
0
 def restore_snapshot(cls, session, data):
     inst = cls(session, None, data['plane'], data['thickness'],
                data['radius'], data['color'])
     Surface.set_state_from_snapshot(inst, session, data['base data'])
     return inst