Merge remote-tracking branch 'origin/main' into codex/dwf-dgn-underlays

# Conflicts:
#	Cargo.lock
This commit is contained in:
ramox81 committed 2026-09-28 16:13:14 +03:00
commit fecbcd8138
51 files changed
+4155 -294

No files matched your search

+123
View File
@@ -2894,3 +2894,126 @@ mod corrupt_guard_tests {
assert!(!is_entity_corrupt(&EntityType::Insert(i)));
}
}
#[cfg(test)]
mod pre_r2000_layer_plot_tests {
use super::*;
use codec::tables::layer::Layer as DocLayer;
use codec::types::DxfVersion;
fn drawing_with_layers() -> CadDocument {
let mut doc = CadDocument::new();
crate::io::linetypes::populate_document(&mut doc);
for name in ["COARSE", "FINE"] {
let mut layer = DocLayer::new(name);
layer.handle = doc.allocate_handle();
doc.layers.add(layer).unwrap();
}
doc
}
/// Tests run in parallel, so each gets its own file.
fn saved_path(test: &str, version: DxfVersion) -> std::path::PathBuf {
std::env::temp_dir().join(format!(
"ocs_plotflag_{test}_{}_{}.dwg",
version.as_str(),
std::process::id()
))
}
/// The LAYER record only grew a plot flag in R2000. Reading an R14 drawing
/// must therefore leave every layer plottable — reading the missing bit as
/// "don't plot" blanked the whole sheet in PLOT, the preview and QUICKPRINT
/// while the drawing still looked right on screen (display and plot
/// visibility are separate flags).
#[test]
fn an_r14_drawing_reads_back_with_every_layer_plottable() {
let doc = drawing_with_layers();
let path = saved_path("r14_bytes", DxfVersion::AC1014);
save_as_version(&doc, &path, DxfVersion::AC1014).expect("save R14 DWG");
let bytes = std::fs::read(&path).expect("read R14 DWG");
let _ = std::fs::remove_file(&path);
assert_eq!(&bytes[..6], b"AC1014", "writer did not emit an R14 header");
let loaded = load_bytes("r14.dwg", bytes).expect("load R14 DWG");
assert_eq!(loaded.version, DxfVersion::AC1014);
assert!(
loaded.layers.iter().all(|layer| layer.is_plottable),
"an R14 layer came back unplottable: {:?}",
loaded
.layers
.iter()
.filter(|layer| !layer.is_plottable)
.map(|layer| layer.name.clone())
.collect::<Vec<_>>()
);
}
/// R13 carries the same four-bit LAYER record as R14, and a path-based open
/// runs its fixes through `finalize_loaded_outcome` rather than
/// `load_bytes`, so this covers that second entry point too.
#[test]
fn an_r13_drawing_reads_back_with_every_layer_plottable() {
let doc = drawing_with_layers();
let path = saved_path("r13_path", DxfVersion::AC1012);
save_as_version(&doc, &path, DxfVersion::AC1012).expect("save R13 DWG");
let loaded = load_file(&path).expect("load R13 DWG");
let _ = std::fs::remove_file(&path);
assert!(
loaded.layers.iter().all(|layer| layer.is_plottable),
"an R13 layer came back unplottable"
);
}
/// From R2000 on the flag is in the file, so what the file says wins — a
/// layer stored unplottable (DEFPOINTS, say) must stay unplottable.
#[test]
fn a_modern_drawing_keeps_the_plot_flag_it_stored() {
let mut doc = drawing_with_layers();
doc.layers.get_mut("FINE").unwrap().is_plottable = false;
let path = saved_path("modern", DxfVersion::AC1032);
save_as_version(&doc, &path, DxfVersion::AC1032).expect("save R2018 DWG");
let loaded = load_file(&path).expect("load R2018 DWG");
let _ = std::fs::remove_file(&path);
assert!(!loaded.layers.get("FINE").unwrap().is_plottable);
assert!(loaded.layers.get("COARSE").unwrap().is_plottable);
}
/// The plot pass keeps a wire only when it is marked plottable, so an R14
/// drawing whose layers came back unplottable plotted a blank sheet while
/// every entity still drew on screen. Lock the whole chain here: load an
/// R14 drawing and check the wires the plot paths consume.
#[test]
fn every_wire_of_an_r14_drawing_stays_plottable() {
use codec::entities::Line;
use codec::types::Vector3;
use codec::EntityType;
let mut doc = drawing_with_layers();
for (index, layer) in ["COARSE", "FINE"].into_iter().enumerate() {
let x = index as f64 * 10.0;
let mut line = Line::from_points(
Vector3::new(x, 0.0, 0.0),
Vector3::new(x + 5.0, 5.0, 0.0),
);
line.common.layer = layer.to_string();
doc.add_entity(EntityType::Line(line)).expect("add line");
}
let path = saved_path("r14_wires", DxfVersion::AC1014);
save_as_version(&doc, &path, DxfVersion::AC1014).expect("save R14 DWG");
let bytes = std::fs::read(&path).expect("read R14 DWG");
let _ = std::fs::remove_file(&path);
let mut scene = crate::scene::Scene::new();
scene.document = load_bytes("r14.dwg", bytes).expect("load R14 DWG");
let (wires, _) = scene.plot_wire_groups(None);
assert!(!wires.is_empty(), "the R14 drawing tessellated to no wires");
let dropped = wires.iter().filter(|wire| !wire.plot_visible).count();
assert_eq!(
dropped,
0,
"{dropped} of {} wires would be dropped from the plot",
wires.len()
);
}
}
+11 -2
View File
@@ -242,8 +242,10 @@ fn emit_image(
{
return Err("Cannot plot bitmap: invalid coordinates, clip boundary, or opacity.".into());
}
// The low bit (free: the pixel buffer is aligned) keeps the opaque copy
// of a picture apart from its transparent one.
let key = (
std::sync::Arc::as_ptr(&image.pixels) as usize,
std::sync::Arc::as_ptr(&image.pixels) as usize | usize::from(!image.use_alpha),
image.width,
image.height,
);
@@ -255,7 +257,14 @@ fn emit_image(
doc.resources.xobjects.map.insert(
id.clone(),
printpdf::XObject::Image(printpdf::RawImage {
pixels: printpdf::RawImageData::U8(image.pixels.as_ref().clone()),
pixels: printpdf::RawImageData::U8(if image.use_alpha {
image.pixels.as_ref().clone()
} else {
// Transparency off: every pixel opaque in its colour.
let mut opaque = image.pixels.as_ref().clone();
opaque.chunks_exact_mut(4).for_each(|px| px[3] = 255);
opaque
}),
width: image.width as usize,
height: image.height as usize,
data_format: printpdf::RawImageFormat::RGBA8,