ANYgeometry
ANYgeometry is the lightweight, deterministic structural-surface geometry kernel shared by ANYmesher, ANYfem, and ANYstructure. It owns neutral geometry, topology, persistent entity references, semantic groups, geometry evaluation, edits, intersections, and geometry serialization. Meshing, finite-element attributes, materials, loads, solver state, project data, and GUIs stay in their owning packages.
The kernel is intentionally focused on engineering plates, beams, panels, cylinders, cones, frames, and shell intersections. It is not a general solid CAD kernel and does not depend on OpenCASCADE, Gmsh, a GUI toolkit, an FE package, or a solver.
Installation
ANYgeometry requires Python 3.11 or newer and NumPy. Install the released package or a sibling checkout directly:
python -m pip install ANYgeometry
For editable development:
python -m pip install -e C:\Github\ANYgeometry
Planar clipping and strict planar qualification use the optional Shapely
backend. Install the planar extra for those workflows:
python -m pip install -e "C:\Github\ANYgeometry[planar]"
Quick start
Build topology directly:
from anygeometry import GeometryModel
geometry = GeometryModel()
vertices = geometry.add_points(
[(0, 0, 0), (4, 0, 0), (4, 3, 0), (0, 3, 0)]
)
face_id = geometry.add_plate(vertices)
face_ref = geometry.entity_ref("face", face_id) # local compatibility reference
face_handle = geometry.handle("face", face_id) # model-bound public identity
geometry.add_to_group("deck", [face_ref])
LLM and automation contract
anygeometry.automation is a provider-neutral protocol boundary. An LLM may
translate natural language into its bounded JSON/record algebra, but the
kernel never parses prompts, executes generated code, accepts arbitrary method
names, or imports an LLM/MCP SDK.
from anygeometry.automation import Command, CommandBatch, apply_plan, plan_commands
q = lambda xyz: {"value": xyz, "unit": "m", "frame": "model_local"}
commands = tuple(
Command(f"p{i}", "create_point", {"position": q(point)})
for i, point in enumerate(((0, 0, 0), (4, 0, 0), (4, 3, 0), (0, 3, 0)), 1)
) + (
Command("deck", "create_plate", {"vertices": [f"p{i}.vertex" for i in range(1, 5)]}),
)
batch = CommandBatch(1, "make-deck", geometry.model_id, geometry.revision, commands)
plan = plan_commands(geometry, batch) # no IDs allocated; no revision/cache change
result = apply_plan(geometry, plan) # one owner transaction / one ChangeSet
deck_sheet = result.outputs["deck.sheet"][0]
Selectors cover canonical handles and aliases (point→vertex,
plate→sheet), groups/tags, ownership and incidence, exact metadata,
spatial/range predicates, bounded nearest queries, Boolean composition,
deterministic ordering, pagination, and explicit mutation cardinality.
Positions and transforms require both units and model_local/world frame.
See docs/AUTOMATION_PROTOCOL.md.
Or use a structural generator:
from anygeometry.generators import stiffened_panel
geometry = stiffened_panel(
4.0,
3.0,
longitudinal_spacing=1.0,
transverse_spacing=2.0,
semantic_group="deck",
)
deck_faces = geometry.group("deck")
stiffener_edges = geometry.group("longitudinal_stiffeners")
EntityHandle(model_id, kind, id) is the model-bound cross-package identity.
The legacy EntityRef(kind, id) remains a compact local compatibility value.
IDs are allocated monotonically and are never reused, including after rollback
or compatibility undo. Splitting or fragmenting an entity records descendants,
updates groups, tags, and structural uses, and lets clients resolve a stale
selection explicitly.
Geometry model
Vertex,Edge, andFaceprovide topology with persistent IDs.- Public entity stores and records are read-only. Edits go through atomic model
methods or a nested
GeometryModel.transaction(). - Model identity, revision, tolerance, units, and coordinate arrays are
owner-controlled. Use
set_document_settings(...)for revisioned coordinate or tolerance changes; returned arrays cannot be written in place. Part,Sheet,FaceUse, andCoedgepersist plate ownership/incidence;MemberandMemberEdgeUsepersist a physical beam axis across edge splits.AttachmentandJunctiondistinguish declared beam/plate and beam/beam relationships from mere geometric coincidence.Straight,Arc, and lightweight BezierSplinecurves are topology-owned.Plane,Cylinder,Cone,RuledSurface, and explicit or topology-backed Coons patches provide evaluation and local UV coordinates.- Groups carry geometric meaning such as
shell,deck,bottom,boundaries,longitudinal_stiffeners, andring_stiffeners. - Tags provide lightweight geometry annotations. Materials, sections, thicknesses, loads, supports, and mesh controls must reference geometry from outside this package.
General operations include projection, closest-point queries, transforms,
edge/face splitting, trimming, holes, fragmentation, and shell/shell
intersection imprinting. Analytical line/plane/cylinder intersections cover
common structural cases; a bounded NumPy-only engine qualifies every built-in
Straight/Arc/Spline and Plane/Cylinder/Cone/Ruled/Coons operand family. It
returns complete point, curve, or trim-aware region components with local
parameter evidence and fails closed when a work budget or degeneracy remains
unresolved. Planar crossings and axial
plane/cylinder cuts become real shared edges immediately. A transverse closed
ring through a complete conformal cylinder band is imprinted atomically as
exact shared arcs: the plane becomes an inner disk plus an outer annular face,
and every cylinder patch is split above and below the ring. Stable face
lineage, groups, tags, and exact plane/cylinder surfaces are preserved.
FaceIntersection.edges contains the complete ring while the compatible
FaceIntersection.edge accessor remains its deterministic first edge.
Topology-changing intersections require caller intent, for example
intersect_faces(model, a, b, policy=MutationPolicy.IMPRINT). Query-only
calls use fragment=False; KEEP_SEPARATE_PART retains both inputs without
imprinting. clip_line_to_face returns every planar material interval and
subtracts holes instead of collapsing a concave or holed face to one span.
The qualified closed-ring topology path deliberately requires at least three positive-sweep cylinder patches forming one complete conformal band, a cut strictly inside the cylinder height, and a convex straight-edged plane face without existing holes that fully contains the ring. Oblique cuts, partial or nonconformal bands, and planes needing nested trim classification remain non-mutating intersection-query workflows rather than being approximated with unrelated edges.
Qualified predicates return typed IntersectionResult values that distinguish
crossing, touching, overlap, coincidence, disjoint, and unclassified cases.
Curved components carry IntersectionCertificate evidence and typed parameter
loops/traces; only complete certificates may feed atomic imprinting. An
optional IntersectionQualificationPolicy controls bounded work without
changing model-owned tolerances. Multi-component curve imprints and qualified
full or contained coincident-region CONNECT preserve structural ownership and
are idempotent on immediate reapplication.
The model-owned TolerancePolicy separates computational, merge, angular,
parameter, area, and surface-residual tolerances using local feature extent,
so translating a complete model does not change a local classification.
geometry.strict_audit() performs deterministic fail-closed full-model
qualification with a spatial broad phase. It checks duplicate/crossing/
overlapping edges, T-junctions, sheet manifoldness, structural member intent,
member-face relationships, face overlap, lineage, and unsupported candidates.
Curved candidates use the same public predicate engine in full and
changed-region audit. Any incomplete certificate or unclassified candidate
blocks certification; reports expose subdivision/trace and affected-closure
work counters.
Large beam lattices should use GeometryModel.add_members(...), which builds
all member chains under one part update and one structural validation. Public
remove_member, remove_sheet, remove_part, remove_attachment, and
remove_junction methods enforce dependency order and rollback atomically.
Editable feature history and owner editing
GeometryModel.features stores an ordered, suppressible modelling history.
Feature inputs use FeatureOutputRef so downstream intent does not depend on
the materialized IDs allocated by a later regeneration. EntityHandle is the
model-bound identity for mesh and analysis packages; feature executors and
local compatibility APIs continue to use compact EntityRef values.
from anygeometry import FeatureOutputRef, GeometryModel
geometry = GeometryModel()
first = geometry.features.append(
"geometry.point", parameters={"position": [0.0, 0.0, 0.0]}
)
second = geometry.features.append(
"geometry.point", parameters={"position": [2.0, 0.0, 0.0]}
)
geometry.features.append(
"geometry.line",
inputs={
"start": [FeatureOutputRef(first.feature_id, "point", "vertex")],
"end": [FeatureOutputRef(second.feature_id, "point", "vertex")],
},
)
report = geometry.regenerate_features()
assert report.success
The registry is extensible by namespaced feature kind, allowing consumers to
add executors without a reverse dependency. Regeneration is atomic, retains
replacement lineage, and reserves IDs above the old materialization so a
stale EntityRef can never be silently reused for a different output.
Flat-face sketches use the built-in geometry.sketch.extrude feature. A
SketchDefinition stores named plane-local points, their ordered path,
distance/coincidence constraints, and the signed normal extrusion distance.
Points are not restricted to the support-face boundary. on_edge and
on_vertex constraints follow the oriented support boundary, and regeneration
returns stable point/*, profile/edge/*, and extrusion/face/* output keys.
The small constraint solver uses minimum-norm corrections and rejects
inconsistent dimensions without changing the live geometry.
High-level owner operations include insert_model, copy_entities, linear
and circular patterns, mirroring, edge/face reversal, deep clone, and typed
measure results. Insertion remaps all topology with fresh IDs, preserves
groups, tags, surfaces, holes, and metadata, and deliberately does not weld
coincident entities.
AffineTransform provides validated translation, axis-angle rotation, scale,
reflection, composition, inverse, and point-array evaluation. In-place
translate_entities / rotate_entities preserve model-bound identities;
copy_translated / copy_rotated allocate fresh identities. Arbitrary
transform lists use pattern_entities, while rectangular_pattern creates a
deterministic one-, two-, or three-axis Cartesian array. Rectangular counts are
copy steps beyond the unchanged original, so counts (1, 1) produce the other
three positions of a 2x2 array. Pattern implementations extract the selected
geometry and structural closure once rather than cloning unrelated model data.
Serialization and CLI
Geometry schema 4 is deterministic and checksummed. It preserves model UUID and revision, coordinates/CRS and tolerance policy, allocator high-water marks, support surfaces and optional parameterizations, construction/control ownership, curves/trims, structural ownership and qualified relationships, groups, tags, geometry and structural lineage, extensions, and feature history. Schemas 1–3 migrate conservatively and one-way; malformed current documents fail closed:
from anygeometry import read_geometry, write_geometry
write_geometry("panel.anygeometry.json", geometry)
restored = read_geometry("panel.anygeometry.json")
Certified output additionally requires a clean strict audit:
write_geometry("panel.certified.anygeometry.json", geometry, certified=True)
certified=True is a validation gate, not a persisted certificate. The audit
report is an ephemeral result bound to the exact model UUID, revision, and
audit policy; schema 4 intentionally stores no reusable certification flag.
Consumers that require a qualified handoff must retain or rerun
strict_audit() for that exact revision.
JSON and gzip-compressed JSON are supported. Mesh and FEM/project serialization remain outside ANYgeometry.
ANYgeometry 0.4.0 reads schemas 1–4 and writes schema 4. Automation consumers
use ANYgeometry>=0.4,<0.5; geometry-only consumers may continue using schema
4 through the public codecs. A 0.2.0 reader intentionally rejects a
schema-4 document. Downstream packages should use the public codecs rather
than parse schema records. Legacy relationship evidence migrates as
UNVERIFIED and never implies exactness or certification.
Trusted importers and local script features that have already materialized
topology through GeometryModel operations can bind that exact last-good
materialization without mutating detached feature records:
geometry.features.adopt_frozen(
geometry,
kind="vendor.script.feature",
outputs={"face": EntityRef("face", face_id)},
)
adopt_frozen accepts only active IDs in the history's owning model; it never
retargets through replacement lineage or geometric proximity. ANYgeometry
computes the closure checksum and publishes the history update atomically.
Callers that already certified a closure may pass expected_checksum= to make
the adoption fail closed if the topology changed.
Feature edits mark the affected record dirty. For additive modelling features, regeneration starts at the earliest dirty record on a clone of the live materialization. The clean prefix keeps its exact entity IDs. A replayed output keeps its prior binding only when its stable output-key set and complete ID-independent topology closure are exactly equal; otherwise its replacement is allocated above the previous ID high-water mark and lineage is extended. This comparison uses no distance, tolerance, or nearest-geometry retargeting.
Ordinary output revalidates complete topological and structural integrity. Certified output adds the full global geometric audit before writing, but the ordinary and certified schema-4 payload shapes are identical. Feature history is owner-observed and validated before writing; direct record tampering is never accepted as a checksummed document.
The package module can create an example or inspect a saved geometry:
python -m anygeometry --version
python -m anygeometry --write-example panel.anygeometry.json
python -m anygeometry panel.anygeometry.json --json
Dependency direction
The intended dependency graph is one-way:
ANYgeometry <- ANYmesher <- ANYfem
^ ^
| |
ANYstructure -------+
ANYgeometry never imports ANYmesher, ANYfem, ANYstructure, ANYsolver, a GUI,
or a finite-element package. See MIGRATION.md when moving code
from the historical anymesher.geometry namespace.
Development
python -m pip install -e ".[dev]"
python -m pytest
python -m build
python -m twine check dist\*
The test suite qualifies persistent identity and history, topology, curves, surfaces, generators, operations, serialization, intersections, CLI behavior, and import boundaries.
The strict-kernel design, invariants, benchmark scope, and completed release
qualification are recorded in
docs/KERNEL_UPDATE_OVERVIEW.md and
KERNEL_UPDATE_REPORT.md.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file anygeometry-0.4.0.tar.gz.
File metadata
- Download URL: anygeometry-0.4.0.tar.gz
- Upload date:
- Size: 412.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d16f2860db17284205f32a7e91dad61d75423ff37d18419e101a17fb982b7f61
|
|
| MD5 |
8c22ccd82388c8b03d64fd6d9cb06f49
|
|
| BLAKE2b-256 |
c0e9fa638ad7e2ff0effe92cbe88409450ab93a107ce419256c5f3ceb1b4f920
|
Provenance
The following attestation bundles were made for anygeometry-0.4.0.tar.gz:
Publisher:
publish.yml on audunarn/ANYgeometry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anygeometry-0.4.0.tar.gz -
Subject digest:
d16f2860db17284205f32a7e91dad61d75423ff37d18419e101a17fb982b7f61 - Sigstore transparency entry: 2583019353
- Sigstore integration time:
-
Permalink:
audunarn/ANYgeometry@069f22f3682ab97c89eb7824d53010c0b60dd575 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/audunarn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@069f22f3682ab97c89eb7824d53010c0b60dd575 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file anygeometry-0.4.0-py3-none-any.whl.
File metadata
- Download URL: anygeometry-0.4.0-py3-none-any.whl
- Upload date:
- Size: 347.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b84d903dd2c990e814b1337a4f8272f9fa0d5bbeb5d107850225dc11770c666e
|
|
| MD5 |
a2ee8933462de56a22ce7ed5a44aa568
|
|
| BLAKE2b-256 |
fade74e7109531ff98ecded6057b7d213f9ad958ab6d842d0b89cd5652f5068a
|
Provenance
The following attestation bundles were made for anygeometry-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on audunarn/ANYgeometry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anygeometry-0.4.0-py3-none-any.whl -
Subject digest:
b84d903dd2c990e814b1337a4f8272f9fa0d5bbeb5d107850225dc11770c666e - Sigstore transparency entry: 2583019378
- Sigstore integration time:
-
Permalink:
audunarn/ANYgeometry@069f22f3682ab97c89eb7824d53010c0b60dd575 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/audunarn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@069f22f3682ab97c89eb7824d53010c0b60dd575 -
Trigger Event:
workflow_dispatch
-
Statement type: