예제 #1
0
def next_direction(direction, e, vertices, normal1, normal2):
    ev = edge_vector(e, vertices)
    from chimerax.geometry import cross_product, inner_product, normalize_vector
    en1, en2 = cross_product(ev, normal1), cross_product(ev, normal2)
    d = inner_product(direction, ev) * ev + inner_product(direction, en1) * en2
    d = normalize_vector(d)
    return d
예제 #2
0
def curve_segment_end(curve, t, length, tolerance=1e-3, max_steps=100):
    '''
    Compute a point on the curve beyond curve parameter value t which is
    a distance length from the point at position t.  Can return None if
    convergence fails.  This iteratively takes linear steps based on the
    curve velocity vector to find the desired end point.
    '''
    if length == 0:
        return t
    xyz0 = curve.position(t)
    v = curve.velocity(t)
    frac = 0.5
    from chimerax.geometry import norm, inner_product
    t1 = t + frac * length / norm(v)
    for step in range(max_steps):
        xyz1 = curve.position(t1)
        d = norm(xyz1 - xyz0)
        if abs(d - length) < tolerance * length:
            return t1
        v1 = curve.velocity(t1)
        # Want |xyz1 + v1*dt - xyz0| = length
        delta = xyz1 - xyz0
        a, b, c = (inner_product(v1, v1), 2 * inner_product(v1, delta),
                   inner_product(delta, delta) - length * length)
        dt1, dt2 = quadratic_roots(a, b, c)
        if dt1 is None:
            # No point in tangent line is within target length.
            # Go to closest approach
            dt1 = dt2 = -b / 2 * a
        dt_min = dt1 if abs(dt1) < abs(dt2) else dt2
        t1 += frac * dt_min
    return None
예제 #3
0
 def z_plane_spacing(self):
   dz = self._z_spacing
   if dz is None:
     files = self._file_info
     if self.multiframe:
       f = files[0]
       fpos = f._frame_positions
       if fpos is None:
         gfov = f._grid_frame_offset_vector
         if gfov is None:
           dz = None
         else:
           dz = self._spacing(gfov)
       else:
         # TODO: Need to reverse order if z decrease as frame number increases
         z_axis = self.plane_normal()
         from chimerax.geometry import inner_product
         z = [inner_product(fp, z_axis) for fp in fpos]
         dz = self._spacing(z)
       if dz is not None and dz < 0:
         self._reverse_frames = True
         dz = abs(dz)
     elif len(files) < 2:
       dz = None
     else:
       nz = self.grid_size()[2]  # For time series just look at first time point.
       z_axis = self.plane_normal()
       from chimerax.geometry import inner_product
       z = [inner_product(f._position, z_axis) for f in files[:nz]]
       dz = self._spacing(z)
     self._z_spacing = dz
     
   return dz
예제 #4
0
def clip_segment_with_planes(xyz_1, xyz_2, planes):

    f1 = 0
    f2 = 1
    for normal, offset in planes:
        c1 = inner_product(normal, xyz_1) - offset
        c2 = inner_product(normal, xyz_2) - offset
        if c1 < 0 and c2 < 0:
            return None, None, None, None  # All of segment is clipped
        if c1 >= 0 and c2 >= 0:
            continue  # None of segment is clipped
        f = c1 / (c1 - c2)
        if c1 < 0:
            f1 = max(f1, f)
        else:
            f2 = min(f2, f)

    if f1 == 0 and f2 == 1:
        return xyz_1, xyz_2, f1, f2

    if f1 > f2:
        return None, None, None, None

    i1 = [(1 - f1) * a + f1 * b
          for a, b in zip(xyz_1, xyz_2)]  # Intercept point
    i2 = [(1 - f2) * a + f2 * b
          for a, b in zip(xyz_1, xyz_2)]  # Intercept point
    return i1, i2, f1, f2
예제 #5
0
 def _closest_point(self, event):
     '''Project start point to view line through mouse position.'''
     xyz1, xyz2 = self._view_line(event)
     p = self._start_point
     dx = xyz2 - xyz1
     from chimerax.geometry import inner_product
     f = inner_product(p - xyz1, dx) / inner_product(dx, dx)
     cp = xyz1 + f * dx
     return cp
