Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 120 additions & 98 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "luma"
version = "0.3.1"
version = "0.3.2"
edition = "2024"
license = "AGPL-3.0-or-later"
description = "Rust tool to assign bone material properties to finite element meshes from CT data"
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<picture>
<source media="(prefers-color-scheme:dark)" srcset="lumasting.png">
<img alt="LUMA: Local Unit Modulus Assignment" src="lumasting.png">
</picture>
<p align="center">
<picture>
<source media="(prefers-color-scheme:dark)" srcset="lumasting.png">
<img alt="LUMA: Local Unit Modulus Assignment" src="lumasting.png" class="center">
</picture>
</p>

<p align="center">
<a href="https://doi.org/10.5281/zenodo.21432058">
Expand Down
20 changes: 19 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
fn main() { tauri_build::build() }
fn main() {
// tauri build embeds common-controls on build but not test which errors the tests on windows
// this fixes the windows test
let is_msvc_windows = std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows")
&& std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc");
if is_msvc_windows {
let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("common-controls-v6.manifest");
println!("cargo:rerun-if-changed=tests/common-controls-v6.manifest");
println!("cargo:rustc-link-arg-tests=/MANIFEST:EMBED");
println!(
"cargo:rustc-link-arg-tests=/MANIFESTINPUT:{}",
manifest.display()
);
}

tauri_build::build()
}
2 changes: 1 addition & 1 deletion docs/content/en/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ layout: hextra-home
</div>

{{< hextra/hero-badge link="https://github.com/HaivuUK/luma" >}}<div class="hx-w-2 hx-h-2 hx-rounded-full hx-bg-primary-400"></div>
<span>Version 0.3.0 available now</span>
<span>Version 0.3.X available now</span>
{{< icon name="arrow-circle-right" attributes="height=14" >}}{{< /hextra/hero-badge >}}

<!-- <div class="hx-mt-6 hx-mb-4">
Expand Down
6 changes: 6 additions & 0 deletions docs/content/en/docs/development/changlelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ weight: 401
- TODO: Look at how the abaqus sets are defined and the part definitions, setting global as part name from mesh/mod.rs is probably not the best approach.
- TODO: Improve the phantom calibration tool, currently it is a bit clunky and could be improved to be more user-friendly and intuitive.

#### [0.3.2]

- Fix fragility in ANSYS node reading that caused failures in unaccounted for string patterns.
- Fix handling of unsigned char and signed char scalar types in VTK files.

#### [0.3.1]

