1
2use serde::{Deserialize, Serialize};
3use wasm_bindgen::prelude::*;
4
5macro_rules! env_read {
10 ($name:literal) => {{
11 static CELL: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
12 $crate::env_read::read($name, &CELL)
13 }};
14}
15#[macro_export]
23macro_rules! switch {
24 (live $name:expr, $default:expr) => {
25 $crate::env_read::switch_live($name, $default, $crate::env_read::Grammar::Switch)
26 };
27 ($name:expr, $default:expr) => {{
28 static CELL: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
29 $crate::env_read::switch($name, &CELL, $default, $crate::env_read::Grammar::Switch)
30 }};
31}
32
33#[macro_export]
37macro_rules! debug_flag {
38 (live $name:expr) => {
39 $crate::env_read::switch_live($name, false, $crate::env_read::Grammar::Flag)
40 };
41 ($name:expr) => {{
42 static CELL: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
43 $crate::env_read::switch($name, &CELL, false, $crate::env_read::Grammar::Flag)
44 }};
45}
46
47#[macro_export]
51macro_rules! mode_switch {
52 (live $name:expr, $default_on:expr) => {
53 $crate::env_read::mode_live($name, $default_on)
54 };
55 ($name:expr, $default_on:expr) => {{
56 static CELL: std::sync::OnceLock<Option<$crate::env_read::Mode>> = std::sync::OnceLock::new();
57 $crate::env_read::mode($name, &CELL, $default_on)
58 }};
59}
60
61macro_rules! profile_line {
64 ($($arg:tt)*) => { $crate::profile::profile_emit(format_args!($($arg)*)) };
65}
66
67#[cfg(all(feature = "wasm-talc", target_family = "wasm", not(target_feature = "atomics")))]
69#[global_allocator]
70static TALC: talc::wasm::WasmDynamicTalc = talc::wasm::new_wasm_dynamic_allocator();
71
72#[cfg(all(feature = "native-rusty-alloc", not(target_family = "wasm")))]
74#[global_allocator]
75static RUSTY_ALLOC: rusty_alloc_api::RustyAlloc = rusty_alloc_api::RustyAlloc;
76
77mod profile;
78
79#[doc(hidden)]
82pub mod env_read;
83
84pub mod panic_hook;
89
90pub mod text;
93
94#[path = "geometry/tolerance.rs"]
95mod tolerance;
96pub use tolerance::{
97 curve_model_scale, model_scale, report_scale_migration, solid_model_scale, solid_scale,
98 offset_construction_band, vertex_tolerance_from_edges, KernelTolerances,
99 MeasuredTolerance, OFFSET_CONSTRUCTION_FLOOR, OFFSET_CONSTRUCTION_REL,
100 VERTEX_MATCH_FLOOR, VOLUME_DRIFT_ABS, VOLUME_DRIFT_REL,
101};
102#[path = "geometry/entity_tolerance.rs"]
107mod entity_tolerance;
108pub use entity_tolerance::{EntityTolerances, EDGE_CAP_FRACTION, VERTEX_CAP_FRACTION};
109#[path = "props/diagnostics.rs"]
110mod diagnostics;
111pub use diagnostics::{
112 Approximation, ApproximationBudget, Backing, BudgetMechanism, BudgetReason, MeasuredComponent, DiagnosticEvent, DiagnosticSeverity, EdgeOrigin, KernelDiagnostics,
113 KernelOutcome, KernelRefusal, OffCarrierEdge,
114 KernelStage, OrRefuse, RefusalClass, SoundnessDefect, UndecidedCause,
115};
116#[path = "geometry/polygon.rs"]
117pub mod polygon;
118#[path = "geometry/curve.rs"]
119mod curve;
120pub use curve::{
121 make_arc, make_circle, make_hyperbola, make_line, make_parabola, uniform_clamped_knots,
122 KnotVector, NurbsCurve, Vec4, KNOT_DEDUP_EPS, KNOT_IDENTITY_TOL,
123};
124#[path = "blending/blend/mod.rs"]
125mod blend;
126pub use blend::{
127 take_blend_approximations, take_blend_notes,
128 blend_timing_capture, take_blend_timings, BlendTiming,
129 blend_closed_edge, blend_edge_variable, blend_open_edge, blend_smooth_chain,
130 round_convex_corner,
131};
132#[path = "blending/fillet.rs"]
133mod fillet;
134pub use fillet::{
135 chamfer_edge, chamfer_edge_angle, chamfer_edge_asymmetric, chamfer_edges_angle,
136 chamfer_edges_asymmetric, fillet_edge, fillet_edges, fillet_edges_reported, fillet_edges_reported_at_offset,
137 fillet_edges_variable, fillet_edges_variable_law, fillet_edges_variable_vertex_radii,
138 BlendSelection,
139};
140#[path = "blending/law.rs"]
141mod law;
142pub use law::{LawSegment, RadiusLaw};
143#[path = "geometry/fit.rs"]
144mod fit;
145pub use fit::{
146 fit_polyline, fit_polyline_at, fit_polyline_of_degree, interpolate_curve, interpolate_curve_closed,
147 interpolate_curve_local, interpolate_curve_thinned, interpolate_curve_with_end_tangents,
148 simplify_polyline, simplify_polyline_indices, solve_banded, solve_dense, PolylineFit,
149 PolylineFitExit, PolylineFitLedger, PolylineFitReport, PolylineFitScope, MAX_FIT_STATIONS,
150};
151#[path = "geometry/image_curve.rs"]
152mod image_curve;
153pub use image_curve::{affine_image_curve, image_curve, image_curve_pair, ImageCurve, ImageCurveTier};
154#[path = "geometry/surface.rs"]
155mod surface;
156pub use surface::{
157 carrier_preview_patch, make_cone_surface, make_cylinder_surface, make_extrusion, make_plane,
158 make_revolution, make_sphere_surface, make_sphere_surface_framed, make_torus_surface,
159 ExtendRefusal, NurbsSurface, SurfaceSide, WeightSite, MAXIMUM_FOLD_ANGLE,
160 MAXIMUM_GROWTH_RATIO,
161};
162#[path = "geometry/control_cage.rs"]
163mod control_cage;
164pub use control_cage::{
165 CagePoint, CagePrimitive, ControlCage, CAGE_DEGREE, MAX_RINGS, MAX_SEGMENTS, MIN_RINGS,
166 MIN_SEGMENTS,
167};
168#[path = "geometry/coons.rs"]
169mod coons;
170pub use coons::{
171 coons_bilinear, coons_bilinear_reported, coons_with_ribbons, CompatWork, CoonsRefusal,
172 CoonsReport, RibbonReport,
173};
174#[path = "geometry/gordon.rs"]
175mod gordon;
176pub use gordon::{gordon_surface, gordon_surface_reported, GordonRefusal, GordonReport};
177#[path = "geometry/analytic_surface.rs"]
178mod analytic_surface;
179pub use analytic_surface::{
180 circle_angle_to_parameter, intersect_analytic_pair, plane_ruled_section_arc,
181 revolution_structure, AnalyticSurface, RevolutionFrame, RevolutionStructure,
182};
183pub(crate) use analytic_surface::{
184 canonical_carriers_enabled, canonicalise_carriers, intersect_analytic_pair_with, ruled_gate,
185 ruled_gate_census, CanonicalReport, CanonicalRewrite, RuledGate,
186};
187#[path = "geometry/sphere_chart.rs"]
188mod sphere_chart;
189pub use sphere_chart::{
190 canonicalize_points, chart_grid_divisions, chart_grid_parameters, corner_index,
191 cube_edge_corner, cube_edge_divisions, cube_edge_index, cube_edge_parameters,
192 cube_edge_parts, Chart, ChartSegment, ChartSide, SphereAtlas,
193 SphericalRegion, CHART_COUNT, CUBE_CORNER_COUNT, CUBE_EDGE_COUNT,
194};
195#[path = "brep/solid_codec.rs"]
196mod solid_codec;
197pub use solid_codec::{decode_solid, encode_solid, SolidNames, SOLID_CODEC_VERSION, SOLID_CODEC_VERSION_KIND};
198#[path = "brep/topology.rs"]
199mod topology;
200pub use topology::{
201 make_box_brep, make_cylinder_brep, make_pyramid_brep, topology_kind, BodyKind, BrepSolid, CellRecord,
202 FaceRecord, IssueKind, KindReport, TopologyKind, ValidationReport,
203};
204#[path = "brep/soundness.rs"]
205mod soundness;
206pub use soundness::{
207 face_self_intersections, loop_self_crossings, shell_vector_areas, solid_connectivity,
208 solid_euler, solid_self_intersections, ConnectivityReport, CrossingConfirmation, EulerReport,
209 CertificateScope, CertifiedFacePair, FaceCrossing, FaceFold, FaceVectorArea,
210 LoopCrossing, LoopCrossingReport, SelfIntersectionOptions, SelfIntersectionReport,
211 ClosureReading, ShellConnectivity, ShellVectorArea, VectorAreaReport, CrossingUndecidedCause, UndecidedCrossing,
212 MAX_LISTED_UNDECIDED,
213};
214#[path = "brep/topology_arena.rs"]
215mod topology_arena;
216pub use topology_arena::{
217 ArenaCoedge, ArenaEdge, ArenaFace, ArenaLoop, ArenaShell, ArenaVertex, CoedgeId, EdgeId,
218 FaceId, LoopId, ShellId, TopologyArena, VertexId,
219};
220#[path = "brep/analytic_topology.rs"]
221mod analytic_topology;
222pub use analytic_topology::{
223 make_cone_brep, make_sphere_brep, make_sphere_brep_framed, make_torus_brep,
224};
225#[path = "construction/sweep_topology.rs"]
226mod sweep_topology;
227pub(crate) use sweep_topology::is_sweep_tight_bend;
228pub use sweep_topology::{
229 extrude_profile_brep, extrude_profile_brep_draft, fit_helix_curve, helix_sample_points,
230 profile_anchor, rib_from_profile, sweep_bend_profile, sweep_closure, BendStation,
231 JointContinuity, PathJoint, SweepClosure,
232 RibExtrusion, RibNames, SweepPath, MAX_JOINT_TANGENT_BREAK, SWEEP_TIGHT_BEND_REFUSAL,
233 SWEEP_TWIST_CLOSURE_REFUSAL,
234 build_swept_envelope, recognize_swept_envelope, swept_envelope_volume, SweptEnvelope,
235 SWEEP_ENVELOPE_REFUSAL, sweep_envelope_bodies,
236 sweep_profile_along_chain, sweep_profile_along_chain_reported,
237 sweep_profile_along_chain_with_stations, sweep_profile_along_chain_with_stations_reported,
238 sweep_profile_along_path,
239 sweep_profile_along_path_anchored,
240 sweep_profile_helix,
241 sweep_profile_twisted, sweep_profile_twisted_anchored, ProfileAnchor, SectionPlacement,
242 StationBudget, SweepStationReport, SweptChain, SWEEP_DEFAULT_TOLERANCE, SWEEP_MAX_STATIONS,
243 SWEEP_REFINEMENT_ROUNDS,
244};
245#[path = "construction/revolve_topology.rs"]
246mod revolve_topology;
247pub use revolve_topology::{revolve_profile_brep, revolve_profile_brep_named};
248#[path = "construction/loft_topology.rs"]
249mod loft_topology;
250pub use loft_topology::{
251 loft_profile_brep, loft_profile_brep_closed, loft_profile_brep_guided,
252 loft_profile_brep_guided_frame, loft_profile_brep_tangent,
253};
254pub(crate) use loft_topology::loft_profile_brep_closed_shifted;
255#[path = "brep/transform_topology.rs"]
256mod transform_topology;
257#[path = "brep/recentre.rs"]
258mod recentre;
259pub use transform_topology::{mirror_brep, transform_brep, AffineTransform};
260#[path = "edit/split.rs"]
261mod split;
262pub use split::{
263 split_solid_by_face_surface, split_solid_by_plane, split_solid_by_surface, SplitSurface,
264};
265#[path = "props/mass_properties.rs"]
266mod mass_properties;
267pub use mass_properties::{
268 curve_arc_length, edge_arc_length, face_area, face_boundary_length, face_volume_contribution,
269 face_set_identity, mass_caller, parameter_space_area, solid_edge_length_total,
270 solid_mass_properties,
271 solid_mass_properties_full, signed_volume_against, solid_signed_volume, solid_signed_volume_for_sign, trim_polygons,
272 DensityMassProperties,
273 FaceSetIdentity, FullMassProperties, MassCaller, MassProperties, MassPropertiesCache,
274};
275#[path = "props/carrier_dimensions.rs"]
276mod carrier_dimensions;
277pub use carrier_dimensions::{curve_carrier_dimensions, surface_carrier_dimensions, CarrierDimensions};
278#[path = "meshing/tessellation.rs"]
279mod tessellation;
280pub use tessellation::{tessellate_brep, tessellate_face, TessellationOptions};
281#[path = "meshing/watertight_tessellation/mod.rs"]
282mod watertight_tessellation;
283pub use watertight_tessellation::{
284 sample_edge_polylines, sample_edges_encoded, tessellate_brep_watertight,
285 tessellate_brep_watertight_face_stride, tessellate_brep_watertight_face_stride_with_samples,
286};
287#[path = "feature_pipeline/mod.rs"]
292pub mod feature_pipeline;
293pub use feature_pipeline::execute_history_json;
294pub use feature_pipeline::{first_reference_name, reference_names};
295pub use feature_pipeline::face_transform_pivot;
299pub use feature_pipeline::{
302 clear_history_cache, execute_history, execute_history_observed, AddedSolid, Axis,
303 ComponentRecord, FeatureDescriptor, FeatureRefusal, FeatureResult, Frame, Fulfilment,
304 HistoryProgress, HistoryRequest, Rejected, RejectedKind,
305 HistoryResult, PortKind, PortRecord, ProfileLoop, ScenePoint, SketchProfile,
306};
307pub use feature_pipeline::wire_harness::{
311 bundle_diameter, Attachment as SplineAttachment, BundleStatus, PortSide, RouteResult,
312 RouteStatus,
313 WireHarnessBundle, WireHarnessConnection,
314 WireHarnessEndpoint, WireHarnessReport, WireHarnessState, BUNDLE_SOLID_PREFIX,
315 WIRE_HARNESS_FEATURE_ID, WIRE_HARNESS_FEATURE_TYPE,
316};
317pub use feature_pipeline::part_pins::{
322 declarations as declared_ports, declared_endpoints as declared_point_endpoints,
323 declared_points, endpoint_occurrence, follow_pin_edit, follow_point_edit, pin_labels,
324 pin_point_report, pins,
325 point_renames, port_group_for_unit, resolve_component_pin, resolve_part_pin,
326 unit_count as symbol_unit_count, unit_groups, DeclaredPin, DeclaredPoint, PinPoint,
327 PinPointChange, PinPointProblem, PinPointReport, PointRenames, DEFAULT_PORT_NAME,
328 DEFAULT_PORT_PURPOSE, PADS_BLOCK, SYMBOL_BLOCK,
329};
330pub use feature_pipeline::ports::{
335 address as port_address, document_is_boundary, seat_of as port_seat_of, seat_point,
336 seat_vector, seated_direction, split_address, unit_map, unseat_point, unseat_vector,
337 world_seat, PortDeclaration, PortPoint, PortPointRow, PortSeat, PortsReport, UnitProblem,
338 BOUNDARY_KEY, PORTS_BLOCK, PORTS_FEATURE_ID, PORTS_FEATURE_TYPE,
339};
340pub use feature_pipeline::pmi::{
344 balloon_head as pmi_balloon_head, clamp_text_size, format_dimension, format_number,
345 nearest_point_on_edge, nearest_point_on_solid, pmi_schema_catalogue, pmi_type,
346 nearest_displayed_point, nearest_displayed_point_on_edge, pose_apply as pmi_pose_apply, pose_unapply as pmi_pose_unapply,
347 resolve_state as pmi_resolve_state, entry_names_solid, BalloonAnchor, BalloonAnchorMode, FcfFrame, HalfSpace as PmiHalfSpace, HeadScope as PmiHeadScope, PmiAnnotation,
348 PmiAnnotationReport, PmiCamera, PmiDisplay, PmiGeometry, PmiPlane, PmiPose, PmiProjection, PmiReport,
349 PmiState, PmiStatus, PmiTypeDef, PmiView, PmiViewReport, SolidPoses as PmiSolidPoses, ToleranceBlock, ToleranceMode, PMI_TYPES,
350};
351pub use feature_pipeline::pmi::layout::{present as pmi_present, LayoutStyle as PmiLayoutStyle, Presentation as PmiPresentation};
352pub use feature_pipeline::pmi::annotations::fcf::{characteristic as pmi_characteristic, Characteristic as PmiCharacteristic, CHARACTERISTICS as PMI_CHARACTERISTICS};
353pub use feature_pipeline::assign_sketch_loop_ids;
357pub use feature_pipeline::features::sketch3d::{
361 reference_record as sketch3d_reference_record, resolve_reference as resolve_sketch3d_reference,
362 ResolvedReference as Sketch3dResolvedReference, REFERENCE_TIP_LENGTH as SKETCH3D_REFERENCE_TIP_LENGTH,
363 SKETCH3D_DOC_KEY, SKETCH3D_EDIT_BUTTON, SKETCH3D_FEATURE_TYPE, SKETCH3D_REFERENCES_PARAM,
364 SKETCH3D_REFS_KEY,
365};
366pub use feature_pipeline::{flat_pattern_dxf, flat_pattern_svg, is_sheet_metal_handle};
368pub use feature_pipeline::{pattern_component_instance, pattern_parse_suppressed};
370pub use feature_pipeline::{native_import_payload, native_import_payload_with_appearance};
374pub use feature_pipeline::IsolatedSceneMetadata;
377pub use feature_pipeline::scene_metadata_colors_json;
380pub use feature_pipeline::family;
383pub use feature_pipeline::{
386 add_part_to_library, add_part_to_library_impl, install_parts_library, missing_library_parts,
387 parts_library_json, parts_library_map, parts_library_revision, refresh_library_entry,
388 refresh_library_entry_impl, same_build, follow_saved_rows, follow_saved_rows_known, kernel_source_stamp, stable_json_hash, PartsLibraryEntry, PartsLibraryMap,
389};
390pub use feature_pipeline::assembly::{
393 assembly_add_constraint_json, assembly_apply_document_json,
394 assembly_apply_inferred_constraints_json, assembly_component_entities_json, assembly_dof_json,
395 assembly_infer_constraints_json, assembly_inferable_types_json,
396 assembly_move_constraint_json, assembly_overlay_json, assembly_pose_updates_json,
397 assembly_drag_solve_json, assembly_frame_solve_json, assembly_remove_constraint_json, assembly_resolve_refs_json,
398 assembly_run_solve_json,
399 assembly_set_constraint_enabled_json, assembly_set_constraint_open_json,
400 assembly_state_json, assembly_statuses_json, assembly_update_constraint_json,
401 constraint_hidden_params, constraint_schema_catalogue,
402 assembly_add_constraint_impl, assembly_apply_document_impl, assembly_move_constraint_impl,
405 assembly_drag_solve_impl, assembly_frame_solve_impl, assembly_flip_plan_json, assembly_rebase_mechanical_impl, assembly_remove_constraint_impl, assembly_run_solve_impl,
406 assembly_set_constraint_enabled_impl, assembly_set_constraint_open_impl,
407 assembly_update_constraint_impl,
408 assembly_session_export, assembly_session_import, assembly_session_serial, RetiredSession, SessionTransfer,
409};
410pub use feature_pipeline::{AssemblyState, ConstraintEntry};
411pub use feature_pipeline::assembly::transform_to_pose_params;
414pub use feature_pipeline::feature_schema_catalogue;
417pub use feature_pipeline::feature_hidden_params;
420pub use feature_pipeline::assembly::{constraint_type, ConstraintTypeDef, CONSTRAINT_TYPES};
423pub use feature_pipeline::{feature_context_applicable, SelectionProbe};
424pub use feature_pipeline::Env;
430
431pub fn eval_expression(
436 expressions: &str,
437 configurator_json: &serde_json::Value,
438 source: &str,
439) -> Result<f64, String> {
440 Env::build(expressions, configurator_json).and_then(|env| env.eval(source))
441}
442
443#[cfg(feature = "wasm-threads")]
450pub use wasm_bindgen_rayon::init_thread_pool;
451#[path = "geometry/projection.rs"]
452mod projection;
453#[path = "geometry/projection_profile.rs"]
454mod projection_profile;
455#[doc(hidden)]
456pub use projection_profile::report as projection_profile_report;
457#[path = "geometry/affine_sphere.rs"]
458mod affine_sphere;
459pub use projection::{
460 project_point_to_curve, project_point_to_surface, project_point_to_surface_seeded,
461 CurveProjection, SurfaceProjection,
462};
463#[doc(hidden)]
464pub use projection::{
465 project_point_to_surface_basin_census, project_point_to_surface_general_lanes, BasinCensus,
466 GlobalStats,
467};
468#[path = "intersect/curve_surface_intersection.rs"]
469mod curve_surface_intersection;
470pub use curve_surface_intersection::{intersect_curve_surface, CurveSurfaceIntersection};
471#[path = "intersect/exact_line_surface.rs"]
472mod exact_line_surface;
473#[path = "intersect/curve_curve_intersection.rs"]
474mod curve_curve_intersection;
475pub use curve_curve_intersection::{intersect_curves, CurveCurveIntersection};
476#[path = "intersect/surface_surface_intersection.rs"]
477mod surface_surface_intersection;
478pub use surface_surface_intersection::{
479 intersect_surfaces, intersect_surfaces_supplemental, SurfaceIntersectionCurve,
480 SurfaceIntersectionOptions,
481};
482pub(crate) use surface_surface_intersection::TRANSVERSE_SEED_CROSS;
483#[path = "intersect/tangent_curve.rs"]
484mod tangent_curve;
485pub use tangent_curve::{
486 classify_tangent_contact_at, find_tangent_contact, trace_tangent_curve, TangentContact,
487 EXTENDED_RANK_FLOOR,
488};
489#[path = "brep/classification.rs"]
490mod classification;
491pub use classification::{
492 classify_point, containment_lane, horizon_cross_frame, parameter_point_in_face,
493 trim_sample_count, trim_station, ContainmentLane, PointClass, PointClassification,
494 PolygonClass, SolidClassifier, COVERING_RIM_STRIP_SWITCH, HORIZON_CONTAINMENT_SWITCH,
495 HORIZON_CROSS_FRAME_SWITCH, HORIZON_SINGLE_LOOP_SWITCH, NO_SPHERE_CHART_TRIM_SWITCH,
496 SEAM_BAND_MERGED_SWITCH,
497};
498#[doc(hidden)]
499pub use classification::parameter_point_in_face_scan;
500#[path = "geometry/spatial.rs"]
501mod spatial;
502pub use spatial::{Aabb, Bvh};
503#[path = "brep/pair_classification.rs"]
504mod pair_classification;
505pub use pair_classification::{
506 classify_surface_pair, classify_surface_pair_cached, SurfaceClassifyData,
507 SurfacePairClassification, SurfacePairRelation,
508};
509#[path = "intersect/arrangement.rs"]
510mod arrangement;
511pub use arrangement::{
512 arrange_segments, point_in_polygon, segment_intersection, ArrangementPiece, ArrangementRegion,
513 CycleUse, Segment2, Vec2,
514};
515#[path = "geometry/pcurve.rs"]
516mod pcurve;
517pub use pcurve::{
518 build_pcurve_on_surface, build_pcurve_on_surface_marched, build_pcurve_on_surface_range,
519 build_pcurve_on_surface_range_dense, build_pcurve_on_surface_stations, fit_pcurve_on_surface,
520 fit_pcurve_on_surface_marched, fit_pcurve_on_surface_range, fit_pcurve_on_surface_range_dense,
521 fit_pcurve_on_surface_stations, PcurveFit, PcurveFitExit, PcurveFitLedger, PcurveFitReport,
522 PcurveFitScope, PCURVE_OFF_BAR, PCURVE_REFINEMENT_TOLERANCE,
523};
524#[path = "csg/imprint.rs"]
525mod imprint;
526pub use imprint::{
527 build_imprints, EdgeSplitRecord, FaceImprints, FaceKey, FacePcurve, ImprintOptions,
528 ImprintPieceRecord, ImprintResultRecord, ImprintVertex, TangentSectionRecord,
529};
530#[path = "csg/edge_split.rs"]
531mod edge_split;
532pub use edge_split::{apply_edge_splits, apply_edge_splits_with_map};
533#[path = "csg/fragment.rs"]
534mod fragment;
535pub use fragment::{
536 fragment_face, fragment_solid, FaceFragmentRecord, FragmentCoedge, FragmentEdgeSource,
537 FragmentLoop, FragmentOrder,
538};
539#[path = "csg/boolean/mod.rs"]
540mod boolean;
541pub use boolean::{
542 boolean_operation, boolean_operation_nary, boolean_operation_nary_with_options, boolean_operation_with_diagnostics, boolean_operation_with_diagnostics_at_offset, boolean_split_operands,
543 BooleanOperation, BooleanOptions,
544};
545#[path = "csg/oracle.rs"]
546mod oracle;
547pub use oracle::{
548 boolean_residual_fusables, boolean_semantic_disagreement, boolean_semantic_disagreement_nary,
549 OracleReport, ResidualFusable, ResidualKind, SemanticDisagreement, DISAGREEMENT_THRESHOLD,
550};
551#[path = "healing/heal.rs"]
552mod heal;
553#[path = "healing/reading_memo.rs"]
556mod reading_memo;
557#[path = "healing/accept.rs"]
563mod accept;
564pub use accept::{
565 accept_sound, accept_sound_against, accept_sound_against_scoped, resolve_face_crossing, resolve_face_crossing_between,
566 take_crossing_repairs,
567 CrossingRepairRecord,
568};
569#[path = "offset/point.rs"]
574mod offset_point;
575pub use offset_point::{OffsetEvaluator, OffsetNormal, OffsetSample};
576#[path = "offset/analytic_pair.rs"]
583mod offset_analytic_pair;
584#[path = "offset/retrim.rs"]
591mod offset_retrim;
592#[path = "offset/reintersect.rs"]
600mod offset_reintersect;
601#[path = "offset/measure.rs"]
611mod offset_measure;
612pub use offset_measure::{
613 measure_edge_against_pcurve_image, measure_surface_fit_against_pointwise_offset,
614 span_midpoint_error, vertex_endpoint_gap,
615};
616#[path = "offset/offset.rs"]
617mod offset;
618pub use offset::{
619 offset_face_carrier, offset_face_carrier_measured, offset_face_carrier_sided, offset_surface,
620 offset_surface_measured, offset_surface_measured_sided, CarrierDeviation, CarrierExtension,
621 MeasuredOffsetSurface, OffsetFaceCarrier, OffsetSurfaceLane,
622};
623#[path = "offset/regularity.rs"]
629mod offset_regularity;
630#[path = "offset/fold_locus.rs"]
636mod offset_fold_locus;
637#[path = "offset/carve.rs"]
643mod offset_carve;
644#[path = "offset/thicken.rs"]
645mod thicken;
646pub use thicken::{thicken_face_sheet, thicken_trimmed_sheet};
647#[path = "healing/coalesce.rs"]
648mod coalesce;
649pub use coalesce::{concatenate_exact_curve_pieces, merge_curve_continuation_edges};
650#[path = "healing/face_merge.rs"]
651mod face_merge;
652#[allow(dead_code)]
655#[path = "healing/faceted_repair.rs"]
656mod faceted_repair;
657pub use face_merge::{merge_faces_within, merge_same_surface_faces, merge_same_surface_faces_excluding, merge_same_surface_faces_scoped};
658pub use faceted_repair::{mesh_to_faceted_brep, repair_triangle_soup, MeshRepairReport};
659#[path = "offset/offset_shell.rs"]
660mod offset_shell;
661pub use offset_shell::{
662 offset_shell, offset_shell_by_boolean, offset_shell_closed, offset_shell_with_diagnostics, offset_solid, OffsetCorners,
663 OffsetFaceRole, OffsetShellFaceImageRecord, OffsetShellResultRecord,
664};
665pub(crate) use offset_shell::{is_offset_shell_no_retained_face, is_offset_shell_open_curved_rim};
666#[path = "io/step_matrix.rs"]
667mod step_matrix;
668#[path = "io/step.rs"]
669mod step;
670pub use step::{
671 assembly_export_tree, audit_step_manifold, audit_step_pcurves, export_step,
672 export_step_assembly, export_step_assembly_report, export_step_report,
673 export_step_report_named, Mat4, StepAssemblyExport, StepColors, StepExportOccurrence,
674 StepExportProduct, StepExportReport, StepPmi, PART_ATTRIBUTES, PART_NUMBER,
675};
676#[path = "io/appearance.rs"]
680mod appearance;
681pub use appearance::{BodyAppearance, ImportedColor, COLOR_METADATA_KEY};
682#[path = "io/step_import/mod.rs"]
683mod step_import;
684pub use step_import::{
685 import_step, import_step_bodies, import_step_report, import_step_trim_readings, import_step_with_appearance,
686 occurrence_ref_parts, read_step_assembly, read_step_pmi, rewrite_occurrence_refs,
687 ImportedStep, StepAssembly, StepBodyError, StepBodyTrimReadings, StepEdgeReading, StepFaceReading, StepImportReport,
688 StepOccurrence, StepProduct, StepSuppliedTrim, StepTrimReadings, OCCURRENCE_REF_PREFIX,
689 STATED_PRECISION_INCONSISTENCY_RATIO,
690};
691#[doc(hidden)]
693pub fn io_step_text_for_tests(value: &str) -> String {
694 step::pmi::step_text(value)
695}
696#[doc(hidden)]
697pub fn io_step_decode_text_for_tests(value: &str) -> String {
698 step_import::decode_step_text_for_tests(value)
699}
700#[path = "io/iges/mod.rs"]
701mod iges;
702pub use iges::{export_iges, import_iges};
703#[path = "io/mesh_io.rs"]
704mod mesh_io;
705pub use mesh_io::{
706 parse_stl_triangles, read_obj, read_stl, write_ascii_stl, write_binary_stl, write_obj,
707 ObjReadResult, StlError, StlFormat, StlReadResult, StlTriangles,
708};
709#[path = "io/three_mf/mod.rs"]
715mod three_mf;
716pub use three_mf::{
717 read_3mf, write_3mf, ThreeMfError, ThreeMfInstance, ThreeMfMesh, ThreeMfReadResult,
718 ThreeMfSolid, ThreeMfUnit, ThreeMfWriteReport,
719};
720#[path = "io/glb.rs"]
724mod glb;
725pub use glb::{write_glb, GlbReport, GlbSolid, GlbUpAxis, GLB_MAGIC};
726#[path = "io/snapshot.rs"]
730mod snapshot;
731pub use snapshot::{
732 restore_solids, snapshot_resident_solids, snapshot_solids, RestoredSnapshot, RestoredSolid,
733 SNAPSHOT_FORMAT_VERSION,
734};
735#[path = "solvers/linear_algebra.rs"]
736mod solver_linear_algebra;
737#[path = "solvers/sketch_solver.rs"]
738mod sketch_solver;
739pub use sketch_solver::{
740 is_sketch_origin_point_id, sketch_id_key, mint_sketch_id, solve_sketch, solve_sketch_from_json,
741 SketchSolverSettings, SolveSketchRequest, SKETCH_ORIGIN_POINT_ID,
742};
743#[path = "solvers/assembly_solver.rs"]
744mod assembly_solver;
745pub use assembly_solver::{
746 solve_assembly, AssemblyBody, AssemblyMate, AssemblySolution, AssemblySolveOptions, BodyFreedom, BodyPose,
747 LinearAlgebra, MateAlign, MateAxis, MateCurve, MateKind, MatePlane, MateResidualReport,
748 SolveStrategy, SymmetricElement,
749};
750#[path = "solvers/sketch3d_solver.rs"]
754mod sketch3d_solver;
755pub use sketch3d_solver::{
756 sketch3d_constraint_type, solve_sketch3d, solve_sketch3d_doc, solve_sketch3d_from_json,
757 Sketch3dConstraint, Sketch3dConstraintType, Sketch3dDiagnostics, Sketch3dDoc,
758 Sketch3dGeometry, Sketch3dPoint, Sketch3dSolveOptions, SolveSketch3dRequest,
759 SKETCH3D_CONSTRAINT_TYPES,
760};
761#[path = "solvers/assembly_resolve.rs"]
762mod assembly_resolve;
763pub use assembly_resolve::{
764 is_component_reference, resolve_component_point, resolve_edge_selection,
765 resolve_face_selection, resolve_named_selection, resolve_vertex_selection,
766 split_component_namespace, ResolveError, SelectionGeometry,
767};
768#[path = "edit/direct_edit.rs"]
769mod direct_edit;
770pub use direct_edit::{
771 delete_face_and_heal, delete_faces_and_heal, move_faces, offset_freeform_face,
772 offset_revolution_face, offset_ruled_face, offset_sphere_face, offset_torus_face,
773 recut_moved_planes, recut_moved_planes_rigid, resolve_face_by_point, rotate_faces,
774 route_reading, RouteReading,
775};
776pub use direct_edit::{face_refusal_slugs, face_transform_reason, FaceTransformReason};
777pub use direct_edit::{
778 refit_faces_as_one, refit_refusal_phrases, RefitCarrier, RefitReport, RefitSurfaceKind,
779};
780#[path = "healing/sew.rs"]
781mod sew;
782pub use sew::{sew_solid, split_pinched_vertices, SewReport};
783#[path = "meshing/mesh_weld.rs"]
784mod mesh_weld;
785pub use mesh_weld::{canonical_bits, VertexWeld};
786#[path = "meshing/mesh_segment.rs"]
787mod mesh_segment;
788pub use mesh_segment::{
789 mesh_regions_to_brep, segment_mesh_faces, MeshRegion, MeshSegmentation, RegionCarrier,
790 SegmentOptions, UNASSIGNED_REGION,
791};
792
793#[path = "meshing/spherical_union.rs"]
794mod spherical_union;
795pub use spherical_union::reconstruct_spherical_mesh_union;
796
797#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
798pub struct Vec3 {
799 pub x: f64,
800 pub y: f64,
801 pub z: f64,
802}
803
804impl Vec3 {
805 pub const ZERO: Self = Self { x: 0.0, y: 0.0, z: 0.0 };
806 pub const X: Self = Self { x: 1.0, y: 0.0, z: 0.0 };
807 pub const Y: Self = Self { x: 0.0, y: 1.0, z: 0.0 };
808 pub const Z: Self = Self { x: 0.0, y: 0.0, z: 1.0 };
809
810 pub fn normalized_or(self, fallback: Self) -> Self {
812 self.normalized().unwrap_or(fallback)
813 }
814
815 #[inline]
817 pub fn rotate_about(self, axis: Self, angle: f64) -> Self {
818 let (sin, cos) = angle.sin_cos();
819 self.scale(cos)
820 .add(axis.cross(self).scale(sin))
821 .add(axis.scale(axis.dot(self) * (1.0 - cos)))
822 }
823
824 #[inline]
826 pub fn distance_to_segment(self, start: Self, end: Self, guard: f64) -> f64 {
827 let segment = end.sub(start);
828 let length_squared = segment.dot(segment);
829 if length_squared <= guard {
830 return self.sub(start).length();
831 }
832 let parameter = (self.sub(start).dot(segment) / length_squared).clamp(0.0, 1.0);
833 self.sub(start.add(segment.scale(parameter))).length()
834 }
835
836 #[inline]
838 pub fn distance_to_segment_squared(self, start: Self, end: Self) -> f64 {
839 let segment = end.sub(start);
840 let length_squared = segment.dot(segment);
841 let parameter = if length_squared > 0.0 {
842 (self.sub(start).dot(segment) / length_squared).clamp(0.0, 1.0)
843 } else {
844 0.0
845 };
846 let residual = self.sub(start.add(segment.scale(parameter)));
847 residual.dot(residual)
848 }
849
850 pub fn new(x: f64, y: f64, z: f64) -> Self {
851 Self { x, y, z }
852 }
853 pub fn sub(self, rhs: Self) -> Self {
854 Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
855 }
856 pub fn add(self, rhs: Self) -> Self {
857 Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
858 }
859 pub fn scale(self, factor: f64) -> Self {
860 Self::new(self.x * factor, self.y * factor, self.z * factor)
861 }
862 pub fn cross(self, rhs: Self) -> Self {
863 Self::new(
864 self.y * rhs.z - self.z * rhs.y,
865 self.z * rhs.x - self.x * rhs.z,
866 self.x * rhs.y - self.y * rhs.x,
867 )
868 }
869 pub fn dot(self, rhs: Self) -> f64 {
870 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
871 }
872 pub fn length(self) -> f64 {
873 self.dot(self).sqrt()
874 }
875 pub fn length_squared(self) -> f64 {
876 self.dot(self)
877 }
878 pub fn normalized(self) -> Result<Self, String> {
879 let length = self.length();
880 if length <= 1e-12 {
881 return Err("Vec3.normalized: zero-length vector".into());
882 }
883 Ok(self.scale(1.0 / length))
884 }
885 pub fn perpendicular(self) -> Result<Self, String> {
886 let x = self.x.abs();
887 let y = self.y.abs();
888 let z = self.z.abs();
889 let axis = if x <= y && x <= z {
890 Self::new(1.0, 0.0, 0.0)
891 } else if y <= z {
892 Self::new(0.0, 1.0, 0.0)
893 } else {
894 Self::new(0.0, 0.0, 1.0)
895 };
896 self.cross(axis).normalized()
897 }
898}
899
900#[derive(Clone, Debug, Default, Deserialize, Serialize)]
901pub struct Mesh {
902 pub positions: Vec<f64>,
903 pub normals: Vec<f64>,
904 pub indices: Vec<u32>,
905 pub face_ids: Vec<u32>,
906}
907
908impl Mesh {
909 fn push_vertex(&mut self, point: Vec3, normal: Vec3) -> u32 {
910 self.positions.extend([point.x, point.y, point.z]);
911 self.normals.extend([normal.x, normal.y, normal.z]);
912 (self.positions.len() / 3 - 1) as u32
913 }
914
915 fn quad(&mut self, points: [Vec3; 4], normal: Vec3, face_id: u32) {
916 let base = self.push_vertex(points[0], normal);
917 for point in points.iter().skip(1) {
918 self.push_vertex(*point, normal);
919 }
920 self.indices
921 .extend([base, base + 1, base + 2, base, base + 2, base + 3]);
922 self.face_ids.extend([face_id, face_id]);
923 }
924
925 pub fn signed_volume(&self) -> f64 {
926 self.indices
927 .chunks_exact(3)
928 .map(|tri| {
929 let point = |index: u32| {
930 let i = index as usize * 3;
931 Vec3::new(
932 self.positions[i],
933 self.positions[i + 1],
934 self.positions[i + 2],
935 )
936 };
937 point(tri[0]).dot(point(tri[1]).cross(point(tri[2]))) / 6.0
938 })
939 .sum()
940 }
941
942 pub fn validate(&self) -> Result<(), String> {
943 if self.positions.len() % 3 != 0 || self.normals.len() != self.positions.len() {
944 return Err("invalid vertex or normal buffer".into());
945 }
946 self.validate_geometry()
947 }
948
949 pub fn validate_geometry(&self) -> Result<(), String> {
954 if self.positions.len() % 3 != 0 {
955 return Err("invalid vertex buffer".into());
956 }
957 if self.indices.len() % 3 != 0 {
958 return Err("index buffer is not triangular".into());
959 }
960 let count = self.positions.len() / 3;
961 if self.indices.iter().any(|index| *index as usize >= count) {
962 return Err("index outside vertex buffer".into());
963 }
964 if !self.positions.iter().all(|value| value.is_finite()) {
965 return Err("non-finite vertex".into());
966 }
967 Ok(())
968 }
969}
970
971pub fn make_box(size_x: f64, size_y: f64, size_z: f64) -> Mesh {
972 let x = size_x.abs();
973 let y = size_y.abs();
974 let z = size_z.abs();
975 let p = [
976 Vec3::new(0.0, 0.0, 0.0),
977 Vec3::new(x, 0.0, 0.0),
978 Vec3::new(x, y, 0.0),
979 Vec3::new(0.0, y, 0.0),
980 Vec3::new(0.0, 0.0, z),
981 Vec3::new(x, 0.0, z),
982 Vec3::new(x, y, z),
983 Vec3::new(0.0, y, z),
984 ];
985 let mut mesh = Mesh::default();
986 mesh.quad([p[0], p[3], p[2], p[1]], Vec3::new(0.0, 0.0, -1.0), 0);
987 mesh.quad([p[4], p[5], p[6], p[7]], Vec3::new(0.0, 0.0, 1.0), 1);
988 mesh.quad([p[0], p[1], p[5], p[4]], Vec3::new(0.0, -1.0, 0.0), 2);
989 mesh.quad([p[3], p[7], p[6], p[2]], Vec3::new(0.0, 1.0, 0.0), 3);
990 mesh.quad([p[0], p[4], p[7], p[3]], Vec3::new(-1.0, 0.0, 0.0), 4);
991 mesh.quad([p[1], p[2], p[6], p[5]], Vec3::new(1.0, 0.0, 0.0), 5);
992 mesh
993}
994
995pub fn make_cylinder(radius: f64, height: f64, segments: usize) -> Mesh {
996 let radius = radius.abs();
997 let height = height.abs();
998 let segments = segments.max(3);
999 let mut mesh = Mesh::default();
1000 for i in 0..segments {
1001 let a = std::f64::consts::TAU * i as f64 / segments as f64;
1002 let b = std::f64::consts::TAU * (i + 1) as f64 / segments as f64;
1003 let (sa, ca) = a.sin_cos();
1004 let (sb, cb) = b.sin_cos();
1005 let pa = Vec3::new(radius * ca, 0.0, -radius * sa);
1006 let pb = Vec3::new(radius * cb, 0.0, -radius * sb);
1007 let ta = Vec3::new(pa.x, height, pa.z);
1008 let tb = Vec3::new(pb.x, height, pb.z);
1009 mesh.quad(
1010 [pa, pb, tb, ta],
1011 Vec3::new((ca + cb) * 0.5, 0.0, -(sa + sb) * 0.5),
1012 0,
1013 );
1014 let bottom = mesh.push_vertex(Vec3::default(), Vec3::new(0.0, -1.0, 0.0));
1015 let bi = mesh.push_vertex(pb, Vec3::new(0.0, -1.0, 0.0));
1016 let bj = mesh.push_vertex(pa, Vec3::new(0.0, -1.0, 0.0));
1017 mesh.indices.extend([bottom, bi, bj]);
1018 mesh.face_ids.push(1);
1019 let top = mesh.push_vertex(Vec3::new(0.0, height, 0.0), Vec3::new(0.0, 1.0, 0.0));
1020 let ti = mesh.push_vertex(ta, Vec3::new(0.0, 1.0, 0.0));
1021 let tj = mesh.push_vertex(tb, Vec3::new(0.0, 1.0, 0.0));
1022 mesh.indices.extend([top, ti, tj]);
1023 mesh.face_ids.push(2);
1024 }
1025 mesh
1026}
1027
1028
1029mod abi;
1030pub use abi::*;
1031
1032
1033#[path = "healing/curve_helpers.rs"]
1034mod curve_helpers;
1035
1036#[path = "geometry/eigen2.rs"]
1037mod eigen2;
1038
1039#[path = "geometry/union_find.rs"]
1040pub mod union_find;
1041pub use union_find::UnionFind;
1042
1043#[path = "geometry/poly.rs"]
1044pub mod poly;
1045
1046pub use analytic_surface::{circumcenter, circumcenter_2d, recognize_circle, RecognizedCircle};
1047
1048#[path = "geometry/triangle.rs"]
1049mod triangle;
1050pub use triangle::closest_point_on_triangle;
1051
1052pub use tolerance::RIGID_TOL;
1053
1054impl std::ops::Index<usize> for Vec3 {
1055 type Output = f64;
1056 fn index(&self, index: usize) -> &Self::Output {
1057 match index { 0 => &self.x, 1 => &self.y, 2 => &self.z, _ => panic!("Vec3 index out of bounds: {index}") }
1058 }
1059}
1060impl std::ops::IndexMut<usize> for Vec3 {
1061 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1062 match index { 0 => &mut self.x, 1 => &mut self.y, 2 => &mut self.z, _ => panic!("Vec3 index out of bounds: {index}") }
1063 }
1064}