예제 #6
0
 def pull_direction(self, atom):
     v = atom.structure.session.main_view
     x0, x1 = v.clip_plane_points(self.x, self.y)
     axyz = atom.scene_coord
     # Project atom onto view ray to get displacement.
     dir = x1 - x0
     da = axyz - x0
     from chimerax.geometry import inner_product
     offset = da - (inner_product(da, dir) / inner_product(dir, dir)) * dir
     return axyz, -offset
예제 #7
0
파일: tugging.py 프로젝트: tristanic/isolde
 def _offset_vector(self, x, y, starting_coord):
     v = self.session.main_view
     x0, x1 = v.clip_plane_points(x, y)
     axyz = starting_coord
     # Project atom onto view ray to get displacement.
     dir = x1 - x0
     da = axyz - x0
     from chimerax.geometry import inner_product
     offset = self.structure.scene_position.inverse(
         is_orthonormal=True).transform_vectors(
             da - (inner_product(da, dir) / inner_product(dir, dir)) * dir)
     return -offset
예제 #8
0
 def _far_clip_point(self, pos):
     view = self.session.main_view
     cam = view.camera
     view_num = 0
     cam_pos = cam.get_position(view_num).origin()
     cam_dir = cam.view_direction(view_num)
     pick_dir = pos - cam_pos
     near, far = view.near_far_distances(cam, view_num)
     from chimerax.geometry import inner_product
     denom = inner_product(pick_dir, cam_dir)
     d = (far -
          inner_product(cam_pos, cam_dir)) / denom if denom != 0 else 1000
     return cam_pos + d * pick_dir
예제 #9
0
def next_edge(p, direction, edges, vertices):
    from chimerax.geometry import cross_product, inner_product
    for e in edges:
        ev1, ev2 = vertices[e[0]] - p, vertices[e[1]] - p
        n = cross_product(ev1, ev2)
        tn = cross_product(direction, n)
        i1, i2 = inner_product(tn, ev1), inner_product(tn, ev2)
        if (i1 < 0 and i2 > 0) or (i1 > 0 and i2 < 0):
            # Edge is split by geodesic direction
            f = i1 / (i1 - i2)
            p2 = (1 - f) * vertices[e[0]] + f * vertices[e[1]]
            return e, f
    return None, None
예제 #10
0
 def near_far_distances(self, camera, view_num, include_clipping=True):
     '''Near and far scene bounds as distances from camera.'''
     cp = camera.get_position(view_num).origin()
     vd = camera.view_direction(view_num)
     near, far = self._near_far_bounds(cp, vd)
     if include_clipping:
         p = self.clip_planes
         np, fp = p.find_plane('near'), p.find_plane('far')
         from chimerax.geometry import inner_product
         if np:
             near = max(near, inner_product(vd, (np.plane_point - cp)))
         if fp:
             far = min(far, inner_product(vd, (fp.plane_point - cp)))
     cnear, cfar = self._clamp_near_far(near, far)
     return cnear, cfar
예제 #11
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
예제 #12
0
def optimize_helix_paramters(v, xyz, w, axis, rise, angle, center):

    m = v.full_matrix()
    xyz_to_ijk_transform = v.data.xyz_to_ijk_transform
    max_steps = 2000
    ijk_step_size_min, ijk_step_size_max = 0.01, 0.5
    optimize_translation = optimize_rotation = True
    metric = 'correlation'

    from chimerax.geometry import helical_symmetry_matrix
    htf = helical_symmetry_matrix(rise, angle, axis, center)
    tf = xyz_to_ijk_transform * htf

    from chimerax.map_fit.fitmap import locate_maximum
    move_tf, stats = locate_maximum(xyz, w, m, tf, max_steps,
                                    ijk_step_size_min, ijk_step_size_max,
                                    optimize_translation, optimize_rotation,
                                    metric)

    ohtf = htf * move_tf
    oaxis, ocenter, oangle, orise = ohtf.axis_center_angle_shift()
    from chimerax.geometry import inner_product
    if inner_product(axis, oaxis) < 0:
        orise = -orise
        oangle = -oangle
    corr = stats['correlation']

    return orise, oangle, corr