- Change the sliders value to use an input (spinbox) so that slices can more precisely be stepped through.
- Updated to the 0.7.0-rc2 of [vtkio](https://docs.rs/vtkio/0.7.0-rc2/vtkio/) to resolve possible lz4 vulnerabilities.

#### [0.3.0] First Public Release

Expand Down
5 changes: 5 additions & 0 deletions docs/content/en/docs/development/known_issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ weight: 400
- Webview2 based visualisation is currently very memory hungry. [=> 0.2.2]
- The _Z_ direction in views in CT views is not consistent. [=> 0.2.2]
- You need a mesh and CT files to use the phantom calibration tool, when you should only need a CT. [0.3.0]
- Large models lag out the mesh ct viewer as it trys to display all the elements of the model. Simplify the representation to fix this. [=> 0.2.2]

## Resolved

### Fixed in 0.3.2
- The logo cdb file hits a node and element read error. [=> 0.2.0]
- The logo vtk file generated by 3D slicer has an unsigned_char error. [=> 0.2.2]

### Fixed in 0.3.1
- The slider is an annoyingly imprecise way to move through the CT scans and having a way to move one at a time would be good. [=> 0.2.0]

Expand Down
52 changes: 12 additions & 40 deletions src/mesh/ansys_cdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,46 +170,18 @@ fn parse_node_line_cdb(line: &str) -> Option<Node> {
// For CDB format, coordinates can be either concatenated or space-separated
// Extract the ID
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 3
&& let Ok(id) = parts[0].parse::<u32>() {
// Try to extract coordinates from different possible formats
let coords_part = if parts.len() >= 6 {
// Case: fully space-separated format
// ["1601", "0", "0", "1.8907520790000E+000", "1.7355024250000E-001", "-7.9881002630000E+001"]
format!("{} {} {}", parts[3], parts[4], parts[5])
} else if parts.len() == 5 {
// Case: partially separated
// ["1", "0", "0", "1.8907520790000E+000", "1.7355024250000E-001-7.9881002630000E+001"]
format!("{} {}", parts[3], parts[4])
} else if parts.len() == 4 {
// Case: second and third coords concatenated
// ["1", "0", "0-4.7796970370000E+001", "6.6293449400000E+000-3.1539065550000E+002"]
format!("{} {}", parts[2], parts[3])
} else if parts.len() == 3 {
// Case: all coords concatenated after "0"
// ["73", "0", "0-4.0867755890000E+001-4.0189343690000E-001-3.2164248660000E+002"]
parts[2].to_string()
} else {
// Fallback: find position after "id 0 0" and extract the rest
let after_id_zeros = line.find(&format!("{} 0 0", id));
// https://rust-lang.github.io/rust-clippy/rust-1.97.0/index.html#question_mark
// let pos = after_id_zeros?;
// let start_pos = pos + format!("{} 0 0", id).len();
// line[start_pos..].to_string()
if let Some(pos) = after_id_zeros {
let start_pos = pos + format!("{} 0 0", id).len();
line[start_pos..].to_string()
} else {
return None;
}
};

// Extract coordinates using regex
if let Some((x, y, z)) = extract_three_coordinates(&coords_part) {
return Some(Node { id, x, y, z });
}
}
None

if parts.len() < 3 {
return None;
}

// coordinate extraction is already written so we use that cause that is sensible
// rather than writing if statements for every pattern
let id = parts[0].parse::<u32>().ok()?;
let rest = parts[1..].join(" ");
let (x, y, z) = extract_three_coordinates(&rest)?;

Some(Node {id, x, y, z})
}

fn extract_three_coordinates(coords_str: &str) -> Option<(f64, f64, f64)> {
Expand Down
2 changes: 2 additions & 0 deletions src/volume/image_vtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub fn load_vtk(path: &str) -> Result<Volume> {
"unsigned_int" | "uint" => { for chunk in payload.chunks_exact(4).take(npoints) { let be = u32::from_be_bytes([chunk[0],chunk[1],chunk[2],chunk[3]]); scalars.push(be as f32); } },
"long" => { for chunk in payload.chunks_exact(8).take(npoints) { let be = i64::from_be_bytes([chunk[0],chunk[1],chunk[2],chunk[3],chunk[4],chunk[5],chunk[6],chunk[7]]); scalars.push((be as f64) as f32); } },
"unsigned_long" | "ulong" => { for chunk in payload.chunks_exact(8).take(npoints) { let be = u64::from_be_bytes([chunk[0],chunk[1],chunk[2],chunk[3],chunk[4],chunk[5],chunk[6],chunk[7]]); scalars.push((be as f64) as f32); } },
"unsigned_char" | "uchar" => { for &b in payload.iter().take(npoints) { scalars.push(b as f32); } },
"char" | "signed_char" => { for &b in payload.iter().take(npoints) { scalars.push(b as i8 as f32); } },
other => return Err(anyhow!(format!("Unsupported binary VTK scalar type '{other}'")))
}
if scalars.len() != npoints { return Err(anyhow!(format!("Parsed {} scalars, expected {}", scalars.len(), npoints))); }
Expand Down
2 changes: 1 addition & 1 deletion tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "luma",
"version": "0.3.1",
"version": "0.3.2",
"identifier": "org.haivu.luma",
"build": {
"frontendDist": "./frontend"
Expand Down
27 changes: 27 additions & 0 deletions tests/common-controls-v6.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Common Controls v6 dependency for cargo TEST binaries only.

tao/wry statically import comctl32 v6-only exports (SetWindowSubclass,
RemoveWindowSubclass, DefSubclassProc, TaskDialogIndirect). The shipped app
binary gets an application manifest declaring Microsoft.Windows.Common-Controls
6.0 from `tauri_build::build()`, so the loader binds comctl32 to the WinSxS v6
assembly. Integration-test binaries produced by `cargo test` get no such
manifest, so they bind to System32\comctl32.dll (v5.82) which lacks those
exports and fail to start with STATUS_ENTRYPOINT_NOT_FOUND (0xC0000139).

build.rs embeds this into test targets via `rustc-link-arg-tests`.
-->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*" />
</dependentAssembly>
</dependency>
</assembly>
Loading
Loading