# SlicerVMTK: the Vascular Modeling Toolkit in 3D Slicer. Vesselness filtering, # level-set vessel segmentation, centerline extraction and analysis, guided # artery/vein segmentation, stenosis measurement (1D/2D/3D), branch clipping, # cross-section analysis and CFD volume meshing. # # Built NON-superbuild against the system 3dslicer foundation, the system vmtk # (vmtk-devel's VMTKConfig.cmake) and 3dslicer-extramarkups-devel. Upstream's # superbuild compiles its own VMTK copy and ships it inside the extension; here # the vmtk package supplies it. Two C++ loadable modules (BranchClipper, # StenosisMeasurement3D), the rest scripted. %global commit 23190ba65227ddd544a1f5f2639184bbdb0d32a3 %global shortcommit %(c=%{commit}; echo ${c:0:8}) %global snapdate 20261009 %global slicer_inst %{_prefix}/lib/slicer %global slicer_subdir Slicer-5.12 # The VMTK commit SlicerVMTK pins (SuperBuild/External_VMTK.cmake) is v1.5.2 plus # one upstream commit, which vmtk 1.5.2-1 carries as a patch. %global vmtk_min 1.5.2-1 Name: 3dslicer-vmtk Version: 0 Release: 0.1.%{snapdate}git%{shortcommit}%{?dist} Summary: Vascular Modeling Toolkit modules for 3D Slicer (SlicerVMTK) License: Apache-2.0 URL: https://github.com/vmtk/SlicerExtension-VMTK Source0: %{url}/archive/%{commit}/SlicerExtension-VMTK-%{shortcommit}.tar.gz BuildRequires: cmake >= 3.20.6 BuildRequires: ninja-build BuildRequires: gcc-c++ BuildRequires: python3-devel BuildRequires: git-core BuildRequires: 3dslicer-devel >= 5.12.4 BuildRequires: 3dslicer-extramarkups-devel BuildRequires: vmtk-devel >= %{vmtk_min} # Full Qt6 set find_package(Slicer)'s Qt check demands. BuildRequires: cmake(Qt6Core) BuildRequires: cmake(Qt6Gui) BuildRequires: cmake(Qt6Widgets) BuildRequires: cmake(Qt6Network) BuildRequires: cmake(Qt6Sql) BuildRequires: cmake(Qt6Svg) BuildRequires: cmake(Qt6Xml) BuildRequires: cmake(Qt6OpenGL) BuildRequires: cmake(Qt6OpenGLWidgets) BuildRequires: cmake(Qt6PrintSupport) BuildRequires: cmake(Qt6Multimedia) BuildRequires: cmake(Qt6MultimediaWidgets) BuildRequires: cmake(Qt6Core5Compat) BuildRequires: cmake(Qt6StateMachine) BuildRequires: cmake(Qt6WebEngineCore) BuildRequires: cmake(Qt6WebEngineWidgets) BuildRequires: cmake(Qt6WebChannel) BuildRequires: cmake(Qt6Qml) BuildRequires: cmake(Qt6Quick) BuildRequires: cmake(Qt6QuickWidgets) BuildRequires: cmake(Qt6Test) BuildRequires: cmake(Qt6UiTools) BuildRequires: qt6-qttools-devel BuildRequires: InsightToolkit5-devel >= 5.4.6-7 BuildRequires: InsightToolkit5-vtk-devel BuildRequires: vtk-devel >= 9.6 BuildRequires: ctk-devel BuildRequires: qttesting-devel BuildRequires: vtkAddon-devel BuildRequires: qRestAPI-devel BuildRequires: python-pythonqt-devel BuildRequires: commontk-applauncher-devel BuildRequires: dcmtk-devel BuildRequires: SlicerExecutionModel-devel BuildRequires: rapidjson-devel BuildRequires: libcurl-devel BuildRequires: jsoncpp-devel # Loading the foundation SlicerConfig.cmake triggers find_package(Teem). BuildRequires: teem-devel Requires: 3dslicer # CrossSectionAnalysis, StenosisMeasurement3D and EditCenterline use the Shape # markups node. Requires: 3dslicer-extramarkups%{?_isa} # QuickArterySegmentation and GuidedArterySegmentation use its Flood filling and # Split volume effects (upstream downloads it on demand; see %%prep). Requires: 3dslicer-segmenteditorextraeffects # The scripted modules import VMTK's wrapped libraries (vtkvmtk*Python). Requires: python3-vmtk%{?_isa} >= %{vmtk_min} # Pin the exact VTK ABI this package was built against. VTK freezes its soname at # libvtk*.so.1 across all of 9.x, so rpm cannot tell 9.5 from 9.6 from 9.7: a consumer # built against one installs cleanly against another and fails at LOAD with undefined # symbols. %%vtk_abi comes from vtk-devel's macros.vtk; the %%build test catches a # buildroot without it (see 3dslicer-igt.spec for why the check is not at parse time). Requires: vtk(abi) = %{?vtk_abi}%{!?vtk_abi:UNSET} %description SlicerVMTK brings the Vascular Modeling Toolkit to 3D Slicer: vesselness filtering, level-set vessel segmentation, centerline extraction, centerline disassembly and junction angles, quick and guided artery and vein segmentation, stenosis measurement in 1D, 2D and 3D, branch and vessel clipping, arterial calcification preprocessing, cross-section analysis and CFD volume mesh generation. The CFD Mesh Generator can also mesh with fTetWild or Netgen, which it installs with pip into Slicer's own Python user site when first asked for. %prep %autosetup -n SlicerExtension-VMTK-%{commit} # Distro build: install modules directly, not as an Extension-Manager bundle, so # skip SlicerExtensionCPack (wants README/license + the s4ext description template # the install tree doesn't ship). sed -i '/include(${Slicer_EXTENSION_CPACK})/d' CMakeLists.txt # Same top-scope Qt6 shim as 3dslicer-igt: module MRML and Logic libraries get no Qt # include path from the install-tree Slicer targets (the ExtraMarkups headers # StenosisMeasurement3D includes pull in ), and Slicer headers the widgets # include reach further (qSlicerExtensionDownloadTask.h -> ). sed -i '/^find_package(Slicer REQUIRED)/a find_package(Qt6 COMPONENTS Core Gui Widgets Xml Network Sql Svg PrintSupport OpenGL OpenGLWidgets Concurrent Multimedia REQUIRED)\nlink_libraries(Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Xml Qt6::Network Qt6::Sql Qt6::Svg Qt6::PrintSupport Qt6::OpenGL Qt6::OpenGLWidgets Qt6::Concurrent Qt6::Multimedia)' CMakeLists.txt grep -q '^link_libraries(Qt6::Core' CMakeLists.txt || { echo "ERROR: Qt6 shim not applied" >&2; exit 1; } # Upstream's superbuild links every module library against Slicer's whole VTK library # list; the install-tree Slicer targets carry only their own closure, so these logic # libraries failed to link (-Wl,--no-undefined) with undefined references to: # vtkExtractEnclosedPoints (VTK::FiltersPoints) CrossSectionAnalysis, StenosisMeasurement3D # vtkImageOpenClose3D (VTK::ImagingMorphological) StenosisMeasurement3D # vtkSQLiteDatabase, vtkTableToSQLiteWriter (VTK::IOSQL) StenosisMeasurement3D # vtkParallelTransportFrame (vtkAddon) CrossSectionAnalysis # All four are in our vtk 9.7 and vtkAddon; only the link line lacked them. sed -i '/^link_libraries(Qt6::Core/a find_package(VTK COMPONENTS FiltersPoints ImagingMorphological IOSQL REQUIRED)\nlink_libraries(VTK::FiltersPoints VTK::ImagingMorphological VTK::IOSQL vtkAddon)' CMakeLists.txt grep -q '^link_libraries(VTK::FiltersPoints' CMakeLists.txt || { echo "ERROR: VTK link shim not applied" >&2; exit 1; } # QuickArterySegmentation and GuidedArterySegmentation call # extensionsManagerModel().installExtensionFromServer("SegmentEditorExtraEffects") with # interactive=True every time their panel is built. Here the Extensions Manager does not # see RPM-installed extensions, so it tried to download one and opened a modal dialog: # offscreen, building the QuickArterySegmentation panel hung until killed (faulthandler: # QuickArterySegmentation.py line 128 in setup). The effects they use (Flood filling, # Split volume) come from 3dslicer-segmenteditorextraeffects, required below. Drop the # download; exactly these two modules carry it. python3 - <<'PYEOF' import sys block = ''' extensionName = "SegmentEditorExtraEffects" em = slicer.app.extensionsManagerModel() em.interactive = True restart = True if not em.installExtensionFromServer(extensionName, restart): raise ValueError(_("Failed to install {nameOfExtension} extension").format(nameOfExtension=extensionName)) ''' for f in ("QuickArterySegmentation/QuickArterySegmentation.py", "GuidedArterySegmentation/GuidedArterySegmentation.py"): s = open(f).read() if s.count(block) != 1: sys.exit("installExtensionFromServer block not found once in %s (upstream changed?)" % f) open(f, "w").write(s.replace(block, "\n")) print("dropped the SegmentEditorExtraEffects download from", f) PYEOF ! grep -rq --include=*.py installExtensionFromServer . \ || { echo "ERROR: an installExtensionFromServer call is left" >&2; grep -rn --include=*.py installExtensionFromServer . >&2; exit 1; } # ClipVessel and CfdMeshGenerator both list Resources/Icons/ToggleEdges.svg, and # every scripted module copies its resources into the one shared # qt-scripted-modules/Resources directory, so two rules make the same file. Make # tolerates that; Ninja stops ("multiple rules generate .../ToggleEdges.svg"). # The two files are identical: build it once, from ClipVessel. cmp -s ClipVessel/Resources/Icons/ToggleEdges.svg CfdMeshGenerator/Resources/Icons/ToggleEdges.svg \ || { echo "ERROR: the two ToggleEdges.svg differ; the dedup below would lose one" >&2; exit 1; } sed -i '/^ Resources\/Icons\/ToggleEdges\.svg$/d' CfdMeshGenerator/CMakeLists.txt ! grep -q 'ToggleEdges' CfdMeshGenerator/CMakeLists.txt || { echo "ERROR: ToggleEdges.svg still listed twice" >&2; exit 1; } %build test -n "%{?vtk_abi}" || { echo "ERROR: vtk_abi undefined - add 'BuildRequires: vtk-devel'" >&2; exit 1; } %cmake -G Ninja \ -DSlicerVMTK_SUPERBUILD:BOOL=OFF \ -DSlicer_DIR:PATH=%{slicer_inst}/lib/%{slicer_subdir} \ -DVMTK_DIR:PATH=%{_libdir}/cmake/vmtk \ -DExtraMarkups_DIR:PATH=%{slicer_inst}/lib/%{slicer_subdir} \ -DSlicerVMTK_USE_ExtraMarkups:BOOL=ON \ -DBUILD_TESTING:BOOL=OFF \ -DSlicer_SKIP_SlicerBlockAdditionalLauncherSettings:BOOL=TRUE \ -DCMAKE_INSTALL_PREFIX:PATH=%{slicer_inst} %cmake_build %install %cmake_install # The scripted modules import VMTK's wrapped libraries as top-level modules # ("import vtkvmtkComputationalGeometryPython"), as upstream's bundled VMTK puts them # straight on Slicer's PYTHONPATH. python3-vmtk ships them inside its vmtk package. # Alias each top-level name to the vmtk submodule, so both names are one module object. # Not in qt-scripted-modules: Slicer loads every .py there as a scripted module ("class # vtkvmtkCommonPython was not found"). qt-loadable-modules/Python is on the launcher's # PYTHONPATH and is not scanned for modules. _qsm=%{buildroot}%{slicer_inst}/lib/%{slicer_subdir}/qt-loadable-modules/Python mkdir -p "$_qsm" _n=0 for _kit in Common ComputationalGeometry Contrib DifferentialGeometry IO ITK Misc Rendering Segmentation; do cat > "$_qsm/vtkvmtk${_kit}Python.py" <&2; exit 1; } # Every vtkvmtk*Python name the modules import must have a shim. for _m in $(grep -rhoE '^\s*import vtkvmtk[A-Za-z]+Python' . --include=*.py | awk '{print $2}' | sort -u); do test -f "$_qsm/$_m.py" || { echo "ERROR: no shim for imported $_m" >&2; exit 1; } done # Catch-all file list (files + symlinks only, so the shared module dirs that # 3dslicer owns are never claimed). ( cd %{buildroot} && find . \( -type f -o -type l \) | sed 's|^\.||' ) \ > %{_builddir}/vmtk.files %files -f %{_builddir}/vmtk.files %license LICENSE.txt %doc README.md %changelog * Sat Oct 10 2026 Morgan Hough - 0-0.1.20261009git23190ba6 - Initial package. SlicerVMTK built non-superbuild against the system 3dslicer, vmtk 1.5.2 and 3dslicer-extramarkups; top-level vtkvmtk*Python aliases (in qt-loadable-modules/Python) for the modules python3-vmtk ships in its vmtk package. - Quick/GuidedArterySegmentation: drop the on-demand SegmentEditorExtraEffects download (it hung building the panel); Requires 3dslicer-segmenteditorextraeffects.