BREP_kernel 0.12.0

A boundary representation (BREP) geometry kernel for building CAD applications.
Documentation
use crate::classification::{parameter_point_in_face, PolygonClass};
use crate::imprint::{FaceKey, ImprintPieceRecord, ImprintResultRecord};
use crate::topology::{BrepSolid, CoedgeRecord, EdgeRecord, FaceRecord};
use crate::{
    arrange_segments, interpolate_curve, project_point_to_curve, KnotVector, NurbsCurve,
    NurbsSurface, Segment2, Vec2, Vec3,
};
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
use serde::Serialize;
use serde_json::json;

#[path = "fragment/types.rs"]
mod types;
#[path = "fragment/sampling.rs"]
mod sampling;
#[path = "fragment/loops.rs"]
mod loops;
#[path = "fragment/face_split.rs"]
mod face_split;
#[path = "fragment/loop_split.rs"]
mod loop_split;

pub use face_split::{fragment_face, fragment_solid};
pub(crate) use face_split::{fragment_solid_against, bounded_carriers, face_separated};
pub use types::{FaceFragmentRecord, FragmentCoedge, FragmentEdgeSource, FragmentLoop, FragmentOrder};
pub(crate) use types::canonical_fragment_order;
use std::time::Duration;
use web_time::Instant;

/// Per-stage wall-clock accumulators for one operand's `fragment_solid`,
/// printed to stderr when `BREP_PROFILE` is set (the `imprint.profile`
/// pattern, "measure before changing"). Stages are the face splitter's in
/// order: the untouched fast return, the domain and strip-resolution setup
/// with the band re-base, the cut hints and keys, the boundary chains, the
/// cut chains, the duplicate drop and bridges, the 2-D arrangement, the
/// regions (interior points, containment, loops) and the uncut rescue. The
/// three slowest faces are named with their time.
#[derive(Default)]
pub(crate) struct FragmentProfile {
    pub(crate) enabled: bool,
    faces: u64,
    cut_faces: u64,
    arranged_faces: u64,
    uncut_probe_faces: u64,
    region_faces: u64,
    box_candidates: u64,
    separated_faces: u64,
    far_arranged: u64,
    far_regions: u64,
    untouched: Duration,
    /// Of `untouched`, the three `parameter_point_in_face` probes alone.
    pub(crate) uncut_probe: Duration,
    setup: Duration,
    hints: Duration,
    boundary: Duration,
    cuts: Duration,
    dedup_bridge: Duration,
    arrange: Duration,
    regions: Duration,
    rescue: Duration,
    loop_split_faces: u64,
    loop_split_declined: u64,
    loop_split: Duration,
    slowest: Vec<(u64, f64)>,
}

impl FragmentProfile {
    pub(crate) fn new() -> Self {
        Self {
            enabled: crate::imprint::profile_enabled(),
            ..Self::default()
        }
    }

    pub(crate) fn lap(&self, started: &mut Option<Instant>) -> Duration {
        crate::profile::lap(self.enabled, started)
    }

    fn face_done(&mut self, face_id: u64, started: Option<Instant>) {
        if !self.enabled {
            return;
        }
        self.faces += 1;
        let ms = started.map_or(0.0, |s| s.elapsed().as_secs_f64() * 1_000.0);
        self.slowest.push((face_id, ms));
        self.slowest.sort_by(|a, b| b.1.total_cmp(&a.1));
        self.slowest.truncate(3);
    }

    pub(crate) fn report(&self, operand: u8) {
        if !self.enabled {
            return;
        }
        crate::imprint::profile_emit(format_args!("fragment.scope operand={operand} faces={} box_candidates={} arranged={} regions={} far_arranged={} far_regions={} separated={} uncut_probes={}", self.faces, self.box_candidates, self.arranged_faces, self.region_faces, self.far_arranged, self.far_regions, self.separated_faces, self.uncut_probe_faces));
        let ms = |d: Duration| d.as_secs_f64() * 1_000.0;
        crate::imprint::profile_emit(format_args!(
            "fragment.profile operand={operand} faces={} cut_faces={} untouched={:.2} uncut_probe={:.2} setup={:.2} hints={:.2} boundary={:.2} cuts={:.2} dedup_bridge={:.2} arrange={:.2} regions={:.2} rescue={:.2} loop_split_faces={} loop_split_declined={} loop_split={:.2} slowest={:?}",
            self.faces,
            self.cut_faces,
            ms(self.untouched),
            ms(self.uncut_probe),
            ms(self.setup),
            ms(self.hints),
            ms(self.boundary),
            ms(self.cuts),
            ms(self.dedup_bridge),
            ms(self.arrange),
            ms(self.regions),
            ms(self.rescue),
            self.loop_split_faces,
            self.loop_split_declined,
            ms(self.loop_split),
            self.slowest.iter().map(|(id, ms)| format!("{id}:{ms:.2}")).collect::<Vec<_>>(),
        ));
    }
}