Skip to main content

Model

Struct Model 

Source
pub struct Model { /* private fields */ }
Expand description

A document: topology, placements, geometry, and where every entity came from.

Implementations§

Source§

impl Model

Source

pub fn new() -> Self

An empty model, in millimetres.

Source

pub fn with_tolerances(tolerances: Tolerances) -> Self

An empty model at a given unit scale.

A document has a scale, and it is the document’s rather than each call’s: a model authored in metres does not become a model in millimetres because one caller passed the default. Algorithms still take a Tolerances argument (that is deliberate, since a caller may want to work coarser or finer than the document’s own setting for one operation), but the document now says what it was built at, so a mismatch is visible rather than assumed away.

Source

pub const fn tolerances(&self) -> Tolerances

The tolerances this document was built at.

Source

pub fn from_parts(parts: ModelParts) -> OgeomResult<Self>

Assemble a model from parts read back from a file.

The one way into a Model that does not go through its builders, and it exists for one reason: a builder mints an identity for every node it makes (docs/DATA_MODEL.md §8). A document rebuilt through the builders is therefore a different document from the one that was written (every EntityId renumbered, every provenance record replaced by a fresh Primitive one), and every reference into it, which is the thing provenance exists to keep alive, is dead. Reading a file has to reproduce the document it describes, identities and all.

This is not a hole in “the builder is the sole mutation path”. Nothing here mutates an existing model; it assembles a new one, and it checks the structural invariants the builders check before handing it back, so a corrupt file is an error, not a model that answers wrongly.

§Errors

OgeomError::Dangling if a node names a child, a datum, a piece of geometry or an identity that is not there; OgeomError::Construction if a node’s data does not match its kind, or a child is of the wrong kind for its parent.

Source

pub fn absorb( &mut self, parts: ModelParts, roots: &[Shape], ) -> OgeomResult<Absorbed>

Absorb another document’s parts into this model.

Model::from_parts lands a document in a fresh model; this lands one in a model that already has things in it: the operation behind bringing a serialized tool body into a live document so a boolean can use it. Everything the parts carry is appended: nodes, datums, geometry, provenance and identities all keep their relative structure, shifted past what the model already holds. The result behaves exactly as if it had been built here, because after the shift it is indistinguishable from having been.

roots are the shapes the source document named, in the unbound state a reader leaves them; they come back bound to this model. The returned Absorbed::entities table says where every source identity landed, which is what a caller holding references against the source document resolves them through.

Three deliberate refusals, each an error rather than a guess:

  • Units. A document authored at another scale is refused, not rescaled; rescaling is a real feature with real decisions in it, and silently absorbing metres into millimetres is a wrong model.
  • Bound handles. Parts whose handles already name an arena did not come from a reader; absorbing them would alias whatever those handles meant elsewhere. Serialization is the one road in.
  • A model with holes. Absorbing appends by offset, which is only sound while the target’s arenas have only ever been appended to. Nothing in this crate removes, so this cannot trigger today; it is checked so a future that removes gets an error, not aliasing.

The current operation is left alone: absorb mints no identities, it transplants a table, and the absorbed provenance keeps its source OpIds verbatim, meaningful in the source document’s rebuild, kept because renumbering them would orphan the source’s own references.

§Errors

OgeomError::Construction for the three refusals above; OgeomError::Dangling if the parts do not describe themselves: a handle that does not resolve, a derivation from an identity no entry issued, a root naming a node that is not there.

On an error past the up-front gates, the model’s prior contents are untouched and still fully usable: an absorbed subgraph is self-contained (its shifted handles cannot reach below the append line), and no identity is committed until every check has passed. What a failed absorb can leave behind is unreachable appended entries, which cost memory and mean nothing.

Source

pub fn bind(&self, shape: &Shape) -> OgeomResult<Shape>

Bind an unscoped shape to this model.

A handle rebuilt by a reader names no arena, so it resolves nowhere until it is told which document it belongs to. This is how a reader says so, and it verifies the answer, so a file naming a node that is not there is an error rather than a shape that fails mysteriously later.

It will not re-home a shape that already belongs to another model. That is exactly the mistake scoping exists to catch, and quietly relabelling it would hand back a shape that resolves and answers about the wrong entity.

§Errors

OgeomError::Construction if the shape already belongs to a different model; OgeomError::Dangling if it does not resolve here once bound.

Source

pub fn bind_location(&self, location: &Location) -> OgeomResult<Location>

Bind a bare location to this model’s datum store.

The persistence path’s sibling of Model::bind: a location read from a file names datum handles that are unscoped until the store that holds them exists. Binding checks them too: a chain naming a datum not in this model is an error here rather than wherever it is first resolved.

§Errors

