use crate::{BrepSolid, FaceRecord, NurbsCurve, NurbsSurface, Vec4};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct FaceSetIdentity {
lanes: [u64; 2],
pub faces: u64,
}
impl FaceSetIdentity {
pub fn hex(&self) -> String {
format!("{:016x}{:016x}", self.lanes[0], self.lanes[1])
}
}
#[inline]
fn mix64(mut z: u64) -> u64 {
z ^= z >> 30;
z = z.wrapping_mul(0xbf58_476d_1ce4_e5b9);
z ^= z >> 27;
z = z.wrapping_mul(0x94d0_49bb_1331_11eb);
z ^ (z >> 31)
}
struct TwoLane {
state: [u64; 2],
}
const SEEDS: [u64; 2] = [0x9e37_79b9_7f4a_7c15, 0xc2b2_ae3d_27d4_eb4f];
const STEPS: [u64; 2] = [0xa076_1d64_78bd_642f, 0xe703_7ed1_a0b4_28db];
impl TwoLane {
fn new() -> Self {
Self { state: SEEDS }
}
#[inline]
fn u64(&mut self, value: u64) {
for lane in 0..2 {
self.state[lane] = mix64(self.state[lane] ^ value).wrapping_add(STEPS[lane]);
}
}
#[inline]
fn usize(&mut self, value: usize) {
self.u64(value as u64);
}
#[inline]
fn bool(&mut self, value: bool) {
self.u64(value as u64);
}
#[inline]
fn f64(&mut self, value: f64) {
self.u64(value.to_bits());
}
fn floats(&mut self, values: &[f64]) {
self.usize(values.len());
for value in values {
self.f64(*value);
}
}
fn control_point(&mut self, point: &Vec4) {
self.f64(point.x);
self.f64(point.y);
self.f64(point.z);
self.f64(point.w);
}
fn finish(self) -> [u64; 2] {
[mix64(self.state[0]), mix64(self.state[1])]
}
}
fn hash_curve(lane: &mut TwoLane, curve: &NurbsCurve) {
lane.usize(curve.degree);
lane.floats(&curve.knots);
lane.usize(curve.control_points.len());
for point in &curve.control_points {
lane.control_point(point);
}
}
fn hash_surface(lane: &mut TwoLane, surface: &NurbsSurface) {
lane.usize(surface.degree_u);
lane.usize(surface.degree_v);
lane.floats(&surface.knots_u);
lane.floats(&surface.knots_v);
lane.usize(surface.control_points.len());
for row in &surface.control_points {
lane.usize(row.len());
for point in row {
lane.control_point(point);
}
}
}
fn hash_face(lane: &mut TwoLane, face: &FaceRecord) {
hash_surface(lane, &face.surface);
lane.bool(face.same_sense);
lane.usize(face.loops.len());
for loop_record in &face.loops {
lane.usize(loop_record.coedges.len());
for coedge in &loop_record.coedges {
lane.bool(coedge.forward);
hash_curve(lane, &coedge.pcurve);
}
}
}
pub(crate) fn coedge_use_identity(
surface: &NurbsSurface,
pcurve: &NurbsCurve,
edge: &crate::topology::EdgeRecord,
forward: bool,
) -> [u64; 2] {
let mut lane = TwoLane::new();
hash_surface(&mut lane, surface);
hash_curve(&mut lane, pcurve);
hash_curve(&mut lane, &edge.curve);
lane.f64(edge.t0);
lane.f64(edge.t1);
lane.bool(edge.degenerate);
lane.bool(forward);
lane.finish()
}
pub(crate) fn face_contribution_identity(face: &FaceRecord, reference: crate::Vec3) -> [u64; 2] {
let mut lane = TwoLane::new();
hash_face(&mut lane, face);
lane.f64(reference.x);
lane.f64(reference.y);
lane.f64(reference.z);
lane.finish()
}
pub fn face_set_identity(solid: &BrepSolid) -> FaceSetIdentity {
let mut lane = TwoLane::new();
let mut faces = 0u64;
lane.usize(solid.shells.len());
for shell in &solid.shells {
lane.usize(shell.faces.len());
for face in &shell.faces {
faces += 1;
hash_face(&mut lane, face);
}
}
FaceSetIdentity {
lanes: lane.finish(),
faces,
}
}