Skip to main content

Geometry

Struct Geometry 

Source
pub struct Geometry {
    pub kind: &'static str,
    pub patches: Vec<Patch>,
}
Expand description

Everything a representation says about its shape.

Fields§

§kind: &'static str

The 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

Source

pub fn undefined_count(&self) -> usize

How many of this geometry’s nodes have no position.

Source

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

Source

pub fn point_count(&self) -> usize

Total number of points across every patch.

Source

pub fn is_empty(&self) -> bool

Whether there is anything to draw.

Source

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.

Source

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.

Source

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.

Source

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

Source

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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl Clone for Geometry

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Geometry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for Geometry

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Geometry

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more