scene
A rotatable collection of spheres and edges, decoupled from chemistry.
Everything below the Scene boundary is geometry: centres, radii, colours and a camera. Nothing here knows what a crystal is, which is what makes it portable to another language later if the frame rate ever demands it.
Scene
dataclass
Source code in chmpy/tui/scene.py
arrow_size()
(shaft, head) radii for the cell vectors, in world units.
Source code in chmpy/tui/scene.py
geometry()
Every point the frame has to contain, with its padding radius.
A bond or an arrow is a rod of finite thickness, so its endpoints need the same padding an atom gets; a cell edge is a hairline and needs none.
Source code in chmpy/tui/scene.py
view_extent(rotation, margin=1.04)
Half-width and half-height needed about the pivot, for this view.
Measured about the rotation pivot rather than the projected centroid, so the structure does not drift across the frame as it turns. The margin keeps the outermost atom off the frame edge, where an exact fit would leave it sitting in the border row.
Source code in chmpy/tui/scene.py
bonding_percolates(crystal, tolerance=0.4)
True when covalent bonding runs through the lattice.
Each component is unwrapped by walking a spanning tree and accumulating the cell translation on every edge. If a remaining edge then disagrees with the shifts that walk assigned, the component closes a loop through a lattice translation - it is a framework or a chain, not a finite molecule.
Source code in chmpy/tui/scene.py
crystal_scene(crystal, cells=(1, 1, 1), style='ball-and-stick')
Spheres and bonds for a block of unit cells, plus the cell edges.
A molecular crystal is built from whole molecules: chopping atoms at the cell boundary would draw half a molecule here and half a cell away, which is not what the structure looks like. A framework or ionic solid has no finite molecule to complete, so it falls back to the atoms of the block with bonds found by distance.
Source code in chmpy/tui/scene.py
format_direction(indices, kind)
The crystallographic spelling of a parsed direction.
Multi-digit indices are spaced out, since running them together would produce something this module could not read back.
Source code in chmpy/tui/scene.py
lattice_direction(crystal, indices, kind='uvw')
Cartesian vector for a [uvw] zone axis or an (hkl) plane normal.
[uvw] is a direction in the direct lattice, ua + vb + wc. (hkl) names a plane, and the direction of interest is its normal, which is the reciprocal-lattice vector ha + kb + lc*. For a non-orthogonal cell these are genuinely different directions, so the distinction matters.
Source code in chmpy/tui/scene.py
look_along(direction, up_hint=None)
Rotation that puts direction out of the screen, toward the viewer.
The returned matrix has the screen basis as its rows, matching what
render_scene expects. up_hint fixes the roll; the component of it
perpendicular to the view direction becomes screen-up.
Source code in chmpy/tui/scene.py
molecule_scene(molecule, style='ball-and-stick')
Spheres, and bonds when the style calls for them.
Source code in chmpy/tui/scene.py
parse_direction(text)
Parse a view direction into (indices, kind).
Accepts crystallographic notation - '[uvw]' for a zone axis, '(hkl)' for a plane normal, bare digits defaulting to a zone axis - as well as the named axes a/b/c, their reciprocals a/b/c*, and the cartesian x/y/z.
Indices may be run together in the usual way, with a minus sign binding to the digit that follows ('1-10' is [1,-1,0]), or separated by spaces or commas when they need more than one digit ('10 -2 1').
Source code in chmpy/tui/scene.py
render_scene(scene, rotation=None, width=88, zoom=1.0, edge_color=None, depth_cue=True, height=None, theme=None, shading='lit', extent=None)
Rasterise a Scene into a Pixels image under the given rotation.
Source code in chmpy/tui/scene.py
rotation_matrix(yaw, pitch, roll=0.0)
Rotation from yaw (about screen y), pitch (about screen x), roll (z).
Source code in chmpy/tui/scene.py
view_rotation(indices, kind='uvw', crystal=None)
Rotation looking along a direction, resolved against a lattice if given.
For a crystal the roll is fixed by whichever cell vector is closest to perpendicular to the view, so an axis-aligned view comes out the way it would be drawn on paper rather than at an arbitrary twist.