예제 #13
0
    def scene_position_6d(self, hand_pose, view):
        from chimerax.geometry import translation, cross_product
        from chimerax.geometry import orthonormal_frame, inner_product

        # Adjust origin
        cpos = translation(-self._center) * hand_pose

        # Scale millimeters to scene units
        scene_center = view.center_of_rotation
        cam = view.camera
        factor = cam.view_width(scene_center) / self._width
        cpos = cpos.scale_translation(factor)  # millimeters to scene units

        # Rotate to screen orientation
        yaxis = self._facing
        zaxis = cross_product(yaxis, self._cord)
        cpos = orthonormal_frame(zaxis, ydir=yaxis) * cpos

        # Adjust depth origin to center of rotation.
        cam_pos = cam.position
        depth = inner_product(scene_center - cam_pos.origin(),
                              -cam_pos.z_axis())
        cpos = translation(
            (0, 0, -depth)) * cpos  # Center in front of camera (-z axis).

        # Convert camera coordinates to scene coordinates
        scene_pos = cam_pos * cpos  # Map from camera to scene coordinates

        return scene_pos
예제 #14
0
    def mouse_drag(self, event):
        v = self._map
        if v is None or self._xy_last is None:
            self.mouse_down(event)
            return

        xl, yl = self._xy_last
        x, y = event.position()
        dx, dy = (x - xl, yl - y)
        if dx == 0 and dy == 0:
            return

        camera = self.session.main_view.camera
        if event.shift_down():
            # Translate slab
            ro = v.rendering_options
            spacing = ro.tilted_slab_spacing
            slab_normal = v.scene_position.transform_vector(
                ro.tilted_slab_axis)
            move_dir = camera.position.transform_vector((dx, dy, 0))
            from chimerax.geometry import inner_product, norm
            sign = 1 if inner_product(move_dir, slab_normal) > 0 else -1
            dist = sign * norm(move_dir) * spacing
            self._move_slab(dist)
        else:
            # Rotate slab
            from math import sqrt
            dn = sqrt(dx * dx + dy * dy)
            rangle = dn
            raxis = camera.position.transform_vector((-dy / dn, dx / dn, 0))
            self._rotate_slab(raxis, rangle)
        self._xy_last = (x, y)
예제 #15
0
def compute_instances_cap(drawing, triangles, plane, offset):
    d = drawing
    doffset = offset + getattr(d, 'clip_offset', 0)
    point = plane.plane_point
    normal = plane.normal

    b = d.geometry_bounds()
    if b is None:
        return None, None, None

    dpos = d.get_scene_positions(displayed_only=True)
    ipos = box_positions_intersecting_plane(dpos, b, point, normal)
    if len(ipos) == 0:
        return None, None, None
    geom = []
    for pos in ipos:
        pinv = pos.inverse()
        pnormal = pinv.transform_vector(normal)
        from chimerax.geometry import inner_product
        poffset = inner_product(pnormal, pinv * point) + doffset
        from . import compute_cap
        ivarray, itarray = compute_cap(-pnormal, -poffset, d.vertices,
                                       triangles)
        pos.transform_points(ivarray, in_place=True)
        geom.append((ivarray, itarray))
    varray, tarray = concatenate_geometry(geom)
    return varray, tarray, normal
예제 #16
0
def interpolate_corkscrew(xf, c0, c1, minimum_rotation = 0.1):
        '''
        Rotate and move along a circular arc perpendicular to the rotation axis and
        translate parallel the rotation axis.  This makes the initial geometric center c0
        traverse a helical path to the final center c1.  The circular arc spans an angle
        equal to the rotation angle so it is nearly a straight segment for small angles,
        and for the largest possible rotation angle of 180 degrees it is a half circle
        centered half-way between c0 and c1 in the plane perpendicular to the rotation axis.
        Rotations less than the minimum (degrees) are treated as no rotation.
        '''
        from chimerax.geometry import normalize_vector
        dc = c1 - c0
        axis, angle = xf.rotation_axis_and_angle()      # a is in degrees.
        if abs(angle) < minimum_rotation:
                # Use linear instead of corkscrew interpolation to
                # avoid numerical precision problems at small rotation angles.
                # ChimeraX bug #2928.
                center = c0
                shift = dc
        else:
                from chimerax.geometry import inner_product, cross_product, norm
                tra = inner_product(dc, axis)           # Magnitude of translation along rotation axis.
                shift = tra*axis
                vt = dc - tra * axis                    # Translation perpendicular to rotation axis.
                v0 = cross_product(axis, vt)
                if norm(v0) == 0 or angle == 0:
                        center = c0
                else:
                        import math
                        l = 0.5*norm(vt) / math.tan(math.radians(angle / 2))
                        center = c0 + 0.5*vt + l*normalize_vector(v0)

        return axis, angle, center, shift
