/******************************************************************************* * Copyright (c) 2012, 2013 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.opencascade.vtk; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh; import org.jcae.opencascade.jni.TopAbs_ShapeEnum; import org.jcae.opencascade.jni.TopExp_Explorer; import org.jcae.opencascade.jni.TopoDS_Face; import org.jcae.opencascade.jni.TopoDS_Shape; import org.simantics.g3d.vtk.common.VtkView; import org.simantics.opencascade.OCCTTool; import org.simantics.utils.datastructures.Pair; import org.simantics.utils.threads.ThreadUtils; import vtk.vtkActor; import vtk.vtkAlgorithmOutput; import vtk.vtkCleanPolyData; import vtk.vtkDataSetMapper; import vtk.vtkFeatureEdges; import vtk.vtkGlyph3D; import vtk.vtkPolyData; import vtk.vtkPolyDataMapper; import vtk.vtkPolyDataNormals; import vtk.vtkPolyDataSilhouette; import vtk.vtkProp3D; import vtk.vtkProperty; import vtk.vtkRenderer; import vtk.vtkSphereSource; public class vtkSolidObject { public static double deflection = 0.001; public static double featureAngle = 30; public static boolean computeNormals = true; public static boolean cleanPart = false; public static boolean mergePoints = false; private VtkView panel; private TopoDS_Shape shape; private List actors = new ArrayList(2); private List solid = new ArrayList(1); private List edges = new ArrayList(1); private vtkActor silhouette = null; private boolean errors = false; public vtkSolidObject(VtkView panel,TopoDS_Shape shape) { this.shape = shape; this.panel = panel; } public void visualizeSolid(boolean showEdges, boolean showVertices) { visualizeSolid(true, showEdges, showVertices); } public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices) { visualizeSolid(showFaces, showEdges, showVertices, false); } public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices, boolean showSilhouette) { clearActorsVTK(); errors = false; Pair res = createSolidMesh(shape); if (res == null) { errors = true; return; } vtkPolyData data = res.first; if (!res.second) errors = true; if (showFaces) { solid.add(createActor(data)); } if (showEdges) { vtkActor edge = createEdgesActor(data); edges.add(edge); if (showVertices) { actors.add(createVerticesActor(edge)); } } if (showSilhouette) { silhouette = createSilhouette(panel.getRenderer(), data); } actors.addAll(solid); actors.addAll(edges); if (silhouette != null) actors.add(silhouette); data.Delete(); showActorsVTK(); } public void visualizeFaces(boolean showEdges, boolean showVertices) { errors = false; clearActorsVTK(); Collection datas = createFaceMeshes(shape); for (vtkPolyData data : datas) { if (data == null) { errors = true; continue; } solid.add(createActor(data)); if (showEdges) { vtkActor edgesActor = createEdgesActor(data); edges.add(edgesActor); if (showVertices) { actors.add(createVerticesActor(edgesActor)); } } data.Delete(); } actors.addAll(solid); actors.addAll(edges); showActorsVTK(); } public boolean hasErrors() { return errors; } public List getActors() { assert (Thread.currentThread() == panel.getThreadQueue().getThread()); return actors; } public List getSolid() { assert (Thread.currentThread() == panel.getThreadQueue().getThread()); return solid; } public List getEdges() { assert (Thread.currentThread() == panel.getThreadQueue().getThread()); return edges; } public vtkActor getSilhouette() { assert (Thread.currentThread() == panel.getThreadQueue().getThread()); return silhouette; } public void showActorsVTK() { assert (Thread.currentThread() == panel.getThreadQueue().getThread()); panel.lock(); vtkRenderer ren = panel.getRenderer(); for (vtkProp3D act : actors) { ren.AddActor(act); } panel.unlock(); } public void showActors() { ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() { @Override public void run() { showActorsVTK(); } }); } public void clearActorsVTK() { assert (Thread.currentThread() == panel.getThreadQueue().getThread()); if (actors.size() == 0) return; vtkRenderer ren = panel.getRenderer(); if (ren == null) return; panel.lock(); for (vtkProp3D act : actors) { if (act.GetVTKId() != 0) { ren.RemoveActor(act); act.Delete(); } } panel.unlock(); actors.clear(); solid.clear(); edges.clear(); } private void clearActorsAWT(List actors) { assert (Thread.currentThread() == panel.getThreadQueue().getThread()); if (actors.size() == 0) return; vtkRenderer ren = panel.getRenderer(); if (ren == null) return; panel.lock(); for (vtkProp3D act : actors) { if (act.GetVTKId() != 0) { ren.RemoveActor(act); act.Delete(); } } panel.unlock(); } public void clearActors() { if (actors.size() == 0) return; final List temp = new ArrayList(actors.size()); temp.addAll(actors); actors.clear(); solid.clear(); edges.clear(); ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() { @Override public void run() { clearActorsAWT(temp); } }); } public void dispose() { if (shape != null) { shape.delete(); shape = null; } clearActors(); } public void delete() { if (shape != null) { shape.delete(); shape = null; } clearActorsVTK(); } private static double TOLERANCE = 0.01; public static Pair createSolidMesh(TopoDS_Shape shape) { boolean success = true; double volume = OCCTTool.getBoundingBoxDiagonal(shape); if (volume < TOLERANCE) return null; BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume); TopExp_Explorer expFace = new TopExp_Explorer(); List meshPoints = new ArrayList(); List meshTriangles = new ArrayList(); for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { TopoDS_Face face = (TopoDS_Face) expFace.current(); if (!OCCTTool.appendToMesh(face, meshPoints, meshTriangles)) success = false; face.delete(); } if (meshPoints.size() == 0 || meshTriangles.size() == 0) return null; vtkPolyData data = VTKOCCTool.createPartGrid(meshPoints, meshTriangles); expFace.delete(); mesh.delete(); return new Pair(data, success); } public static Collection createFaceMeshes(TopoDS_Shape shape) { double volume = OCCTTool.getBoundingBoxDiagonal(shape); Collection faces = new ArrayList(); if (volume > TOLERANCE) { BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume); TopExp_Explorer expFace = new TopExp_Explorer(); for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { TopoDS_Face face = (TopoDS_Face) expFace.current(); vtkPolyData data = VTKOCCTool.createPartGrid(face); face.delete(); faces.add(data); } expFace.delete(); mesh.delete(); } return faces; } public static vtkActor createActor(vtkPolyData partGrid) { vtkDataSetMapper partMapper = new vtkDataSetMapper(); vtkCleanPolyData partCleaner = null; if (cleanPart) { partCleaner = new vtkCleanPolyData(); partCleaner.SetInputData(partGrid); if(mergePoints) { partCleaner.PointMergingOn(); } else { partCleaner.PointMergingOff(); } } if (computeNormals) { vtkPolyDataNormals partNormals = new vtkPolyDataNormals(); if (cleanPart) { vtkAlgorithmOutput out = partCleaner.GetOutputPort(); partNormals.SetInputConnection(out); out.Delete(); } else partNormals.SetInputData(partGrid); partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called vtkAlgorithmOutput out = partNormals.GetOutputPort(); partMapper.SetInputConnection(out); out.Delete(); partNormals.Delete(); } else { if (cleanPart) { vtkAlgorithmOutput out = partCleaner.GetOutputPort(); partMapper.SetInputConnection(out); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 out.Delete(); } else partMapper.SetInputData(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 } partMapper.ScalarVisibilityOn(); vtkActor partActor = new vtkActor(); // partActor.SetPickable(1); vtkProperty prop = partActor.GetProperty(); prop.SetColor(1, 1, 0); prop.Delete(); partActor.SetMapper(partMapper); partMapper.Delete(); if (cleanPart) partCleaner.Delete(); return partActor; } public static vtkActor createEdgesActor(vtkPolyData partGrid) { vtkCleanPolyData partCleaner = null; if (cleanPart) { partCleaner = new vtkCleanPolyData(); partCleaner.SetInputData(partGrid); if(mergePoints) { partCleaner.PointMergingOn(); } else { partCleaner.PointMergingOff(); } } vtkFeatureEdges partEdges = new vtkFeatureEdges(); if (cleanPart) { vtkAlgorithmOutput out = partCleaner.GetOutputPort(); partEdges.SetInputConnection(out); out.Delete(); } else partEdges.SetInputData(partGrid); // partEdges.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called partEdges.FeatureEdgesOn(); partEdges.BoundaryEdgesOn(); partEdges.NonManifoldEdgesOn(); partEdges.ManifoldEdgesOn(); vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper(); vtkAlgorithmOutput out = partEdges.GetOutputPort(); partEdgesMapper.SetInputConnection(out); out.Delete(); partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset(); partEdgesMapper.ScalarVisibilityOff(); vtkActor partEdgesActor = new vtkActor(); vtkProperty prop = partEdgesActor.GetProperty(); prop.SetColor(0, 0, 0); prop.SetLineWidth(1.0); prop.Delete(); partEdgesActor.SetMapper(partEdgesMapper); partEdgesMapper.Delete(); partEdges.Delete(); if (cleanPart) partCleaner.Delete(); return partEdgesActor; } public static vtkActor createVerticesActor(vtkActor partEdgesActor) { vtkDataSetMapper partEdgesMapper = (vtkDataSetMapper) partEdgesActor.GetMapper(); vtkAlgorithmOutput out = partEdgesMapper.GetInputConnection(0, 0); vtkFeatureEdges partEdges = (vtkFeatureEdges)out.GetProducer(); vtkActor edgePointsActor = createVerticesActor(partEdges); partEdges.Delete(); //out.Delete(); partEdgesMapper.Delete(); return edgePointsActor; } public static vtkActor createVerticesActor(vtkFeatureEdges partEdges) { EdgePointsFilter edgePoints = new EdgePointsFilter(); vtkAlgorithmOutput out = partEdges.GetOutputPort(); edgePoints.SetInputConnection(out); out.Delete(); vtkSphereSource sphereSource = new vtkSphereSource(); vtkGlyph3D glyph3D = new vtkGlyph3D(); out = sphereSource.GetOutputPort(); glyph3D.SetSourceConnection(out); out.Delete(); out = edgePoints.GetOutputPort(); glyph3D.SetInputConnection(out); out.Delete(); glyph3D.SetScaleFactor(0.03); glyph3D.Update(); vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper(); out = glyph3D.GetOutputPort(); partEdgePointsMapper.SetInputConnection(out); out.Delete(); vtkActor edgePointsActor = new vtkActor(); vtkProperty prop = edgePointsActor.GetProperty(); prop.SetColor(0, 0, 1); prop.Delete(); edgePointsActor.SetMapper(partEdgePointsMapper); edgePointsActor.PickableOn(); partEdgePointsMapper.Delete(); edgePoints.Delete(); sphereSource.Delete(); return edgePointsActor; } public static vtkActor createSilhouette(vtkRenderer ren, vtkPolyData data) { vtkPolyDataSilhouette silhouette = new vtkPolyDataSilhouette(); silhouette.SetInputData(data); silhouette.SetCamera(ren.GetActiveCamera()); silhouette.SetEnableFeatureAngle(0); vtkPolyDataMapper mapper = new vtkPolyDataMapper(); mapper.SetInputConnection(silhouette.GetOutputPort()); vtkActor actor = new vtkActor(); actor.SetMapper(mapper); actor.GetProperty().SetColor(0,0,1); actor.GetProperty().SetLineWidth(6); return actor; } }