OgeomError::Dangling if the chain names a datum not in this model.

Source

pub const fn begin_operation(&mut self) -> OpId

Begin a new operation, and return its identifier.

Every node created from here on is attributed to it until the next call. The counter is deterministic (the third operation in a rebuild is OpId(3) every time), which is what lets provenance survive a parameter change (docs/DATA_MODEL.md §8).

Source

pub const fn current_operation(&self) -> OpId

The operation nodes are currently attributed to.

Source

pub fn identity_of(&self, shape: &Shape) -> Option<EntityId>

The stable identity of a shape’s node.

Distinct from its arena handle: the handle says where the data is and dies when the shape is rebuilt, while this says what the entity is and survives.

Source

pub fn provenance_of(&self, shape: &Shape) -> Option<&Provenance>

Where a shape’s node came from.

Source

pub const fn provenance(&self) -> &ProvenanceTable

The provenance table.

Source

pub fn roots_of(&self, shape: &Shape) -> Vec<EntityId>

Trace a shape back to the entities it ultimately came from.

How a reference into a rebuilt model is resolved: find what the user originally picked, then find what that became.

Source

pub fn shape_of(&self, id: EntityId) -> Option<Shape>

The shape carrying a given identity, if this document has one.

The inverse of Model::identity_of, and the answer to “I kept a reference and the document has been saved and reloaded since”. A raw Shape cannot survive that: the reloaded document is a new set of arenas and Model::bind refuses a handle from another one, on purpose. An EntityId can, because it names what the entity is rather than where it sits (docs/DATA_MODEL.md §8), and that is the whole reason it exists.

Returns the shape in its default placement and orientation. A caller that wants a particular occurrence explores from here.

Source

pub fn set_derived( &mut self, shape: &Shape, from: &[Shape], role: Role, ) -> OgeomResult<EntityId>

Record that a node was derived from other entities.

Overwrites the Primitive attribution a builder assigns by default. An operation that splits or reshapes existing topology calls this, and what it records is what a later rebuild will match against.

§Errors

OgeomError::Dangling if the shape does not resolve in this model.

Source

pub const fn datums(&self) -> &DatumStore

The placement datums.

Source

pub const fn geometry(&self) -> &GeometryStore

The geometry.

Source

pub const fn geometry_mut(&mut self) -> &mut GeometryStore

Mutable access to the geometry, for adding curves and surfaces.

Source

pub fn add_datum(&mut self, transform: Transform) -> DatumId

Intern a transform for use in placements.

Source

pub fn node(&self, shape: &Shape) -> Option<&TShape>

The node behind a shape’s handle.

Source

pub fn node_by_id(&self, id: TShapeId) -> Option<&TShape>

The node behind a handle.

Source

pub fn node_mut(&mut self, shape: &Shape) -> Option<&mut TShape>

Mutable access to the node behind a shape’s handle.

For attaching geometry to an entity that already exists: a pcurve joining an edge to a face it has just come to bound. Structural change still goes through the builders; this reaches the node’s data, which no invariant here constrains on its own.

Source

pub fn kind_of(&self, shape: &Shape) -> OgeomResult<ShapeType>

What kind of shape this is.

§Errors

OgeomError::Dangling if the handle does not resolve in this model.

Source

pub fn tolerance_of(&self, shape: &Shape) -> OgeomResult<Option<Tolerance>>

The tolerance a shape carries, if it carries one.

§Errors

As Model::kind_of.

Source

pub fn node_count(&self) -> usize

Number of topology nodes.

Source

pub fn is_empty(&self) -> bool

Whether the model holds no topology.

Source

pub fn nodes(&self) -> impl Iterator<Item = (TShapeId, &TShape)>

Every topology node, with its handle, in arena order.

For writing a document out. Traversal from a root shape reaches only what that root bounds; a document is everything in it.

Source

pub fn identities(&self) -> impl Iterator<Item = (TShapeId, EntityId)>

Every node that has been given an identity, with it.

Source

pub fn add_vertex(&mut self, data: VertexData) -> Shape

Add a vertex.

Source

pub fn add_point(&mut self, point: Point) -> Shape

Add a vertex at point with the minimum tolerance.

Source

pub fn add_edge( &mut self, data: EdgeData, bounds: &[Shape], ) -> OgeomResult<Shape>

Add an edge bounded by the given vertices.

The vertices are the edge’s ends, in order. A closed edge (a full circle) names the same vertex twice rather than once, so that walking its boundary yields a start and an end as every other edge does.

§Errors

OgeomError::Construction if a bound is not a vertex, or if there are more than two; OgeomError::Invariant if a vertex’s tolerance is tighter than the edge’s, breaking the containment rule.

Source