예제 #17
0
def perspective_view_all(bounds,
                         position,
                         field_of_view,
                         window_size=None,
                         pad=0):
    '''
    Return the camera position that shows the specified bounds.
    Camera has perspective projection.
    '''
    from math import radians, sin, cos
    fov2 = radians(field_of_view) / 2
    s, c = sin(fov2), cos(fov2)
    face_normals = [
        position.transform_vector(v) for v in ((c / s, 0, 1), (-c / s, 0, 1))
    ]  # frustum side normals
    if window_size is not None:
        aspect = window_size[1] / window_size[0]
        from math import tan, atan
        fov2y = atan(aspect * tan(fov2))
        sy, cy = sin(fov2y), cos(fov2y)
        face_normals.extend([
            position.transform_vector(v)
            for v in ((0, cy / sy, 1), (0, -cy / sy, 1))
        ])  # frustum top/bottom normals
    center = bounds.center()
    bc = bounds.box_corners() - center
    from chimerax.geometry import inner_product, Place
    d = max(inner_product(n, c) for c in bc for n in face_normals)
    d *= 1 / max(0.01, 1 - pad)
    view_direction = -position.z_axis()
    camera_center = center - d * view_direction
    va_position = Place(axes=position.axes(), origin=camera_center)
    return va_position
예제 #18
0
    def clip_move(self, delta_xy, front_shift, back_shift, delta=None):
        pf, pb = self._planes(front_shift, back_shift)
        if pf is None and pb is None:
            return

        from chimerax.graphics import SceneClipPlane, CameraClipPlane
        p = pf or pb
        if delta is not None:
            d = delta
        elif isinstance(p, SceneClipPlane):
            # Move scene clip plane
            d = self._tilt_shift(delta_xy, self.view.camera, p.normal)
        elif isinstance(p, CameraClipPlane):
            # near/far clip
            d = delta_xy[1] * self.pixel_size()

        # Check if slab thickness becomes less than zero.
        dt = -d * (front_shift + back_shift)
        if pf and pb and dt < 0:
            from chimerax.geometry import inner_product
            sep = inner_product(pb.plane_point - pf.plane_point, pf.normal)
            if sep + dt <= 0:
                # Would make slab thickness less than zero.
                return

        if pf:
            pf.plane_point = pf.plane_point + front_shift * d * pf.normal
        if pb:
            pb.plane_point = pb.plane_point + back_shift * d * pb.normal
예제 #19
0
def line_position(xyz, line):
    xyz1, xyz2 = line
    dxyz = xyz - xyz1
    xyz12 = xyz2 - xyz1
    from chimerax.geometry import norm, inner_product
    d2 = norm(xyz12)
    f = inner_product(dxyz, xyz12) / d2
    return f
예제 #20
0
def point_in_view(point, view):
    w, h = view.window_size
    cam = view.camera
    # Compute planes bounding view
    planes = cam.rectangle_bounding_planes((0, 0), (w, h), (w, h))
    from chimerax.geometry import inner_product
    for p in planes:
        if inner_product(point, p[:3]) + p[3] < 0:
            return False

    # Check near/far planes
    near, far = view.near_far_distances(cam, view_num=0)
    dist = inner_product(point - cam.position.origin(), cam.view_direction())
    if dist < near or dist > far:
        return False

    return True
예제 #21
0
def circle_in_circles(i, circles):
    from chimerax.geometry import inner_product
    p, a = circles[i].center, circles[i].angle
    for j, c in enumerate(circles):
        if c.angle >= a and inner_product(
                p, c.center) >= cos(c.angle - a) and j != i:
            return True
    return False
예제 #22
0
 def _near_far_bounds(self, camera_pos, view_dir):
     b = self.drawing_bounds(allow_drawing_changes=False)
     if b is None:
         return self._min_near_fraction, 1  # Nothing shown
     from chimerax.geometry import inner_product
     d = inner_product(b.center() - camera_pos,
                       view_dir)  # camera to center of drawings
     r = (1 + self._near_far_pad) * b.radius()
     return (d - r, d + r)
