const std = @import("std");
const c = @cImport({
@cInclude("vtkImageViewer2_c.h");
});
// Error types
pub const VtkError = error{
NullPointer,
InvalidArgument,
CreationFailed,
};
// Slice orientation constants
pub const SliceOrientation = enum(c_int) {
YZ = c.VTK_SLICE_ORIENTATION_YZ,
XZ = c.VTK_SLICE_ORIENTATION_XZ,
XY = c.VTK_SLICE_ORIENTATION_XY,
};
// Opaque wrapper types
pub const ImageData = opaque {};
pub const RenderWindow = opaque {};
pub const Renderer = opaque {};
pub const ImageActor = opaque {};
pub const WindowLevel = opaque {};
pub const InteractorStyle = opaque {};
pub const RenderWindowInteractor = opaque {};
pub const AlgorithmOutput = opaque {};
// Position and Size helper types
pub const Position = struct {
x: i32,
y: i32,
};
pub const Size = struct {
width: i32,
height: i32,
};
pub const SliceRange = struct {
min: i32,
max: i32,
};
// Main ImageViewer2 wrapper
pub const ImageViewer2 = struct {
ptr: *c.vtkImageViewer2_C,
const Self = @This();
// Object lifecycle
pub fn init() VtkError!Self {
const ptr = c.vtkImageViewer2_New();
if (ptr == null) {
return VtkError.CreationFailed;
}
return Self{ .ptr = ptr.? };
}
pub fn deinit(self: Self) void {
c.vtkImageViewer2_Delete(self.ptr);
}
// Basic rendering
pub fn render(self: Self) void {
c.vtkImageViewer2_Render(self.ptr);
}
pub fn getWindowName(self: Self) ?[]const u8 {
const name = c.vtkImageViewer2_GetWindowName(self.ptr);
if (name == null) return null;
return std.mem.span(name);
}
// Input data management
pub fn setInputData(self: Self, input: *const ImageData) void {
c.vtkImageViewer2_SetInputData(self.ptr, @ptrCast(input));
}
pub fn getInput(self: Self) ?*ImageData {
const input = c.vtkImageViewer2_GetInput(self.ptr);
if (input == null) return null;
return @ptrCast(input);
}
pub fn setInputConnection(self: Self, input: *const AlgorithmOutput) void {
c.vtkImageViewer2_SetInputConnection(self.ptr, @ptrCast(input));
}
// Slice orientation
pub fn getSliceOrientation(self: Self) SliceOrientation {
const orientation = c.vtkImageViewer2_GetSliceOrientation(self.ptr);
return @enumFromInt(orientation);
}
pub fn setSliceOrientation(self: Self, orientation: SliceOrientation) void {
c.vtkImageViewer2_SetSliceOrientation(self.ptr, @intFromEnum(orientation));
}
pub fn setSliceOrientationToXY(self: Self) void {
c.vtkImageViewer2_SetSliceOrientationToXY(self.ptr);
}
pub fn setSliceOrientationToYZ(self: Self) void {
c.vtkImageViewer2_SetSliceOrientationToYZ(self.ptr);
}
pub fn setSliceOrientationToXZ(self: Self) void {
c.vtkImageViewer2_SetSliceOrientationToXZ(self.ptr);
}
// Slice management
pub fn getSlice(self: Self) i32 {
return c.vtkImageViewer2_GetSlice(self.ptr);
}
pub fn setSlice(self: Self, slice: i32) void {
c.vtkImageViewer2_SetSlice(self.ptr, slice);
}
pub fn updateDisplayExtent(self: Self) void {
c.vtkImageViewer2_UpdateDisplayExtent(self.ptr);
}
// Slice range information
pub fn getSliceMin(self: Self) i32 {
return c.vtkImageViewer2_GetSliceMin(self.ptr);
}
pub fn getSliceMax(self: Self) i32 {
return c.vtkImageViewer2_GetSliceMax(self.ptr);
}
pub fn getSliceRange(self: Self) SliceRange {
var range = [2]c_int{ 0, 0 };
c.vtkImageViewer2_GetSliceRange(self.ptr, &range);
return SliceRange{
.min = range[0],
.max = range[1],
};
}
pub fn getSliceRangeMinMax(self: Self) SliceRange {
var min: c_int = 0;
var max: c_int = 0;
c.vtkImageViewer2_GetSliceRangeMinMax(self.ptr, &min, &max);
return SliceRange{
.min = min,
.max = max,
};
}
// Color window/level
pub fn getColorWindow(self: Self) f64 {
return c.vtkImageViewer2_GetColorWindow(self.ptr);
}
pub fn getColorLevel(self: Self) f64 {
return c.vtkImageViewer2_GetColorLevel(self.ptr);
}
pub fn setColorWindow(self: Self, window: f64) void {
c.vtkImageViewer2_SetColorWindow(self.ptr, window);
}
pub fn setColorLevel(self: Self, level: f64) void {
c.vtkImageViewer2_SetColorLevel(self.ptr, level);
}
pub fn setColorWindowLevel(self: Self, window: f64, level: f64) void {
self.setColorWindow(window);
self.setColorLevel(level);
}
// Window management
pub fn setDisplayId(self: Self, display_id: ?*anyopaque) void {
c.vtkImageViewer2_SetDisplayId(self.ptr, display_id);
}
pub fn setWindowId(self: Self, window_id: ?*anyopaque) void {
c.vtkImageViewer2_SetWindowId(self.ptr, window_id);
}
pub fn setParentId(self: Self, parent_id: ?*anyopaque) void {
c.vtkImageViewer2_SetParentId(self.ptr, parent_id);
}
// Position and size
pub fn getPosition(self: Self) Position {
const pos = c.vtkImageViewer2_GetPosition(self.ptr);
if (pos == null) return Position{ .x = 0, .y = 0 };
return Position{
.x = pos[0],
.y = pos[1],
};
}
pub fn setPosition(self: Self, pos: Position) void {
c.vtkImageViewer2_SetPosition(self.ptr, pos.x, pos.y);
}
pub fn setPositionXY(self: Self, x: i32, y: i32) void {
c.vtkImageViewer2_SetPosition(self.ptr, x, y);
}
pub fn getSize(self: Self) Size {
const size = c.vtkImageViewer2_GetSize(self.ptr);
if (size == null) return Size{ .width = 0, .height = 0 };
return Size{
.width = size[0],
.height = size[1],
};
}
pub fn setSize(self: Self, size: Size) void {
c.vtkImageViewer2_SetSize(self.ptr, size.width, size.height);
}
pub fn setSizeWH(self: Self, width: i32, height: i32) void {
c.vtkImageViewer2_SetSize(self.ptr, width, height);
}
// Component access
pub fn getRenderWindow(self: Self) ?*RenderWindow {
const window = c.vtkImageViewer2_GetRenderWindow(self.ptr);
if (window == null) return null;
return @ptrCast(window);
}
pub fn getRenderer(self: Self) ?*Renderer {
const renderer = c.vtkImageViewer2_GetRenderer(self.ptr);
if (renderer == null) return null;
return @ptrCast(renderer);
}
pub fn getImageActor(self: Self) ?*ImageActor {
const actor = c.vtkImageViewer2_GetImageActor(self.ptr);
if (actor == null) return null;
return @ptrCast(actor);
}
pub fn getWindowLevel(self: Self) ?*WindowLevel {
const window_level = c.vtkImageViewer2_GetWindowLevel(self.ptr);
if (window_level == null) return null;
return @ptrCast(window_level);
}
pub fn getInteractorStyle(self: Self) ?*InteractorStyle {
const style = c.vtkImageViewer2_GetInteractorStyle(self.ptr);
if (style == null) return null;
return @ptrCast(style);
}
// Component setup
pub fn setRenderWindow(self: Self, window: *const RenderWindow) void {
c.vtkImageViewer2_SetRenderWindow(self.ptr, @ptrCast(window));
}
pub fn setRenderer(self: Self, renderer: *const Renderer) void {
c.vtkImageViewer2_SetRenderer(self.ptr, @ptrCast(renderer));
}
pub fn setupInteractor(self: Self, interactor: *const RenderWindowInteractor) void {
c.vtkImageViewer2_SetupInteractor(self.ptr, @ptrCast(interactor));
}
// Off-screen rendering
pub fn getOffScreenRendering(self: Self) bool {
return c.vtkImageViewer2_GetOffScreenRendering(self.ptr) != 0;
}
pub fn setOffScreenRendering(self: Self, enable: bool) void {
c.vtkImageViewer2_SetOffScreenRendering(self.ptr, if (enable) 1 else 0);
}
pub fn offScreenRenderingOn(self: Self) void {
c.vtkImageViewer2_OffScreenRenderingOn(self.ptr);
}
pub fn offScreenRenderingOff(self: Self) void {
c.vtkImageViewer2_OffScreenRenderingOff(self.ptr);
}
// Type checking
pub fn isTypeOf(type_name: []const u8) bool {
const c_type = @as([*c]const u8, @ptrCast(type_name.ptr));
return c.vtkImageViewer2_IsTypeOf(c_type) != 0;
}
pub fn isA(self: Self, type_name: []const u8) bool {
const c_type = @as([*c]const u8, @ptrCast(type_name.ptr));
return c.vtkImageViewer2_IsA(self.ptr, c_type) != 0;
}
// Object information
pub fn getClassName(self: Self) ?[]const u8 {
const name = c.vtkImageViewer2_GetClassName(self.ptr);
if (name == null) return null;
return std.mem.span(name);
}
pub fn printSelf(self: Self) void {
c.vtkImageViewer2_PrintSelf(self.ptr);
}
// Reference counting
pub fn getReferenceCount(self: Self) i32 {
return c.vtkImageViewer2_GetReferenceCount(self.ptr);
}
pub fn register(self: Self, object: ?*anyopaque) void {
c.vtkImageViewer2_Register(self.ptr, object);
}
pub fn unRegister(self: Self, object: ?*anyopaque) void {
c.vtkImageViewer2_UnRegister(self.ptr, object);
}
// Debug support
pub fn getDebug(self: Self) bool {
return c.vtkImageViewer2_GetDebug(self.ptr) != 0;
}
pub fn setDebug(self: Self, debug_flag: bool) void {
c.vtkImageViewer2_SetDebug(self.ptr, if (debug_flag) 1 else 0);
}
pub fn debugOn(self: Self) void {
c.vtkImageViewer2_DebugOn(self.ptr);
}
pub fn debugOff(self: Self) void {
c.vtkImageViewer2_DebugOff(self.ptr);
}
// Modification time
pub fn getMTime(self: Self) u64 {
return @intCast(c.vtkImageViewer2_GetMTime(self.ptr));
}
pub fn modified(self: Self) void {
c.vtkImageViewer2_Modified(self.ptr);
}
// Object name and description
pub fn setObjectName(self: Self, name: []const u8) VtkError!void {
// Create null-terminated string
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
const c_name = allocator.dupeZ(u8, name) catch return VtkError.InvalidArgument;
c.vtkImageViewer2_SetObjectName(self.ptr, c_name.ptr);
}
pub fn getObjectName(self: Self) ?[]const u8 {
const name = c.vtkImageViewer2_GetObjectName(self.ptr);
if (name == null) return null;
return std.mem.span(name);
}
pub fn getObjectDescription(self: Self) ?[]const u8 {
const desc = c.vtkImageViewer2_GetObjectDescription(self.ptr);
if (desc == null) return null;
return std.mem.span(desc);
}
};
// Global warning display functions
pub const GlobalWarning = struct {
pub fn getDisplay() bool {
return c.vtkImageViewer2_GetGlobalWarningDisplay() != 0;
}
pub fn setDisplay(enable: bool) void {
c.vtkImageViewer2_SetGlobalWarningDisplay(if (enable) 1 else 0);
}
pub fn displayOn() void {
c.vtkImageViewer2_GlobalWarningDisplayOn();
}
pub fn displayOff() void {
c.vtkImageViewer2_GlobalWarningDisplayOff();
}
};
// Convenience functions and utilities
pub const Utils = struct {
// Helper to create and setup a basic image viewer
pub fn createBasicViewer(allocator: std.mem.Allocator) VtkError!ImageViewer2 {
_ = allocator; // Currently unused, but reserved for future use
var viewer = try ImageViewer2.init();
// Set up basic defaults
viewer.setSliceOrientationToXY();
viewer.setOffScreenRendering(false);
return viewer;
}
// Helper to setup window with specific size and position
pub fn setupWindow(viewer: *ImageViewer2, pos: Position, size: Size) void {
viewer.setPosition(pos);
viewer.setSize(size);
}
// Helper to navigate slices safely
pub fn navigateSlice(viewer: *ImageViewer2, direction: enum { next, previous, first, last }) void {
const range = viewer.getSliceRange();
const current = viewer.getSlice();
const new_slice = switch (direction) {
.next => @min(current + 1, range.max),
.previous => @max(current - 1, range.min),
.first => range.min,
.last => range.max,
};
viewer.setSlice(new_slice);
}
// Helper to auto-adjust window/level based on data range
pub fn autoWindowLevel(viewer: *ImageViewer2) void {
// This would typically analyze the image data to determine
// optimal window/level values. For now, we'll use common defaults.
viewer.setColorWindow(255.0);
viewer.setColorLevel(127.5);
}
};
// Tests
test "ImageViewer2 basic functionality" {
const testing = std.testing;
// Test creation and destruction
var viewer = ImageViewer2.init() catch |err| {
std.debug.print("Failed to create ImageViewer2: {}\n", .{err});
return;
};
defer viewer.deinit();
// Test basic properties
const initial_slice = viewer.getSlice();
viewer.setSlice(initial_slice + 1);
try testing.expect(viewer.getSlice() == initial_slice + 1);
// Test orientation
viewer.setSliceOrientation(.XY);
try testing.expect(viewer.getSliceOrientation() == .XY);
// Test color settings
viewer.setColorWindow(100.0);
viewer.setColorLevel(50.0);
try testing.expect(viewer.getColorWindow() == 100.0);
try testing.expect(viewer.getColorLevel() == 50.0);
// Test off-screen rendering
viewer.setOffScreenRendering(true);
try testing.expect(viewer.getOffScreenRendering() == true);
viewer.setOffScreenRendering(false);
try testing.expect(viewer.getOffScreenRendering() == false);
}
test "Utils functionality" {
const testing = std.testing;
const allocator = testing.allocator;
// Test basic viewer creation
var viewer = Utils.createBasicViewer(allocator) catch |err| {
std.debug.print("Failed to create basic viewer: {}\n", .{err});
return;
};
defer viewer.deinit();
// Test window setup
const pos = Position{ .x = 100, .y = 100 };
const size = Size{ .width = 800, .height = 600 };
Utils.setupWindow(&viewer, pos, size);
const actual_pos = viewer.getPosition();
const actual_size = viewer.getSize();
try testing.expect(actual_pos.x == pos.x);
try testing.expect(actual_pos.y == pos.y);
try testing.expect(actual_size.width == size.width);
try testing.expect(actual_size.height == size.height);
}
test "Global warning display" {
const testing = std.testing;
// Test global warning display functions
const initial_state = GlobalWarning.getDisplay();
GlobalWarning.setDisplay(true);
try testing.expect(GlobalWarning.getDisplay() == true);
GlobalWarning.setDisplay(false);
try testing.expect(GlobalWarning.getDisplay() == false);
// Restore initial state
GlobalWarning.setDisplay(initial_state);
}