Skip to main content

ifc_geometry/authoring/
mod.rs

1//! Author IFC geometry entities from plain numbers.
2//!
3//! The write direction of this bridge (ADR 0011). Everything here is
4//! kernel-free: arguments are `f64`, `[f64; 3]`, and index buffers, no
5//! signature names an axiolid type, and the module compiles with
6//! `--no-default-features`. That is what lets an application compute with
7//! CGAL, OCCT, or Axiolid and still author through one API -- the kernel is
8//! a source of numbers, never a dependency of the writer.
9//!
10//! IFC geometry entities are exact *descriptions*, not evaluations, so
11//! writing them needs no evaluator. A cut is stored as an unevaluated
12//! `IfcBooleanResult`: this module never tessellates, matching the standing
13//! invariant of the read direction.
14//!
15//! Slot positions are not restated here. Each writer indexes the same
16//! `pub(crate) mod slot` constants its reader uses, so a layout correction
17//! lands once and serves both directions.
18//!
19//! Values follow the declared attribute type (#200): a defined type such as
20//! `IfcParameterValue` is written bare, and only a SELECT slot carries the
21//! typed parameter of its member. Where a slot changes kind between releases
22//! (the directrix sweeps' trims), a `*_in` writer takes the model and binds
23//! its declared release.
24
25mod brep;
26mod connection;
27mod csg;
28mod curve;
29mod grid;
30mod placement;
31mod profile;
32mod profile2;
33mod release;
34mod solid;
35mod spiral;
36mod std_profile;
37mod surface;
38mod surface_curve;
39mod swept;
40mod swept_in;
41mod tessellation;
42mod transform;
43
44pub use brep::{
45    bare_topology, edge, edge_curve, edge_loop, face, face_based_surface_model, face_bound,
46    face_outer_bound, face_surface, manifold_solid_brep, oriented_edge, poly_loop, shell,
47    shell_based_surface_model, subedge, vertex_loop, vertex_point, BareTopology, BrepKind,
48    ShellKind,
49};
50pub use connection::{
51    boolean_clipping_result, connection_geometry, connection_point_eccentricity, geometric_set,
52    grid_axis, grid_placement, local_placement, path, point_on_curve, point_on_surface,
53    sectioned_spine, virtual_grid_intersection, ConnectionKind,
54};
55pub use csg::{
56    block, bounding_box, boxed_half_space, cone, csg_solid, cylinder, half_space,
57    polygonal_bounded_half_space, rectangular_pyramid, sphere,
58};
59pub use curve::{
60    bspline_curve_with_knots, circle, composite_curve, composite_curve_segment, ellipse,
61    indexed_poly_curve, line, offset_curve_2d, offset_curve_3d, offset_curve_by_distances,
62    polynomial_curve, rational_bspline_curve_with_knots, segmented_reference_curve, trimmed_curve,
63    vector, KnotVector, PolyCurveSegment, PolynomialCoefficients,
64};
65pub use grid::{grid, grid_with_owner_history};
66pub use placement::{axis2_placement_2d, axis2_placement_3d, cartesian_point, direction};
67pub use profile::{
68    arbitrary_closed_profile, circle_profile, polyline, rectangle_profile, ProfileType,
69};
70pub use profile2::{
71    arbitrary_open_profile, arbitrary_profile_with_voids, center_line_profile, composite_profile,
72    derived_profile, mirrored_profile, open_cross_profile, profile_def, rounded_rectangle_profile,
73};
74pub use solid::{boolean_result, extruded_area_solid, revolved_area_solid};
75pub use spiral::{spiral, SpiralKind};
76pub use std_profile::{
77    asymmetric_i_shape, c_shape, circle_hollow_profile, ellipse_profile, i_shape, l_shape,
78    rectangle_hollow_profile, t_shape, trapezium_profile, u_shape, z_shape, AsymmetricIDims,
79    AsymmetricIExtras, CShapeDims, FlangedDims, IShapeDims, IShapeExtras, LShapeExtras,
80    ProfileHeader, RectangleHollowDims, RectangleHollowFillets, TShapeExtras, TrapeziumDims,
81    UShapeExtras, ZShapeExtras,
82};
83pub use surface::{
84    bspline_surface_with_knots, curve_bounded_plane, curve_bounded_surface,
85    rational_bspline_surface_with_knots, rectangular_trimmed_surface, spherical_surface,
86    toroidal_surface, SurfaceBasis, SurfaceKnots,
87};
88pub use surface_curve::{
89    composite_curve_on_surface, curve_segment, gradient_curve, pcurve,
90    reparametrised_composite_curve_segment, surface_curve, CurveMeasure, OnSurfaceKind,
91    SurfaceCurveKind, SurfaceCurveRepresentation,
92};
93pub use swept::{
94    axis1_placement, cylindrical_surface, directrix_derived_reference_swept_area_solid,
95    extruded_area_solid_tapered, fixed_reference_swept_area_solid, plane,
96    revolved_area_solid_tapered, sectioned, surface_curve_swept_area_solid,
97    surface_of_linear_extrusion, surface_of_revolution, swept_disk_solid,
98    swept_disk_solid_polygonal, SectionedKind, SweepTrim,
99};
100pub use swept_in::{fixed_reference_swept_area_solid_in, surface_curve_swept_area_solid_in};
101pub use tessellation::{
102    cartesian_point_list_2d, cartesian_point_list_3d, indexed_polygonal_face,
103    indexed_polygonal_face_with_voids, polygonal_face_set, triangulated_face_set,
104    triangulated_irregular_network, TriangulatedExtras,
105};
106pub use transform::{
107    mapped_item, representation_map, shape_aspect, topology_representation,
108    transformation_operator_2d, transformation_operator_2d_non_uniform, transformation_operator_3d,
109    transformation_operator_3d_non_uniform, Transform,
110};
111
112use ifc_model::{EntityId, Value};
113
114use crate::error::GeometryError;
115
116/// Build an [`GeometryError::InvalidAuthoredValue`].
117fn invalid(
118    type_name: &'static str,
119    attribute: &'static str,
120    detail: impl Into<String>,
121) -> GeometryError {
122    GeometryError::InvalidAuthoredValue {
123        type_name,
124        attribute,
125        detail: detail.into(),
126    }
127}
128
129/// Refuse NaN and infinity before they reach a file.
130///
131/// Every downstream consumer -- placement composition, profile bounds,
132/// tessellation -- assumes finite input, and a NaN coordinate propagates
133/// silently through all of them rather than failing where it was introduced.
134fn require_finite(
135    type_name: &'static str,
136    attribute: &'static str,
137    values: &[f64],
138) -> Result<(), GeometryError> {
139    if let Some(bad) = values.iter().position(|v| !v.is_finite()) {
140        return Err(invalid(
141            type_name,
142            attribute,
143            format!("value at index {bad} is not finite"),
144        ));
145    }
146    Ok(())
147}
148
149/// A list of `IfcReal`/`IfcLengthMeasure` values.
150fn reals(values: &[f64]) -> Value {
151    Value::List(values.iter().copied().map(Value::Real).collect())
152}
153
154/// A list of entity references.
155fn refs(ids: &[EntityId]) -> Value {
156    Value::List(ids.iter().copied().map(Value::Ref).collect())
157}