Skip to content

Commit

Permalink
Add importer for OpenInventor .iv mesh file
Browse files Browse the repository at this point in the history
A very simple VRML 1.0 mesh reader file. It assumes a single triangle mesh in the file.

It can read mesh files requested at the Slicer forum - https://discourse.slicer.org/t/displaying-iv-bone-files-onto-slicer/26942
  • Loading branch information
lassoan committed Dec 31, 2022
1 parent d4a0d5c commit 14753df
Show file tree
Hide file tree
Showing 4 changed files with 35,800 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -29,6 +29,7 @@ if (Slicer_VERSION VERSION_LESS 5.1)
add_subdirectory(ImportItkSnapLabel)
endif()
add_subdirectory(ImportOCT)
add_subdirectory(ImportOpenInventor)
add_subdirectory(ImportOsirixROI)
add_subdirectory(ImportSliceOmatic)
add_subdirectory(Lights)
Expand Down
28 changes: 28 additions & 0 deletions ImportOpenInventor/CMakeLists.txt
@@ -0,0 +1,28 @@
#-----------------------------------------------------------------------------
set(MODULE_NAME ImportOpenInventor)

#-----------------------------------------------------------------------------
set(MODULE_PYTHON_SCRIPTS
${MODULE_NAME}.py
)

set(MODULE_PYTHON_RESOURCES
Resources/14819_cap_R.iv
)

#-----------------------------------------------------------------------------
slicerMacroBuildScriptedModule(
NAME ${MODULE_NAME}
SCRIPTS ${MODULE_PYTHON_SCRIPTS}
RESOURCES ${MODULE_PYTHON_RESOURCES}
WITH_GENERIC_TESTS
)

#-----------------------------------------------------------------------------
if(BUILD_TESTING)

# Register the unittest subclass in the main script as a ctest.
# Note that the test will also be available at runtime.
slicer_add_python_unittest(SCRIPT ${MODULE_NAME}.py)

endif()
132 changes: 132 additions & 0 deletions ImportOpenInventor/ImportOpenInventor.py
@@ -0,0 +1,132 @@
import os
import unittest
import logging
import vtk, qt, ctk, slicer
from slicer.ScriptedLoadableModule import *

#
# ImportOpenInventor
#

class ImportOpenInventor(ScriptedLoadableModule):
def __init__(self, parent):
ScriptedLoadableModule.__init__(self, parent)
self.parent.title = "ImportOpenInventor"
self.parent.categories = ["Informatics"]
self.parent.dependencies = []
self.parent.contributors = ["Andras Lasso (PerkLab)"]
self.parent.helpText = """Load simple triangle mesh from OpenInventor (.iv) VRML 1.0 file"""
self.parent.acknowledgementText = """This file was originally developed by Andras Lasso, PerkLab."""
# don't show this module - it is only for registering a reader
parent.hidden = True

#
# Reader plugin
# (identified by its special name <moduleName>FileReader)
#

class ImportOpenInventorFileReader(object):

def __init__(self, parent):
self.parent = parent

def description(self):
return 'OpenInventor mesh'

def fileType(self):
return 'OpenInventorMesh'

def extensions(self):
return ['OpenInventor mesh file (*.iv)']

def canLoadFile(self, filePath):
try:
with open(filePath) as f:
firstline = f.readline().rstrip()
except Exception as e:
return False
return "VRML V1.0 ascii" in firstline

def load(self, properties):
try:
filePath = properties['fileName']

with open(filePath) as file:
vrml = file.read()

import re
match = re.search(r'Separator\s+{\s+Coordinate3\s+{\s+point\s+\[([\s\d.,+-]+)\]\s+}\s+IndexedFaceSet\s+{\s+coordIndex\s+\[([\s\d.,+-]+)\]\s+}\s+}', vrml)

pointsStr = match.groups()[0]
trianglesStr = match.groups()[1]

import numpy as np
pointsArray = np.array([float(s) for s in re.findall(r'([\d.+-]+)', pointsStr)])
pointsArray = pointsArray.reshape(int(len(pointsArray)/3), 3)
trianglesArray = np.array([int(s) for s in re.findall(r'([\d.+-]+)', trianglesStr)])
trianglesArray = trianglesArray.reshape(int(len(trianglesArray)/4), 4)

points = vtk.vtkPoints()
for point in pointsArray:
points.InsertNextPoint(*point)

polygons = vtk.vtkCellArray()
for triangle in trianglesArray:
polygon = vtk.vtkPolygon()
polygonPointIds = polygon.GetPointIds()
polygonPointIds.SetNumberOfIds(3)
for pointIndex in range(3):
polygonPointIds.SetId(pointIndex, triangle[pointIndex])
polygons.InsertNextCell(polygon)

polyData = vtk.vtkPolyData()
polyData.SetPoints(points)
polyData.SetPolys(polygons)

modelNode = slicer.modules.models.logic().AddModel(polyData)

# Get node base name from filename
if 'name' in properties.keys():
baseName = properties['name']
else:
baseName = os.path.splitext(os.path.basename(filePath))[0]
baseName = slicer.mrmlScene.GenerateUniqueName(baseName)

modelNode.SetName(slicer.mrmlScene.GenerateUniqueName(baseName))

except Exception as e:
logging.error('Failed to load file: '+str(e))
import traceback
traceback.print_exc()
return False

self.parent.loadedNodes = [modelNode.GetID()]
return True


#
# ImportOpenInventorTest
#

class ImportOpenInventorTest(ScriptedLoadableModuleTest):

def setUp(self):
slicer.mrmlScene.Clear()

def runTest(self):
self.setUp()
self.test_ImportOpenInventor1()

def test_ImportOpenInventor1(self):

self.delayDisplay("Loading test image as model")
testDataPath = os.path.join(os.path.dirname(__file__), 'Resources')
tagFilePath = os.path.join(testDataPath, '14819_cap_R.iv')
node = slicer.util.loadNodeFromFile(tagFilePath, 'OpenInventorMesh')
self.assertIsNotNone(node)

self.delayDisplay('Checking loaded model')
self.assertEqual(node.GetPolyData().GetNumberOfPoints(), 11878)
self.assertEqual(node.GetPolyData().GetNumberOfCells(), 23752)

self.delayDisplay('Test passed')

0 comments on commit 14753df

Please sign in to comment.