forked from Kitware/vtk-js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(objwriter): add support for vtkOBJWriter
fix Kitware#2404
- Loading branch information
Showing
3 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import 'vtk.js/Sources/favicon'; | ||
|
||
// Load the rendering pieces we want to use (for both WebGL and WebGPU) | ||
import 'vtk.js/Sources/Rendering/Profiles/Geometry'; | ||
|
||
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow'; | ||
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'; | ||
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'; | ||
|
||
import vtkOBJWriter from 'vtk.js/Sources/IO/Misc/OBJWriter'; | ||
import vtkOBJReader from 'vtk.js/Sources/IO/Misc/OBJReader'; | ||
import vtkPolyDataReader from 'vtk.js/Sources/IO/Legacy/PolyDataReader'; | ||
// ---------------------------------------------------------------------------- | ||
// Standard rendering code setup | ||
// ---------------------------------------------------------------------------- | ||
|
||
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ | ||
background: [0.5, 0.5, 0.5], | ||
}); | ||
const renderer = fullScreenRenderer.getRenderer(); | ||
const renderWindow = fullScreenRenderer.getRenderWindow(); | ||
|
||
const resetCamera = renderer.resetCamera; | ||
const render = renderWindow.render; | ||
|
||
const reader = vtkPolyDataReader.newInstance(); | ||
const writerReader = vtkOBJReader.newInstance(); | ||
const writer = vtkOBJWriter.newInstance(); | ||
|
||
reader | ||
.setUrl(`${__BASE_PATH__}/data/legacy/sphere.vtk`, { loadData: true }) | ||
.then(() => { | ||
writer.setInputData(reader.getOutputData()); | ||
const fileContents = writer.getOutputData(); | ||
// Can also use a static function to write to OBJ: | ||
// const fileContents = vtkOBJWriter.writeOBJ(reader.getOutputData()); | ||
|
||
// Display the resulting OBJ | ||
writerReader.parseAsText(fileContents); | ||
|
||
const polydata = reader.getOutputData(0); | ||
const mapper = vtkMapper.newInstance(); | ||
const actor = vtkActor.newInstance(); | ||
actor.setMapper(mapper); | ||
mapper.setInputData(polydata); | ||
|
||
renderer.addActor(actor); | ||
resetCamera(); | ||
render(); | ||
|
||
// Add a download link for it | ||
const blob = new Blob([fileContents], { type: 'application/octet-steam' }); | ||
const a = window.document.createElement('a'); | ||
a.href = window.URL.createObjectURL(blob, { | ||
type: 'application/octet-steam', | ||
}); | ||
a.download = 'sphere.obj'; | ||
a.text = 'Download'; | ||
a.style.position = 'absolute'; | ||
a.style.left = '50%'; | ||
a.style.bottom = '10px'; | ||
document.body.appendChild(a); | ||
a.style.background = 'white'; | ||
a.style.padding = '5px'; | ||
}); | ||
|
||
global.writer = writer; | ||
global.writerReader = writerReader; | ||
global.fullScreenRenderer = fullScreenRenderer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import vtkPolyData from "../../../Common/DataModel/PolyData"; | ||
import { vtkAlgorithm, vtkObject } from "../../../interfaces"; | ||
|
||
/** | ||
* | ||
*/ | ||
export interface IOBJWriterInitialValues {} | ||
|
||
type vtkOBJWriterBase = vtkObject & vtkAlgorithm; | ||
|
||
export interface vtkOBJWriter extends vtkOBJWriterBase { | ||
|
||
/** | ||
* | ||
* @param inData | ||
* @param outData | ||
*/ | ||
requestData(inData: any, outData: any): void; | ||
} | ||
|
||
/** | ||
* Method used to decorate a given object (publicAPI+model) with vtkOBJWriter characteristics. | ||
* | ||
* @param publicAPI object on which methods will be bounds (public) | ||
* @param model object on which data structure will be bounds (protected) | ||
* @param {IOBJWriterInitialValues} [initialValues] (default: {}) | ||
*/ | ||
export function extend(publicAPI: object, model: object, initialValues?: IOBJWriterInitialValues): void; | ||
|
||
/** | ||
* Method used to create a new instance of vtkOBJWriter | ||
* @param {IOBJWriterInitialValues} [initialValues] for pre-setting some of its content | ||
*/ | ||
export function newInstance(initialValues?: IOBJWriterInitialValues): vtkOBJWriter; | ||
|
||
/** | ||
* | ||
* @param {vktPolyData} polyData | ||
*/ | ||
export function writeOBJ(polyData: vtkPolyData): vtkPolyData; | ||
|
||
/** | ||
* vtkOBJWriter writes wavefront obj (.obj) files in ASCII form. OBJ files | ||
* contain the geometry including lines, triangles and polygons. Normals and | ||
* texture coordinates on points are also written if they exist. | ||
*/ | ||
export declare const vtkOBJWriter: { | ||
newInstance: typeof newInstance; | ||
extend: typeof extend; | ||
writeOBJ: typeof writeOBJ; | ||
} | ||
export default vtkOBJWriter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import macro from 'vtk.js/Sources/macros'; | ||
|
||
const { vtkErrorMacro } = macro; | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Global methods | ||
// ---------------------------------------------------------------------------- | ||
|
||
// ---------------------------------------------------------------------------- | ||
// vtkOBJWriter methods | ||
// ---------------------------------------------------------------------------- | ||
|
||
const writeFaces = (faces, withNormals, withTCoords) => { | ||
let outputData = ''; | ||
const fd = faces.getData(); | ||
|
||
let offset = 0; | ||
while (offset < fd.length) { | ||
const faceSize = fd[offset++]; | ||
outputData += 'f'; | ||
for (let i = 0; i < faceSize; i++) { | ||
outputData += ` ${fd[offset + i] + 1}`; | ||
if (withTCoords) { | ||
outputData += `/${fd[offset + i] + 1}`; | ||
if (withNormals) { | ||
outputData += `//${fd[offset + i] + 1}`; | ||
} | ||
} else if (withNormals) { | ||
outputData += `//${fd[offset + i] + 1}`; | ||
} | ||
} | ||
offset += faceSize; | ||
outputData += '\n'; | ||
} | ||
return outputData; | ||
}; | ||
|
||
const writeLines = (lines) => { | ||
let outputData = ''; | ||
const ld = lines.getData(); | ||
|
||
let offset = 0; | ||
while (offset < ld.length) { | ||
const lineSize = ld[offset++]; | ||
outputData += 'l'; | ||
for (let i = 0; i < lineSize; i++) { | ||
outputData += ` ${ld[offset + i] + 1}`; | ||
} | ||
offset += lineSize; | ||
outputData += '\n'; | ||
} | ||
|
||
return outputData; | ||
}; | ||
|
||
const writePoints = (pts, normals, tcoords) => { | ||
let outputData = ''; | ||
const nbPts = pts.getNumberOfPoints(); | ||
|
||
let p; | ||
|
||
// Positions | ||
for (let i = 0; i < nbPts; i++) { | ||
p = pts.getPoint(i, p); | ||
outputData += `v ${p[0]} ${p[1]} ${p[2]}\n`; | ||
} | ||
|
||
// Normals | ||
if (normals) { | ||
for (let i = 0; i < nbPts; i++) { | ||
p = normals.getTuple(i, p); | ||
outputData += `vn ${p[0]} ${p[1]} ${p[2]}\n`; | ||
} | ||
} | ||
|
||
// Textures | ||
if (tcoords) { | ||
for (let i = 0; i < nbPts; i++) { | ||
p = tcoords.getTuple(i, p); | ||
outputData += `vt ${p[0]} ${p[1]}\n`; | ||
} | ||
} | ||
return outputData; | ||
}; | ||
|
||
const writeOBJ = (polyData) => { | ||
let outputData = '# Generated by Visualization Toolkit\n'; | ||
const pts = polyData.getPoints(); | ||
const polys = polyData.getPolys(); | ||
const strips = polyData.getStrips() ? polyData.getStrips().getData() : null; | ||
const lines = polyData.getLines(); | ||
|
||
const normals = polyData.getPointData().getNormals(); | ||
const tcoords = polyData.getPointData().getTCoords(); | ||
|
||
const hasPtNormals = normals !== null; | ||
const hasPtTCoords = tcoords !== null; | ||
|
||
if (!pts) { | ||
vtkErrorMacro('No data to write!'); | ||
} | ||
|
||
// Write points | ||
outputData += writePoints(pts, normals, tcoords); | ||
|
||
// Unsupported triangle strips | ||
if (strips && strips.length > 0) { | ||
vtkErrorMacro('Unsupported strips'); | ||
} | ||
|
||
// Write polygons. | ||
if (polys) { | ||
outputData += writeFaces(polys, hasPtNormals, hasPtTCoords); | ||
} | ||
|
||
// Write lines. | ||
if (lines) { | ||
outputData += writeLines(lines); | ||
} | ||
|
||
return outputData; | ||
}; | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Static API | ||
// ---------------------------------------------------------------------------- | ||
|
||
export const STATIC = { | ||
writeOBJ, | ||
}; | ||
|
||
// ---------------------------------------------------------------------------- | ||
// vtkOBJWriter methods | ||
// ---------------------------------------------------------------------------- | ||
|
||
function vtkOBJWriter(publicAPI, model) { | ||
// Set our className | ||
model.classHierarchy.push('vtkOBJWriter'); | ||
|
||
publicAPI.requestData = (inData, outData) => { | ||
const input = inData[0]; | ||
|
||
if (!input || !input.isA('vtkPolyData')) { | ||
vtkErrorMacro('Invalid or missing input'); | ||
return; | ||
} | ||
|
||
outData[0] = writeOBJ(input); | ||
}; | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Object factory | ||
// ---------------------------------------------------------------------------- | ||
|
||
const DEFAULT_VALUES = {}; | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
export function extend(publicAPI, model, initialValues = {}) { | ||
Object.assign(model, DEFAULT_VALUES, initialValues); | ||
|
||
// Make this a VTK object | ||
macro.obj(publicAPI, model); | ||
|
||
// Also make it an algorithm with one input and one output | ||
macro.algo(publicAPI, model, 1, 1); | ||
|
||
// Object specific methods | ||
vtkOBJWriter(publicAPI, model); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
export const newInstance = macro.newInstance(extend, 'vtkOBJWriter'); | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
export default { newInstance, extend, ...STATIC }; |