pub fn add_wire(&mut self, edges: &[Shape]) -> OgeomResult<Shape>

Add a wire from a sequence of edges.

§Errors

OgeomError::Construction if a child is not an edge, or the wire is empty.

Source

pub fn add_face( &mut self, data: FaceData, wires: &[Shape], ) -> OgeomResult<Shape>

Add a face bounded by the given wires.

A face with no wires covers its surface’s whole domain, and is recorded as naturally restricted.

§Errors

OgeomError::Construction if a bound is not a wire; OgeomError::Invariant if the containment rule is broken.

Source

pub fn add_shell(&mut self, faces: &[Shape]) -> OgeomResult<Shape>

Add a shell from a set of faces.

§Errors

OgeomError::Construction if a child is not a face, or the shell is empty.

Source

pub fn add_solid(&mut self, shells: &[Shape]) -> OgeomResult<Shape>

Add a solid bounded by the given shells.

§Errors

OgeomError::Construction if a child is not a shell, or the solid is empty.

Source

pub fn add_compsolid(&mut self, solids: &[Shape]) -> OgeomResult<Shape>

Add a compsolid from solids sharing faces.

§Errors

OgeomError::Construction if a child is not a solid, or it is empty.

Source

pub fn add_compound(&mut self, shapes: &[Shape]) -> OgeomResult<Shape>

Add a compound of arbitrary shapes.

The one container with no type constraint; that is what a compound is for. It may be empty, since an empty result is a legitimate answer from a boolean and needs somewhere to live.

§Errors

OgeomError::Dangling if a child does not resolve in this model.

Source

pub fn children_of(&self, shape: &Shape) -> OgeomResult<Vec<Shape>>

The direct children of a shape, with this shape’s placement and orientation composed onto each.

The single most important method on the model, and the reason traversal is correct by default rather than by discipline: a child’s placement in the world is its parent’s composed with its own, and its orientation is its parent’s composed with its own. Returning raw children would leave every caller to remember both, and the failure is silent: face normals that flip inconsistently, sub-shapes drawn at the origin.

§Errors

OgeomError::Dangling if the shape does not resolve in this model.

Source

pub fn ordered_children_of(&self, shape: &Shape) -> OgeomResult<Vec<Shape>>

A shape’s children in traversal order.

The same shapes as Model::children_of, but with the list reversed when the parent is reversed. Order carries meaning for a wire (its edges run head to tail), and reversing a wire has to reverse the walk as well as each edge, or consecutive edges stop sharing a vertex and the boundary comes apart. For a shell or a solid the order means nothing and the reversal is invisible.

Model::children_of stays the raw accessor: it returns what is stored, which is what a rebuild or a comparison wants.

§Errors

OgeomError::Dangling if the shape does not resolve in this model.

Source

pub fn widen(&mut self, shape: &Shape, to: Tolerance) -> OgeomResult<()>

Widen a shape’s tolerance, and every sub-shape’s with it.

The cascade is the point. The containment rule is transitive: a face’s edges must be no tighter than the face, and those edges’ vertices no tighter than the edges. Widening only one level leaves the rule broken two levels down, where nothing will notice until a containment test quietly answers about geometry that does not meet.

Tolerances only ever grow, so this is the sanctioned repair: raise what bounds, never lower what is bounded.

§Errors

OgeomError::Dangling if the shape, or anything below it, does not resolve in this model.

Source

pub fn check_tolerances(&self, root: &Shape) -> OgeomResult<()>

Verify the containment rule across a whole shape tree.

docs/DATA_MODEL.md §5. Walks parent to child and checks that whatever bounds is no tighter than what it bounds.

§Errors

OgeomError::Invariant at the first violation, naming the two shape types involved.

Source

pub fn same_position( &self, a: &Shape, b: &Shape, tol: Tolerances, ) -> OgeomResult<bool>

Whether two shapes coincide in position, comparing composed transforms.

§Errors

As Location::composed.

Source

pub fn placed(&mut self, shape: &Shape, transform: Transform) -> Shape

A shape placed by an additional transform.

Interns the transform and composes it onto the shape’s placement, so the underlying node (and all its geometry) is shared rather than copied. Placing ten thousand instances of a part costs ten thousand short chains and one copy of the geometry.

Trait Implementations§

Source§

impl Clone for Model

Source§

fn clone(&self) -> Model

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 Model

Source§

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

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

impl Default for Model

Source§

fn default() -> Model

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Model

§

impl RefUnwindSafe for Model

§

impl Send for Model

§

impl Sync for Model

§

impl Unpin for Model

§

impl UnsafeUnpin for Model

§

impl UnwindSafe for Model

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, 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> Same for T

Source§

type Output = T

Should always be Self
§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.