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)
}
pub(crate) 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 {
pub(crate) fn new() -> Self {
Self { state: SEEDS }
}
#[inline]
pub(crate) fn u64(&mut self, value: u64) {
for lane in 0..2 {
self.state[lane] = mix64(self.state[lane] ^ value).wrapping_add(STEPS[lane]);
}
}
#[inline]
pub(crate) fn usize(&mut self, value: usize) {
self.u64(value as u64);
}
#[inline]
pub(crate) fn bool(&mut self, value: bool) {
self.u64(value as u64);
}
#[inline]
pub(crate) fn f64(&mut self, value: f64) {
self.u64(value.to_bits());
}
pub(crate) 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);
}
pub(crate) fn finish(self) -> [u64; 2] {
[mix64(self.state[0]), mix64(self.state[1])]
}
}
pub(crate) 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);
}
}
pub(crate) 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);
}
}
}
pub(crate) 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 carrier_residual_identity(
curve: &NurbsCurve, t0: f64, t1: f64, surfaces: &[&NurbsSurface],
) -> [u64; 2] {
let mut lane = TwoLane::new();
hash_curve(&mut lane, curve);
lane.f64(t0);
lane.f64(t1);
lane.usize(surfaces.len());
for surface in surfaces { hash_surface(&mut lane, surface); }
lane.finish()
}
pub(crate) fn identity_with_model(key: [u64; 2], model: f64) -> [u64; 2] {
let mut lane = TwoLane::new();
lane.u64(key[0]);
lane.u64(key[1]);
lane.f64(model);
lane.finish()
}
pub(crate) fn edge_claim_identity(uses: &[[u64; 2]], ranks: &[usize], model: f64) -> [u64; 2] {
let mut lane = TwoLane::new();
lane.usize(uses.len());
for key in uses {
lane.u64(key[0]);
lane.u64(key[1]);
}
lane.usize(ranks.len());
for &rank in ranks {
lane.usize(rank);
}
lane.f64(model);
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,
}
}