pub struct Geometry {
pub kind: &'static str,
pub patches: Vec<Patch>,
}Expand description
Everything a representation says about its shape.
Fields§
§kind: &'static strThe representation’s own type, for a caller that wants to label it.
patches: Vec<Patch>One entry per patch, in order.
Implementations§
Source§impl Geometry
impl Geometry
Sourcepub fn undefined_count(&self) -> usize
pub fn undefined_count(&self) -> usize
How many of this geometry’s nodes have no position.
Sourcepub fn defined_only(&self) -> Option<Compaction>
pub fn defined_only(&self) -> Option<Compaction>
This geometry with every undefined node removed - or None when there
is none, which is the ordinary case and costs one pass and no copy.
None rather than a clone of self on purpose: the caller can then
keep borrowing the original, and the overwhelmingly common package pays
nothing for a rule that exists for the others.
Source§impl Geometry
impl Geometry
Sourcepub fn point_count(&self) -> usize
pub fn point_count(&self) -> usize
Total number of points across every patch.
Sourcepub fn nodes_at(&self, ranks: &[usize]) -> Result<Vec<[f64; 3]>, String>
pub fn nodes_at(&self, ranks: &[usize]) -> Result<Vec<[f64; 3]>, String>
The nodes of these ranks, in the order asked - the representation’s
own numbering, the running sum of its patches’ points (Patch::node_offset).
The numbering a click in the scene returns and transform’s nodes
reads. A rank the shape does not hold is refused by name: a node taken
from past the end would be another shape’s, or nothing.
Sourcepub fn cell_count(&self) -> usize
pub fn cell_count(&self) -> usize
Total number of cells, whatever kind of cell this shape has.
A triangle, a polyline, a hexahedron and a grid cell all count as one, because that is what a per-cell property has one value for - and what a consumer will line those values up against. A shape of loose points has no cells at all.
Sourcepub fn merged(&self) -> (Vec<Point>, Vec<[u32; 3]>)
pub fn merged(&self) -> (Vec<Point>, Vec<[u32; 3]>)
Every patch’s points in one array, with the triangles renumbered into it.
One vertex buffer and one index buffer is what a renderer actually
uploads, and doing the renumbering here is the point: it is the one
place Patch::node_offset has to be applied, and applying it wrong
draws a mesh instead of failing.
Patches that are not triangulated contribute their points and no
indices. That includes both volumetric kinds: a cell is not a surface,
and the exporters draw its faces themselves rather than take a
triangulation decided here. Polyhedra::triangles is there for a
caller that does want one.
Sourcepub fn drawable(&self) -> Drawable
pub fn drawable(&self) -> Drawable
Points, triangles and line segments, ready for a graphics API.
§Why this exists next to Geometry::merged
merged emits indices only for Topology::Triangles, which is right
for what it is for. But a viewer given nothing else draws a point
cloud - and that is what a 2D grid and a well trajectory came out as:
a horizon rendered as a spray of dots, a borehole as a dotted line. The
data was there the whole time; nothing turned a cell into two triangles
or a station list into segments.
So every topology gets an answer here:
- a grid becomes two triangles per cell, in the lattice’s own row-major order;
- quadrilaterals and polygons are fanned from their first corner, which is correct for the convex rings RESQML produces;
- polylines become the segments between consecutive stations;
- bare points stay points, because that is what they are.
A cell with a non-finite corner is dropped rather than drawn. A grid
with holes is ordinary - an eroded horizon, a survey clipped to a
licence block - and a triangle through NaN does not render as a hole,
it renders as a spike across the whole scene.
And the node itself goes with it. Dropping only the cells leaves the
NaN in the buffer a viewer uploads, which is not a missing dot: three
numbers that are not numbers make the object’s bounding sphere NaN, the
frustum test fails for the whole object, and the framing of the entire
scene goes with it - one console line per frame, about a node that only
ever meant “no data here”. So Drawable carries locations only, the
indices are renumbered onto them, and Drawable::dropped says how many
there were: a surface that comes out empty because every node was NaN
must not look like a reader that found nothing.
Source§impl Geometry
impl Geometry
Sourcepub fn can_be(&self, shape: Shape) -> bool
pub fn can_be(&self, shape: Shape) -> bool
Whether every patch can be drawn in this shape.
Asked before an export starts, so a caller can report or skip rather
than find a half-written file - the same reason
Exporter::handles exists.
Sourcepub fn as_shape(&self, shape: Shape) -> Result<Geometry>
pub fn as_shape(&self, shape: Shape) -> Result<Geometry>
This geometry in the shape asked for, or a refusal naming both ends.
The points are untouched - every conversion here is arithmetic on indices - so a node’s position, and anything indexed on nodes, survives unchanged. What changes is only what joins them.
Sourcepub fn wireframe(&self) -> Result<Vec<[u32; 2]>>
pub fn wireframe(&self) -> Result<Vec<[u32; 2]>>
The cell edges, indexed on the points Geometry::drawable gives.
§The bug this exists for
Reported as IJK grids with edges shooting off to the origin,
and the reading was never the problem: a viewer drew the faces from
drawable() and the wireframe from as_shape(Lines).drawable(), and
those two do not share a point list.
They diverge for exactly one reason, and it is a rule this crate applies
on purpose: a node of a volume that no cell names is not a location -
CellGeometryIsDefined marks cells undefined while their coordinates
stay perfectly finite in the file - so Geometry::drawable turns those
orphans into holes and drops them. Reshaping to segments first destroys
the volume topology, nothing is an orphan of a segment list, and every
node survives. On h+g_PaleoGTM.epc that is 37 772 points against the
mesh’s 36 363, and 156 099 of the wireframe’s indices addressed
vertices that were not there.
Out-of-range indices are not an error a viewer reports; WebGL reads whatever the buffer holds, so the edges land somewhere - near the origin, as it happened. A wrong picture with no message is this workspace’s least favourite kind of failure.
§Why the orphans are holed first
So that the same nodes are dropped, in the same order, by the same compaction. The survivors of a reshaped geometry are then exactly the survivors of the original, and an index means the same thing in both - which is the property a caller drawing one buffer with two index lists needs, and the one it cannot check for itself.