20 Commits

Author SHA1 Message Date
AndreaRigoni
f2133c31d5 DetectorChamber vtk handler 2026-03-10 08:18:17 +00:00
AndreaRigoni
00275ac56d vtk camera position widget on viewer 2026-03-08 16:51:39 +00:00
AndreaRigoni
1374821344 added gizmo but not yet working 2026-03-08 10:21:38 +00:00
AndreaRigoni
2548582036 attach a widget (not working well yet) 2026-03-08 09:42:28 +00:00
AndreaRigoni
32a1104769 detector chamber in vtk 2026-03-08 08:46:21 +00:00
AndreaRigoni
3be7ec2274 add stl test 2026-03-08 08:05:22 +00:00
AndreaRigoni
38dd416ced vix raytracer representation 2026-03-07 09:07:07 +00:00
AndreaRigoni
e8f8e96521 reorganization of sources, moving cmt pertaining structures into HEP folder 2026-03-07 08:58:31 +00:00
AndreaRigoni
49cf0aeedd feat: disable camera spin/inertia by introducing a custom interactor style.r 2026-03-06 17:31:29 +00:00
40846bba78 Update .gitea/workflows/publish-docs.yaml
All checks were successful
MkDocs Subpath Deploy / build-and-deploy (push) Successful in 11s
2026-03-06 17:52:45 +01:00
4d681e3373 Update .gitea/workflows/publish-docs.yaml
Some checks failed
MkDocs Subpath Deploy / build-and-deploy (push) Failing after 12s
2026-03-06 17:51:53 +01:00
3a9efd5598 Update .gitea/workflows/publish-docs.yaml 2026-03-06 17:50:13 +01:00
fa1930f9d7 Merge pull request 'andrea-dev' (#1) from andrea-dev into main
Reviewed-on: #1
added CUDA for images and raytracing, added python bindings via pybind11, removed LTK, added documentation
2026-03-06 17:17:52 +01:00
AndreaRigoni
b64afe8773 add documention workflow 2026-03-06 10:45:33 +00:00
AndreaRigoni
f3ebba4931 add thrust 2026-03-06 10:45:14 +00:00
AndreaRigoni
79e1abb2ff add USE_CUDA env in python_build 2026-03-05 15:17:30 +00:00
AndreaRigoni
554eff9b55 add filters in python bindings 2026-03-05 15:03:19 +00:00
AndreaRigoni
42db99759f fix py dense 2026-03-05 14:26:05 +00:00
AndreaRigoni
69920acd61 poetry python build 2026-03-05 12:42:14 +00:00
AndreaRigoni
647d0caa1c feat: Add Python packaging infrastructure and comprehensive bindings for math and vector types. 2026-03-05 11:39:27 +00:00
125 changed files with 5264 additions and 2142 deletions

View File

@@ -0,0 +1,42 @@
name: MkDocs Subpath Deploy
on:
workflow_dispatch: # trigger manuale
push:
branches:
- main # Trigger on main branch
jobs:
build-and-deploy:
runs-on: mildpub # Runner that can access to SSH_YFINPUB_HOST
steps:
- name: Checkout del codice
uses: actions/checkout@v4
- name: Configura Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Installa dipendenze
run: |
python -m pip install --upgrade pip
pip install mkdocs-material
pip install -r docs/docker/requirements.txt
- name: Build del sito
run: mkdocs build
- name: Deploy via SSH (SCP)
uses: https://github.com/appleboy/scp-action@master
with:
host: ${{ vars.SSH_YFINPUB_HOST }}
username: ${{ vars.SSH_YFINPUB_USER }}
key: ${{ secrets.MILD_PUB }}
port: 22
source: "site/*"
# Il percorso sul server deve corrispondere alla tua sottopagina
target: "/var/www/docs/cmt/uLib/"
strip_components: 1 # Rimuove la cartella "site/" e mette solo il contenuto
rm: true # Pulisce la cartella prima di copiare (opzionale, stile Vercel)

8
.gitignore vendored
View File

@@ -5,3 +5,11 @@ build_warnings*.log
final_build.log final_build.log
cmake_configure.log cmake_configure.log
compile_commands.json compile_commands.json
dist/
build_python/
src/Python/uLib/*.so*
src/Python/uLib/*.pyd
src/Python/uLib/*.pyc
src/Python/uLib/__pycache__
src/Python/uLib/.nfs*

View File

@@ -146,7 +146,8 @@ else()
RenderingFreeType RenderingFreeType
RenderingGL2PSOpenGL2 RenderingGL2PSOpenGL2
RenderingOpenGL2 RenderingOpenGL2
RenderingVolumeOpenGL2) RenderingVolumeOpenGL2
IOGeometry)
endif() endif()
set(CMAKE_REQUIRED_INCLUDES CMAKE_REQUIRED_INCLUDES math.h) set(CMAKE_REQUIRED_INCLUDES CMAKE_REQUIRED_INCLUDES math.h)
@@ -204,8 +205,8 @@ add_subdirectory(${SRC_DIR}/Core)
include_directories(${SRC_DIR}/Math) include_directories(${SRC_DIR}/Math)
add_subdirectory(${SRC_DIR}/Math) add_subdirectory(${SRC_DIR}/Math)
include_directories(${SRC_DIR}/Detectors) include_directories(${SRC_DIR}/HEP)
add_subdirectory(${SRC_DIR}/Detectors) add_subdirectory(${SRC_DIR}/HEP)
include_directories(${SRC_DIR}/Root) include_directories(${SRC_DIR}/Root)
add_subdirectory(${SRC_DIR}/Root) add_subdirectory(${SRC_DIR}/Root)

16
CMakePresets.json Normal file
View File

@@ -0,0 +1,16 @@
{
"version": 8,
"configurePresets": [
{
"name": "andrea",
"displayName": "Custom configure preset",
"description": "Sets Ninja generator, build and install directory",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
}
}
]
}

View File

@@ -61,3 +61,10 @@ cmake --preset conan-release
```bash ```bash
cmake --build build -j10 cmake --build build -j10
``` ```
### Make python package
```bash
micromamba run -n mutom env USE_CUDA=ON poetry install
```

54
build_python.py Normal file
View File

@@ -0,0 +1,54 @@
import os
import subprocess
import sys
import shutil
def build(setup_kwargs):
"""
Build the C++ extension using CMake.
This function is called by poetry-core during the build process.
The binary is placed directly inside the uLib directory in src/Python.
"""
# Root of the whole project where this build_extension.py is located
project_root = os.path.abspath(os.path.dirname(__file__))
# Where the extension should go
package_dir = os.path.join(project_root, "src/Python/uLib")
# Ensure package directory exists
os.makedirs(package_dir, exist_ok=True)
# Temporary build directory
build_temp = os.path.join(project_root, "build_python")
os.makedirs(build_temp, exist_ok=True)
print(f"--- Running CMake build in {build_temp} ---")
print(f"Project root: {project_root}")
print(f"Target binary dir: {package_dir}")
# Determine if CUDA should be enabled
use_cuda = os.environ.get("USE_CUDA", "OFF").upper()
if use_cuda in ["ON", "1", "TRUE", "YES"]:
use_cuda = "ON"
else:
use_cuda = "OFF"
# CMake configuration
cmake_args = [
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={package_dir}",
f"-DPYTHON_EXECUTABLE={sys.executable}",
"-DCMAKE_BUILD_TYPE=Release",
f"-DUSE_CUDA={use_cuda}",
"-G", "Unix Makefiles",
]
# Use micromamba to ensure Boost and VTK are found during the build
subprocess.check_call(["cmake", project_root] + cmake_args, cwd=build_temp)
subprocess.check_call(["cmake", "--build", ".", "--parallel", "--target", "uLib_python"], cwd=build_temp)
# Ensure the package is found by poetry during the wheel creation process.
# Return setup_kwargs for poetry-core.
return setup_kwargs
if __name__ == "__main__":
build({})

View File

@@ -0,0 +1,41 @@
.tabbed-set {
display: flex;
position: relative;
flex-wrap: wrap;
}
.tabbed-set .highlight {
background: #ddd;
}
.tabbed-set .tabbed-content {
display: none;
order: 99;
width: 100%;
}
.tabbed-set label {
width: auto;
margin: 0 0.5em;
padding: 0.25em;
font-size: 120%;
cursor: pointer;
color: #ffffff !important;
}
.tabbed-set input {
position: absolute;
opacity: 0;
}
.tabbed-set input:nth-child(n+1) {
color: #333333;
}
.tabbed-set input:nth-child(n+1):checked + label {
color: cyan !important;
}
.tabbed-set input:nth-child(n+1):checked + label + .tabbed-content {
display: block;
}

17
docs/assets/css/extra.css Normal file
View File

@@ -0,0 +1,17 @@
@import "extensions/tabbed.css";
.md-grid {
max-width: 100%;
}
.md-main__inner {
margin-top: 0;
padding-top: 0;
}
.md-sidebar--secondary {
right: 1.5rem;
top: 4.8rem;
transform: none;
width: 18rem;
}

30
docs/docker/Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
# Stage 1: Build the static site using MkDocs
FROM python:3.9-slim-buster as builder
# Set the working directory
WORKDIR /app
# Copy the requirements file
COPY requirements.txt .
# Install the Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application files
COPY ../.. .
# Build the MkDocs site
RUN mkdocs build
# Stage 2: Serve the static files with Nginx
FROM nginx:alpine
# Copy the built site from the builder stage
COPY --from=builder /app/site /usr/share/nginx/html
# Expose port 80 for the web server
EXPOSE 80
# Command to run Nginx in the foreground
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1,14 @@
# Dockerfile for development with live-reloading
FROM python:3.9-slim-buster
WORKDIR /app
# Copy and install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Expose the port MkDocs serve will run on
EXPOSE 8000
# Command to run the development server
CMD ["mkdocs", "serve", "--dev-addr", "0.0.0.0:8000"]

View File

@@ -0,0 +1,13 @@
version: '3.8'
services:
mkdocs:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "8000:8000"
volumes:
- ../..:/app
environment:
- GIT_DISCOVERY_ACROSS_FILESYSTEM=1

View File

@@ -0,0 +1,17 @@
# ------------------------------------------------------------------
# MkDocs runtime dependencies for the docs Docker image
# ------------------------------------------------------------------
# Core: theme (provides mkdocs itself as a transitive dep)
mkdocs-material==9.7.1
# pymdownx.* extensions used in mkdocs.yml:
# arithmatex, highlight, superfences, tabbed, details, blocks.caption
# (also a hard dep of mkdocs-material, pinned here for reproducibility)
pymdown-extensions>=10.0
# Markdown math rendering support (arithmatex generic mode)
# JS side is loaded via CDN (polyfill.io + MathJax), no extra Python pkg needed
# Optional: PDF export plugin (exporter: block, currently commented out in mkdocs.yml)
mkdocs-exporter

1
docs/docker/runtime.txt Normal file
View File

@@ -0,0 +1 @@
3.7

63
docs/index.md Normal file
View File

@@ -0,0 +1,63 @@
# uLib
[![DOI](https://zenodo.org/badge/36926725.svg)](https://zenodo.org/badge/latestdoi/36926725)
**uLib** is the base toolkit library for the **CMT (Cosmic Muon Tomography)** project, developed at the University of Padova and INFN Sezione di Padova, Italy.
It provides:
- **Core** object model, timers, configuration, UUID utilities.
- **Math** linear algebra (Eigen3), structured grids, voxel images, ray-tracing, image filters.
- **Python bindings** full pybind11 interface for scripting and analysis workflows.
- Optional **CUDA** acceleration for voxel filtering (transparent RAM ↔ VRAM management).
---
## Quick Start
=== "Users (pip / poetry)"
```bash
# Activate your conda/micromamba environment first
micromamba activate mutom
poetry install # CPU build
USE_CUDA=ON poetry install # GPU build
```
=== "Developers (CMake)"
```bash
conan install . --output-folder=build --build=missing
cmake --preset conan-release
cmake --build build --target uLib_python -j$(nproc)
export PYTHONPATH="$(pwd)/build/src/Python:$(pwd)/src/Python"
```
Then in Python:
```python
import uLib
# Core
timer = uLib.Core.Timer()
timer.Start()
# Math
grid = uLib.Math.StructuredGrid([10, 10, 10])
grid.SetSpacing([1.0, 1.0, 1.0])
img = uLib.Math.VoxImage([10, 10, 10])
img.SetValue(0, 3.14)
print(img.GetValue(0))
```
---
## Documentation Sections
| Section | Description |
|---|---|
| [Python Installation](python/installation.md) | Environment setup, user install, developer build |
| [Python API Usage](python/usage.md) | Full API reference with examples |
| [Python Developer Guide](python/developer_guide.md) | Adding bindings, running tests, build details |
| [C++ Build Usage & CUDA](usage/usage.md) | CMake build, CUDA configuration |

View File

@@ -0,0 +1,179 @@
# Developer Guide Python Bindings
This guide is aimed at contributors who want to extend or modify the Python bindings for `uLib`.
---
## Repository Layout
```
ulib/
├── src/
│ └── Python/
│ ├── module.cpp # pybind11 module entry point
│ ├── core_bindings.cpp # uLib::Core bindings
│ ├── math_bindings.cpp # uLib::Math bindings
│ ├── math_filters_bindings.cpp# VoxImageFilter bindings
│ ├── CMakeLists.txt # builds uLib_python shared lib
│ ├── testing/ # Python unit tests
│ │ ├── pybind_test.py
│ │ ├── core_pybind_test.py
│ │ ├── math_pybind_test.py
│ │ └── math_filters_test.py
│ └── uLib/ # Python package (uLib_python.so lands here)
│ └── __init__.py
├── build_python.py # poetry build hook (calls CMake)
├── pyproject.toml # poetry metadata
└── condaenv.yml # conda/micromamba environment
```
---
## Adding a New Binding
All bindings live in the four source files listed above. The module entry point `module.cpp` calls `init_core()`, `init_math()`, and `init_math_filters()` in order.
### 1. Pick (or create) the right binding file
| C++ header location | Binding file |
|---|---|
| `src/Core/` | `core_bindings.cpp` |
| `src/Math/` (geometry, grids, VoxImage) | `math_bindings.cpp` |
| `src/Math/VoxImageFilter*.hpp` | `math_filters_bindings.cpp` |
### 2. Add the `#include` directive
```cpp
// math_bindings.cpp
#include "Math/MyNewClass.h"
```
### 3. Write the pybind11 binding inside the appropriate `init_*` function
```cpp
void init_math(py::module_ &m) {
// ... existing bindings ...
py::class_<MyNewClass>(m, "MyNewClass")
.def(py::init<>())
.def("MyMethod", &MyNewClass::MyMethod)
.def("AnotherMethod", &MyNewClass::AnotherMethod,
py::arg("x"), py::arg("y") = 0.0f);
}
```
### 4. Rebuild only the Python target
```bash
cmake --build build --target uLib_python -j$(nproc)
```
### 5. Write a Python test
Add a new test class to the relevant test file (or create a new one under `src/Python/testing/`):
```python
# src/Python/testing/math_pybind_test.py
class TestMyNewClass(unittest.TestCase):
def test_basic(self):
obj = uLib.Math.MyNewClass()
result = obj.MyMethod()
self.assertAlmostEqual(result, expected_value)
```
Register the test in `src/Python/CMakeLists.txt` if you add a new file:
```cmake
add_test(NAME pybind_my_new
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/my_new_test.py)
set_tests_properties(pybind_my_new PROPERTIES
ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>:${PROJECT_SOURCE_DIR}/src/Python")
```
---
## Build System Details
### CMakeLists.txt (`src/Python/`)
`pybind11_add_module` compiles the shared library `uLib_python` and links it against the C++ static/shared libraries `uLibCore` and `uLibMath`. The install target copies the `.so` into the standard library directory.
```cmake
pybind11_add_module(uLib_python
module.cpp core_bindings.cpp math_bindings.cpp math_filters_bindings.cpp)
target_link_libraries(uLib_python PRIVATE uLibCore uLibMath)
```
### poetry / build_python.py
`pyproject.toml` declares `build_python.py` as the custom build hook. When `poetry install` or `poetry build` is invoked it:
1. Calls `cmake <root> -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=<pkg_dir> ...` in `build_python/`.
2. Builds only the `uLib_python` target.
3. The resulting `.so` is placed inside `src/Python/uLib/` so it is picked up by Poetry as a package data file.
The `USE_CUDA` environment variable gates CUDA support at build time:
```bash
USE_CUDA=ON poetry install # with CUDA
USE_CUDA=OFF poetry install # CPU only (default)
```
---
## Running All Tests
```bash
# From the repository root, with PYTHONPATH set:
export PYTHONPATH="$(pwd)/build/src/Python:$(pwd)/src/Python"
python -m pytest src/Python/testing/ -v
```
Or through CMake's test runner (after building the full project):
```bash
cd build
ctest --output-on-failure -R pybind
```
Expected output (all passing):
```
Start 1: pybind_general
1/4 Test #1: pybind_general ............. Passed
Start 2: pybind_core
2/4 Test #2: pybind_core ................ Passed
Start 3: pybind_math
3/4 Test #3: pybind_math ................ Passed
Start 4: pybind_math_filters
4/4 Test #4: pybind_math_filters ........ Passed
```
---
## Memory Management Notes
`uLib::Vector<T>` has explicit GPU memory management. When wrapping methods that return references to internal data, use `py::return_value_policy::reference_internal` to avoid dangling references:
```cpp
.def("Data", &VoxImage<Voxel>::Data,
py::return_value_policy::reference_internal)
```
For objects held by `std::unique_ptr` without Python-side deletion, use `py::nodelete`:
```cpp
py::class_<Abstract::VoxImageFilter,
std::unique_ptr<Abstract::VoxImageFilter, py::nodelete>>(m, "AbstractVoxImageFilter")
```
---
## Useful References
- [pybind11 documentation](https://pybind11.readthedocs.io)
- [pybind11 STL containers](https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html)
- [pybind11 Eigen integration](https://pybind11.readthedocs.io/en/stable/advanced/cast/eigen.html)
- [CMake pybind11 integration](https://pybind11.readthedocs.io/en/stable/compiling.html)

146
docs/python/installation.md Normal file
View File

@@ -0,0 +1,146 @@
# Python Installation
The `uLib` Python package exposes the Core and Math C++ libraries via [pybind11](https://pybind11.readthedocs.io) bindings. There are two ways to install it: as an **end user** (pre-built wheel / pip) or as a **developer** (editable build from source).
---
## Prerequisites
`uLib` depends on native C++ libraries that must be compiled. Ensure the following are available in your environment before installing:
| Dependency | Minimum version | Notes |
|---|---|---|
| Python | 3.9 | |
| CMake | 3.12 | |
| pybind11 | 2.6.0 | |
| Conan | 2.x | for Eigen3 / Boost |
| micromamba / conda | any | recommended provides ROOT, VTK |
### Creating the `mutom` Conda/Micromamba Environment
A ready-to-use environment definition is provided as `condaenv.yml` at the repository root.
=== "Micromamba"
```bash
micromamba env create -f condaenv.yml
micromamba activate mutom
```
=== "Conda"
```bash
conda env create -f condaenv.yml
conda activate mutom
```
The environment installs CMake, Conan, ROOT, VTK, and the compiler toolchain.
> **CUDA (optional)**
> If you want GPU-accelerated voxel filtering, you also need NVCC inside the environment:
> ```bash
> micromamba install cuda-nvcc -c conda-forge
> ```
---
## User Installation (wheel / pip)
Once the native dependencies are present in your environment, install the package with Poetry or pip:
```bash
# Activate your environment first
micromamba activate mutom
# Build and install (CUDA disabled by default)
poetry install
# Build and install with CUDA support
USE_CUDA=ON poetry install
```
After installation the module is importable from anywhere in the environment:
```python
import uLib
print(dir(uLib.Core))
print(dir(uLib.Math))
```
---
## Developer Installation (editable / in-tree build)
For development you typically want to skip the packaging layer and work directly against the CMake build tree.
### Step 1 Install Conan dependencies
```bash
conan profile detect # first time only
conan install . --output-folder=build --build=missing
```
### Step 2 Configure and build
```bash
# Standard release build
cmake --preset conan-release
# …or manually
cmake -B build \
-DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_CUDA=OFF # set to ON when a GPU is available
cmake --build build --target uLib_python -j$(nproc)
```
The shared library (`uLib_python*.so`) is written to `build/src/Python/`.
### Step 3 Make the module importable
Point `PYTHONPATH` at the build output **and** the Python source directory (the latter carries the `uLib/__init__.py` that stitches sub-modules together):
```bash
export PYTHONPATH="$(pwd)/build/src/Python:$(pwd)/src/Python:$PYTHONPATH"
python -c "import uLib; print(uLib.__version__)"
```
Or, for a one-shot check:
```bash
PYTHONPATH="build/src/Python:src/Python" python src/Python/testing/pybind_test.py
```
### Step 4 Run the tests
CMake registers the Python tests alongside the C++ ones; use `ctest` from the build directory:
```bash
cd build
ctest --output-on-failure -R pybind
```
Individual test scripts can also be run directly once `PYTHONPATH` is set:
```bash
python src/Python/testing/core_pybind_test.py
python src/Python/testing/math_pybind_test.py
python src/Python/testing/math_filters_test.py
```
---
## Verifying the Installation
```python
import uLib
# Core module
obj = uLib.Core.Object()
timer = uLib.Core.Timer()
timer.Start()
elapsed = timer.StopWatch() # float, seconds
# Math module
v3 = uLib.Math.Vector3f([1.0, 0.0, 0.0])
print(v3[0]) # 1.0
```

373
docs/python/usage.md Normal file
View File

@@ -0,0 +1,373 @@
# Python API Usage
The `uLib` Python package is split into two sub-modules mirroring the C++ library:
| Sub-module | Contents |
|---|---|
| `uLib.Core` | Low-level utilities: `Object`, `Timer`, `Options`, `TypeRegister` |
| `uLib.Math` | Geometry, grids, voxel images, ray-tracing, image filters |
```python
import uLib
# Sub-modules are accessible as attributes
uLib.Core # core utilities
uLib.Math # mathematical structures
```
---
## uLib.Core
### Object
Base class for uLib objects; exposed to Python for type-hierarchy purposes.
```python
obj = uLib.Core.Object()
copy = obj.DeepCopy()
```
### Timer
Precision wall-clock timer.
```python
import time
timer = uLib.Core.Timer()
timer.Start()
time.sleep(0.5)
elapsed = timer.StopWatch() # returns elapsed seconds as float
print(f"Elapsed: {elapsed:.3f} s")
```
### Options
Wraps Boost.ProgramOptions for INI-style configuration files.
```python
opt = uLib.Core.Options("My Program")
opt.parse_config_file("config.ini") # load settings
n = opt.count("my_key") # check if key exists
opt.save_config_file("out.ini")
```
---
## uLib.Math Linear Algebra
The math module exposes Eigen3 vectors and matrices as well-typed Python objects with NumPy interoperability.
### Fixed-size Vectors
```python
import numpy as np
import uLib
# Construct from list
v3 = uLib.Math.Vector3f([1.0, 2.0, 3.0])
print(v3[0], v3[1], v3[2]) # 1.0 2.0 3.0
# Construct from NumPy array
arr = np.array([4.0, 5.0, 6.0], dtype=np.float32)
v3b = uLib.Math.Vector3f(arr)
# Zero-initialise
v4d = uLib.Math.Vector4d() # all zeros
# Available types
# Vector1f / 2f / 3f / 4f (float32)
# Vector1d / 2d / 3d / 4d (float64)
# Vector1i / 2i / 3i / 4i (int32)
```
### Fixed-size Matrices
```python
# 2-by-2 float matrix
m2f = uLib.Math.Matrix2f()
m2f[0, 0] = 1; m2f[0, 1] = 2
m2f[1, 0] = 3; m2f[1, 1] = 4
# From list (row-major)
m4f = uLib.Math.Matrix4f([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1])
# From NumPy (2-D array)
mat = np.eye(3, dtype=np.float32)
m3f = uLib.Math.Matrix3f(mat)
# Dynamic matrices
mXf = uLib.Math.MatrixXf(4, 4) # 4×4 float, zeros
```
### Homogeneous Types
```python
# HPoint3f a 3-D point in homogeneous coordinates (w = 1)
p = uLib.Math.HPoint3f(1.0, 2.0, 3.0)
# HVector3f a free vector (w = 0)
v = uLib.Math.HVector3f(0.0, 1.0, 0.0)
# HLine3f a parametric ray
line = uLib.Math.HLine3f()
line.origin = uLib.Math.HPoint3f(0, 0, 0)
line.direction = uLib.Math.HVector3f(0, 0, 1)
```
---
## uLib.Math Transforms and Geometry
### AffineTransform
A rigid-body / affine transform stored as a 4×4 matrix.
```python
tf = uLib.Math.AffineTransform()
tf.SetPosition([1.0, 0.0, 0.0]) # translate
tf.Translate([0.0, 1.0, 0.0]) # cumulative translate
tf.Scale([2.0, 2.0, 2.0]) # uniform scale
tf.Rotate(uLib.Math.Vector3f([0, 0, 3.14159])) # Euler angles (rad)
mat4 = tf.GetWorldMatrix() # 4×4 matrix
pos = tf.GetPosition() # Vector3f
```
### Geometry
Inherits `AffineTransform`; converts points between world and local frames.
```python
geo = uLib.Math.Geometry()
geo.SetPosition([1.0, 1.0, 1.0])
world_pt = uLib.Math.Vector4f([2.0, 3.0, 2.0, 1.0])
local_pt = geo.GetLocalPoint(world_pt)
back = geo.GetWorldPoint(local_pt)
# back ≈ [2, 3, 2, 1]
```
### ContainerBox
An axis-aligned bounding box with an associated transform.
```python
box = uLib.Math.ContainerBox()
box.SetOrigin([-1.0, -1.0, -1.0])
box.SetSize([2.0, 2.0, 2.0])
print(box.GetSize()) # [2, 2, 2]
```
---
## uLib.Math Structured Grids
### StructuredGrid (3-D)
A 3-D voxel grid (origin, spacing, and integer dimensions).
```python
dims = uLib.Math.Vector3i([10, 10, 10])
grid = uLib.Math.StructuredGrid(dims)
grid.SetSpacing([1.0, 1.0, 1.0])
grid.SetOrigin([0.0, 0.0, 0.0])
print(grid.GetSpacing()) # [1, 1, 1]
print(grid.IsInsideBounds([5, 5, 5, 1])) # True
idx = grid.Find([2.5, 2.5, 2.5]) # returns grid cell index
```
### Structured2DGrid / Structured4DGrid
```python
grid2d = uLib.Math.Structured2DGrid()
grid2d.SetDims([100, 100])
grid2d.SetPhysicalSpace([0, 0], [1, 1])
print(grid2d.GetSpacing())
```
---
## uLib.Math VoxImage
`VoxImage` is a 3-D voxel volume where each cell stores a `Voxel` ( `.Value` + `.Count`).
```python
dims = uLib.Math.Vector3i([20, 20, 20])
img = uLib.Math.VoxImage(dims)
img.SetSpacing([0.5, 0.5, 0.5])
# Access by linear index
img.SetValue(0, 42.0)
print(img.GetValue(0)) # 42.0
# Access by 3-D index
img.SetValue(uLib.Math.Vector3i([1, 1, 1]), 7.5)
print(img.GetValue(uLib.Math.Vector3i([1, 1, 1]))) # 7.5
# Clipping / masking helpers
cropped = img.clipImage(uLib.Math.Vector3i([2, 2, 2]),
uLib.Math.Vector3i([18, 18, 18]))
masked = img.maskImage(0.0, 100.0, 0.0) # mask outside [0, 100]
# I/O
img.ExportToVti("output.vti")
img.ImportFromVti("output.vti")
```
### Voxel (element type)
```python
vox = uLib.Math.Voxel()
vox.Value = 1.5
vox.Count = 3
data = img.Data() # returns the underlying Vector_Voxel
vox0 = data[0]
print(vox0.Value, vox0.Count)
```
---
## uLib.Math VoxRaytracer
Performs ray-tracing through a `StructuredGrid` and returns per-voxel chord lengths.
```python
import numpy as np
import uLib
grid = uLib.Math.StructuredGrid([10, 10, 10])
grid.SetSpacing([1.0, 1.0, 1.0])
grid.SetOrigin([0.0, 0.0, 0.0])
rt = uLib.Math.VoxRaytracer(grid)
# Trace a ray between two homogeneous points (x, y, z, w=1)
p1 = np.array([0.5, 0.5, -1.0, 1.0], dtype=np.float32)
p2 = np.array([0.5, 0.5, 11.0, 1.0], dtype=np.float32)
result = rt.TraceBetweenPoints(p1, p2)
print("Voxels crossed:", result.Count())
print("Total length :", result.TotalLength())
elements = result.Data()
for i in range(result.Count()):
print(f" vox_id={elements[i].vox_id} L={elements[i].L:.4f}")
```
---
## uLib.Math Image Filters
All filters share the same interface: construct with a kernel size, attach a `VoxImage`, optionally set parameters, then call `.Run()`.
```python
import uLib
dims = uLib.Math.Vector3i([10, 10, 10])
img = uLib.Math.VoxImage(dims)
for i in range(10**3):
img.SetValue(i, float(i))
kernel_dims = uLib.Math.Vector3i([3, 3, 3])
```
### Linear (Gaussian / Box) Filter
```python
filt = uLib.Math.VoxFilterAlgorithmLinear(kernel_dims)
filt.SetImage(img)
filt.SetKernelNumericXZY([1.0] * 27) # uniform box kernel, length = product of dims
filt.Run()
```
### ABTrim Filter
Applies alpha-beta trimming to remove outliers before averaging.
```python
filt = uLib.Math.VoxFilterAlgorithmAbtrim(kernel_dims)
filt.SetImage(img)
filt.SetKernelNumericXZY([1.0] * 27)
filt.SetABTrim(2, 2) # trim 2 low and 2 high values
filt.Run()
```
### Bilateral Filter
Edge-preserving smoothing controlled by a spatial sigma (from the kernel shape) and an intensity sigma.
```python
filt = uLib.Math.VoxFilterAlgorithmBilateral(kernel_dims)
filt.SetImage(img)
filt.SetKernelNumericXZY([1.0] * 27)
filt.SetIntensitySigma(0.3)
filt.Run()
```
### Threshold Filter
Zeros voxels below a threshold.
```python
filt = uLib.Math.VoxFilterAlgorithmThreshold(kernel_dims)
filt.SetImage(img)
filt.SetKernelNumericXZY([1.0] * 27)
filt.SetThreshold(0.5)
filt.Run()
```
### Median Filter
```python
filt = uLib.Math.VoxFilterAlgorithmMedian(kernel_dims)
filt.SetImage(img)
filt.SetKernelNumericXZY([1.0] * 27)
filt.Run()
```
---
## uLib.Math Accumulators
Accumulators collect scalar samples and return a summary statistic.
```python
# Arithmetic mean
acc = uLib.Math.Accumulator_Mean_f()
acc(10.0)
acc(20.0)
mean = acc() # 15.0
# Alpha-beta trimmed mean
acc2 = uLib.Math.Accumulator_ABTrim_f()
acc2.SetABTrim(0.1, 0.1) # trim bottom 10 % and top 10 %
acc2 += 1.0
acc2 += 9999.0 # outlier
acc2 += 5.0
result = acc2() # trimmed mean ≈ 3.0
```
---
## Dynamic Vectors (`uLib.Math.Vector_*`)
Typed dynamic arrays backed by `uLib::Vector<T>` with optional CUDA memory management.
```python
# Integer vector
vi = uLib.Math.Vector_i()
vi.append(1); vi.append(2); vi.append(3)
print(len(vi), vi[0])
# Float vector with CUDA management
vf = uLib.Math.Vector_f()
vf.append(1.5)
vf.MoveToVRAM() # copy to GPU (no-op when CUDA is absent)
vf.MoveToRAM() # copy back to CPU
# Other types: Vector_ui, Vector_l, Vector_ul, Vector_d
# Compound element types: Vector_Vector3f, Vector_Vector4f, Vector_Voxel …
```

561
mkdocs.yml Normal file
View File

@@ -0,0 +1,561 @@
# site_name: uLib Documentation
# site_description: CMT Cosmic Muon Tomography uLib toolkit
# site_author: Andrea Rigoni Garola
# repo_url: https://github.com/cmt/ulib
# docs_dir: docs
# +--------------------------------------------------------------------------------------------------------+
# | |
# | This is the main file used by MkDocs to build the pages. |
# | It contains a lot of information and settings for you to read and use. |
# | Comments may contain "Read More" URLs to more in-depth documentation about the option for you to read. |
# | |
# | You can check out https://www.mkdocs.org/user-guide/configuration/ for a more detailed explanation of |
# | all the options MkDocs offers by default. |
# | |
# +------------------------------------------------- NOTE -------------------------------------------------+
# | |
# | Some of the options listed here are only available through the usage of Material for MkDocs. |
# | Those options will usually have a link to the docs of this Theme and also mention "Material" as name. |
# | The actual name of the theme is "Material for MkDocs" and "Material" is used for simplicity reasons. |
# | |
# +--------------------------------------------------------------------------------------------------------+
# +--------------------------------------------------------------------------------------------------------+
# | |
# | Main Page Settings for MkDocs. |
# | Those settings are site name, site description, Site author and also Site URL (Canonical URL) |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#site_name |
# | - https://www.mkdocs.org/user-guide/configuration/#site_description |
# | - https://www.mkdocs.org/user-guide/configuration/#site_author |
# | - https://www.mkdocs.org/user-guide/configuration/#site_url |
# | |
# +--------------------------------------------------------------------------------------------------------+
site_name: OpenCMT uLib Documentation
site_url: https://docs.mildstone.org/uLib/ # <--- project subfolder
use_directory_urls: true
site_description: 'Documentation for OpenCMT uLib'
site_author: 'Andrea Rigoni Garola'
# +--------------------------------------------------------------------------------------------------------+
# | |
# | This setting allows you to define your own Copyright notice. |
# | The text is treated as HTML code so you can use things like <a> tags or &copy; to display the |
# | Copyright icon. |
# | |
# | Where or IF the Copyright is displayed depends on the theme you use. |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#copyright |
# | |
# +--------------------------------------------------------------------------------------------------------+
copyright: |
&copy; Author
# +--------------------------------------------------------------------------------------------------------+
# | |
# | The base folder to use. |
# | Any Markdown files you put into this folder will be turned into a static HTML page once you build or |
# | publish your page. |
# | |
# | It is also used as the base directory for other settings like the "extra_css" or "extra_javascript" |
# | option. |
# | |
# +--------------------------------------------------------------------------------------------------------+
docs_dir: docs/
# +--------------------------------------------------------------------------------------------------------+
# | |
# | These options allow to define a Repository to link to. |
# | The result will, depending on the theme, be a link somewhere shown on the page that links to the |
# | Repository with the specified repo_name. |
# | |
# | This will also enable a "edit" button on the page itself that allows the direct editing of the page. |
# | You can disable this by setting "edit_uri" to an empty String. |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#repo_name |
# | - https://www.mkdocs.org/user-guide/configuration/#repo_url |
# | - https://www.mkdocs.org/user-guide/configuration/#edit_uri |
# | |
# +--------------------------------------------------------------------------------------------------------+
repo_name: OpenCMT/uLib
repo_url: https://gitea.mildstone.org/OpenCMT/uLib.git
#edit_uri: tree/master/docs # Uncomment to define a different URI/URL for the "edit" option
# +--------------------------------------------------------------------------------------------------------+
# | |
# | The "nav" option is where you define the navigation to show in MkDocs. |
# | |
# | Depending on the theme you use will the resulting Navigation look different. |
# | |
# | You can set different types of navigations. Either just the path, the path with a separate title or |
# | an external URL. |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#documentation-layout |
# | |
# +--------------------------------------------------------------------------------------------------------+
nav:
- Home: index.md
- Python:
- Installation: python/installation.md
- API Usage: python/usage.md
- Developer Guide: python/developer_guide.md
- C++ Build:
- Usage & CUDA: usage/usage.md
# +--------------------------------------------------------------------------------------------------------+
# | |
# | The "theme" section allows you to define what theme to use. |
# | It is also used for theme-specific options, but also for advanced stuff such as theme-extensions, if |
# | the theme actually supports it. |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#theme |
# | |
# +--------------------------------------------------------------------------------------------------------+
theme:
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "name" option is where you define the theme to use. |
# | |
# | Note that not all themes are included by default and will require you to install them first. |
# | The Material theme is one of them. See the "Read More" link for instructions on how to install it. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/getting-started/ |
# | |
# +------------------------------------------------------------------------------------------------------+
name: 'material'
# +------------------------------------------------------------------------------------------------------+
# | |
# | The Material theme allows "theme-extsnions", meaning that you can override parts of it by either |
# | overriding a particular file, or only parts (blocks) of it. |
# | |
# | If you want to override parts of Material, uncomment the "custom_dir" option below and set the |
# | folder (relative to the mkdocs.yml file) where your theme extensions will be located at. |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#custom_dir |
# | - https://squidfunk.github.io/mkdocs-material/customization/#extending-the-theme |
# | |
# +------------------------------------------------------------------------------------------------------+
#custom_dir: 'theme'
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "favicon" option allows you to set your own image/icon to use in the browser-tab. |
# | |
# | Pretty much all image types are supported, but it's recommended to use a PNG, SVG or ICO image for |
# | the favicon. |
# | |
# | The directory is relative to the "docs_dir". |
# | |
# | Example: Having a favicon.png in docs/assets/images will result in the "favicon" setting showing |
# | 'assets/images/favicon.png' |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-logo-and-icons/#favicon |
# | |
# +------------------------------------------------------------------------------------------------------+
#favicon: 'assets/images/favicon.png'
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "palette" section is a Material option and allows you to define specific style options such as |
# | Color-Scheme, and primary and secondary Color. |
# | |
# | You can also define multiple palettes that can have different Color Schemses and primary and/or |
# | secondary Colors. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/ |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/#color-palette-toggle |
# | |
# +------------------------------------------------------------------------------------------------------+
palette:
# Palette toggle for light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: 'indigo'
accent: 'indigo'
toggle:
icon: material/brightness-7
name: Switch to dark mode
# Palette toggle for dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: 'indigo'
accent: 'indigo'
toggle:
icon: material/brightness-4
name: Switch to light mode
# +------------------------------------------------------------------------------------------------------+
# | |
# | With the "font" option can you set a different font to use. |
# | |
# | Material supports all Google fonts, but you can also define your own ones if you choose so. |
# | |
# | The "text" option is used for the regular font while "code" is used for code blocks, inline code and |
# | similar. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-fonts/ |
# | |
# +------------------------------------------------------------------------------------------------------+
#font:
# text: 'Roboto'
# code: 'Roboto Mono'
# +------------------------------------------------------------------------------------------------------+
# | |
# | Material suppors more than 40 different languages which you can set using the "language" option |
# | below. |
# | |
# | The default language is "en" (English). |
# | |
# | You can also enable/set a "selector" to allow switching between languages. |
# | See the "alternate" option in the "extra" section below for more information on this topic. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-language/ |
# | |
# +------------------------------------------------------------------------------------------------------+
#language: 'en'
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "direction" option is commonly used together with the "language" option. |
# | |
# | It allows you to change the text direction from the default left-to-right (ltr) to right-to-left |
# | (rtl) which is used in certain languages. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-language/#directionality |
# | |
# +------------------------------------------------------------------------------------------------------+
#direction: 'ltr'
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "features" option allows you to enable specific features of Material, by adding them to the |
# | list. |
# | |
# | Features are in the format <category>.<name>. As an example, the feature to enable tabs is called |
# | navigation.tabs. |
# | |
# | The list below contains all known features of Material. |
# | |
# | Features marked with a * are currently Insiders-only. (Last update: 11th December 2021) |
# | https://squidfunk.github.io/mkdocs-material/insiders/ |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/ |
# | |
# +------------------------------------------------------------------------------------------------------+
features:
# Announce
#
#- announce.dismiss # Adds a "X" button to dismiss a news banner/mark it as read.*
# Header
#
#- header.autohide # Hide header when user scrolls past a specific point.
# Navigation:
#
#- navigation.expand # Expand all collapsable sections.
#- navigation.instant # Instant loading pages.
#- navigation.indexes # Attach pages directly to Sections. Incompatible with "toc.integrate"
#- navigation.sections # Render top sections as groups.
- navigation.tabs # Render top sections as tabs at the top.
#- navigation.tabs.sticky # Tabs won't disappear when scrolling down. Requires "navigation.tabs".
#- navigation.top # Adds a "Back to top" that is shown when scrolling up.
#- navigation.tracking # Updates the url with highlighted section anchor.
# Search
#
#- search.highlight # Search will highlight the searched word(s) on the page.*
#- search.share # Adds an option to share a search query link.*
#- search.suggest # Search will suggest the likeliest completion for a word.*
# Table of Contents
#
#- toc.integrate # Include the TOC sections in the left navugation.
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "icon" section allows you to define a icon to use for the logo and/or repository. |
# | |
# | To use already available icons will you need to set the right path for it, depending on which you |
# | want to use. |
# | |
# | Available icons: |
# | - FontAwesome |
# | - Brands: fontawesome/brands/... (https://fontawesome.com/icons?d=gallery&p=2&s=brands&m=free) |
# | - Regular: fontawesome/regular/... (https://fontawesome.com/icons?d=gallery&p=2&s=regular&m=free) |
# | - Solid: fontawesome/solid/... (https://fontawesome.com/icons?d=gallery&p=2&s=solid&m=free) |
# | |
# | - Material Design Icons: material/... (https://materialdesignicons.com/) |
# | |
# | - Octicons: octicons/... (https://primer.style/octicons/) |
# | |
# | You can also define your own Image for the logo. To do that, remove the "logo" option from "icon" |
# | instead add a "logo" option on the same level as the "icon" one, where you then set the path |
# | (relative to the "docs_dir") to the icon to use. Supported are all images types, including SVG. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-logo-and-icons/#logo |
# | |
# +------------------------------------------------------------------------------------------------------+
icon:
logo: 'material/library'
repo: 'material/library'
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "admonition" option allows you to set a different icon for each admonition type. |
# | |
# | This is currently a Insiders-only feature. (Last update: 7th October 2021) |
# | https://squidfunk.github.io/mkdocs-material/insiders/ |
# | |
# | Supported are all bundled icons: |
# | - FontAwesome |
# | - Brands: fontawesome/brands/... (https://fontawesome.com/icons?d=gallery&p=2&s=brands&m=free) |
# | - Regular: fontawesome/regular/... (https://fontawesome.com/icons?d=gallery&p=2&s=regular&m=free) |
# | - Solid: fontawesome/solid/... (https://fontawesome.com/icons?d=gallery&p=2&s=solid&m=free) |
# | |
# | - Material Design Icons: material/... (https://materialdesignicons.com/) |
# | |
# | - Octicons: octicons/... (https://primer.style/octicons/) |
# | |
# | You can also create and use your own icons. See the documentation for more information. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/reference/admonitions/#changing-the-icons |
# | |
# +------------------------------------------------------------------------------------------------------+
#admonition:
# note: 'octicons/tag-16'
# abstract: 'octicons/checklist-16'
# info: 'octicons/info-16'
# tip: 'octicons/squirrel-16'
# success: 'octicons/check-16'
# question: 'octicons/question-16'
# warning: 'octicons/alert-16'
# failure: 'octicons/x-circle-16'
# danger: 'octicons/zap-16'
# bug: 'octicons/bug-16'
# example: 'octicons/beaker-16'
# quote: 'octicons/quote-16'
# +--------------------------------------------------------------------------------------------------------+
# | |
# | With the "extra_css" option can you add your own (S)CSS files to enhance the documentation. |
# | |
# | The path to the file is relative to the "docs_dir". |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#extra_css |
# | |
# +--------------------------------------------------------------------------------------------------------+
extra_css:
- assets/css/extra.css
# +--------------------------------------------------------------------------------------------------------+
# | |
# | Similar to the "extra_css" option does the "extra_javascript" option allow you to set custom JS files |
# | to add extra featurues. |
# | |
# | The path to the file is relative to the "docs_dir". |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#extra_javascript |
# | |
# +--------------------------------------------------------------------------------------------------------+
extra_javascript:
- https://polyfill.io/v3/polyfill.min.js?features=es6
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
# +--------------------------------------------------------------------------------------------------------+
# | |
# | The "extra" section contains pretty much anything you want, as long as it is a valid key-value pair. |
# | |
# | Material uses this section for different custom settings that wouldn't fit in the theme section. |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#extra |
# | |
# +--------------------------------------------------------------------------------------------------------+
extra:
# +------------------------------------------------------------------------------------------------------+
# | |
# | The social section allows you to set a list of entries which would be displayed in the footer of the |
# | page. |
# | |
# | Each entry has the exact same options: |
# | - icon: Path to the SVG icon to use. See "icon" section for available icon sets. |
# | - link: URL to which the icon should link. |
# | - name: Optional Name that would be displayed as title on hover. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/setting-up-the-footer/#social-links |
# | |
# +------------------------------------------------------------------------------------------------------+
social:
- icon: 'fontawesome/brands/github'
link: 'https://github.com/Andre601/mkdocs-template'
# +------------------------------------------------------------------------------------------------------+
# | |
# | Allows you to hide the "Made with Material for MkDocs" text in the footer of the pages by setting |
# | this to "true". |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/setting-up-the-footer/#generator-notice |
# | |
# +------------------------------------------------------------------------------------------------------+
#generator: true
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "manifest" option allows you to define a .manifest file to use. |
# | |
# | A .manifest file makes the doc act like a web-application and tells it how to behave when installed. |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/reference/meta-tags/#adding-a-web-app-manifest |
# | |
# +------------------------------------------------------------------------------------------------------+
#manifest: manifest.webmanifest
# +------------------------------------------------------------------------------------------------------+
# | |
# | The "alternate" option can be used to create a selector to switch languages. |
# | |
# | Using this requires you to create a specific, more complicated MkDocs setup. |
# | |
# | A Setup Guide for multi-language docs can be found here: |
# | https://github.com/squidfunk/mkdocs-material/discussions/2346 |
# | |
# | Read More: |
# | - https://squidfunk.github.io/mkdocs-material/setup/changing-the-language/#site-language-selector |
# | |
# +------------------------------------------------------------------------------------------------------+
#alternate:
# +--------------------------------------------------------------------------------------------------------+
# | |
# | MkDocs allows the usage of Markdown extensions which can do various things. |
# | |
# | Material includes the pymdownx extension which provides a lot of useful features to use. |
# | |
# | Note that some extensions may use specific settings that you need to set. |
# | Please check out the official documentation of PyMdownx for more information: |
# | https://facelessuser.github.io/pymdown-extensions/ |
# | |
# | Material already provides required CSS and JS values for the PyMdownX Extensions, which means you do |
# | not need to set them up yourself. |
# | |
# | Read More: |
# | - https://www.mkdocs.org/user-guide/configuration/#markdown_extensions |
# | |
# +--------------------------------------------------------------------------------------------------------+
markdown_extensions:
- markdown.extensions.admonition:
- markdown.extensions.codehilite:
guess_lang: false
- markdown.extensions.toc:
permalink: true
- pymdownx.arithmatex:
generic: true
- attr_list
- md_in_html
- pymdownx.blocks.caption
- admonition
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
- pymdownx.details
- attr_list
- tables
#- pymdownx.b64:
#- pymdownx.betterem:
#- pymdownx.caret:
#- pymdownx.critic:
#- pymdownx.details:
#- pymdownx.emoji:
#- pymdownx.escapeall:
#- pymdownx.extra:
#- pymdownx.extrarawhtml:
#- pymdownx.highlight:
#- pymdownx.inlinehilite:
#- pymdownx.keys:
#- pymdownx.magiclink:
#- pymdownx.mark:
#- pymdownx.pathconverter:
#- pymdownx.progressbar:
#- pymdownx.smartsymbols:
#- pymdownx.snippets:
#- pymdownx.striphtml:
#- pymdownx.superfences:
#- pymdownx.tabbed:
#- pymdownx.tasklist:
#- pymdownx.tilde:
# - exporter:
# formats:
# pdf:
# enabled: !ENV [MKDOCS_EXPORTER_PDF, true]
# concurrency: 8
# stylesheets:
# - resources/stylesheets/pdf.scss
# covers:
# front: resources/templates/covers/front.html.j2
# back: resources/templates/covers/back.html.j2
# aggregator:
# enabled: true
# output: .well-known/site.pdf
# covers: all
# theme:
# name: material
# palette:
# - scheme: default
# primary: indigo
# accent: blue
# toggle:
# icon: material/brightness-7
# name: Switch to dark mode
# - scheme: slate
# primary: indigo
# accent: blue
# toggle:
# icon: material/brightness-4
# name: Switch to light mode
# features:
# - navigation.tabs
# - navigation.sections
# - navigation.top
# - content.code.copy
# - content.tabs.link
# plugins:
# - search
# markdown_extensions:

7
poetry.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Poetry 2.3.1 and should not be changed by hand.
package = []
[metadata]
lock-version = "2.1"
python-versions = ">=3.9"
content-hash = "db9b4c08b159b17b239e26c67ead7c37b82d9f9eb06550245ae3134c095f98f7"

15
pyproject.toml Normal file
View File

@@ -0,0 +1,15 @@
[tool.poetry]
name = "uLib"
version = "0.6.0"
description = "CMT Cosmic Muon Tomography project uLib python bindings"
authors = ["Andrea Rigoni Garola <andrea.rigoni@pd.infn.it>"]
readme = "README.md"
packages = [{ include = "uLib", from = "src/Python" }]
build = "build_python.py"
[tool.poetry.dependencies]
python = ">=3.9"
[build-system]
requires = ["poetry-core>=2.0.0", "pybind11>=2.6.0", "cmake>=3.12"]
build-backend = "poetry.core.masonry.api"

View File

@@ -1,7 +1,36 @@
set(HEADERS Archives.h Array.h Collection.h DataAllocator.h Debug.h Export.h Function.h Macros.h Mpl.h Object.h Options.h Serializable.h Signal.h Singleton.h SmartPointer.h StaticInterface.h StringReader.h Types.h Uuid.h Vector.h) set(HEADERS
Archives.h
Array.h
Collection.h
DataAllocator.h
Debug.h
Export.h
Function.h
Macros.h
Mpl.h
Object.h
Options.h
Serializable.h
Signal.h
Singleton.h
SmartPointer.h
StaticInterface.h
StringReader.h
Types.h
Uuid.h
Vector.h
)
set(SOURCES Archives.cpp Debug.cpp Object.cpp Options.cpp Serializable.cpp Signal.cpp Uuid.cpp) set(SOURCES
Archives.cpp
Debug.cpp
Object.cpp
Options.cpp
Serializable.cpp
Signal.cpp
Uuid.cpp
)
set(LIBRARIES Boost::program_options Boost::serialization) set(LIBRARIES Boost::program_options Boost::serialization)
@@ -20,7 +49,7 @@ endif()
target_link_libraries(${libname} ${LIBRARIES}) target_link_libraries(${libname} ${LIBRARIES})
install(TARGETS ${libname} install(TARGETS ${libname}
EXPORT "${PROJECT_NAME}Targets" EXPORT "uLibTargets"
RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin
LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib) LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib)

View File

@@ -34,6 +34,7 @@
#ifdef USE_CUDA #ifdef USE_CUDA
#include <cuda_runtime.h> #include <cuda_runtime.h>
#include <thrust/device_vector.h>
#endif #endif
namespace uLib { namespace uLib {

View File

@@ -37,6 +37,11 @@
#include <Core/SmartPointer.h> #include <Core/SmartPointer.h>
#include <Core/StaticInterface.h> #include <Core/StaticInterface.h>
#ifdef USE_CUDA
#include <thrust/device_ptr.h>
#include <thrust/device_vector.h>
#endif
namespace uLib { namespace uLib {
// MetaAllocator Implementation ... // MetaAllocator Implementation ...
@@ -136,6 +141,7 @@ public:
Vector(unsigned int size) : BaseClass(size) {} Vector(unsigned int size) : BaseClass(size) {}
Vector(unsigned int size, T &value) : BaseClass(size, value) {} Vector(unsigned int size, T &value) : BaseClass(size, value) {}
Vector() : BaseClass(0) {} Vector() : BaseClass(0) {}
Vector(std::initializer_list<T> init) : BaseClass(init) {}
inline VectorCommaInit operator<<(T scalar) { inline VectorCommaInit operator<<(T scalar) {
return VectorCommaInit(this, scalar); return VectorCommaInit(this, scalar);
@@ -168,6 +174,42 @@ public:
return nullptr; return nullptr;
} }
#ifdef USE_CUDA
/// Returns a thrust::device_ptr to the VRAM data (valid after MoveToVRAM()).
/// thrust::device_ptr<T> is itself a random-access iterator compatible with
/// all thrust algorithms (thrust::transform, thrust::sort,
/// thrust::for_each…).
thrust::device_ptr<T> DeviceData() {
if (auto alloc = MetaAllocator<T>::GetDataAllocator(BaseClass::data())) {
return thrust::device_pointer_cast(alloc->GetVRAMData());
}
return thrust::device_ptr<T>(nullptr);
}
thrust::device_ptr<const T> DeviceData() const {
if (auto alloc = MetaAllocator<T>::GetDataAllocator(
const_cast<T *>(BaseClass::data()))) {
return thrust::device_pointer_cast(
static_cast<const T *>(alloc->GetVRAMData()));
}
return thrust::device_ptr<const T>(nullptr);
}
/// Device-side begin iterator (valid after MoveToVRAM()).
thrust::device_ptr<T> DeviceBegin() { return DeviceData(); }
/// Device-side end iterator (valid after MoveToVRAM()).
thrust::device_ptr<T> DeviceEnd() {
return DeviceData() + static_cast<std::ptrdiff_t>(BaseClass::size());
}
thrust::device_ptr<const T> DeviceBegin() const { return DeviceData(); }
thrust::device_ptr<const T> DeviceEnd() const {
return DeviceData() + static_cast<std::ptrdiff_t>(BaseClass::size());
}
#endif // USE_CUDA
inline void PrintSelf(std::ostream &o); inline void PrintSelf(std::ostream &o);
// Overrides for auto-sync // // Overrides for auto-sync //
@@ -274,6 +316,11 @@ public:
this->MoveToRAM(); this->MoveToRAM();
return BaseClass::insert(pos, std::move(x)); return BaseClass::insert(pos, std::move(x));
} }
template <typename InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last) {
this->MoveToRAM();
return BaseClass::insert(pos, first, last);
}
iterator erase(const_iterator pos) { iterator erase(const_iterator pos) {
this->MoveToRAM(); this->MoveToRAM();
return BaseClass::erase(pos); return BaseClass::erase(pos);

View File

@@ -1,31 +0,0 @@
#include <Core/Vector.h>
#include <iostream>
int main() {
uLib::Vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::cout << "RAM Vector elements: ";
for (int i = 0; i < v.size(); ++i) {
std::cout << v[i] << " ";
}
std::cout << std::endl;
#ifdef USE_CUDA
std::cout << "Moving to VRAM..." << std::endl;
v.MoveToVRAM();
int *vram_ptr = v.GetVRAMData();
if (vram_ptr) {
std::cout << "Successfully got VRAM pointer!" << std::endl;
} else {
std::cout << "Failed to get VRAM pointer!" << std::endl;
}
std::cout << "Moving back to RAM..." << std::endl;
v.MoveToRAM();
#endif
return 0;
}

View File

@@ -31,3 +31,8 @@ set(LIBRARIES
${ROOT_LIBRARIES} ${ROOT_LIBRARIES}
) )
uLib_add_tests(Core) uLib_add_tests(Core)
if(USE_CUDA)
set_source_files_properties(VectorMetaAllocatorTest.cpp PROPERTIES LANGUAGE CUDA)
endif()

View File

@@ -12,6 +12,15 @@
#include "testing-prototype.h" #include "testing-prototype.h"
#include <Core/Vector.h> #include <Core/Vector.h>
#ifdef USE_CUDA
#include <thrust/device_ptr.h>
#include <thrust/transform.h>
struct DoubleFunctor {
__host__ __device__ int operator()(int x) const { return x * 2; }
};
#endif
int main() { int main() {
BEGIN_TESTING(VectorMetaAllocator); BEGIN_TESTING(VectorMetaAllocator);
@@ -41,14 +50,31 @@ int main() {
exit(1); exit(1);
} }
// Verify DeviceData() matches GetVRAMData()
{
thrust::device_ptr<int> dev_ptr = v.DeviceData();
if (dev_ptr.get() != vram_ptr) {
std::cout << "Error: DeviceData() does not match GetVRAMData()!\n";
exit(1);
}
std::cout << "DeviceData() matches GetVRAMData(). OK\n";
}
// Use thrust::transform via DeviceBegin()/DeviceEnd() to double all elements
// on device
std::cout << "Doubling elements on device via thrust::transform...\n";
thrust::transform(v.DeviceBegin(), v.DeviceEnd(), v.DeviceBegin(),
DoubleFunctor{});
std::cout << "Moving back to RAM...\n"; std::cout << "Moving back to RAM...\n";
v.MoveToRAM(); v.MoveToRAM();
std::cout << "RAM contents after VRAM trip: "; std::cout << "RAM contents after VRAM trip + thrust transform: ";
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
std::cout << v[i] << " "; std::cout << v[i] << " ";
if (v[i] != (int)(i + 1)) { if (v[i] != (int)((i + 1) * 2)) {
std::cout << "\nError: Data corrupted after RAM->VRAM->RAM trip at index " std::cout << "\nError: Data corrupted after RAM->VRAM->thrust->RAM trip "
"at index "
<< i << "\n"; << i << "\n";
exit(1); exit(1);
} }

View File

@@ -1,12 +0,0 @@
set(HEADERS MuonScatter.h MuonError.h MuonEvent.h)
set(ULIB_SELECTED_MODULES ${ULIB_SELECTED_MODULES} Detectors PARENT_SCOPE)
install(FILES ${HEADERS}
DESTINATION ${INSTALL_INC_DIR}/Detectors)
if(BUILD_TESTING)
include(uLibTargetMacros)
add_subdirectory(testing)
endif()

12
src/HEP/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
################################################################################
##### HEP - High Energy Physics modules ########################################
################################################################################
include_directories(${SRC_DIR}/HEP)
add_subdirectory(Detectors)
add_subdirectory(Geant)
set(ULIB_SHARED_LIBRARIES ${ULIB_SHARED_LIBRARIES} PARENT_SCOPE)
set(ULIB_SELECTED_MODULES ${ULIB_SELECTED_MODULES} PARENT_SCOPE)

View File

@@ -0,0 +1,34 @@
set(HEADERS
ChamberHitEvent.h
DetectorChamber.h
ExperimentFitEvent.h
HierarchicalEncoding.h
Hit.h
HitMC.h
LinearFit.h
MuonError.h
MuonEvent.h
MuonScatter.h
)
set(libname ${PACKAGE_LIBPREFIX}Detectors)
set(ULIB_SHARED_LIBRARIES ${ULIB_SHARED_LIBRARIES} ${libname} PARENT_SCOPE)
set(ULIB_SELECTED_MODULES ${ULIB_SELECTED_MODULES} Detectors PARENT_SCOPE)
## Headers-only INTERFACE library
add_library(${libname} INTERFACE)
target_include_directories(${libname} INTERFACE
$<BUILD_INTERFACE:${SRC_DIR}>
$<INSTALL_INTERFACE:${INSTALL_INC_DIR}>
)
install(TARGETS ${libname}
EXPORT "uLibTargets")
install(FILES ${HEADERS}
DESTINATION ${INSTALL_INC_DIR}/HEP/Detectors)
if(BUILD_TESTING)
include(uLibTargetMacros)
add_subdirectory(testing)
endif()

View File

@@ -0,0 +1,52 @@
################################################################################
##### HEP/Geant - Geant4 integration library ###################################
################################################################################
find_package(Geant4 QUIET)
if(NOT Geant4_FOUND)
message(STATUS "Geant4 not found - skipping mutomGeant library")
return()
endif()
message(STATUS "Geant4 found: ${Geant4_VERSION}")
include(${Geant4_USE_FILE})
set(HEADERS
GeantEvent.h
Matter.h
Scene.h
Solid.h
)
set(SOURCES
Scene.cpp
Solid.cpp
)
set(libname ${PACKAGE_LIBPREFIX}Geant)
set(ULIB_SHARED_LIBRARIES ${ULIB_SHARED_LIBRARIES} ${libname} PARENT_SCOPE)
set(ULIB_SELECTED_MODULES ${ULIB_SELECTED_MODULES} Geant PARENT_SCOPE)
add_library(${libname} SHARED ${SOURCES})
set_target_properties(${libname} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_SOVERSION})
target_include_directories(${libname} PRIVATE ${Geant4_INCLUDE_DIRS})
target_link_libraries(${libname}
${PACKAGE_LIBPREFIX}Core
${PACKAGE_LIBPREFIX}Math
${PACKAGE_LIBPREFIX}Detectors
${Geant4_LIBRARIES}
)
install(TARGETS ${libname}
EXPORT "uLibTargets"
RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin
LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib)
install(FILES ${HEADERS}
DESTINATION ${INSTALL_INC_DIR}/HEP/Geant)

View File

@@ -23,8 +23,6 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#ifndef U_GEANTEVENT_H #ifndef U_GEANTEVENT_H
#define U_GEANTEVENT_H #define U_GEANTEVENT_H
@@ -38,14 +36,11 @@ namespace uLib {
class GeantEventData { class GeantEventData {
public: public:
uLibGetMacro (EventID, Id_t ) uLibGetMacro(EventID, Id_t) uLibGetMacro(Momentum, Scalarf)
uLibGetMacro (Momentum,Scalarf ) uLibConstRefMacro(GenPos, Vector3f) uLibConstRefMacro(GenDir, Vector3f)
uLibConstRefMacro (GenPos, Vector3f)
uLibConstRefMacro (GenDir, Vector3f)
uLibConstRefMacro(ChEvents, Vector<ChamberHitEventData>) uLibConstRefMacro(ChEvents, Vector<ChamberHitEventData>)
private: private : friend class GeantEvent;
friend class GeantEvent;
Id_t m_EventID; Id_t m_EventID;
Scalarf m_Momentum; Scalarf m_Momentum;
Vector3f m_GenPos; Vector3f m_GenPos;
@@ -55,15 +50,11 @@ private:
class GeantEvent { class GeantEvent {
public: public:
uLibSetMacro (EventID, Id_t ) uLibSetMacro(EventID, Id_t) uLibSetMacro(Momentum, Scalarf)
uLibSetMacro (Momentum,Scalarf ) uLibRefMacro(GenPos, Vector3f) uLibRefMacro(GenDir, Vector3f)
uLibRefMacro (GenPos, Vector3f)
uLibRefMacro (GenDir, Vector3f)
uLibRefMacro(ChEvents, Vector<ChamberHitEventData>) uLibRefMacro(ChEvents, Vector<ChamberHitEventData>)
}; };
} // namespace uLib
}
#endif // GEANTEVENT_H #endif // GEANTEVENT_H

View File

@@ -54,7 +54,7 @@ endif()
install(TARGETS ${libname} install(TARGETS ${libname}
EXPORT "${PROJECT_NAME}Targets" EXPORT "uLibTargets"
RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin
LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib) LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib)

View File

@@ -29,62 +29,146 @@
#define U_CONTAINERBOX_H #define U_CONTAINERBOX_H
#include "Geometry.h" #include "Geometry.h"
#include "Math/Dense.h"
#include "Math/Transform.h"
#include <utility>
namespace uLib { namespace uLib {
/**
* @brief Represents an oriented bounding box (OBB) within a hierarchical transformation system.
*
* ContainerBox inherits from AffineTransform, which defines its parent coordinate system.
* It contains an internal local transformation (m_LocalT) that defines the box's
* specific origin and size relative to its own coordinate system.
*/
class ContainerBox : public AffineTransform { class ContainerBox : public AffineTransform {
public:
ContainerBox() : m_LocalT(this) {}
typedef AffineTransform BaseClass;
public:
/**
* @brief Default constructor.
* Initializes the local transformation with this instance as its parent.
*/
ContainerBox() :
m_LocalT(this) // BaseClass is Parent of m_LocalTransform
{}
/**
* @brief Copy constructor.
* @param copy The ContainerBox instance to copy from.
*/
ContainerBox(const ContainerBox &copy) : ContainerBox(const ContainerBox &copy) :
m_LocalT(this), m_LocalT(this), // BaseClass is Parent of m_LocalTransform
AffineTransform(copy) AffineTransform(copy)
{ {
// FIX for performance //
this->SetOrigin(copy.GetOrigin()); this->SetOrigin(copy.GetOrigin());
this->SetSize(copy.GetSize()); this->SetSize(copy.GetSize());
} }
/**
* @brief Sets the box origin relative to its coordinate system.
* @param v The origin position vector.
*/
inline void SetOrigin(const Vector3f &v) { m_LocalT.SetPosition(v); } inline void SetOrigin(const Vector3f &v) { m_LocalT.SetPosition(v); }
/**
* @brief Gets the box origin relative to its coordinate system.
* @return The origin position vector.
*/
inline Vector3f GetOrigin() const { return m_LocalT.GetPosition(); } inline Vector3f GetOrigin() const { return m_LocalT.GetPosition(); }
/**
* @brief Sets the size of the box.
* Re-initializes the local transformation and applies the new scale.
* @param v The size vector (width, height, depth).
*/
void SetSize(const Vector3f &v) { void SetSize(const Vector3f &v) {
Vector3f pos = this->GetOrigin(); Vector3f pos = this->GetOrigin();
m_LocalT = AffineTransform(this); m_LocalT = AffineTransform(this); // regenerate local transform
m_LocalT.Scale(v); m_LocalT.Scale(v);
m_LocalT.SetPosition(pos); m_LocalT.SetPosition(pos);
} }
/**
* @brief Gets the current size (scale) of the box.
* @return The size vector.
*/
inline Vector3f GetSize() const { return m_LocalT.GetScale(); } inline Vector3f GetSize() const { return m_LocalT.GetScale(); }
// FIX... // /**
* @brief Swaps two local axes of the box.
* @param first Index of the first axis (0=X, 1=Y, 2=Z).
* @param second Index of the second axis (0=X, 1=Y, 2=Z).
*/
inline void FlipLocalAxes(int first, int second) inline void FlipLocalAxes(int first, int second)
{ m_LocalT.FlipAxes(first,second); } { m_LocalT.FlipAxes(first,second); }
/**
* @brief Returns the world transformation matrix of the box's volume.
* @return A 4x4 transformation matrix.
*/
Matrix4f GetWorldMatrix() const { return m_LocalT.GetWorldMatrix(); } Matrix4f GetWorldMatrix() const { return m_LocalT.GetWorldMatrix(); }
/**
* @brief Returns the local transformation matrix of the box's volume.
* @return A 4x4 transformation matrix.
*/
Matrix4f GetLocalMatrix() const { return m_LocalT.GetMatrix(); }
/**
* @brief Transforms a point from box-local space to world space.
* @param v The local point (4D homogeneous vector).
* @return The transformed point in world space.
*/
inline Vector4f GetWorldPoint(const Vector4f &v) const { inline Vector4f GetWorldPoint(const Vector4f &v) const {
return m_LocalT.GetWorldMatrix() * v; return m_LocalT.GetWorldMatrix() * v;
} }
/**
* @brief Transforms a point from box-local space coordinates to world space.
* @param x X coordinate in local space.
* @param y Y coordinate in local space.
* @param z Z coordinate in local space.
* @return The transformed point in world space.
*/
inline Vector4f GetWorldPoint(const float x, const float y, const float z) { inline Vector4f GetWorldPoint(const float x, const float y, const float z) {
return this->GetWorldPoint(Vector4f(x,y,z,1)); return this->GetWorldPoint(Vector4f(x,y,z,1));
} }
/**
* @brief Transforms a point from world space to box-local space.
* @param v The world point (4D homogeneous vector).
* @return The transformed point in box-local space.
*/
inline Vector4f GetLocalPoint(const Vector4f &v) const { inline Vector4f GetLocalPoint(const Vector4f &v) const {
return m_LocalT.GetWorldMatrix().inverse() * v; return m_LocalT.GetWorldMatrix().inverse() * v;
} }
/**
* @brief Transforms a point from world space coordinates to box-local space.
* @param x X coordinate in world space.
* @param y Y coordinate in world space.
* @param z Z coordinate in world space.
* @return The transformed point in box-local space.
*/
inline Vector4f GetLocalPoint(const float x, const float y, const float z) { inline Vector4f GetLocalPoint(const float x, const float y, const float z) {
return this->GetLocalPoint(Vector4f(x,y,z,1)); return this->GetLocalPoint(Vector4f(x,y,z,1));
} }
/** Translate using transformation chain */
using BaseClass::Translate;
/** Rotate using transformation chain */
using BaseClass::Rotate;
/** Scale using transformation chain */
using BaseClass::Scale;
protected:
private: private:
AffineTransform m_LocalT; AffineTransform m_LocalT;

View File

@@ -47,6 +47,7 @@
#ifndef ULIB_DENSEMATRIX_H #ifndef ULIB_DENSEMATRIX_H
#define ULIB_DENSEMATRIX_H #define ULIB_DENSEMATRIX_H
// #include <Eigen/src/Core/Matrix.h>
#include <stdlib.h> #include <stdlib.h>
#include <Eigen/Dense> #include <Eigen/Dense>
@@ -114,6 +115,21 @@ typedef unsigned long Scalarul;
typedef float Scalarf; typedef float Scalarf;
typedef double Scalard; typedef double Scalard;
typedef Eigen::Matrix<int, 1, 1> Vector1i;
typedef Eigen::Vector2i Vector2i;
typedef Eigen::Vector3i Vector3i;
typedef Eigen::Vector4i Vector4i;
typedef Eigen::Matrix<float, 1, 1> Vector1f;
typedef Eigen::Vector2f Vector2f;
typedef Eigen::Vector3f Vector3f;
typedef Eigen::Vector4f Vector4f;
typedef Eigen::Matrix<double, 1, 1> Vector1d;
typedef Eigen::Vector2d Vector2d;
typedef Eigen::Vector3d Vector3d;
typedef Eigen::Vector4d Vector4d;
typedef Eigen::Matrix<int, 1, 1> Matrix1i; typedef Eigen::Matrix<int, 1, 1> Matrix1i;
typedef Eigen::Matrix2i Matrix2i; typedef Eigen::Matrix2i Matrix2i;
typedef Eigen::Matrix3i Matrix3i; typedef Eigen::Matrix3i Matrix3i;
@@ -124,15 +140,15 @@ typedef Eigen::Matrix2f Matrix2f;
typedef Eigen::Matrix3f Matrix3f; typedef Eigen::Matrix3f Matrix3f;
typedef Eigen::Matrix4f Matrix4f; typedef Eigen::Matrix4f Matrix4f;
typedef Eigen::Matrix<int, 1, 1> Vector1i; typedef Eigen::Matrix<double, 1, 1> Matrix1d;
typedef Eigen::Vector2i Vector2i; typedef Eigen::Matrix2d Matrix2d;
typedef Eigen::Vector3i Vector3i; typedef Eigen::Matrix3d Matrix3d;
typedef Eigen::Vector4i Vector4i; typedef Eigen::Matrix4d Matrix4d;
typedef Eigen::MatrixXi MatrixXi;
typedef Eigen::MatrixXf MatrixXf;
typedef Eigen::MatrixXd MatrixXd;
typedef Eigen::Matrix<float, 1, 1> Vector1f;
typedef Eigen::Vector2f Vector2f;
typedef Eigen::Vector3f Vector3f;
typedef Eigen::Vector4f Vector4f;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Vector String interaction /////////////////////////////////////////////////// // Vector String interaction ///////////////////////////////////////////////////
@@ -188,6 +204,9 @@ public:
typedef Eigen::Matrix<Scalarf, 4, 1> BaseClass; typedef Eigen::Matrix<Scalarf, 4, 1> BaseClass;
_HPoint3f() : BaseClass(0, 0, 0, p) {} _HPoint3f() : BaseClass(0, 0, 0, p) {}
_HPoint3f(int rows, int cols) : BaseClass() {
this->operator()(3) = p;
}
_HPoint3f(float x, float y, float z) : BaseClass(x, y, z, p) {} _HPoint3f(float x, float y, float z) : BaseClass(x, y, z, p) {}
_HPoint3f(Vector3f &in) : BaseClass(in.homogeneous()) { _HPoint3f(Vector3f &in) : BaseClass(in.homogeneous()) {
this->operator()(3) = p; this->operator()(3) = p;

View File

@@ -36,7 +36,7 @@ namespace uLib {
class Geometry : public AffineTransform { class Geometry : public AffineTransform {
public: public:
inline Vector4f GetWorldPoint(const Vector4f &v) const { inline Vector4f GetWorldPoint(const Vector4f v) const {
return this->GetWorldMatrix() * v; return this->GetWorldMatrix() * v;
} }
@@ -44,7 +44,7 @@ public:
return this->GetWorldPoint(Vector4f(x,y,z,1)); return this->GetWorldPoint(Vector4f(x,y,z,1));
} }
inline Vector4f GetLocalPoint(const Vector4f &v) const { inline Vector4f GetLocalPoint(const Vector4f v) const {
return this->GetWorldMatrix().inverse() * v; return this->GetWorldMatrix().inverse() * v;
} }

View File

@@ -84,8 +84,8 @@ public:
inline void SetParent(AffineTransform *name) { this->m_Parent = name; } inline void SetParent(AffineTransform *name) { this->m_Parent = name; }
inline void SetMatrix (Matrix4f &mat) { m_T.matrix() = mat; } inline void SetMatrix (Matrix4f mat) { m_T.matrix() = mat; }
inline Matrix4f& GetMatrix () { return m_T.matrix(); } inline Matrix4f GetMatrix() const { return m_T.matrix(); }
Matrix4f GetWorldMatrix() const Matrix4f GetWorldMatrix() const
{ {
@@ -93,22 +93,22 @@ public:
else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A // else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A //
} }
inline void SetPosition(const Vector3f &v) { this->m_T.translation() = v; } inline void SetPosition(const Vector3f v) { this->m_T.translation() = v; }
inline Vector3f GetPosition() const { return this->m_T.translation(); } inline Vector3f GetPosition() const { return this->m_T.translation(); }
inline void SetRotation(const Matrix3f &m) { this->m_T.linear() = m; } inline void SetRotation(const Matrix3f m) { this->m_T.linear() = m; }
inline Matrix3f GetRotation() const { return this->m_T.rotation(); } inline Matrix3f GetRotation() const { return this->m_T.rotation(); }
inline void Translate(const Vector3f &v) { this->m_T.translate(v); } inline void Translate(const Vector3f v) { this->m_T.translate(v); }
inline void Scale(const Vector3f &v) { this->m_T.scale(v); } inline void Scale(const Vector3f v) { this->m_T.scale(v); }
inline Vector3f GetScale() const { return this->m_T.linear() * Vector3f(1,1,1); } // FIXXXXXXX inline Vector3f GetScale() const { return this->m_T.linear() * Vector3f(1,1,1); } // FIXXXXXXX
inline void Rotate(const Matrix3f &m) { this->m_T.rotate(m); } inline void Rotate(const Matrix3f m) { this->m_T.rotate(m); }
inline void Rotate(const float angle, Vector3f axis) inline void Rotate(const float angle, Vector3f axis)
{ {
@@ -122,12 +122,12 @@ public:
Rotate(angle,euler_axis); Rotate(angle,euler_axis);
} }
inline void PreRotate(const Matrix3f &m) { this->m_T.prerotate(m); } inline void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); }
inline void QuaternionRotate(const Vector4f &q) inline void QuaternionRotate(const Vector4f q)
{ this->m_T.rotate(Eigen::Quaternion<float>(q)); } { this->m_T.rotate(Eigen::Quaternion<float>(q)); }
inline void EulerYZYRotate(const Vector3f &e) { inline void EulerYZYRotate(const Vector3f e) {
Matrix3f mat; Matrix3f mat;
mat = Eigen::AngleAxisf(e.x(), Vector3f::UnitY()) mat = Eigen::AngleAxisf(e.x(), Vector3f::UnitY())
* Eigen::AngleAxisf(e.y(), Vector3f::UnitZ()) * Eigen::AngleAxisf(e.y(), Vector3f::UnitZ())

View File

@@ -70,8 +70,8 @@ public:
int ImportFromVti(const char *file, bool density_type = 0); int ImportFromVti(const char *file, bool density_type = 0);
protected:
virtual ~VoxImage() {} virtual ~VoxImage() {}
protected:
VoxImage(const Vector3i &size) : BaseClass(size) {} VoxImage(const Vector3i &size) : BaseClass(size) {}
}; };
@@ -90,7 +90,8 @@ struct Voxel {
} // namespace Interface } // namespace Interface
struct Voxel { struct Voxel {
Scalarf Value; Scalarf Value = 0.0f;
Scalari Count = 0;
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -36,7 +36,7 @@
namespace uLib { namespace uLib {
#ifdef USE_CUDA #if defined(USE_CUDA) && defined(__CUDACC__)
template <typename VoxelT> template <typename VoxelT>
__global__ void ABTrimFilterKernel(const VoxelT *in, VoxelT *out, __global__ void ABTrimFilterKernel(const VoxelT *in, VoxelT *out,
const VoxelT *kernel, int vox_size, const VoxelT *kernel, int vox_size,
@@ -108,7 +108,7 @@ public:
mBtrim = 0; mBtrim = 0;
} }
#ifdef USE_CUDA #if defined(USE_CUDA) && defined(__CUDACC__)
void Run() { void Run() {
if (this->m_Image->Data().GetDevice() == MemoryDevice::VRAM || if (this->m_Image->Data().GetDevice() == MemoryDevice::VRAM ||
this->m_KernelData.Data().GetDevice() == MemoryDevice::VRAM) { this->m_KernelData.Data().GetDevice() == MemoryDevice::VRAM) {
@@ -206,7 +206,7 @@ public:
mBtrim = 0; mBtrim = 0;
} }
#ifdef USE_CUDA #if defined(USE_CUDA) && defined(__CUDACC__)
void Run() { void Run() {
if (this->m_Image->Data().GetDevice() == MemoryDevice::VRAM || if (this->m_Image->Data().GetDevice() == MemoryDevice::VRAM ||
this->m_KernelData.Data().GetDevice() == MemoryDevice::VRAM) { this->m_KernelData.Data().GetDevice() == MemoryDevice::VRAM) {

View File

@@ -36,7 +36,7 @@
namespace uLib { namespace uLib {
#ifdef USE_CUDA #if defined(USE_CUDA) && defined(__CUDACC__)
template <typename VoxelT> template <typename VoxelT>
__global__ void LinearFilterKernel(const VoxelT *in, VoxelT *out, __global__ void LinearFilterKernel(const VoxelT *in, VoxelT *out,
const VoxelT *kernel, int vox_size, const VoxelT *kernel, int vox_size,
@@ -66,7 +66,7 @@ public:
typedef VoxImageFilter<VoxelT, VoxFilterAlgorithmLinear<VoxelT>> BaseClass; typedef VoxImageFilter<VoxelT, VoxFilterAlgorithmLinear<VoxelT>> BaseClass;
VoxFilterAlgorithmLinear(const Vector3i &size) : BaseClass(size) {} VoxFilterAlgorithmLinear(const Vector3i &size) : BaseClass(size) {}
#ifdef USE_CUDA #if defined(USE_CUDA) && defined(__CUDACC__)
void Run() { void Run() {
if (this->m_Image->Data().GetDevice() == MemoryDevice::VRAM || if (this->m_Image->Data().GetDevice() == MemoryDevice::VRAM ||
this->m_KernelData.Data().GetDevice() == MemoryDevice::VRAM) { this->m_KernelData.Data().GetDevice() == MemoryDevice::VRAM) {

View File

@@ -63,9 +63,16 @@ public:
inline size_t Count() const { return this->m_Count; } inline size_t Count() const { return this->m_Count; }
inline size_t size() const { return this->m_Count; }
inline const Scalarf &TotalLength() const { return this->m_TotalLength; } inline const Scalarf &TotalLength() const { return this->m_TotalLength; }
inline void SetCount(size_t c) { this->m_Count = c; } inline void SetCount(size_t c) {
this->m_Count = c;
if (this->m_Data.size() != c) {
this->m_Data.resize(c);
}
}
inline void SetTotalLength(Scalarf tl) { this->m_TotalLength = tl; } inline void SetTotalLength(Scalarf tl) { this->m_TotalLength = tl; }

View File

@@ -31,6 +31,7 @@
#include "Math/Dense.h" #include "Math/Dense.h"
#include "Math/ContainerBox.h" #include "Math/ContainerBox.h"
#include <cmath>
#include <iostream> #include <iostream>
#include <math.h> #include <math.h>
@@ -52,41 +53,82 @@ int main()
BEGIN_TESTING(Math ContainerBox); BEGIN_TESTING(Math ContainerBox);
{
ContainerBox Cnt; ContainerBox Cnt;
Cnt.SetOrigin(Vector3f(0,0,0));
// // Local transform: Cnt.SetSize(Vector3f(2,2,2));
Cnt.SetOrigin(Vector3f(-1,-1,-1)); TEST0( Vector4f0(Cnt.GetOrigin().homogeneous() - HVector3f(0,0,0)) );
Cnt.SetSize(Vector3f(2,2,2)); // scaling //
std::cout << "Container scale is: " << Cnt.GetSize().transpose() << "\n";
std::cout << "Container scale is: " << Cnt.GetSize().transpose() << "\n";
TEST0( Vector4f0(Cnt.GetSize().homogeneous() - HVector3f(2,2,2)) ); TEST0( Vector4f0(Cnt.GetSize().homogeneous() - HVector3f(2,2,2)) );
ContainerBox Box; HPoint3f pt = Cnt.GetLocalPoint(HPoint3f(0,0,0));
HPoint3f wp = Cnt.GetWorldPoint(pt);
TEST0( Vector4f0(wp - HPoint3f(0,0,0)) );
HPoint3f pt2 = Cnt.GetLocalPoint(HPoint3f(2,2,2));
HPoint3f wp2 = Cnt.GetWorldPoint(pt2);
TEST0( Vector4f0(wp2 - HPoint3f(2,2,2)) );
HPoint3f pt3 = Cnt.GetLocalPoint(HPoint3f(1,1,1));
HPoint3f wp3 = Cnt.GetWorldPoint(pt3);
TEST0( Vector4f0(wp3 - HPoint3f(1,1,1)) );
HPoint3f pt4 = Cnt.GetLocalPoint(HPoint3f(1,2,3));
HPoint3f wp4 = Cnt.GetWorldPoint(pt4);
TEST0( Vector4f0(wp4 - HPoint3f(1,2,3)) );
}
{
ContainerBox Cnt;
Cnt.SetOrigin(Vector3f(0,0,0));
Cnt.SetSize(Vector3f(2,2,2));
Cnt.EulerYZYRotate(Vector3f(M_PI,0,0));
HPoint3f pt = Cnt.GetLocalPoint(HPoint3f(0,0,0));
HPoint3f wp = Cnt.GetWorldPoint(pt);
TEST0( Vector4f0(wp - HPoint3f(0,0,0)) );
HPoint3f pt2 = Cnt.GetLocalPoint(HPoint3f(2,2,2));
HPoint3f wp2 = Cnt.GetWorldPoint(pt2);
TEST0( Vector4f0(wp2 - HPoint3f(2,2,2)) );
pt2 = HPoint3f(1,1,1);
wp2 = Cnt.GetWorldPoint(pt2);
TEST0( Vector4f0(wp2 - HPoint3f(-2,2,-2)) );
pt2 = HPoint3f(1,2,3);
wp2 = Cnt.GetWorldPoint(pt2);
TEST0( Vector4f0(wp2 - HPoint3f(-2,4,-6)) );
}
{
ContainerBox Cnt;
Cnt.SetOrigin(Vector3f(-1,-1,-1));
Cnt.SetSize(Vector3f(2,2,2)); // scaling //
HPoint3f pt2 = HPoint3f(.5,.5,.5);
HPoint3f wp2 = Cnt.GetWorldPoint(pt2);
TEST0( Vector4f0(wp2 - HPoint3f(0,0,0)) );
pt2 = HPoint3f(0,0,0);
wp2 = Cnt.GetWorldPoint(pt2);
TEST0( Vector4f0(wp2 - HPoint3f(-1,-1,-1)) );
Cnt.EulerYZYRotate(Vector3f(M_PI,0,0));
pt2 = HPoint3f(0,0,0);
wp2 = Cnt.GetWorldPoint(pt2);
TEST0( Vector4f0(wp2 - HPoint3f(1,-1,1)) );
}
{
ContainerBox Box;
Box.SetPosition(Vector3f(1,1,1)); Box.SetPosition(Vector3f(1,1,1));
Box.SetSize(Vector3f(2,2,2)); Box.SetSize(Vector3f(2,2,2));
Box.EulerYZYRotate(Vector3f(0,0,0)); Box.EulerYZYRotate(Vector3f(0,0,0));
HPoint3f pt = Box.GetLocalPoint(HPoint3f(2,3,2)); HPoint3f pt = Box.GetLocalPoint(HPoint3f(2,3,2));
HPoint3f wp = Box.GetWorldPoint(pt); HPoint3f wp = Box.GetWorldPoint(pt);
TEST0( Vector4f0(wp - HPoint3f(2,3,2)) ); TEST0( Vector4f0(wp - HPoint3f(2,3,2)) );
}
//// // Global
// Cnt.SetPosition(Vector3f(1,1,1));
// Cnt.EulerYZYRotate(Vector3f(M_PI_2,M_PI_2,0));
// HPoint3f p = Cnt.GetWorldPoint(1,1,1);
// //std::cout << p.transpose() << "\n";
// TEST0( Vector4f0(p - HVector3f(2,1,2)) );
// p = Cnt.GetWorldPoint(1,2,3);
// //std::cout << p.transpose() << "\n";
// TEST0( Vector4f0(p - HVector3f(4,1,3)) );
// // scaling //
END_TESTING; END_TESTING;
} }

View File

@@ -48,7 +48,7 @@ int main() {
Raytracer rt(img); Raytracer rt(img);
const size_t NUM_RAYS = 1000000; const size_t NUM_RAYS = 100000;
std::cout << "Generating " << NUM_RAYS std::cout << "Generating " << NUM_RAYS
<< " random ray pairs across a 100x100x100 grid...\n"; << " random ray pairs across a 100x100x100 grid...\n";

View File

@@ -1,14 +0,0 @@
include $(top_srcdir)/Common.am
library_includedir = $(includedir)/libmutom-${PACKAGE_VERSION}/ParticlePhysics/Geant
library_include_HEADERS =
_PPGEANT_SOURCES =
noinst_LTLIBRARIES = libmutomppgeant.la
libmutomppgeant_la_SOURCES = ${_PPGEANT_SOURCES}

View File

@@ -4,10 +4,11 @@ set(SOURCES
module.cpp module.cpp
core_bindings.cpp core_bindings.cpp
math_bindings.cpp math_bindings.cpp
math_filters_bindings.cpp
) )
# Use pybind11 to add the python module # Use pybind11 to add the python module
pybind11_add_module(uLib_python module.cpp core_bindings.cpp math_bindings.cpp) pybind11_add_module(uLib_python module.cpp core_bindings.cpp math_bindings.cpp math_filters_bindings.cpp)
# Link against our C++ libraries # Link against our C++ libraries
target_link_libraries(uLib_python PRIVATE target_link_libraries(uLib_python PRIVATE
@@ -22,6 +23,14 @@ target_include_directories(uLib_python PRIVATE
${PROJECT_BINARY_DIR} ${PROJECT_BINARY_DIR}
) )
# Install uLib_python within the uLib install target
install(TARGETS uLib_python
EXPORT "uLibTargets"
RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin
LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib
ARCHIVE DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib
)
# --- Python Tests ---------------------------------------------------------- # # --- Python Tests ---------------------------------------------------------- #
if(BUILD_TESTING) if(BUILD_TESTING)
@@ -30,15 +39,20 @@ if(BUILD_TESTING)
add_test(NAME pybind_general add_test(NAME pybind_general
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/pybind_test.py) COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/pybind_test.py)
set_tests_properties(pybind_general PROPERTIES set_tests_properties(pybind_general PROPERTIES
ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>") ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>:${PROJECT_SOURCE_DIR}/src/Python")
add_test(NAME pybind_core add_test(NAME pybind_core
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/core_pybind_test.py) COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/core_pybind_test.py)
set_tests_properties(pybind_core PROPERTIES set_tests_properties(pybind_core PROPERTIES
ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>") ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>:${PROJECT_SOURCE_DIR}/src/Python")
add_test(NAME pybind_math add_test(NAME pybind_math
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/math_pybind_test.py) COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/math_pybind_test.py)
set_tests_properties(pybind_math PROPERTIES set_tests_properties(pybind_math PROPERTIES
ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>") ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>:${PROJECT_SOURCE_DIR}/src/Python")
add_test(NAME pybind_math_filters
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/math_filters_test.py)
set_tests_properties(pybind_math_filters PROPERTIES
ENVIRONMENT "PYTHONPATH=$<TARGET_FILE_DIR:uLib_python>:${PROJECT_SOURCE_DIR}/src/Python")
endif() endif()

View File

@@ -1,6 +1,9 @@
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include <pybind11/eigen.h> #include <pybind11/eigen.h>
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/numpy.h>
#include "Math/Dense.h" #include "Math/Dense.h"
#include "Math/Transform.h" #include "Math/Transform.h"
@@ -13,13 +16,224 @@
#include "Math/TriangleMesh.h" #include "Math/TriangleMesh.h"
#include "Math/VoxRaytracer.h" #include "Math/VoxRaytracer.h"
#include "Math/Accumulator.h" #include "Math/Accumulator.h"
#include "Math/VoxImage.h"
namespace py = pybind11; namespace py = pybind11;
using namespace uLib; using namespace uLib;
PYBIND11_MAKE_OPAQUE(uLib::Vector<Scalari>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Scalarui>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Scalarl>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Scalarul>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Scalarf>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Scalard>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Vector3f>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Vector3i>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Vector4f>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Vector4i>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Vector3d>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Vector4d>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<Voxel>);
PYBIND11_MAKE_OPAQUE(uLib::Vector<VoxRaytracer::RayData::Element>);
template <typename MatrixType>
void bind_eigen_type(py::module_ &m, const char *name) {
using Scalar = typename MatrixType::Scalar;
constexpr bool is_vector = MatrixType::IsVectorAtCompileTime;
// Default constructor (zeros)
m.def(name, []() -> MatrixType {
if constexpr (MatrixType::RowsAtCompileTime == Eigen::Dynamic || MatrixType::ColsAtCompileTime == Eigen::Dynamic) {
return MatrixType(); // Empty dynamic matrix
} else {
return MatrixType::Zero(); // Zero static matrix
}
});
// Specialized constructor for dynamic matrices
if constexpr (MatrixType::RowsAtCompileTime == Eigen::Dynamic || MatrixType::ColsAtCompileTime == Eigen::Dynamic) {
m.def(name, [](int rows, int cols) -> MatrixType {
MatrixType mat;
mat.setZero(rows, cols);
return mat;
});
}
// Initialize from list
m.def(name, [](py::list l) -> MatrixType {
MatrixType mat;
if constexpr (is_vector) {
mat.setZero(l.size());
for (size_t i = 0; i < l.size(); ++i) {
mat(i) = l[i].cast<Scalar>();
}
} else {
int rows = MatrixType::RowsAtCompileTime == Eigen::Dynamic ? (int)std::sqrt(l.size()) : MatrixType::RowsAtCompileTime;
int cols = MatrixType::ColsAtCompileTime == Eigen::Dynamic ? (int)std::sqrt(l.size()) : MatrixType::ColsAtCompileTime;
mat.setZero(rows, cols);
for (size_t i = 0; i < (size_t)l.size(); ++i) {
mat(i / cols, i % cols) = l[i].cast<Scalar>();
}
}
return mat;
});
// Initialize from py::array
m.def(name, [](py::array_t<Scalar, py::array::c_style | py::array::forcecast> arr) -> MatrixType {
auto buf = arr.request();
MatrixType mat;
if constexpr (is_vector) {
mat.setZero(buf.size);
Scalar* ptr = static_cast<Scalar*>(buf.ptr);
for (ssize_t i = 0; i < buf.size; ++i) mat(i) = ptr[i];
} else {
int rows = buf.shape.size() > 0 ? (int)buf.shape[0] : 1;
int cols = buf.shape.size() > 1 ? (int)buf.shape[1] : 1;
mat.setZero(rows, cols);
Scalar* ptr = static_cast<Scalar*>(buf.ptr);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
mat(i, j) = ptr[i * cols + j];
}
}
}
return mat;
});
}
void init_math(py::module_ &m) { void init_math(py::module_ &m) {
// Math/Transform.h // 1. Basic Eigen Types (Vectors and Matrices)
bind_eigen_type<Vector1f>(m, "Vector1f");
bind_eigen_type<Vector2f>(m, "Vector2f");
bind_eigen_type<Vector3f>(m, "Vector3f");
bind_eigen_type<Vector4f>(m, "Vector4f");
bind_eigen_type<Vector1i>(m, "Vector1i");
bind_eigen_type<Vector2i>(m, "Vector2i");
bind_eigen_type<Vector3i>(m, "Vector3i");
bind_eigen_type<Vector4i>(m, "Vector4i");
bind_eigen_type<Vector1d>(m, "Vector1d");
bind_eigen_type<Vector2d>(m, "Vector2d");
bind_eigen_type<Vector3d>(m, "Vector3d");
bind_eigen_type<Vector4d>(m, "Vector4d");
bind_eigen_type<Matrix2f>(m, "Matrix2f");
bind_eigen_type<Matrix3f>(m, "Matrix3f");
bind_eigen_type<Matrix4f>(m, "Matrix4f");
bind_eigen_type<Matrix2i>(m, "Matrix2i");
bind_eigen_type<Matrix3i>(m, "Matrix3i");
bind_eigen_type<Matrix4i>(m, "Matrix4i");
bind_eigen_type<Matrix2d>(m, "Matrix2d");
bind_eigen_type<Matrix3d>(m, "Matrix3d");
bind_eigen_type<Matrix4d>(m, "Matrix4d");
bind_eigen_type<MatrixXi>(m, "MatrixXi");
bind_eigen_type<MatrixXf>(m, "MatrixXf");
bind_eigen_type<MatrixXd>(m, "MatrixXd");
// 2. Homogeneous types
py::class_<HPoint3f>(m, "HPoint3f")
.def(py::init<>())
.def(py::init<float, float, float>())
.def(py::init<Vector3f &>());
py::class_<HVector3f>(m, "HVector3f")
.def(py::init<>())
.def(py::init<float, float, float>())
.def(py::init<Vector3f &>());
py::class_<HLine3f>(m, "HLine3f")
.def(py::init<>())
.def_readwrite("origin", &HLine3f::origin)
.def_readwrite("direction", &HLine3f::direction);
py::class_<HError3f>(m, "HError3f")
.def(py::init<>())
.def_readwrite("position_error", &HError3f::position_error)
.def_readwrite("direction_error", &HError3f::direction_error);
// 3. Dynamic Vectors (uLib::Vector)
py::bind_vector<uLib::Vector<Scalari>>(m, "Vector_i")
.def("MoveToVRAM", &uLib::Vector<Scalari>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Scalari>::MoveToRAM);
py::bind_vector<uLib::Vector<Scalarui>>(m, "Vector_ui")
.def("MoveToVRAM", &uLib::Vector<Scalarui>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Scalarui>::MoveToRAM);
py::bind_vector<uLib::Vector<Scalarl>>(m, "Vector_l")
.def("MoveToVRAM", &uLib::Vector<Scalarl>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Scalarl>::MoveToRAM);
py::bind_vector<uLib::Vector<Scalarul>>(m, "Vector_ul")
.def("MoveToVRAM", &uLib::Vector<Scalarul>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Scalarul>::MoveToRAM);
py::bind_vector<uLib::Vector<Scalarf>>(m, "Vector_f")
.def("MoveToVRAM", &uLib::Vector<Scalarf>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Scalarf>::MoveToRAM);
py::bind_vector<uLib::Vector<Scalard>>(m, "Vector_d")
.def("MoveToVRAM", &uLib::Vector<Scalard>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Scalard>::MoveToRAM);
py::bind_vector<uLib::Vector<Vector3f>>(m, "Vector_Vector3f")
.def("MoveToVRAM", &uLib::Vector<Vector3f>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Vector3f>::MoveToRAM);
py::bind_vector<uLib::Vector<Vector3i>>(m, "Vector_Vector3i")
.def("MoveToVRAM", &uLib::Vector<Vector3i>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Vector3i>::MoveToRAM);
py::bind_vector<uLib::Vector<Vector4f>>(m, "Vector_Vector4f")
.def("MoveToVRAM", &uLib::Vector<Vector4f>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Vector4f>::MoveToRAM);
py::bind_vector<uLib::Vector<Vector4i>>(m, "Vector_Vector4i")
.def("MoveToVRAM", &uLib::Vector<Vector4i>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Vector4i>::MoveToRAM);
py::bind_vector<uLib::Vector<Vector3d>>(m, "Vector_Vector3d")
.def("MoveToVRAM", &uLib::Vector<Vector3d>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Vector3d>::MoveToRAM);
py::bind_vector<uLib::Vector<Vector4d>>(m, "Vector_Vector4d")
.def("MoveToVRAM", &uLib::Vector<Vector4d>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Vector4d>::MoveToRAM);
py::bind_vector<uLib::Vector<Voxel>>(m, "Vector_Voxel")
.def("MoveToVRAM", &uLib::Vector<Voxel>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<Voxel>::MoveToRAM);
py::bind_vector<uLib::Vector<VoxRaytracer::RayData::Element>>(m, "Vector_VoxRaytracerRayDataElement")
.def("MoveToVRAM", &uLib::Vector<VoxRaytracer::RayData::Element>::MoveToVRAM)
.def("MoveToRAM", &uLib::Vector<VoxRaytracer::RayData::Element>::MoveToRAM);
// 4. Accumulators
py::class_<Accumulator_Mean<float>>(m, "Accumulator_Mean_f")
.def(py::init<>())
.def("AddPass", &Accumulator_Mean<float>::AddPass)
.def("__call__", py::overload_cast<const float>(&Accumulator_Mean<float>::operator()))
.def("__call__", py::overload_cast<>(&Accumulator_Mean<float>::operator(), py::const_));
py::class_<Accumulator_Mean<double>>(m, "Accumulator_Mean_d")
.def(py::init<>())
.def("AddPass", &Accumulator_Mean<double>::AddPass)
.def("__call__", py::overload_cast<const double>(&Accumulator_Mean<double>::operator()))
.def("__call__", py::overload_cast<>(&Accumulator_Mean<double>::operator(), py::const_));
py::class_<Accumulator_ABTrim<float>>(m, "Accumulator_ABTrim_f")
.def(py::init<>())
.def("SetABTrim", &Accumulator_ABTrim<float>::SetABTrim)
.def("__iadd__", [](Accumulator_ABTrim<float> &self, float val) { self += val; return &self; })
.def("__call__", &Accumulator_ABTrim<float>::operator());
py::class_<Accumulator_ABTrim<double>>(m, "Accumulator_ABTrim_d")
.def(py::init<>())
.def("SetABTrim", &Accumulator_ABTrim<double>::SetABTrim)
.def("__iadd__", [](Accumulator_ABTrim<double> &self, double val) { self += val; return &self; })
.def("__call__", &Accumulator_ABTrim<double>::operator());
py::class_<Accumulator_ABClip<float>>(m, "Accumulator_ABClip_f")
.def(py::init<>())
.def("SetABTrim", &Accumulator_ABClip<float>::SetABTrim)
.def("__iadd__", [](Accumulator_ABClip<float> &self, float val) { self += val; return &self; })
.def("__call__", &Accumulator_ABClip<float>::operator());
py::class_<Accumulator_ABClip<double>>(m, "Accumulator_ABClip_d")
.def(py::init<>())
.def("SetABTrim", &Accumulator_ABClip<double>::SetABTrim)
.def("__iadd__", [](Accumulator_ABClip<double> &self, double val) { self += val; return &self; })
.def("__call__", &Accumulator_ABClip<double>::operator());
// 5. Core Math Structures
py::class_<AffineTransform>(m, "AffineTransform") py::class_<AffineTransform>(m, "AffineTransform")
.def(py::init<>()) .def(py::init<>())
.def("GetWorldMatrix", &AffineTransform::GetWorldMatrix) .def("GetWorldMatrix", &AffineTransform::GetWorldMatrix)
@@ -29,18 +243,15 @@ void init_math(py::module_ &m) {
.def("Scale", &AffineTransform::Scale) .def("Scale", &AffineTransform::Scale)
.def("SetRotation", &AffineTransform::SetRotation) .def("SetRotation", &AffineTransform::SetRotation)
.def("GetRotation", &AffineTransform::GetRotation) .def("GetRotation", &AffineTransform::GetRotation)
.def("Rotate", py::overload_cast<const Matrix3f &>(&AffineTransform::Rotate)) .def("Rotate", &AffineTransform::Rotate)
.def("Rotate", py::overload_cast<const Vector3f>(&AffineTransform::Rotate))
.def("EulerYZYRotate", &AffineTransform::EulerYZYRotate) .def("EulerYZYRotate", &AffineTransform::EulerYZYRotate)
.def("FlipAxes", &AffineTransform::FlipAxes); .def("FlipAxes", &AffineTransform::FlipAxes);
// Math/Geometry.h
py::class_<Geometry, AffineTransform>(m, "Geometry") py::class_<Geometry, AffineTransform>(m, "Geometry")
.def(py::init<>()) .def(py::init<>())
.def("GetWorldPoint", py::overload_cast<const Vector4f &>(&Geometry::GetWorldPoint, py::const_)) .def("GetWorldPoint", &Geometry::GetWorldPoint)
.def("GetLocalPoint", py::overload_cast<const Vector4f &>(&Geometry::GetLocalPoint, py::const_)); .def("GetLocalPoint", &Geometry::GetLocalPoint);
// Math/ContainerBox.h
py::class_<ContainerBox, AffineTransform>(m, "ContainerBox") py::class_<ContainerBox, AffineTransform>(m, "ContainerBox")
.def(py::init<>()) .def(py::init<>())
.def("SetOrigin", &ContainerBox::SetOrigin) .def("SetOrigin", &ContainerBox::SetOrigin)
@@ -48,10 +259,9 @@ void init_math(py::module_ &m) {
.def("SetSize", &ContainerBox::SetSize) .def("SetSize", &ContainerBox::SetSize)
.def("GetSize", &ContainerBox::GetSize) .def("GetSize", &ContainerBox::GetSize)
.def("GetWorldMatrix", &ContainerBox::GetWorldMatrix) .def("GetWorldMatrix", &ContainerBox::GetWorldMatrix)
.def("GetWorldPoint", py::overload_cast<const Vector4f &>(&ContainerBox::GetWorldPoint, py::const_)) .def("GetWorldPoint", &ContainerBox::GetWorldPoint)
.def("GetLocalPoint", py::overload_cast<const Vector4f &>(&ContainerBox::GetLocalPoint, py::const_)); .def("GetLocalPoint", &ContainerBox::GetLocalPoint);
// Math/StructuredData.h
py::enum_<StructuredData::_Order>(m, "StructuredDataOrder") py::enum_<StructuredData::_Order>(m, "StructuredDataOrder")
.value("CustomOrder", StructuredData::CustomOrder) .value("CustomOrder", StructuredData::CustomOrder)
.value("XYZ", StructuredData::XYZ) .value("XYZ", StructuredData::XYZ)
@@ -74,7 +284,6 @@ void init_math(py::module_ &m) {
.def("Map", &StructuredData::Map) .def("Map", &StructuredData::Map)
.def("UnMap", &StructuredData::UnMap); .def("UnMap", &StructuredData::UnMap);
// Math/StructuredGrid.h
py::class_<StructuredGrid, ContainerBox, StructuredData>(m, "StructuredGrid") py::class_<StructuredGrid, ContainerBox, StructuredData>(m, "StructuredGrid")
.def(py::init<const Vector3i &>()) .def(py::init<const Vector3i &>())
.def("SetSpacing", &StructuredGrid::SetSpacing) .def("SetSpacing", &StructuredGrid::SetSpacing)
@@ -84,7 +293,6 @@ void init_math(py::module_ &m) {
return self.Find(HPoint3f(pt)); return self.Find(HPoint3f(pt));
}); });
// Math/Structured2DGrid.h
py::class_<Structured2DGrid>(m, "Structured2DGrid") py::class_<Structured2DGrid>(m, "Structured2DGrid")
.def(py::init<>()) .def(py::init<>())
.def("SetDims", &Structured2DGrid::SetDims) .def("SetDims", &Structured2DGrid::SetDims)
@@ -100,7 +308,6 @@ void init_math(py::module_ &m) {
.def("UnitToPhysicsSpace", &Structured2DGrid::UnitToPhysicsSpace) .def("UnitToPhysicsSpace", &Structured2DGrid::UnitToPhysicsSpace)
.def("SetDebug", &Structured2DGrid::SetDebug); .def("SetDebug", &Structured2DGrid::SetDebug);
// Math/Structured4DGrid.h
py::class_<Structured4DGrid>(m, "Structured4DGrid") py::class_<Structured4DGrid>(m, "Structured4DGrid")
.def(py::init<>()) .def(py::init<>())
.def("SetDims", &Structured4DGrid::SetDims) .def("SetDims", &Structured4DGrid::SetDims)
@@ -116,7 +323,37 @@ void init_math(py::module_ &m) {
.def("UnitToPhysicsSpace", &Structured4DGrid::UnitToPhysicsSpace) .def("UnitToPhysicsSpace", &Structured4DGrid::UnitToPhysicsSpace)
.def("SetDebug", &Structured4DGrid::SetDebug); .def("SetDebug", &Structured4DGrid::SetDebug);
// Math/TriangleMesh.h // 6. High-level Structures
py::class_<Voxel>(m, "Voxel")
.def(py::init<>())
.def_readwrite("Value", &Voxel::Value)
.def_readwrite("Count", &Voxel::Count);
py::class_<Abstract::VoxImage, StructuredGrid>(m, "AbstractVoxImage")
.def("GetValue", py::overload_cast<const Vector3i &>(&Abstract::VoxImage::GetValue, py::const_))
.def("GetValue", py::overload_cast<const int>(&Abstract::VoxImage::GetValue, py::const_))
.def("SetValue", py::overload_cast<const Vector3i &, float>(&Abstract::VoxImage::SetValue))
.def("SetValue", py::overload_cast<const int, float>(&Abstract::VoxImage::SetValue))
.def("ExportToVtk", &Abstract::VoxImage::ExportToVtk)
.def("ExportToVti", &Abstract::VoxImage::ExportToVti)
.def("ImportFromVtk", &Abstract::VoxImage::ImportFromVtk)
.def("ImportFromVti", &Abstract::VoxImage::ImportFromVti);
py::class_<VoxImage<Voxel>, Abstract::VoxImage>(m, "VoxImage")
.def(py::init<>())
.def(py::init<const Vector3i &>())
.def("Data", &VoxImage<Voxel>::Data, py::return_value_policy::reference_internal)
.def("InitVoxels", &VoxImage<Voxel>::InitVoxels)
.def("Abs", &VoxImage<Voxel>::Abs)
.def("clipImage", py::overload_cast<const Vector3i, const Vector3i>(&VoxImage<Voxel>::clipImage, py::const_))
.def("clipImage", py::overload_cast<const HPoint3f, const HPoint3f>(&VoxImage<Voxel>::clipImage, py::const_))
.def("clipImage", py::overload_cast<const float>(&VoxImage<Voxel>::clipImage, py::const_))
.def("maskImage", py::overload_cast<const HPoint3f, const HPoint3f, float>(&VoxImage<Voxel>::maskImage, py::const_))
.def("maskImage", py::overload_cast<const float, float, float>(&VoxImage<Voxel>::maskImage, py::const_), py::arg("threshold"), py::arg("belowValue") = 0, py::arg("aboveValue") = 0)
.def("fixVoxels", py::overload_cast<const float, float>(&VoxImage<Voxel>::fixVoxels, py::const_))
.def("__getitem__", py::overload_cast<unsigned int>(&VoxImage<Voxel>::operator[]))
.def("__getitem__", py::overload_cast<const Vector3i &>(&VoxImage<Voxel>::operator[]));
py::class_<TriangleMesh>(m, "TriangleMesh") py::class_<TriangleMesh>(m, "TriangleMesh")
.def(py::init<>()) .def(py::init<>())
.def("AddPoint", &TriangleMesh::AddPoint) .def("AddPoint", &TriangleMesh::AddPoint)
@@ -124,7 +361,6 @@ void init_math(py::module_ &m) {
.def("Points", &TriangleMesh::Points, py::return_value_policy::reference_internal) .def("Points", &TriangleMesh::Points, py::return_value_policy::reference_internal)
.def("Triangles", &TriangleMesh::Triangles, py::return_value_policy::reference_internal); .def("Triangles", &TriangleMesh::Triangles, py::return_value_policy::reference_internal);
// Math/VoxRaytracer.h
py::class_<VoxRaytracer::RayData::Element>(m, "VoxRaytracerRayDataElement") py::class_<VoxRaytracer::RayData::Element>(m, "VoxRaytracerRayDataElement")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("vox_id", &VoxRaytracer::RayData::Element::vox_id) .def_readwrite("vox_id", &VoxRaytracer::RayData::Element::vox_id)
@@ -133,6 +369,7 @@ void init_math(py::module_ &m) {
py::class_<VoxRaytracer::RayData>(m, "VoxRaytracerRayData") py::class_<VoxRaytracer::RayData>(m, "VoxRaytracerRayData")
.def(py::init<>()) .def(py::init<>())
.def("AppendRay", &VoxRaytracer::RayData::AppendRay) .def("AppendRay", &VoxRaytracer::RayData::AppendRay)
.def("Data", py::overload_cast<>(&VoxRaytracer::RayData::Data), py::return_value_policy::reference_internal)
.def("Count", &VoxRaytracer::RayData::Count) .def("Count", &VoxRaytracer::RayData::Count)
.def("TotalLength", &VoxRaytracer::RayData::TotalLength) .def("TotalLength", &VoxRaytracer::RayData::TotalLength)
.def("SetCount", &VoxRaytracer::RayData::SetCount) .def("SetCount", &VoxRaytracer::RayData::SetCount)
@@ -140,13 +377,8 @@ void init_math(py::module_ &m) {
py::class_<VoxRaytracer>(m, "VoxRaytracer") py::class_<VoxRaytracer>(m, "VoxRaytracer")
.def(py::init<StructuredGrid &>(), py::keep_alive<1, 2>()) .def(py::init<StructuredGrid &>(), py::keep_alive<1, 2>())
.def("GetImage", &VoxRaytracer::GetImage, py::return_value_policy::reference_internal); .def("GetImage", &VoxRaytracer::GetImage, py::return_value_policy::reference_internal)
.def("TraceLine", &VoxRaytracer::TraceLine)
// Math/Accumulator.h .def("TraceBetweenPoints", &VoxRaytracer::TraceBetweenPoints);
py::class_<Accumulator_Mean<float>>(m, "Accumulator_Mean_f")
.def(py::init<>())
.def("AddPass", &Accumulator_Mean<float>::AddPass)
.def("__call__", py::overload_cast<const float>(&Accumulator_Mean<float>::operator()))
.def("__call__", py::overload_cast<>(&Accumulator_Mean<float>::operator(), py::const_));
} }

View File

@@ -0,0 +1,100 @@
#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include <pybind11/stl.h>
#include "Math/VoxImage.h"
#include "Math/VoxImageFilter.h"
#include "Math/VoxImageFilterLinear.hpp"
#include "Math/VoxImageFilterABTrim.hpp"
#include "Math/VoxImageFilterBilateral.hpp"
#include "Math/VoxImageFilterThreshold.hpp"
#include "Math/VoxImageFilterMedian.hpp"
#include "Math/VoxImageFilter2ndStat.hpp"
#include "Math/VoxImageFilterCustom.hpp"
namespace py = pybind11;
using namespace uLib;
template <typename Algorithm>
void bind_common_filter(py::class_<Algorithm, Abstract::VoxImageFilter> &cls) {
cls.def(py::init<const Vector3i &>())
.def("Run", &Algorithm::Run)
.def("SetKernelNumericXZY", &Algorithm::SetKernelNumericXZY)
.def("GetImage", &Algorithm::GetImage, py::return_value_policy::reference_internal)
.def("SetImage", &Algorithm::SetImage);
}
void init_math_filters(py::module_ &m) {
// Abstract::VoxImageFilter
py::class_<Abstract::VoxImageFilter, std::unique_ptr<Abstract::VoxImageFilter, py::nodelete>>(m, "AbstractVoxImageFilter")
.def("Run", &Abstract::VoxImageFilter::Run)
.def("SetImage", &Abstract::VoxImageFilter::SetImage);
// Helper macro to define standard bindings for a filter
#define BIND_FILTER(ClassName) \
{ \
auto cls = py::class_<ClassName<Voxel>, Abstract::VoxImageFilter>(m, #ClassName); \
bind_common_filter(cls); \
}
// VoxFilterAlgorithmLinear
{
auto cls = py::class_<VoxFilterAlgorithmLinear<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmLinear");
bind_common_filter(cls);
}
// VoxFilterAlgorithmAbtrim
{
auto cls = py::class_<VoxFilterAlgorithmAbtrim<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmAbtrim");
bind_common_filter(cls);
cls.def("SetABTrim", &VoxFilterAlgorithmAbtrim<Voxel>::SetABTrim);
}
// VoxFilterAlgorithmSPR
{
auto cls = py::class_<VoxFilterAlgorithmSPR<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmSPR");
bind_common_filter(cls);
cls.def("SetABTrim", &VoxFilterAlgorithmSPR<Voxel>::SetABTrim);
}
// VoxFilterAlgorithmBilateral
{
auto cls = py::class_<VoxFilterAlgorithmBilateral<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmBilateral");
bind_common_filter(cls);
cls.def("SetIntensitySigma", &VoxFilterAlgorithmBilateral<Voxel>::SetIntensitySigma);
}
// VoxFilterAlgorithmBilateralTrim
{
auto cls = py::class_<VoxFilterAlgorithmBilateralTrim<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmBilateralTrim");
bind_common_filter(cls);
cls.def("SetIntensitySigma", &VoxFilterAlgorithmBilateralTrim<Voxel>::SetIntensitySigma);
cls.def("SetABTrim", &VoxFilterAlgorithmBilateralTrim<Voxel>::SetABTrim);
}
// VoxFilterAlgorithmThreshold
{
auto cls = py::class_<VoxFilterAlgorithmThreshold<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmThreshold");
bind_common_filter(cls);
cls.def("SetThreshold", &VoxFilterAlgorithmThreshold<Voxel>::SetThreshold);
}
// VoxFilterAlgorithmMedian
{
auto cls = py::class_<VoxFilterAlgorithmMedian<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmMedian");
bind_common_filter(cls);
}
// VoxFilterAlgorithm2ndStat
{
auto cls = py::class_<VoxFilterAlgorithm2ndStat<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithm2ndStat");
bind_common_filter(cls);
}
// VoxFilterAlgorithmCustom (Omit CustomEvaluate since it uses static function ptrs)
{
auto cls = py::class_<VoxFilterAlgorithmCustom<Voxel>, Abstract::VoxImageFilter>(m, "VoxFilterAlgorithmCustom");
bind_common_filter(cls);
}
}

View File

@@ -4,6 +4,7 @@ namespace py = pybind11;
void init_core(py::module_ &m); void init_core(py::module_ &m);
void init_math(py::module_ &m); void init_math(py::module_ &m);
void init_math_filters(py::module_ &m);
PYBIND11_MODULE(uLib_python, m) { PYBIND11_MODULE(uLib_python, m) {
m.doc() = "Python bindings for uLib Core and Math libraries"; m.doc() = "Python bindings for uLib Core and Math libraries";
@@ -15,4 +16,5 @@ PYBIND11_MODULE(uLib_python, m) {
// Math submodule // Math submodule
py::module_ math = m.def_submodule("Math", "Math library bindings"); py::module_ math = m.def_submodule("Math", "Math library bindings");
init_math(math); init_math(math);
init_math_filters(math);
} }

View File

@@ -3,11 +3,11 @@ import os
import unittest import unittest
import time import time
import uLib_python import uLib
class TestCoreOptions(unittest.TestCase): class TestCoreOptions(unittest.TestCase):
def test_options(self): def test_options(self):
opt = uLib_python.Core.Options("Test Options") opt = uLib.Core.Options("Test Options")
# Test basic config file parsing # Test basic config file parsing
with open("test_configuration.ini", "w") as f: with open("test_configuration.ini", "w") as f:
@@ -18,12 +18,12 @@ class TestCoreOptions(unittest.TestCase):
class TestCoreObject(unittest.TestCase): class TestCoreObject(unittest.TestCase):
def test_object(self): def test_object(self):
obj = uLib_python.Core.Object() obj = uLib.Core.Object()
self.assertIsNotNone(obj) self.assertIsNotNone(obj)
class TestCoreTimer(unittest.TestCase): class TestCoreTimer(unittest.TestCase):
def test_timer(self): def test_timer(self):
timer = uLib_python.Core.Timer() timer = uLib.Core.Timer()
timer.Start() timer.Start()
time.sleep(0.1) time.sleep(0.1)
val = timer.StopWatch() val = timer.StopWatch()

View File

@@ -0,0 +1,151 @@
import unittest
import numpy as np
import os
import sys
# Ensure PYTHONPATH is correct if run from root
sys.path.append(os.path.join(os.getcwd(), 'src', 'Python'))
import uLib
class TestMathFilters(unittest.TestCase):
def test_filter_creation(self):
# 1. Linear Filter
dims = [10, 10, 10]
v_dims = uLib.Math.Vector3i(dims)
linear_filter = uLib.Math.VoxFilterAlgorithmLinear(v_dims)
self.assertIsNotNone(linear_filter)
# 2. ABTrim Filter
abtrim_filter = uLib.Math.VoxFilterAlgorithmAbtrim(v_dims)
self.assertIsNotNone(abtrim_filter)
abtrim_filter.SetABTrim(1, 1)
# 3. Bilateral Filter
bilat_filter = uLib.Math.VoxFilterAlgorithmBilateral(v_dims)
self.assertIsNotNone(bilat_filter)
bilat_filter.SetIntensitySigma(0.5)
# 4. Threshold Filter
threshold_filter = uLib.Math.VoxFilterAlgorithmThreshold(v_dims)
self.assertIsNotNone(threshold_filter)
threshold_filter.SetThreshold(0.5)
# 5. Median Filter
median_filter = uLib.Math.VoxFilterAlgorithmMedian(v_dims)
self.assertIsNotNone(median_filter)
def test_filter_run(self):
# Create image
dims = [10, 10, 10]
vox_img = uLib.Math.VoxImage(dims)
for i in range(10*10*10):
vox_img.SetValue(i, 1.0)
# Linear filter
linear_filter = uLib.Math.VoxFilterAlgorithmLinear([3, 3, 3])
linear_filter.SetImage(vox_img)
# Set kernel (simple 3x3x3 all ones)
# Weights are usually normalized in linear filter logic?
# Let's just test it runs.
linear_filter.SetKernelNumericXZY([1.0] * 27)
# Run filter
linear_filter.Run()
# Value should be 1.0 (mean of all 1.0 is 1.0)
self.assertAlmostEqual(vox_img.GetValue(0), 1.0)
def test_filter_run_abtrim(self):
# Create image
dims = [10, 10, 10]
vox_img = uLib.Math.VoxImage(dims)
for i in range(10*10*10):
vox_img.SetValue(i, 1.0)
# ABTrim filter
abtrim_filter = uLib.Math.VoxFilterAlgorithmAbtrim([3, 3, 3])
abtrim_filter.SetImage(vox_img)
# Set kernel (simple 3x3x3 all ones)
# Weights are usually normalized in linear filter logic?
# Let's just test it runs.
abtrim_filter.SetKernelNumericXZY([1.0] * 27)
# Run filter
abtrim_filter.Run()
# Value should be 1.0 (mean of all 1.0 is 1.0)
self.assertAlmostEqual(vox_img.GetValue(0), 1.0)
def test_filter_run_bilateral(self):
# Create image
dims = [10, 10, 10]
vox_img = uLib.Math.VoxImage(dims)
for i in range(10*10*10):
vox_img.SetValue(i, 1.0)
# Bilateral filter
bilat_filter = uLib.Math.VoxFilterAlgorithmBilateral([3, 3, 3])
bilat_filter.SetImage(vox_img)
# Set kernel (simple 3x3x3 all ones)
# Weights are usually normalized in linear filter logic?
# Let's just test it runs.
bilat_filter.SetKernelNumericXZY([1.0] * 27)
# Run filter
bilat_filter.Run()
# Value should be 1.0 (mean of all 1.0 is 1.0)
self.assertAlmostEqual(vox_img.GetValue(0), 1.0)
def test_filter_run_threshold(self):
# Create image
dims = [10, 10, 10]
vox_img = uLib.Math.VoxImage(dims)
for i in range(10*10*10):
vox_img.SetValue(i, 1.0)
# Threshold filter
threshold_filter = uLib.Math.VoxFilterAlgorithmThreshold([3, 3, 3])
threshold_filter.SetImage(vox_img)
# Set kernel (simple 3x3x3 all ones)
# Weights are usually normalized in linear filter logic?
# Let's just test it runs.
threshold_filter.SetKernelNumericXZY([1.0] * 27)
# Run filter
threshold_filter.Run()
# Value should be 1.0 (mean of all 1.0 is 1.0)
self.assertAlmostEqual(vox_img.GetValue(0), 1.0)
def test_filter_run_median(self):
# Create image
dims = [10, 10, 10]
vox_img = uLib.Math.VoxImage(dims)
for i in range(10*10*10):
vox_img.SetValue(i, 1.0)
# Median filter
median_filter = uLib.Math.VoxFilterAlgorithmMedian([3, 3, 3])
median_filter.SetImage(vox_img)
# Set kernel (simple 3x3x3 all ones)
# Weights are usually normalized in linear filter logic?
# Let's just test it runs.
median_filter.SetKernelNumericXZY([1.0] * 27)
# Run filter
median_filter.Run()
# Value should be 1.0 (mean of all 1.0 is 1.0)
self.assertAlmostEqual(vox_img.GetValue(0), 1.0)
if __name__ == '__main__':
unittest.main()

View File

@@ -3,16 +3,77 @@ import os
import unittest import unittest
import numpy as np import numpy as np
import uLib_python import uLib
def vector4f0(v, target): def vector4f0(v, target):
diff = np.array(v) - np.array(target) diff = np.array(v) - np.array(target)
diff[3] = 0 # ignoring w diff[3] = 0 # ignoring w
return np.all(np.abs(diff) < 0.001) return np.all(np.abs(diff) < 0.001)
class TestMathMatrix(unittest.TestCase):
def test_matrix(self):
def check_1234(m2f):
self.assertEqual(m2f[0, 0], 1)
self.assertEqual(m2f[0, 1], 2)
self.assertEqual(m2f[1, 0], 3)
self.assertEqual(m2f[1, 1], 4)
m2f = uLib.Math.Matrix2f()
m2f[0, 0] = 1
m2f[0, 1] = 2
m2f[1, 0] = 3
m2f[1, 1] = 4
check_1234(m2f)
m2f = uLib.Math.Matrix2f([1, 2, 3, 4])
check_1234(m2f)
# m2f = uLib.Math.Matrix2f([[1, 2], [3, 4]])
# check_1234(m2f)
m2f = uLib.Math.Matrix2f(np.array([[1, 2], [3, 4]]))
check_1234(m2f)
def test_vector2(self):
v2f = uLib.Math.Vector2f()
v2f[0] = 1
v2f[1] = 2
self.assertEqual(v2f[0], 1)
self.assertEqual(v2f[1], 2)
v2f = uLib.Math.Vector2f([1, 2])
self.assertEqual(v2f[0], 1)
self.assertEqual(v2f[1], 2)
v2f = uLib.Math.Vector2f(np.array([1, 2]))
self.assertEqual(v2f[0], 1)
self.assertEqual(v2f[1], 2)
def test_vector3(self):
v3f = uLib.Math.Vector3f()
v3f[0] = 1
v3f[1] = 2
v3f[2] = 3
self.assertEqual(v3f[0], 1)
self.assertEqual(v3f[1], 2)
self.assertEqual(v3f[2], 3)
v3f = uLib.Math.Vector3f([1, 2, 3])
self.assertEqual(v3f[0], 1)
self.assertEqual(v3f[1], 2)
self.assertEqual(v3f[2], 3)
v3f = uLib.Math.Vector3f(np.array([1, 2, 3]))
self.assertEqual(v3f[0], 1)
self.assertEqual(v3f[1], 2)
self.assertEqual(v3f[2], 3)
class TestMathGeometry(unittest.TestCase): class TestMathGeometry(unittest.TestCase):
def test_geometry(self): def test_geometry(self):
Geo = uLib_python.Math.Geometry() Geo = uLib.Math.Geometry()
Geo.SetPosition([1, 1, 1]) Geo.SetPosition([1, 1, 1])
@@ -27,7 +88,7 @@ class TestMathGeometry(unittest.TestCase):
class TestMathContainerBox(unittest.TestCase): class TestMathContainerBox(unittest.TestCase):
def test_container_box_local(self): def test_container_box_local(self):
Cnt = uLib_python.Math.ContainerBox() Cnt = uLib.Math.ContainerBox()
Cnt.SetOrigin([-1, -1, -1]) Cnt.SetOrigin([-1, -1, -1])
Cnt.SetSize([2, 2, 2]) Cnt.SetSize([2, 2, 2])
@@ -35,7 +96,7 @@ class TestMathContainerBox(unittest.TestCase):
self.assertTrue(np.allclose(size, [2, 2, 2])) self.assertTrue(np.allclose(size, [2, 2, 2]))
def test_container_box_global(self): def test_container_box_global(self):
Box = uLib_python.Math.ContainerBox() Box = uLib.Math.ContainerBox()
Box.SetPosition([1, 1, 1]) Box.SetPosition([1, 1, 1])
Box.SetSize([2, 2, 2]) Box.SetSize([2, 2, 2])
@@ -45,7 +106,7 @@ class TestMathContainerBox(unittest.TestCase):
class TestMathStructuredGrid(unittest.TestCase): class TestMathStructuredGrid(unittest.TestCase):
def test_structured_grid(self): def test_structured_grid(self):
grid = uLib_python.Math.StructuredGrid([10, 10, 10]) grid = uLib.Math.StructuredGrid([10, 10, 10])
grid.SetSpacing([1, 1, 1]) grid.SetSpacing([1, 1, 1])
spacing = grid.GetSpacing() spacing = grid.GetSpacing()
@@ -53,10 +114,76 @@ class TestMathStructuredGrid(unittest.TestCase):
class TestMathAccumulator(unittest.TestCase): class TestMathAccumulator(unittest.TestCase):
def test_accumulator_mean(self): def test_accumulator_mean(self):
acc = uLib_python.Math.Accumulator_Mean_f() acc = uLib.Math.Accumulator_Mean_f()
acc(10.0) acc(10.0)
acc(20.0) acc(20.0)
self.assertAlmostEqual(acc(), 15.0) self.assertAlmostEqual(acc(), 15.0)
class TestMathNewTypes(unittest.TestCase):
def test_eigen_vectors(self):
v1f = uLib.Math.Vector1f()
v3d = uLib.Math.Vector3d()
m4f = uLib.Math.Matrix4f()
self.assertIsNotNone(v1f)
self.assertIsNotNone(v3d)
self.assertIsNotNone(m4f)
def test_ulib_vectors(self):
vi = uLib.Math.Vector_i()
vi.append(1)
vi.append(2)
self.assertEqual(len(vi), 2)
self.assertEqual(vi[0], 1)
self.assertEqual(vi[1], 2)
vf = uLib.Math.Vector_f()
vf.append(1.5)
self.assertAlmostEqual(vf[0], 1.5)
def test_homogeneous(self):
p = uLib.Math.HPoint3f(1.0, 2.0, 3.0)
v = uLib.Math.HVector3f(0.0, 1.0, 0.0)
self.assertIsNotNone(p)
self.assertIsNotNone(v)
def test_vox_image(self):
img = uLib.Math.VoxImage([2, 2, 2])
self.assertEqual(img.GetDims()[0], 2)
img.SetValue([0, 0, 0], 10.5)
# Note: GetValue returns float, and there might be internal scaling (1.E-6 observed in code)
# Actually in VoxImage.h: GetValue(id) returns At(id).Value
# SetValue(id, value) sets At(id).Value = value
self.assertAlmostEqual(img.GetValue([0, 0, 0]), 10.5)
class TestMathVoxRaytracer(unittest.TestCase):
def test_raytracer(self):
grid = uLib.Math.StructuredGrid([10, 10, 10])
grid.SetSpacing([1, 1, 1])
grid.SetOrigin([0, 0, 0])
rt = uLib.Math.VoxRaytracer(grid)
self.assertIsNotNone(rt)
# Test TraceBetweenPoints
p1 = np.array([0.5, 0.5, -1.0, 1.0], dtype=np.float32)
p2 = np.array([0.5, 0.5, 11.0, 1.0], dtype=np.float32)
data = rt.TraceBetweenPoints(p1, p2)
self.assertGreater(data.Count(), 0)
self.assertAlmostEqual(data.TotalLength(), 10.0)
# Check elements
elements = data.Data()
for i in range(data.Count()):
self.assertGreaterEqual(elements[i].vox_id, 0)
self.assertGreater(elements[i].L, 0)
def test_ray_data(self):
data = uLib.Math.VoxRaytracerRayData()
data.SetCount(10)
data.SetTotalLength(5.5)
self.assertEqual(data.Count(), 10)
self.assertAlmostEqual(data.TotalLength(), 5.5)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@@ -1,42 +1,42 @@
import sys import sys
import os import os
import uLib_python import uLib
def test_core(): def test_core():
print("Testing Core module...") print("Testing Core module...")
obj = uLib_python.Core.Object() obj = uLib.Core.Object()
print("Core Object created:", obj) print("Core Object created:", obj)
timer = uLib_python.Core.Timer() timer = uLib.Core.Timer()
timer.Start() timer.Start()
print("Core Timer started") print("Core Timer started")
options = uLib_python.Core.Options("Test Options") options = uLib.Core.Options("Test Options")
print("Core Options created:", options) print("Core Options created:", options)
def test_math(): def test_math():
print("Testing Math module...") print("Testing Math module...")
# Test AffineTransform # Test AffineTransform
transform = uLib_python.Math.AffineTransform() transform = uLib.Math.AffineTransform()
print("AffineTransform created") print("AffineTransform created")
# Test Geometry # Test Geometry
geom = uLib_python.Math.Geometry() geom = uLib.Math.Geometry()
print("Geometry created") print("Geometry created")
# Test StructuredData # Test StructuredData
data = uLib_python.Math.StructuredData([10, 10, 10]) data = uLib.Math.StructuredData([10, 10, 10])
print("StructuredData created with dims:", data.GetDims()) print("StructuredData created with dims:", data.GetDims())
# Test Structured2DGrid # Test Structured2DGrid
grid2d = uLib_python.Math.Structured2DGrid() grid2d = uLib.Math.Structured2DGrid()
grid2d.SetDims([100, 100]) grid2d.SetDims([100, 100])
print("Structured2DGrid created with dims:", grid2d.GetDims()) print("Structured2DGrid created with dims:", grid2d.GetDims())
# Test TriangleMesh # Test TriangleMesh
mesh = uLib_python.Math.TriangleMesh() mesh = uLib.Math.TriangleMesh()
print("TriangleMesh created") print("TriangleMesh created")
print("All tests passed successfully!") print("All tests passed successfully!")

View File

@@ -0,0 +1,7 @@
try:
from .uLib_python import Core, Math
except ImportError:
# Handle cases where the binary extension is not yet built
pass
__all__ = ["Core", "Math"]

View File

@@ -56,7 +56,7 @@ set_target_properties(${libname} PROPERTIES
target_link_libraries(${libname} ${LIBRARIES}) target_link_libraries(${libname} ${LIBRARIES})
install(TARGETS ${libname} install(TARGETS ${libname}
EXPORT "${PROJECT_NAME}Targets" EXPORT "uLibTargets"
RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin
LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib) LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib)

View File

@@ -1,23 +1,35 @@
set(HEADERS uLibVtkInterface.h set(HEADERS uLibVtkInterface.h
uLibVtkViewer.h uLibVtkViewer.h
vtkContainerBox.h vtkContainerBox.h
vtkMuonScatter.h vtkHandlerWidget.h
vtkStructuredGrid.h )
vtkVoxRaytracerRepresentation.h
vtkVoxImage.h)
set(SOURCES uLibVtkInterface.cxx set(SOURCES uLibVtkInterface.cxx
uLibVtkViewer.cpp uLibVtkViewer.cpp
vtkContainerBox.cpp vtkContainerBox.cpp
vtkMuonScatter.cxx vtkHandlerWidget.cpp
vtkStructuredGrid.cpp )
vtkVoxRaytracerRepresentation.cpp
vtkVoxImage.cpp) ## Pull in Math VTK wrappers (sets MATH_SOURCES / MATH_HEADERS)
add_subdirectory(Math)
list(APPEND SOURCES ${MATH_SOURCES})
list(APPEND HEADERS ${MATH_HEADERS})
## Pull in HEP/Detectors VTK wrappers (sets HEP_DETECTORS_SOURCES / HEADERS)
add_subdirectory(HEP/Detectors)
list(APPEND SOURCES ${HEP_DETECTORS_SOURCES})
list(APPEND HEADERS ${HEP_DETECTORS_HEADERS})
## Pull in HEP/MuonTomography VTK wrappers (sets HEP_MUONTOMOGRAPHY_SOURCES / HEADERS)
add_subdirectory(HEP/MuonTomography)
list(APPEND SOURCES ${HEP_MUONTOMOGRAPHY_SOURCES})
list(APPEND HEADERS ${HEP_MUONTOMOGRAPHY_HEADERS})
set(LIBRARIES Eigen3::Eigen set(LIBRARIES Eigen3::Eigen
${ROOT_LIBRARIES} ${ROOT_LIBRARIES}
${VTK_LIBRARIES} ${VTK_LIBRARIES}
${PACKAGE_LIBPREFIX}Math) ${PACKAGE_LIBPREFIX}Math
${PACKAGE_LIBPREFIX}Detectors)
if(USE_CUDA) if(USE_CUDA)
find_package(CUDAToolkit REQUIRED) find_package(CUDAToolkit REQUIRED)
@@ -35,11 +47,14 @@ set_target_properties(${libname} PROPERTIES
target_link_libraries(${libname} ${LIBRARIES}) target_link_libraries(${libname} ${LIBRARIES})
install(TARGETS ${libname} install(TARGETS ${libname}
EXPORT "${PROJECT_NAME}Targets" EXPORT "uLibTargets"
RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin
LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib) LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT lib)
install(FILES ${HEADERS} DESTINATION ${INSTALL_INC_DIR}/Vtk) install(FILES ${HEADERS} DESTINATION ${INSTALL_INC_DIR}/Vtk)
install(FILES ${MATH_HEADERS} DESTINATION ${INSTALL_INC_DIR}/Vtk/Math)
install(FILES ${HEP_DETECTORS_HEADERS} DESTINATION ${INSTALL_INC_DIR}/Vtk/HEP/Detectors)
install(FILES ${HEP_MUONTOMOGRAPHY_HEADERS} DESTINATION ${INSTALL_INC_DIR}/Vtk/HEP/MuonTomography)
if(BUILD_TESTING) if(BUILD_TESTING)
include(uLibTargetMacros) include(uLibTargetMacros)

View File

@@ -0,0 +1,24 @@
################################################################################
##### Vtk/HEP/Detectors - VTK wrappers for HEP Detectors objects ##############
################################################################################
## Sources and headers are exported to parent scope so they get compiled
## into the single mutomVtk shared library.
set(HEP_DETECTORS_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/vtkMuonScatter.cxx
${CMAKE_CURRENT_SOURCE_DIR}/vtkMuonEvent.cxx
${CMAKE_CURRENT_SOURCE_DIR}/vtkDetectorChamber.cxx
PARENT_SCOPE)
set(HEP_DETECTORS_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/vtkMuonScatter.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkMuonEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkDetectorChamber.h
PARENT_SCOPE)
if(BUILD_TESTING)
include(uLibTargetMacros)
add_subdirectory(testing)
endif()

View File

@@ -0,0 +1,16 @@
# TESTS
set(TESTS
vtkMuonScatterTest
vtkDetectorChamberTest
)
set(LIBRARIES
${PACKAGE_LIBPREFIX}Core
${PACKAGE_LIBPREFIX}Detectors
${PACKAGE_LIBPREFIX}Vtk
${VTK_LIBRARIES}
Boost::unit_test_framework
)
uLib_add_tests(VtkDetectors)

View File

@@ -0,0 +1,62 @@
/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/HEP/Detectors/vtkDetectorChamber.h"
#include "HEP/Detectors/DetectorChamber.h"
#include "Vtk/uLibVtkViewer.h"
#define BOOST_TEST_MODULE vtkDetectorChamberTest
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(vtkDetectorChamberTest) {
uLib::DetectorChamber d1, d2;
d1.SetSize(uLib::Vector3f(1, 1, 1));
d1.SetPosition(uLib::Vector3f(0, 0, 0));
d1.Scale(uLib::Vector3f(5, 10, 2));
d1.Translate(uLib::Vector3f(0, 0, 0));
d2.SetSize(uLib::Vector3f(1, 1, 1));
d2.SetPosition(uLib::Vector3f(0, 0, 0));
d2.Scale(uLib::Vector3f(5, 10, 2));
d2.Translate(uLib::Vector3f(0, 0, 10));
uLib::Vtk::vtkDetectorChamber vtkDetectorChamber(&d1);
uLib::Vtk::vtkDetectorChamber vtkDetectorChamber2(&d2);
if (!vtkDetectorChamber.GetProp()) {
BOOST_FAIL("vtkDetectorChamber::GetProp() returned NULL");
}
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
uLib::Vtk::Viewer viewer;
viewer.AddPuppet(vtkDetectorChamber);
viewer.AddPuppet(vtkDetectorChamber2);
viewer.Start();
}
BOOST_CHECK(true); // reached here without crash
}

View File

@@ -23,53 +23,40 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/HEP/Detectors/vtkMuonScatter.h"
#include "HEP/Detectors/MuonScatter.h"
#include "Vtk/uLibVtkViewer.h"
#define BOOST_TEST_MODULE VtkMuonScatterTest
#include "Math/TriangleMesh.h" #include <boost/test/unit_test.hpp>
#include "Vtk/vtkTriangleMesh.h"
#include "testing-prototype.h"
using namespace uLib; using namespace uLib;
BOOST_AUTO_TEST_CASE(vtkMuonScatterTest) {
MuonScatter event;
event.LineIn().direction << 0, -1, 1, 0;
event.LineIn().origin << 0, 1, -1, 1;
int main() event.LineOut().direction << 0, -1, 0, 0;
{ event.LineOut().origin << 0, -1, 0, 1;
BEGIN_TESTING(Vtk Triangle Mesh);
// { // SIMPLE TESTS // Vtk::vtkMuonScatter v_event(event);
v_event.AddPocaPoint(HPoint3f(0, 0, 0));
v_event.SaveToXMLFile("vtk_testing_muonevent.vtp");
// TriangleMesh mesh; if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
Vtk::Viewer viewer;
// mesh.AddPoint(Vector3f(0,0,0)); // Vtk::Tie<Vtk::vtkMuonScatter> tms;
// mesh.AddPoint(Vector3f(0,1,0)); // tms.DoAction();
// mesh.AddPoint(Vector3f(1,0,0)); // Vtk::Tie<Vtk::Viewer> vms;
// vms.DoAction();
// mesh.AddTriangle(Vector3i(0,1,2)); viewer.AddPuppet(v_event);
viewer.Start();
// mesh.PrintSelf(std::cout);
// vtkTriangleMesh v_mesh(mesh);
// v_mesh.Update();
// TestingRenderWidow(&v_mesh);
// }
{ // SIMPLE TESTS //
TriangleMesh mesh;
vtkTriangleMesh v_mesh(mesh);
v_mesh.ReadFromStlFile("prova.stl");
mesh.PrintSelf(std::cout);
TestingRenderWidow(&v_mesh);
} }
BOOST_CHECK(true); // reached here without crash
END_TESTING;
} }

View File

@@ -0,0 +1,198 @@
/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
#include <vtkAbstractTransform.h>
#include <vtkAxes.h>
#include <vtkCubeSource.h>
#include <vtkLineSource.h>
#include <vtkMatrix4x4.h>
#include <vtkPolyDataMapper.h>
#include <vtkPropPicker.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkSmartPointer.h>
#include <vtkTransform.h>
#include "Vtk/HEP/Detectors/vtkDetectorChamber.h"
#include <vtkBoxWidget.h>
#include <vtkTransformPolyDataFilter.h>
namespace uLib {
namespace Vtk {
vtkDetectorChamber::vtkDetectorChamber(DetectorChamber *content)
: vtkContainerBox(content), m_Actor(vtkActor::New()),
m_Widget(vtkBoxWidget::New()) {
m_Callback = vtkWidgetCallback::New();
m_PickerCallback = vtkSelectionCallback::New();
m_Callback->SetChamber(this);
m_PickerCallback->SetChamber(this);
m_Widget->AddObserver(vtkCommand::InteractionEvent, m_Callback);
m_InitialTransform = vtkSmartPointer<vtkTransform>::New();
m_RelativeTransform = vtkSmartPointer<vtkTransform>::New();
m_TotalTransform = vtkSmartPointer<vtkTransform>::New();
this->InstallPipe();
}
vtkDetectorChamber::~vtkDetectorChamber() {
m_Actor->Delete();
m_Widget->Delete();
m_Callback->Delete();
m_PickerCallback->Delete();
}
DetectorChamber *vtkDetectorChamber::GetContent() {
return static_cast<DetectorChamber *>(m_Content);
}
void vtkDetectorChamber::PrintSelf(std::ostream &o) const {
vtkContainerBox::PrintSelf(o);
}
/**
* Connect the interactor to the widget
*/
void vtkDetectorChamber::ConnectInteractor(
vtkRenderWindowInteractor *interactor) {
if (!interactor)
return;
m_Widget->SetInteractor(interactor);
m_Widget->SetProp3D(m_Actor);
interactor->AddObserver(vtkCommand::LeftButtonPressEvent, m_PickerCallback);
}
void vtkDetectorChamber::SetTransform(vtkTransform *t) {
m_RelativeTransform->SetMatrix(t->GetMatrix());
m_RelativeTransform->Update();
// Set content global transform (BaseClass of ContainerBox) //
vtkMatrix4x4 *vmat = m_TotalTransform->GetMatrix();
Matrix4f transform;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
transform(i, j) = vmat->GetElement(i, j);
this->GetContent()->SetMatrix(transform);
this->Update();
}
vtkBoxWidget *vtkDetectorChamber::GetWidget() { return m_Widget; }
void vtkDetectorChamber::Update() {
if (m_Actor->GetMapper())
m_Actor->GetMapper()->Update();
BaseClass::Update();
}
void vtkDetectorChamber::InstallPipe() {
if (!m_Content)
return;
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
cube->SetBounds(0, 1, 0, 1, 0, 1);
// 1. Initialize Global Transform (m_Transform) from Content's matrix (Base
// class AffineTransform)
vtkSmartPointer<vtkMatrix4x4> vmatGlobal =
vtkSmartPointer<vtkMatrix4x4>::New();
Matrix4f matGlobal = this->GetContent()->GetMatrix();
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
vmatGlobal->SetElement(i, j, matGlobal(i, j));
m_InitialTransform->SetMatrix(vmatGlobal);
m_InitialTransform->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(cube->GetOutputPort());
m_Actor->SetMapper(mapper);
m_Actor->GetProperty()->SetRepresentationToSurface();
m_Actor->GetProperty()->SetEdgeVisibility(true);
m_Actor->GetProperty()->SetOpacity(0.4);
m_Actor->GetProperty()->SetAmbient(0.7);
// Temporarily disable UserTransform to place widget on local base
m_Widget->SetProp3D(m_Actor);
m_TotalTransform->SetInput(m_RelativeTransform);
m_TotalTransform->Concatenate(m_InitialTransform);
m_Actor->SetUserTransform(m_TotalTransform);
m_TotalTransform->Update();
m_Widget->PlaceWidget();
m_Widget->SetPlaceFactor(2);
this->SetProp(m_Actor);
this->Update();
}
void vtkDetectorChamber::vtkWidgetCallback::Execute(vtkObject *caller,
unsigned long, void *) {
vtkBoxWidget *widget = reinterpret_cast<vtkBoxWidget *>(caller);
// Get the Relative transform from the widget //
vtkSmartPointer<vtkTransform> t = vtkSmartPointer<vtkTransform>::New();
widget->GetTransform(t);
chamber->SetTransform(t);
// Apply to both the content and the actor state //
chamber->Update();
}
void vtkDetectorChamber::vtkSelectionCallback::Execute(vtkObject *caller,
unsigned long, void *) {
vtkRenderWindowInteractor *interactor =
reinterpret_cast<vtkRenderWindowInteractor *>(caller);
vtkSmartPointer<vtkPropPicker> picker = vtkSmartPointer<vtkPropPicker>::New();
int *pos = interactor->GetEventPosition();
picker->Pick(
pos[0], pos[1], 0,
interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer());
vtkProp *picked = picker->GetViewProp();
if (picked == chamber->m_Actor) {
if (!chamber->m_Widget->GetEnabled()) {
chamber->m_Widget->SetInteractor(interactor);
chamber->m_Widget->On();
}
} else {
if (chamber->m_Widget->GetEnabled()) {
chamber->m_Widget->Off();
}
}
}
} // namespace Vtk
} // namespace uLib

View File

@@ -0,0 +1,104 @@
/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
#ifndef VTK_DETECTOR_CHAMBER_H
#define VTK_DETECTOR_CHAMBER_H
#include <vtkActor.h>
#include <vtkCommand.h>
#include <vtkSmartPointer.h>
#include <vtkTransform.h>
#include "HEP/Detectors/DetectorChamber.h"
#include "Math/Dense.h"
#include "Vtk/uLibVtkInterface.h"
#include "Vtk/vtkContainerBox.h"
#include <vtkActor.h>
#include <vtkBoxWidget.h>
#include <vtkTransformPolyDataFilter.h>
namespace uLib {
namespace Vtk {
// class vtkHandlerWidget; // Removed as we use vtkBoxWidget now
class vtkDetectorChamber : public vtkContainerBox {
typedef DetectorChamber Content;
typedef vtkContainerBox BaseClass;
public:
vtkDetectorChamber(DetectorChamber *content);
~vtkDetectorChamber();
Content *GetContent();
void SetTransform(class vtkTransform *t);
class vtkBoxWidget *GetWidget();
void Update();
void ConnectInteractor(vtkRenderWindowInteractor *interactor) override;
void PrintSelf(std::ostream &o) const;
protected:
void InstallPipe() override;
private:
class vtkWidgetCallback : public vtkCommand {
public:
static vtkWidgetCallback *New() { return new vtkWidgetCallback; }
void SetChamber(uLib::Vtk::vtkDetectorChamber *ch) { this->chamber = ch; }
virtual void Execute(vtkObject *caller, unsigned long, void *) override;
private:
uLib::Vtk::vtkDetectorChamber *chamber;
};
class vtkSelectionCallback : public vtkCommand {
public:
static vtkSelectionCallback *New() { return new vtkSelectionCallback; }
void SetChamber(uLib::Vtk::vtkDetectorChamber *ch) { this->chamber = ch; }
virtual void Execute(vtkObject *caller, unsigned long, void *) override;
private:
uLib::Vtk::vtkDetectorChamber *chamber;
};
vtkActor *m_Actor;
vtkBoxWidget *m_Widget;
vtkWidgetCallback *m_Callback;
vtkSelectionCallback *m_PickerCallback;
vtkSmartPointer<vtkTransform> m_InitialTransform;
vtkSmartPointer<vtkTransform> m_RelativeTransform;
vtkSmartPointer<vtkTransform> m_TotalTransform;
};
} // namespace Vtk
} // namespace uLib
#endif // VTK_DETECTOR_CHAMBER_H

View File

@@ -0,0 +1,145 @@
/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "Math/Dense.h"
#include "Vtk/HEP/Detectors/vtkMuonEvent.h"
namespace uLib {
namespace Vtk {
///// CALLBACK /////////////////////////////////////////////////////////////////
class vtkWidgetCallback : public vtkCommand {
public:
static vtkWidgetCallback *New() { return new vtkWidgetCallback; }
void SetParent(uLib::Vtk::vtkMuonEvent *parent) { this->parent = parent; }
virtual void Execute(vtkObject *caller, unsigned long, void *) {
vtkSmartPointer<vtkTransform> t = vtkSmartPointer<vtkTransform>::New();
vtkBoxWidget *widget = reinterpret_cast<vtkBoxWidget *>(caller);
widget->GetTransform(t);
// parent->SetTransform(t);
// std::cout << "event\n";
}
private:
uLib::Vtk::vtkMuonEvent *parent;
};
////////////////////////////////////////////////////////////////////////////////
///// VTK MUON EVENT /////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
vtkMuonEvent::vtkMuonEvent(MuonEventData &content)
: m_PolyData(NULL), m_Appender(vtkAppendPolyData::New()),
content(&content) {
InstallPipe();
}
vtkMuonEvent::vtkMuonEvent(const MuonEventData &content)
: m_PolyData(NULL), m_Appender(vtkAppendPolyData::New()),
content(const_cast<MuonEventData *>(&content)) {
InstallPipe();
}
vtkMuonEvent::~vtkMuonEvent() {}
vtkMuonEvent::Content &vtkMuonEvent::GetContent() { return *content; }
void vtkMuonEvent::PrintSelf(std::ostream &o) const {
o << "..:: MuonEvent ::..\n"
"\t[in] Origin > "
<< content->LineIn().origin.transpose() << "\n"
<< "\t[in] Direction > " << content->LineIn().direction.transpose() << "\n"
<< "\t[out] Origin > " << content->LineOut().origin.transpose() << "\n"
<< "\t[out] Direction > " << content->LineOut().direction.transpose()
<< "\n"
<< "\tMomentum > " << content->GetMomentum() << "\n"
<< "...................\n";
}
void vtkMuonEvent::InstallPipe() {
vtkAppendPolyData *appender = m_Appender;
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
if (content) {
vtkSmartPointer<vtkLineSource> line_in =
vtkSmartPointer<vtkLineSource>::New();
vtkSmartPointer<vtkLineSource> line_out =
vtkSmartPointer<vtkLineSource>::New();
float distance =
(content->LineIn().origin - content->LineOut().origin).norm() / 10;
HPoint3f pt;
pt = content->LineIn().origin;
line_in->SetPoint1(pt(0), pt(1), pt(2));
pt = content->LineIn().origin + content->LineIn().direction * distance;
line_in->SetPoint2(pt(0), pt(1), pt(2));
pt = content->LineOut().origin;
line_out->SetPoint1(pt(0), pt(1), pt(2));
pt = content->LineOut().origin + content->LineOut().direction * distance;
line_out->SetPoint2(pt(0), pt(1), pt(2));
appender->AddInputConnection(line_in->GetOutputPort());
appender->AddInputConnection(line_out->GetOutputPort());
}
appender->Update();
mapper->SetInputConnection(appender->GetOutputPort());
mapper->Update();
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
this->SetProp(actor);
}
vtkPolyData *vtkMuonEvent::GetPolyData() const {
return m_Appender->GetOutput();
}
void vtkMuonEvent::AddPocaPoint(HPoint3f poca) {
m_Poca = poca;
vtkSmartPointer<vtkSphereSource> sphere =
vtkSmartPointer<vtkSphereSource>::New();
float size =
(content->LineIn().origin - content->LineOut().origin).head(3).norm();
size /= 100;
sphere->SetRadius(size);
sphere->SetCenter(poca(0), poca(1), poca(2));
sphere->Update();
m_Appender->AddInputConnection(sphere->GetOutputPort());
m_Appender->Update();
}
HPoint3f vtkMuonEvent::GetPocaPoint() { return m_Poca; }
} // namespace Vtk
} // namespace uLib

View File

@@ -23,17 +23,15 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#ifndef VTKMUONEVENT_H #ifndef VTKMUONEVENT_H
#define VTKMUONEVENT_H #define VTKMUONEVENT_H
#include <vtkActor.h>
#include <vtkAppendPolyData.h>
#include <vtkLineSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkSmartPointer.h> #include <vtkSmartPointer.h>
#include <vtkSphereSource.h> #include <vtkSphereSource.h>
#include <vtkAppendPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkLineSource.h>
#include <vtkActor.h>
#include <vtk3DWidget.h> #include <vtk3DWidget.h>
#include <vtkBoxWidget.h> #include <vtkBoxWidget.h>
@@ -45,16 +43,15 @@
#include "Math/Dense.h" #include "Math/Dense.h"
#include "uLibVtkInterface.h" #include "HEP/Detectors/MuonEvent.h"
#include "Detectors/MuonEvent.h" #include "Vtk/uLibVtkInterface.h"
namespace uLib { namespace uLib {
namespace Vtk {
class vtkMuonEvent : public Abstract::uLibVtkPolydata { class vtkMuonEvent : public Puppet, public Polydata {
typedef MuonEventData Content; typedef MuonEventData Content;
public: public:
vtkMuonEvent(const MuonEventData &content); vtkMuonEvent(const MuonEventData &content);
vtkMuonEvent(MuonEventData &content); vtkMuonEvent(MuonEventData &content);
@@ -64,8 +61,6 @@ public:
void PrintSelf(std::ostream &o) const; void PrintSelf(std::ostream &o) const;
virtual vtkProp *GetProp();
virtual vtkPolyData *GetPolyData() const; virtual vtkPolyData *GetPolyData() const;
void AddPocaPoint(HPoint3f poca); void AddPocaPoint(HPoint3f poca);
@@ -74,13 +69,11 @@ public:
void vtkStartInteractive(); void vtkStartInteractive();
private: private:
void InstallPipe(); void InstallPipe();
vtkMuonEvent::Content *content; vtkMuonEvent::Content *content;
vtkPolyData *m_PolyData; vtkPolyData *m_PolyData;
vtkActor *m_Prop;
vtkAppendPolyData *m_Appender; vtkAppendPolyData *m_Appender;
vtkBoxWidget *m_WidgetIN; vtkBoxWidget *m_WidgetIN;
@@ -88,7 +81,7 @@ private:
HPoint3f m_Poca; HPoint3f m_Poca;
}; };
} // namespace Vtk
} // namespace uLib
} #endif // VTKMUONEVENT_H
#endif // VTKMUONSCATTER_H

View File

@@ -0,0 +1,144 @@
/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "Math/Dense.h"
#include "Vtk/HEP/Detectors/vtkMuonScatter.h"
namespace uLib {
namespace Vtk {
////////////////////////////////////////////////////////////////////////////////
///// VTK MUON Scatter ///////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
vtkMuonScatter::vtkMuonScatter(MuonScatter &content)
: m_Content(&content), m_LineIn(vtkLineSource::New()),
m_LineOut(vtkLineSource::New()), m_PolyData(vtkPolyData::New()),
m_SpherePoca(NULL) {
InstallPipe();
}
vtkMuonScatter::vtkMuonScatter(const MuonScatter &content)
: m_Content(const_cast<MuonScatter *>(&content)),
m_LineIn(vtkLineSource::New()), m_LineOut(vtkLineSource::New()),
m_PolyData(vtkPolyData::New()), m_SpherePoca(NULL) {
InstallPipe();
}
vtkMuonScatter::~vtkMuonScatter() {
m_LineIn->Delete();
m_LineOut->Delete();
if (m_SpherePoca)
m_SpherePoca->Delete();
}
vtkMuonScatter::Content &vtkMuonScatter::GetContent() { return *m_Content; }
void vtkMuonScatter::PrintSelf(std::ostream &o) const {}
void vtkMuonScatter::InstallPipe() {
if (m_Content) {
vtkLineSource *line_in = m_LineIn;
vtkLineSource *line_out = m_LineOut;
float distance =
(m_Content->LineIn().origin - m_Content->LineOut().origin).norm() / 10;
HPoint3f pt;
pt = m_Content->LineIn().origin;
line_in->SetPoint1(pt(0), pt(1), pt(2));
pt = m_Content->LineIn().origin + m_Content->LineIn().direction * distance;
line_in->SetPoint2(pt(0), pt(1), pt(2));
pt = m_Content->LineOut().origin;
line_out->SetPoint1(pt(0), pt(1), pt(2));
pt =
m_Content->LineOut().origin + m_Content->LineOut().direction * distance;
line_out->SetPoint2(pt(0), pt(1), pt(2));
}
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(m_LineIn->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
this->SetProp(actor);
mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(m_LineOut->GetOutputPort());
actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
this->SetProp(actor);
}
vtkPolyData *vtkMuonScatter::GetPolyData() const {
vtkSmartPointer<vtkAppendPolyData> append =
vtkSmartPointer<vtkAppendPolyData>::New();
append->AddInputConnection(m_LineIn->GetOutputPort());
append->AddInputConnection(m_LineOut->GetOutputPort());
if (m_SpherePoca)
append->AddInputConnection(m_SpherePoca->GetOutputPort());
append->Update();
m_PolyData->DeepCopy(append->GetOutput());
return m_PolyData;
}
void vtkMuonScatter::AddPocaPoint(HPoint3f poca) {
vtkSphereSource *sphere = vtkSphereSource::New();
float size =
(m_Content->LineIn().origin - m_Content->LineOut().origin).head(3).norm();
size /= 100;
sphere->SetRadius(size);
sphere->SetCenter(poca(0), poca(1), poca(2));
sphere->Update();
m_SpherePoca = sphere;
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(m_SpherePoca->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
this->SetProp(actor);
}
HPoint3f vtkMuonScatter::GetPocaPoint() {
double center[3];
if (m_SpherePoca) {
m_SpherePoca->GetCenter(center);
return HPoint3f(center[0], center[1], center[2]);
} else {
return HPoint3f(0, 0, 0);
}
}
void vtkMuonScatter::ConnectInteractor(vtkRenderWindowInteractor *interactor) {
// TODO
}
} // namespace Vtk
} // namespace uLib

View File

@@ -23,18 +23,16 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#ifndef VTKMUONSCATTER_H #ifndef VTKMUONSCATTER_H
#define VTKMUONSCATTER_H #define VTKMUONSCATTER_H
#include <vtkVersion.h> #include <vtkActor.h>
#include <vtkAppendPolyData.h>
#include <vtkLineSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkSmartPointer.h> #include <vtkSmartPointer.h>
#include <vtkSphereSource.h> #include <vtkSphereSource.h>
#include <vtkAppendPolyData.h> #include <vtkVersion.h>
#include <vtkPolyDataMapper.h>
#include <vtkLineSource.h>
#include <vtkActor.h>
#include <vtk3DWidget.h> #include <vtk3DWidget.h>
#include <vtkBoxWidget.h> #include <vtkBoxWidget.h>
@@ -46,8 +44,8 @@
#include "Math/Dense.h" #include "Math/Dense.h"
#include "uLibVtkInterface.h" #include "HEP/Detectors/MuonScatter.h"
#include "Detectors/MuonScatter.h" #include "Vtk/uLibVtkInterface.h"
class vtkRenderWindowInteractor; class vtkRenderWindowInteractor;
@@ -56,8 +54,8 @@ namespace Vtk {
class vtkMuonScatter : public Puppet, public Polydata { class vtkMuonScatter : public Puppet, public Polydata {
typedef MuonScatter Content; typedef MuonScatter Content;
public:
public:
vtkMuonScatter(const MuonScatter &content); vtkMuonScatter(const MuonScatter &content);
vtkMuonScatter(MuonScatter &content); vtkMuonScatter(MuonScatter &content);
@@ -88,7 +86,7 @@ private:
vtkPolyData *m_PolyData; vtkPolyData *m_PolyData;
}; };
} // vtk } // namespace Vtk
} // uLib } // namespace uLib
#endif // VTKMUONSCATTER_H #endif // VTKMUONSCATTER_H

View File

@@ -0,0 +1,17 @@
################################################################################
##### Vtk/HEP/MuonTomography - VTK wrappers for MuonTomography objects ########
################################################################################
set(HEP_MUONTOMOGRAPHY_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxRaytracerRepresentation.cpp
PARENT_SCOPE)
set(HEP_MUONTOMOGRAPHY_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxRaytracerRepresentation.h
PARENT_SCOPE)
if(BUILD_TESTING)
include(uLibTargetMacros)
add_subdirectory(testing)
endif()

View File

@@ -0,0 +1,15 @@
# TESTS
set(TESTS
vtkVoxRaytracerTest
)
set(LIBRARIES
${PACKAGE_LIBPREFIX}Core
${PACKAGE_LIBPREFIX}Math
${PACKAGE_LIBPREFIX}Detectors
${PACKAGE_LIBPREFIX}Vtk
${VTK_LIBRARIES}
Boost::unit_test_framework
)
uLib_add_tests(VtkMuonTomography)

View File

@@ -23,38 +23,30 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include <vtkBoxWidget.h> #include <vtkBoxWidget.h>
#include <vtkSmartPointer.h>
#include <vtkCommand.h> #include <vtkCommand.h>
#include <vtkSmartPointer.h>
#include <Detectors/MuonScatter.h>
#include <Math/VoxRaytracer.h>
#include "Vtk/vtkMuonScatter.h"
#include "Vtk/vtkStructuredGrid.h"
#include "Vtk/vtkVoxRaytracerRepresentation.h"
#include "Vtk/uLibVtkViewer.h"
// remove
#include <vtkCornerAnnotation.h> #include <vtkCornerAnnotation.h>
#include "testing-prototype.h" #include <HEP/Detectors/MuonScatter.h>
#include <Math/VoxRaytracer.h>
#include "Vtk/HEP/Detectors/vtkMuonScatter.h"
#include "Vtk/HEP/MuonTomography/vtkVoxRaytracerRepresentation.h"
#include "Vtk/Math/vtkStructuredGrid.h"
#include "Vtk/uLibVtkViewer.h"
#define BOOST_TEST_MODULE VtkVoxRaytracerTest
#include <boost/test/unit_test.hpp>
using namespace uLib; using namespace uLib;
class vtkWidgetCallback : public vtkCommand {
class vtkWidgetCallback : public vtkCommand
{
public: public:
static vtkWidgetCallback *New() { return new vtkWidgetCallback; } static vtkWidgetCallback *New() { return new vtkWidgetCallback; }
void SetTracer(Vtk::vtkVoxRaytracerRepresentation *parent) void SetTracer(Vtk::vtkVoxRaytracerRepresentation *parent) {
{
this->vtk_raytr = parent; this->vtk_raytr = parent;
} }
@@ -64,28 +56,22 @@ public:
this->annotation = annotation; this->annotation = annotation;
} }
virtual void Execute(vtkObject *caller, unsigned long, void*) virtual void Execute(vtkObject *caller, unsigned long, void *) {
{
char str[40]; char str[40];
vtk_raytr->SetMuon(*muon); vtk_raytr->SetMuon(*muon);
if(annotation) if (annotation) {
{
sprintf(str, "total length = %f", vtk_raytr->GetRay().TotalLength()); sprintf(str, "total length = %f", vtk_raytr->GetRay().TotalLength());
annotation->SetText(1, str); annotation->SetText(1, str);
for(int i=0; i<vtk_raytr->GetRay().Data().size(); ++i) for (int i = 0; i < vtk_raytr->GetRay().size(); ++i) {
{ std::cout << "L[" << i << "] = " << vtk_raytr->GetRay().Data().at(i).L
std::cout << "L[" << i << "] = " << "\n";
<< vtk_raytr->GetRay().Data().at(i).L << "\n";
} }
std::cout << "\n"; std::cout << "\n";
} }
} }
private: private:
vtkWidgetCallback() : vtkWidgetCallback() : vtk_raytr(NULL), muon(NULL), annotation(NULL) {}
vtk_raytr(NULL),
muon(NULL),
annotation(NULL) {}
uLib::VoxRaytracer *raytracer; uLib::VoxRaytracer *raytracer;
Vtk::vtkVoxRaytracerRepresentation *vtk_raytr; Vtk::vtkVoxRaytracerRepresentation *vtk_raytr;
@@ -93,14 +79,7 @@ private:
vtkCornerAnnotation *annotation; vtkCornerAnnotation *annotation;
}; };
BOOST_AUTO_TEST_CASE(vtkVoxRaytracerRepresentationTest) {
int main()
{
BEGIN_TESTING(vtk VoxRaytracer);
// muon scatter // // muon scatter //
MuonScatter muon; MuonScatter muon;
muon.LineIn().origin << -6, 12, -6, 1; muon.LineIn().origin << -6, 12, -6, 1;
@@ -110,16 +89,13 @@ int main()
Vtk::vtkMuonScatter v_muon(muon); Vtk::vtkMuonScatter v_muon(muon);
// structured grid // // structured grid //
StructuredGrid grid(Vector3i(12, 10, 12)); StructuredGrid grid(Vector3i(12, 10, 12));
grid.SetSpacing(Vector3f(1, 1, 1)); grid.SetSpacing(Vector3f(1, 1, 1));
grid.SetPosition(Vector3f(0, 0, 0)); grid.SetPosition(Vector3f(0, 0, 0));
Vtk::vtkStructuredGrid v_grid(grid); Vtk::vtkStructuredGrid v_grid(grid);
// voxraytracer // // voxraytracer //
VoxRaytracer rt(grid); VoxRaytracer rt(grid);
HPoint3f pt; HPoint3f pt;
@@ -130,13 +106,13 @@ int main()
v_rt.SetMuon(muon); v_rt.SetMuon(muon);
v_rt.SetRayColor(Vector4f(1, 0, 0, 1)); v_rt.SetRayColor(Vector4f(1, 0, 0, 1));
// // renderer // if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
// renderer //
Vtk::Viewer viewer; Vtk::Viewer viewer;
// widget // // widget //
vtkBoxWidget *widget = v_grid.GetWidget(); vtkBoxWidget *widget = v_grid.GetWidget();
vtkWidgetCallback *cbk = vtkWidgetCallback::New(); vtkWidgetCallback *cbk = vtkWidgetCallback::New();
cbk->SetTracer(&v_rt); cbk->SetTracer(&v_rt);
cbk->SetMuon(&muon); cbk->SetMuon(&muon);
@@ -150,7 +126,7 @@ int main()
viewer.AddPuppet(v_rt); viewer.AddPuppet(v_rt);
viewer.AddPuppet(v_muon); viewer.AddPuppet(v_muon);
viewer.Start(); viewer.Start();
}
END_TESTING; BOOST_CHECK(v_rt.GetRay().Count() > 0);
} }

View File

@@ -27,12 +27,12 @@
#include "config.h" #include "config.h"
#endif #endif
#include "vtkVoxRaytracerRepresentation.h" #include "Vtk/HEP/MuonTomography/vtkVoxRaytracerRepresentation.h"
#include "Math/VoxRaytracer.h" #include "Math/VoxRaytracer.h"
// #include "vtkMuonEvent.h" // #include "Vtk/HEP/Detectors/vtkMuonEvent.h"
#include "vtkMuonScatter.h" #include "Vtk/HEP/Detectors/vtkMuonScatter.h"
namespace uLib { namespace uLib {
namespace Vtk { namespace Vtk {
@@ -114,12 +114,10 @@ void vtkVoxRaytracerRepresentation::SetMuon(MuonScatter &muon) {
m_Line3->SetPoint1(pt1(0), pt1(1), pt1(2)); m_Line3->SetPoint1(pt1(0), pt1(1), pt1(2));
m_Line3->SetPoint2(pt2(0), pt2(1), pt2(2)); m_Line3->SetPoint2(pt2(0), pt2(1), pt2(2));
// Create a vtkPoints object and store the points in it
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint(pt1(0), pt1(1), pt1(2)); points->InsertNextPoint(pt1(0), pt1(1), pt1(2));
points->InsertNextPoint(pt2(0), pt2(1), pt2(2)); points->InsertNextPoint(pt2(0), pt2(1), pt2(2));
// Create a cell array to store the lines in and add the lines to it
vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New(); vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
@@ -127,19 +125,16 @@ void vtkVoxRaytracerRepresentation::SetMuon(MuonScatter &muon) {
line->GetPointIds()->SetId(1, 1); line->GetPointIds()->SetId(1, 1);
lines->InsertNextCell(line); lines->InsertNextCell(line);
// Create a polydata to store everything in
vtkSmartPointer<vtkPolyData> linesPolyData = vtkSmartPointer<vtkPolyData> linesPolyData =
vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkPolyData>::New();
// Add the points to the dataset
linesPolyData->SetPoints(points); linesPolyData->SetPoints(points);
// Add the lines to the dataset
linesPolyData->SetLines(lines); linesPolyData->SetLines(lines);
m_RayLine->RemoveAllInputs(); m_RayLine->RemoveAllInputs();
#if VTK_MAJOR_VERSION <= 5 #if VTK_MAJOR_VERSION <= 5
m_RayLine->AddInputConnection(linesPolyData->GetProducerPort()); m_RayLine->AddInputConnection(linesPolyData->GetProducerPort());
#else
m_RayLine->AddInputData(linesPolyData);
#endif #endif
m_RayLine->AddInputConnection(m_Line1->GetOutputPort()); m_RayLine->AddInputConnection(m_Line1->GetOutputPort());
m_RayLine->AddInputConnection(m_Sphere1->GetOutputPort()); m_RayLine->AddInputConnection(m_Sphere1->GetOutputPort());
@@ -177,15 +172,12 @@ void vtkVoxRaytracerRepresentation::SetMuon(MuonScatter &muon, HPoint3f poca) {
m_Line3->SetPoint1(pt1(0), pt1(1), pt1(2)); m_Line3->SetPoint1(pt1(0), pt1(1), pt1(2));
m_Line3->SetPoint2(pt2(0), pt2(1), pt2(2)); m_Line3->SetPoint2(pt2(0), pt2(1), pt2(2));
// Create a vtkPoints object and store the points in it
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint(pt1(0), pt1(1), pt1(2)); points->InsertNextPoint(pt1(0), pt1(1), pt1(2));
points->InsertNextPoint(poca(0), poca(1), poca(2)); points->InsertNextPoint(poca(0), poca(1), poca(2));
points->InsertNextPoint(pt2(0), pt2(1), pt2(2)); points->InsertNextPoint(pt2(0), pt2(1), pt2(2));
// Create a cell array to store the lines in and add the lines to it
vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
for (unsigned int i = 0; i < 2; i++) { for (unsigned int i = 0; i < 2; i++) {
vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New(); vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
line->GetPointIds()->SetId(0, i); line->GetPointIds()->SetId(0, i);
@@ -193,19 +185,16 @@ void vtkVoxRaytracerRepresentation::SetMuon(MuonScatter &muon, HPoint3f poca) {
lines->InsertNextCell(line); lines->InsertNextCell(line);
} }
// Create a polydata to store everything in
vtkSmartPointer<vtkPolyData> linesPolyData = vtkSmartPointer<vtkPolyData> linesPolyData =
vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkPolyData>::New();
// Add the points to the dataset
linesPolyData->SetPoints(points); linesPolyData->SetPoints(points);
// Add the lines to the dataset
linesPolyData->SetLines(lines); linesPolyData->SetLines(lines);
m_RayLine->RemoveAllInputs(); m_RayLine->RemoveAllInputs();
#if VTK_MAJOR_VERSION <= 5 #if VTK_MAJOR_VERSION <= 5
m_RayLine->AddInputConnection(linesPolyData->GetProducerPort()); m_RayLine->AddInputConnection(linesPolyData->GetProducerPort());
#else
m_RayLine->AddInputData(linesPolyData);
#endif #endif
m_RayLine->AddInputConnection(m_Line1->GetOutputPort()); m_RayLine->AddInputConnection(m_Line1->GetOutputPort());
m_RayLine->AddInputConnection(m_Sphere1->GetOutputPort()); m_RayLine->AddInputConnection(m_Sphere1->GetOutputPort());
@@ -263,9 +252,11 @@ void vtkVoxRaytracerRepresentation::SetRay(VoxRaytracer::RayData *ray) {
cube->Update(); cube->Update();
#if VTK_MAJOR_VERSION <= 5 #if VTK_MAJOR_VERSION <= 5
appender->AddInput(cube->GetOutput()); appender->AddInput(cube->GetOutput());
#else
appender->AddInputData(cube->GetOutput());
#endif #endif
appender->Update();
} }
appender->Modified();
} }
void vtkVoxRaytracerRepresentation::SetVoxelsColor(Vector4f rgba) { void vtkVoxRaytracerRepresentation::SetVoxelsColor(Vector4f rgba) {
@@ -294,21 +285,18 @@ void vtkVoxRaytracerRepresentation::InstallPipe() {
append->AddInputConnection(m_Line1->GetOutputPort()); append->AddInputConnection(m_Line1->GetOutputPort());
append->AddInputConnection(m_Line2->GetOutputPort()); append->AddInputConnection(m_Line2->GetOutputPort());
append->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New(); vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(append->GetOutputPort()); mapper->SetInputConnection(append->GetOutputPort());
mapper->Update();
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); vtkSmartPointer<vtkActor> actor = vtkActor::New();
actor->SetMapper(mapper); actor->SetMapper(mapper);
actor->GetProperty()->SetColor(0.6, 0.6, 1); actor->GetProperty()->SetColor(0.6, 0.6, 1);
this->SetProp(actor); this->SetProp(actor);
mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(m_RayLine->GetOutputPort()); mapper->SetInputConnection(m_RayLine->GetOutputPort());
mapper->Update();
m_RayLineActor->SetMapper(mapper); m_RayLineActor->SetMapper(mapper);
m_RayLineActor->GetProperty()->SetColor(1, 0, 0); m_RayLineActor->GetProperty()->SetColor(1, 0, 0);
@@ -322,7 +310,6 @@ void vtkVoxRaytracerRepresentation::InstallPipe() {
mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(polyfilter->GetOutputPort()); mapper->SetInputConnection(polyfilter->GetOutputPort());
mapper->Update();
vtkActor *vra = m_RayRepresentationActor; vtkActor *vra = m_RayRepresentationActor;
vra->SetMapper(mapper); vra->SetMapper(mapper);

View File

@@ -23,39 +23,36 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#ifndef U_VTKVOXRAYTRACERREPRESENTATION_H #ifndef U_VTKVOXRAYTRACERREPRESENTATION_H
#define U_VTKVOXRAYTRACERREPRESENTATION_H #define U_VTKVOXRAYTRACERREPRESENTATION_H
#include <vtkLine.h>
#include <vtkCellArray.h> #include <vtkCellArray.h>
#include <vtkLine.h>
#include <vtkLineSource.h> #include <vtkActor.h>
#include <vtkSphereSource.h> #include <vtkAppendPolyData.h>
#include <vtkAssembly.h>
#include <vtkBoundingBox.h> #include <vtkBoundingBox.h>
#include <vtkCubeSource.h> #include <vtkCubeSource.h>
#include <vtkSmartPointer.h> #include <vtkLineSource.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h> #include <vtkPolyDataMapper.h>
#include <vtkAppendPolyData.h>
#include <vtkActor.h>
#include <vtkAssembly.h>
#include <vtkProp3DCollection.h> #include <vtkProp3DCollection.h>
#include <vtkProperty.h> #include <vtkProperty.h>
#include <vtkPolyData.h> #include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkTransform.h> #include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h> #include <vtkTransformPolyDataFilter.h>
#include "Math/Dense.h" #include "Math/Dense.h"
#include "uLibVtkInterface.h" #include "Vtk/uLibVtkInterface.h"
#include "Detectors/MuonScatter.h" #include "HEP/Detectors/MuonScatter.h"
#include "Math/StructuredGrid.h" #include "Math/StructuredGrid.h"
#include "Math/VoxRaytracer.h" #include "Math/VoxRaytracer.h"
class vtkActor; class vtkActor;
namespace uLib { namespace uLib {
@@ -63,6 +60,7 @@ namespace Vtk {
class vtkVoxRaytracerRepresentation : public Puppet { class vtkVoxRaytracerRepresentation : public Puppet {
typedef VoxRaytracer Content; typedef VoxRaytracer Content;
public: public:
vtkVoxRaytracerRepresentation(Content &content); vtkVoxRaytracerRepresentation(Content &content);
~vtkVoxRaytracerRepresentation(); ~vtkVoxRaytracerRepresentation();
@@ -73,10 +71,7 @@ public:
vtkPolyData *GetPolyData() const; vtkPolyData *GetPolyData() const;
enum RepresentationElements { enum RepresentationElements { RayElements, VoxelsElements };
RayElements,
VoxelsElements
};
void SetRepresentationElements(enum RepresentationElements el); void SetRepresentationElements(enum RepresentationElements el);
void SetMuon(MuonScatter &muon); void SetMuon(MuonScatter &muon);
@@ -98,8 +93,6 @@ public:
void SetVoxelsColor(Vector4f rgba); void SetVoxelsColor(Vector4f rgba);
void SetRayColor(Vector4f rgba); void SetRayColor(Vector4f rgba);
private: private:
void InstallPipe(); void InstallPipe();
@@ -124,9 +117,7 @@ private:
vtkAppendPolyData *m_SelectedElement; vtkAppendPolyData *m_SelectedElement;
}; };
} // namespace Vtk
} // vtk } // namespace uLib
} // uLib
#endif // VTKVOXRAYTRACERREPRESENTATION_H #endif // VTKVOXRAYTRACERREPRESENTATION_H

View File

@@ -0,0 +1,22 @@
################################################################################
##### Vtk/Math - VTK wrappers for Math module objects #########################
################################################################################
set(MATH_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/vtkStructuredGrid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vtkTriangleMesh.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.cpp
PARENT_SCOPE)
set(MATH_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/vtkHLineRepresentation.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkStructuredGrid.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkTriangleMesh.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.h
PARENT_SCOPE)
if(BUILD_TESTING)
include(uLibTargetMacros)
add_subdirectory(testing)
endif()

View File

@@ -0,0 +1,18 @@
# TESTS
set(TESTS
vtkStructuredGridTest
vtkTriangleMeshTest
vtkVoxImageTest
)
set(LIBRARIES
${PACKAGE_LIBPREFIX}Core
${PACKAGE_LIBPREFIX}Math
${PACKAGE_LIBPREFIX}Vtk
${VTK_LIBRARIES}
Boost::unit_test_framework
)
uLib_add_tests(VtkMath)
configure_file(capelluzzo.stl ${CMAKE_CURRENT_BINARY_DIR}/capelluzzo.stl COPYONLY)

Binary file not shown.

View File

@@ -23,29 +23,26 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/Math/vtkStructuredGrid.h"
#include "Math/StructuredGrid.h" #include "Math/StructuredGrid.h"
#include "Vtk/vtkStructuredGrid.h"
#include "Vtk/uLibVtkViewer.h" #include "Vtk/uLibVtkViewer.h"
#include "testing-prototype.h" #define BOOST_TEST_MODULE VtkStructuredGridTest
#include <boost/test/unit_test.hpp>
using namespace uLib; using namespace uLib;
int main() BOOST_AUTO_TEST_CASE(vtkStructuredGridTest) {
{
StructuredGrid grid(Vector3i(10, 10, 100)); StructuredGrid grid(Vector3i(10, 10, 100));
grid.SetSpacing(Vector3f(3, 1, 1)); grid.SetSpacing(Vector3f(3, 1, 1));
Vtk::vtkStructuredGrid grid_viewer(grid); Vtk::vtkStructuredGrid grid_viewer(grid);
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
Vtk::Viewer viewer; Vtk::Viewer viewer;
viewer.AddPuppet(grid_viewer); viewer.AddPuppet(grid_viewer);
viewer.Start(); viewer.Start();
}
return 0;
BOOST_CHECK(grid_viewer.GetWidget() != nullptr);
} }

View File

@@ -0,0 +1,71 @@
/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/Math/vtkTriangleMesh.h"
#include "Math/TriangleMesh.h"
#include "Vtk/uLibVtkViewer.h"
#define BOOST_TEST_MODULE VtkTriangleMeshTest
#include <boost/test/unit_test.hpp>
using namespace uLib;
BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction) {
TriangleMesh mesh;
mesh.AddPoint(Vector3f(0, 0, 0));
mesh.AddPoint(Vector3f(0, 1, 0));
mesh.AddPoint(Vector3f(1, 0, 0));
mesh.AddTriangle(Vector3i(0, 1, 2));
Vtk::vtkTriangleMesh v_mesh(mesh);
v_mesh.Update();
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
Vtk::Viewer viewer;
viewer.AddPuppet(v_mesh);
viewer.Start();
}
BOOST_CHECK_EQUAL(mesh.Points().size(), 3u);
BOOST_CHECK_EQUAL(mesh.Triangles().size(), 1u);
}
BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction2) {
TriangleMesh mesh;
Vtk::vtkTriangleMesh v_mesh(mesh);
v_mesh.ReadFromStlFile("capelluzzo.stl");
v_mesh.Update();
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
Vtk::Viewer viewer;
viewer.AddPuppet(v_mesh);
viewer.Start();
}
BOOST_CHECK_EQUAL(mesh.Points().size(), 3u);
BOOST_CHECK_EQUAL(mesh.Triangles().size(), 1u);
}

Some files were not shown because too many files have changed in this diff Show More