예제 #23
0
 def _shift_near_far_clip_planes(self, shift):
     p = self.clip_planes
     np, fp = p.find_plane('near'), p.find_plane('far')
     if np or fp:
         vd = self.camera.view_direction()
         from chimerax.geometry import inner_product
         plane_shift = inner_product(shift, vd) * vd
         if np:
             np.plane_point += plane_shift
         if fp:
             fp.plane_point += plane_shift
예제 #24
0
def circle_intercepts(c0, c1):

    from chimerax.geometry import inner_product, cross_product
    ca01 = inner_product(c0.center, c1.center)
    x01 = cross_product(c0.center, c1.center)
    s2 = inner_product(x01, x01)
    if s2 == 0:
        return None, None

    ca0 = c0.cos_angle
    ca1 = c1.cos_angle
    a = (ca0 - ca01 * ca1) / s2
    b = (ca1 - ca01 * ca0) / s2
    d2 = (s2 - ca0 * ca0 - ca1 * ca1 + 2 * ca01 * ca0 * ca1)
    if d2 < 0:
        return None, None
    d = sqrt(d2) / s2

    return (a * c0.center + b * c1.center - d * x01,
            a * c0.center + b * c1.center + d * x01)
예제 #25
0
 def set_focus_depth(self, point_on_screen, window_width):
     from chimerax.geometry import inner_product
     z = inner_product(self.view_direction(),
                       point_on_screen - self.position.origin())
     if z <= 0:
         return
     from math import tan, radians
     screen_width = 2 * z * tan(0.5 * radians(self.field_of_view))
     es = screen_width * self.eye_separation_pixels / window_width
     self.eye_separation_scene = es
     self.redraw_needed = True
예제 #26
0
 def vr_motion(self, event):
     # Virtual reality hand controller motion.
     br = self._bond_rot
     if br:
         axis, angle = event.motion.rotation_axis_and_angle()
         from chimerax.geometry import inner_product
         if inner_product(axis, br.axis) < 0:
             angle = -angle
         angle_change = self._speed_factor * angle
         if abs(angle_change) < self._minimum_angle_step:
             return "accumulate drag"
         br.angle += angle_change
예제 #27
0
 def _center_point_matching_depth(self, point):
     cam_pos = self.camera.position.origin()
     vd = self.camera.view_direction()
     hyp = point - cam_pos
     from chimerax.geometry import inner_product, norm
     distance = inner_product(hyp, vd)
     cr = cam_pos + distance * vd
     old_cofr = self._center_of_rotation
     if norm(cr - old_cofr) < 1e-6 * distance:
         # Avoid jitter if camera has not moved
         cr = old_cofr
     return cr
예제 #28
0
 def _update_focus_depth(self):
     v = self._session.main_view
     b = v.drawing_bounds()
     if b is None:
         return
     view_dir = -self.position.z_axis()
     delta = b.center() - self.position.origin()
     from chimerax.geometry import inner_product
     d = inner_product(delta, view_dir)
     d -= self._depth_offset
     if d != self._focus_depth:
         self._focus_depth = d
         self._redraw_needed()
예제 #29
0
def zoom_camera(c, point, factor):
    if hasattr(c, 'field_width'):
        # Orthographic camera
        c.field_width /= factor
    else:
        # Perspective camera
        v = c.view_direction()
        p = c.position
        from chimerax.geometry import inner_product, translation
        delta_z = inner_product(p.origin() - point, v)
        zmove = (delta_z * (1 - factor) / factor) * v
        c.position = translation(zmove) * p
    c.redraw_needed = True
예제 #30
0
    def vr_motion(self, event):
        v = self._map
        if v is None:
            return

        trans = event.tip_motion
        dxyz = v.scene_position.inverse().transform_vector(trans)
        ro = v.rendering_options
        from chimerax.geometry import inner_product
        dist = inner_product(ro.tilted_slab_axis, dxyz)
        self._move_slab(dist)
        center = event.tip_position
        axis, angle = event.motion.rotation_axis_and_angle()
        self._rotate_slab(axis, angle, center)