pub mod opencrg;
pub mod opendrive;
pub mod openscenario;
pub const DEFAULT_CIRCLE_SEGMENTS: usize = 32;
pub(crate) fn next_sample_index(selected_count: usize, total: usize, quota: usize) -> usize {
if quota == 0 {
return total;
}
((selected_count as u128 * total as u128) / quota as u128) as usize
}
pub(crate) fn allocate_sample_quotas(point_counts: &[usize], maximum: usize) -> Vec<usize> {
let total = point_counts
.iter()
.copied()
.fold(0usize, usize::saturating_add);
let active = point_counts.iter().filter(|count| **count > 0).count();
let target = total.min(maximum);
let mut quotas = vec![0; point_counts.len()];
if target == 0 {
return quotas;
}
if target < active {
let mut remaining = target;
for (quota, count) in quotas.iter_mut().zip(point_counts) {
if *count > 0 && remaining > 0 {
*quota = 1;
remaining -= 1;
}
}
return quotas;
}
for (quota, count) in quotas.iter_mut().zip(point_counts) {
if *count > 0 {
*quota = 1;
}
}
let remaining_target = target.saturating_sub(active);
let remaining_points = total.saturating_sub(active);
let mut assigned = active;
if remaining_target > 0 && remaining_points > 0 {
for (quota, count) in quotas.iter_mut().zip(point_counts) {
let weight = count.saturating_sub(1);
let extra = ((remaining_target as u128 * weight as u128) / remaining_points as u128)
.min(weight as u128) as usize;
*quota += extra;
assigned += extra;
}
}
let mut remainder = target.saturating_sub(assigned);
for (quota, count) in quotas.iter_mut().zip(point_counts) {
if remainder == 0 {
break;
}
if *quota < *count {
*quota += 1;
remainder -= 1;
}
}
quotas
}
#[cfg(test)]
mod sample_quota_tests {
use super::allocate_sample_quotas;
#[test]
fn quotas_preserve_all_small_scans_and_cap_the_total() {
let quotas = allocate_sample_quotas(&[10, 90], 50);
assert_eq!(quotas, [6, 44]);
assert_eq!(quotas.iter().sum::<usize>(), 50);
}
#[test]
fn empty_scans_receive_no_quota() {
assert_eq!(allocate_sample_quotas(&[0, 5, 100], 10), [0, 2, 8]);
}
}
pub(crate) mod amf;
pub(crate) mod collada;
pub mod color;
pub mod dxf;
pub(crate) mod e57;
pub mod eagle;
pub mod excellon;
pub mod gcode;
pub mod gerber;
pub(crate) mod gltf;
pub mod hpgl;
pub(crate) mod ifc;
pub mod iges;
pub mod kicad;
pub mod kicad_sch;
pub mod kicad_sch_modern;
pub(crate) mod las;
pub mod ltspice;
pub mod obj;
pub(crate) mod off;
pub(crate) mod openfoam_field;
pub(crate) mod pcd;
pub mod ply;
pub(crate) mod pts;
pub(crate) mod ptx;
pub(crate) mod sat;
pub mod simulation;
pub mod spice;
pub mod step;
pub mod stl;
pub mod svg_reader;
pub mod threemf;
pub(crate) mod vrml;
pub(crate) mod x3d;
pub(crate) mod xyz;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;
use crate::convert::{ConvertOptions, PageConsumer};
use crate::error::{Error, Result};
pub(crate) fn convert(
path: &Path,
options: &ConvertOptions,
sink: &mut dyn PageConsumer,
) -> Result<Vec<String>> {
let extension = path
.extension()
.and_then(|v| v.to_str())
.map(str::to_ascii_lowercase)
.unwrap_or_default();
match extension.as_str() {
"dae" => return collada::convert(path, options, sink),
"x3d" => return x3d::convert(path, options, sink),
"dxf" => {
let mut probe = File::open(path)?;
let mut signature = [0u8; 22];
if probe.read_exact(&mut signature).is_ok()
&& signature == *dxf::binary::BINARY_DXF_SENTINEL
{
return dxf::binary::convert(File::open(path)?, options, sink);
}
}
"gltf" | "glb" => return gltf::convert(path, options, sink),
"3mf" => return threemf::convert(path, options, sink),
"iges" | "igs" => return iges::convert(path, options, sink),
"ptx" => return ptx::convert(File::open(path)?, options, sink),
"pts" => return pts::convert(File::open(path)?, options, sink),
"xyz" => return xyz::convert(File::open(path)?, options, sink),
"e57" => return e57::convert(path, options, sink),
"las" | "laz" => return las::convert(path, options, sink),
_ => {}
}
let file = File::open(path)?;
let reader = BufReader::new(file);
match extension.as_str() {
"dxf" => dxf::convert(reader, options, sink),
"gbr" | "gerber" | "gtl" | "gbl" | "gts" | "gbs" | "gto" | "gbo" | "gko" | "gm1"
| "gm2" | "art" | "pho" | "cmp" | "sol" | "stc" | "sts" => {
gerber::convert(reader, options, sink)
}
"plt" | "hpgl" | "hpg" | "gl2" => hpgl::convert(reader, options, sink),
"gcode" | "nc" | "ngc" | "tap" | "gco" | "cnc" => gcode::convert(reader, options, sink),
"drl" | "drd" | "xln" | "exc" => excellon::convert(reader, options, sink),
"stl" => stl::convert(reader, options, sink),
"pcd" => pcd::convert(reader, options, sink),
"ply" => ply::convert(reader, options, sink),
"step" | "stp" | "p21" => step::convert(reader, options, sink),
"obj" => obj::convert(reader, options, sink),
"meshb" => simulation::convert_medit(reader, options, sink),
"msh" | "vtk" | "vtu" | "vtp" | "vti" | "vtr" | "vts" => {
simulation::convert(reader, options, sink)
}
"unv" => simulation::convert_unv(reader, options, sink),
_ => {
use std::io::Read;
let mut check_file = File::open(path)?;
let mut buf = vec![0u8; 1024];
let n = check_file.read(&mut buf).unwrap_or(0);
buf.truncate(n);
if buf.starts_with(dxf::binary::BINARY_DXF_SENTINEL) {
dxf::binary::convert(File::open(path)?, options, sink)
} else if buf.starts_with(b"LASF") {
las::convert(path, options, sink)
} else if buf.starts_with(b"ISO-10303-21;")
|| buf.windows(13).any(|w| w == b"ISO-10303-21;")
{
step::convert(reader, options, sink)
} else if buf.starts_with(b"0\nSECTION")
|| buf.starts_with(b" 0\r\nSECTION")
|| buf.starts_with(b" 0\nSECTION")
|| buf.starts_with(b"0\r\nSECTION")
{
dxf::convert(reader, options, sink)
} else if buf.starts_with(b"%FSLA")
|| buf.starts_with(b"%MO")
|| buf.starts_with(b"G04")
{
gerber::convert(reader, options, sink)
} else if buf.starts_with(b"IN;")
|| buf.starts_with(b"SP")
|| buf.starts_with(b"PU")
|| buf.starts_with(b"PD")
{
hpgl::convert(reader, options, sink)
} else if buf.starts_with(b"M48")
|| buf.starts_with(b"T01")
|| buf.starts_with(b"FMAT,2")
{
excellon::convert(reader, options, sink)
} else if buf.starts_with(b"G0 ")
|| buf.starts_with(b"G1 ")
|| buf.starts_with(b"G21")
|| buf.starts_with(b"G90")
|| buf.starts_with(b"(Generated")
{
gcode::convert(reader, options, sink)
} else if buf.starts_with(b"solid ") {
stl::convert(reader, options, sink)
} else if collada::looks_like_prefix(&buf) {
collada::convert(path, options, sink)
} else if x3d::looks_like_prefix(&buf) {
x3d::convert(path, options, sink)
} else if buf.starts_with(b"ply\n") || buf.starts_with(b"ply\r\n") {
ply::convert(reader, options, sink)
} else if buf.starts_with(b"$MeshFormat")
|| buf.starts_with(b"# vtk DataFile Version")
|| buf.starts_with(b"<VTKFile")
{
simulation::convert(reader, options, sink)
} else if simulation::looks_like_unv_prefix(&buf) {
simulation::convert_unv(reader, options, sink)
} else {
Err(Error::Unsupported(format!(
"unsupported CAD format extension '.{extension}'"
)))
}
}
}
}