Packages
ex_quiddity
0.1.2
An Elixir wrapper of github.com/pzfreo/quiddity to bring feature extraction from CAD, with the geometry underneath it: rays, frames, meshes and surface samples. Wrapped via rustler.
Current section
Files
Jump to
Current section
Files
ex_quiddity
README.md
README.md
# ex_quiddity
An Elixir wrapper of [quiddity](https://github.com/pzfreo/quiddity) to bring
feature extraction from CAD, with the geometry underneath it: rays, frames,
meshes and surface samples. Wrapped via rustler.
It is a binding of quiddity and
[haecceity](https://github.com/pzfreo/quiddity/tree/main/crates/haecceity), both
pure Rust with no OpenCascade and no CAD system: read a STEP file, and ask what
its holes, pockets, slots, bosses, fillets and turned features are, where its
surfaces are, and what a sensor placed on it would perceive.
```elixir
{:ok, part} = Quiddity.open("bracket.step")
{:ok, recognition} = Quiddity.features(part)
Quiddity.Recognition.families(recognition)
#=> [{"holes", 4}, {"fillets", 6}, {"pockets", 1}]
```
Everything is in millimetres, in the file's own coordinates, and the same file
always gives the same answer.
## What it answers
| Question | Call |
| ---------------------------- | --------------------------------------------- |
| What is this part? | `Quiddity.open/1`, `Quiddity.features/1` |
| What is this face, and whose? | `Quiddity.face/2`, `Quiddity.Recognition.owner/2` |
| What is at this point? | `Quiddity.ray/4`, `Quiddity.nearest/3` |
| Inside, outside, or on it? | `Quiddity.classify/2` |
| How heavy is it? | `Quiddity.mass/2` |
| What would a camera see? | `Quiddity.frame/2` |
| What does the file demand? | `Quiddity.pmi/2` — dimensions, tolerances, datums |
| What changed between revisions? | `Quiddity.correspond/2` |
| What is it made of? | `Quiddity.mesh/2`, `Quiddity.samples/2` |
A frame is the interesting one: rays are cast against the **exact B-rep**, so
every pixel knows the point on the surface, the outward normal there, and which
face it landed on — not a depth buffer's approximation of it.
## A note on the sensor model, and where it lives
A frame is a rendering: `Quiddity.Camera` builds the pinhole camera, including
the geometry of a 64 × 64 patch sensor with a 66° field of view, and
`Quiddity.Frame` decodes the answer into points, normals, face ids, depth,
shaded RGBA and `semantic_3d` rows.
What a perception or learning framework makes of that frame is that framework's
business, and it is not in this package. `Quiddity.Camera.cam_to_world/1` and
`Quiddity.Frame.semantic_3d/2` produce the two matrices such a framework
conventionally wants; nothing here interprets them.
## As an MCP server
`mix quiddity.mcp` speaks the Model Context Protocol over stdio, so an assistant
can ask about a part directly:
```json
{"mcpServers": {"quiddity": {"command": "mix", "args": ["run", "--no-halt", "quiddity.mcp"]}}}
```
Seven tools: `quiddity_part`, `quiddity_features`, `quiddity_face`,
`quiddity_probe`, `quiddity_sense`, `quiddity_correspond`,
`quiddity_export_mjcf`.
## Install
```elixir
def deps do
[{:ex_quiddity, "~> 0.1"}]
end
```
The Rust engine is compiled when the dependency is: **building wants a Rust
toolchain** (`scripts/install-rust.sh` installs one), and running wants none.
## The engine is generated from one table
`Quiddity.Api.operations/0` lists every operation the Rust side has, and
`Quiddity.Native` is generated from it at compile time — the stubs, their
arities, and the MCP catalogue all come from the one list. A Rust function that
is not listed cannot be called, and a listed one that does not exist fails a
test rather than a call.
## Limits, said out loud
- quiddity reports what it can prove from the geometry. A file that reads without
errors is not a promise every feature was found:
`Quiddity.Recognition.unexplained_faces/1` is where that promise is kept, and
`unproved/1` names the records whose evidence it could not verify.
- A B-rep has no colour. `Quiddity.Frame.rgba/2` is *shading*, so an `hsv`
feature read from a CAD frame says how the surface turns, not what it is
painted.
- A geometry handle is a Rust resource: it serves every process on its node at
once and cannot be sent to another node.
## Licence
MPL-2.0 (`LICENSE`). The engine it binds is Apache-2.0 and stays a dependency;
`NOTICE` says what came from where.