package org.simantics.opencascade.vtk; import java.util.List; import javax.vecmath.Matrix4d; import javax.vecmath.Point3d; import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh; import org.jcae.opencascade.jni.BRep_Tool; import org.jcae.opencascade.jni.GP_Trsf; import org.jcae.opencascade.jni.Poly_Triangulation; import org.jcae.opencascade.jni.TopAbs_Orientation; import org.jcae.opencascade.jni.TopAbs_ShapeEnum; import org.jcae.opencascade.jni.TopExp_Explorer; import org.jcae.opencascade.jni.TopLoc_Location; import org.jcae.opencascade.jni.TopoDS_Face; import org.jcae.opencascade.jni.TopoDS_Shape; import org.simantics.opencascade.OCCTTool; import vtk.vtkActor; import vtk.vtkAlgorithmOutput; import vtk.vtkAppendPolyData; import vtk.vtkAssembly; import vtk.vtkCleanPolyData; import vtk.vtkDataSetMapper; import vtk.vtkFeatureEdges; import vtk.vtkGlyph3D; import vtk.vtkIdList; import vtk.vtkPoints; import vtk.vtkPolyData; import vtk.vtkPolyDataMapper; import vtk.vtkPolyDataNormals; import vtk.vtkProp; import vtk.vtkPropCollection; import vtk.vtkProperty; import vtk.vtkSphereSource; import vtk.vtkTriangle; public class VTKOCCTool { public static vtkAssembly vtkTestAssembly() { vtkAssembly assemblies = new vtkAssembly(); vtkPolyData partGrid = createTestPartGrid(); gridToAssembly(assemblies, partGrid); return assemblies; } public static vtkAssembly vtkOCCShapeToAssembly(TopoDS_Shape shape) { double deflection = 0.001; if (deflection <= 0.0) { deflection = 0.0005; System.out.println("Bad value for deflection. Using: " + deflection); } // FIXME : leaks memory! //BRepTools.clean(shape); double mass = OCCTTool.getMass(shape); if (mass < 1.0e-12) { System.out.println("Non 3D-shape detected"); System.out.println("The cad import features are currently limited to 3D models."); } double length = OCCTTool.getBoundingBoxDiagonal(shape); deflection *= length; // use relative units BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection); int faceNumber = 0; TopExp_Explorer expFace = new TopExp_Explorer(); vtkAssembly assemblies = new vtkAssembly(); for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { TopoDS_Face face = (TopoDS_Face) expFace.current(); vtkPolyData partGrid = createPartGrid(face); face.delete(); if (partGrid == null) continue; faceNumber++; //gridToAssembly(assemblies, partGrid, stlSurfaceData, stlEdgeData); gridToAssembly(assemblies, partGrid); } expFace.delete(); mesh.delete(); if (faceNumber == 0) { System.out .println("Cad import: error: no surface triangulation was generated."); return null; } return assemblies; } private static void gridToAssembly(vtkAssembly assemblies, vtkPolyData partGrid, vtkAppendPolyData stlSurfaceData, vtkAppendPolyData stlEdgeData) { double featureAngle = 30; vtkDataSetMapper partMapper = new vtkDataSetMapper(); boolean computeNormals = true; boolean cleanPart = true; boolean mergePoints = false; vtkCleanPolyData partCleaner = new vtkCleanPolyData(); if (cleanPart) { partCleaner.SetInput(partGrid); if(mergePoints) { partCleaner.PointMergingOn(); } else { partCleaner.PointMergingOff(); } } if (computeNormals) { vtkPolyDataNormals partNormals = new vtkPolyDataNormals(); if (cleanPart) { partNormals.SetInputConnection(partCleaner.GetOutputPort()); } else partNormals.SetInput(partGrid); partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called partMapper.SetInputConnection(partNormals.GetOutputPort()); partNormals.Delete(); } else { if (cleanPart) partMapper.SetInputConnection(partCleaner.GetOutputPort()); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681 else partMapper.SetInput(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); partActor.GetProperty().SetColor(1, 1, 0); partActor.SetMapper(partMapper); // EDGES OF PARTS DETECTION vtkFeatureEdges partEdges = new vtkFeatureEdges(); if (cleanPart) partEdges.SetInputConnection(partCleaner.GetOutputPort()); else partEdges.SetInput(partGrid); partEdges.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called partEdges.FeatureEdgesOn(); partEdges.BoundaryEdgesOn(); partEdges.NonManifoldEdgesOn(); partEdges.ManifoldEdgesOn(); vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper(); partEdgesMapper.SetInputConnection(partEdges.GetOutputPort()); partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset(); partEdgesMapper.ScalarVisibilityOff(); vtkActor partEdgesActor = new vtkActor(); partEdgesActor.SetPickable(0); partEdgesActor.GetProperty().SetColor(1, 0, 1); partEdgesActor.SetMapper(partEdgesMapper); // Add triangles and edges to STL structures: //-------------------------------------------- if (cleanPart) stlSurfaceData.AddInput(partCleaner.GetOutput()); else stlSurfaceData.AddInput(partGrid); stlEdgeData.AddInput(partEdges.GetOutput()); assemblies.AddPart(partActor); assemblies.AddPart(partEdgesActor); // Clean up: //---------- partEdgesActor.Delete(); partEdgesMapper.Delete(); partEdges.Delete(); partActor.Delete(); partMapper.Delete(); partGrid.Delete(); partCleaner.Delete(); } public static void gridToAssembly(vtkAssembly assemblies, vtkPolyData partGrid) { double featureAngle = 30; vtkDataSetMapper partMapper = new vtkDataSetMapper(); boolean computeNormals = true; boolean cleanPart = false; boolean mergePoints = false; vtkCleanPolyData partCleaner = new vtkCleanPolyData(); if (cleanPart) { partCleaner.SetInput(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.SetInput(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.SetInput(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); assemblies.AddPart(partActor); { // EDGES OF PARTS DETECTION vtkFeatureEdges partEdges = new vtkFeatureEdges(); if (cleanPart) { vtkAlgorithmOutput out = partCleaner.GetOutputPort(); partEdges.SetInputConnection(out); out.Delete(); } else partEdges.SetInput(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(); prop = partEdgesActor.GetProperty(); prop.SetColor(0, 0, 0); prop.SetLineWidth(2.0); prop.Delete(); partEdgesActor.SetMapper(partEdgesMapper); partEdgesActor.PickableOn(); assemblies.AddPart(partEdgesActor); { EdgePointsFilter edgePoints = new EdgePointsFilter(); out = partEdges.GetOutputPort(); edgePoints.SetInputConnection(out); out.Delete(); // vtkDataSetMapper partEdgePointsMapper = new vtkDataSetMapper(); // out = edgePoints.GetOutputPort(); // partEdgePointsMapper.SetInputConnection(out); // out.Delete(); // vtkVertexGlyphFilter glyphFilter = new vtkVertexGlyphFilter(); // out = edgePoints.GetOutputPort(); // glyphFilter.SetInputConnection(out); // glyphFilter.Update(); // out.Delete(); // // vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper(); // out = glyphFilter.GetOutputPort(); // partEdgePointsMapper.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.ScalingOff(); glyph3D.SetScaleFactor(0.03); glyph3D.Update(); vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper(); out = glyph3D.GetOutputPort(); partEdgePointsMapper.SetInputConnection(out); out.Delete(); vtkActor edgePointsActor = new vtkActor(); prop = edgePointsActor.GetProperty(); prop.SetColor(0, 0, 1); //prop.SetPointSize(10.0); //prop.SetRepresentationToPoints(); prop.Delete(); edgePointsActor.SetMapper(partEdgePointsMapper); edgePointsActor.PickableOn(); assemblies.AddPart(edgePointsActor); edgePointsActor.Delete(); partEdgePointsMapper.Delete(); // edgePoints.Delete(); } // Clean up: //---------- partEdgesActor.Delete(); partEdgesMapper.Delete(); partEdges.Delete(); } partActor.Delete(); partMapper.Delete(); partGrid.Delete(); partCleaner.Delete(); } public static vtkPolyData createPartGrid ( TopoDS_Face face) { TopLoc_Location Location = new TopLoc_Location(); Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location); if(triangulation == null) { Location.delete(); System.out.println("Encountered empty triangulation after face"); return null; } boolean reverse = face.orientation()==TopAbs_Orientation.REVERSED; int[]triangles = triangulation.triangles(); double[]nodes = triangulation.nodes(); int nofTriangles = triangulation.nbTriangles(); int nofNodes = triangulation.nbNodes(); triangulation.delete(); if(nofTriangles < 1) { System.out.println("No triangles for mesh on face"); Location.delete(); return null; } if(nofNodes < 1) { System.out.println("No nodes for mesh on face:"); Location.delete(); return null; } //System.out.println("v " + nofNodes + " t " +nofTriangles); vtkPolyData partGrid = new vtkPolyData(); partGrid.Allocate(nofTriangles, nofTriangles); vtkTriangle triangle = new vtkTriangle(); vtkIdList list = triangle.GetPointIds(); for(int i = 0; i < nofTriangles; i++) { int n0, n1, n2; if (!reverse) { n0 = triangles[3 * i]; n1 = triangles[3 * i + 1]; n2 = triangles[3 * i + 2]; } else { n0 = triangles[3 * i + 2]; n1 = triangles[3 * i + 1]; n2 = triangles[3 * i]; } list.SetId(0, n0); list.SetId(1, n1); list.SetId(2, n2); partGrid.InsertNextCell(triangle.GetCellType(), list); } list.Delete(); triangle.Delete(); GP_Trsf transformation = Location.transformation(); Location.delete(); double d_mat[] = new double[16]; double d_p[] = new double[3]; transformation.getValues(d_mat); Matrix4d mat = new Matrix4d(d_mat); vtkPoints partPoints = new vtkPoints(); for(int i = 0; i < nofNodes; i++) { // FIXME: GP_Trsf.transform(double[]) leaks memory //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]}; //transformation.transforms(xyz); //partPoints.InsertPoint(i, xyz); Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]); mat.transform(p); d_p[0] = p.x; d_p[1] = p.y; d_p[2] = p.z; partPoints.InsertPoint(i, d_p); } transformation.delete(); partGrid.SetPoints(partPoints); partPoints.Delete(); return partGrid; } public static vtkPolyData createPartGrid ( List meshPoints, List meshTriangles) { int nofTriangles = meshTriangles.size() / 3; int nofNodes = meshPoints.size() /3; if(nofTriangles < 1) { System.out.println("No triangles for mesh on face"); return null; } if(nofNodes < 1) { System.out.println("No nodes for mesh on face:"); return null; } //System.out.println("v " + nofNodes + " t " +nofTriangles); vtkPolyData partGrid = new vtkPolyData(); partGrid.Allocate(nofTriangles, nofTriangles); vtkTriangle triangle = new vtkTriangle(); vtkIdList list = triangle.GetPointIds(); for(int i = 0; i < nofTriangles; i++) { int n0, n1, n2; n0 = meshTriangles.get(3 * i); n1 = meshTriangles.get(3 * i + 1); n2 = meshTriangles.get(3 * i + 2); list.SetId(0, n0); list.SetId(1, n1); list.SetId(2, n2); partGrid.InsertNextCell(triangle.GetCellType(), list); } list.Delete(); triangle.Delete(); double d_p[] = new double[3]; vtkPoints partPoints = new vtkPoints(); for(int i = 0; i < nofNodes; i++) { d_p[0] = meshPoints.get(3*i); d_p[1] = meshPoints.get(3*i+1); d_p[2] = meshPoints.get(3*i+2); partPoints.InsertPoint(i, d_p); } partGrid.SetPoints(partPoints); partPoints.Delete(); return partGrid; } private static vtkPolyData createTestPartGrid () { int size = 64; double[] nodes = new double[(size+1)*(size+1)*3]; int[] triangles = new int[3 * size * size * 2]; double es = 1.0; for (int i = 0; i <= size; i++) { for (int j = 0; j <= size; j++) { int index = j * size + i; index *= 3; double x = (double)i * es; double y = (Math.sin((double)i/(double)size) + Math.sin((double)j/(double)size)) * es; double z = (double)j * es; nodes[index] = x; nodes[index+1] = y; nodes[index+2] = z; } } for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { int index = j * size + i; index *= 3; index *= 2; triangles[index ] = (j * (size+1) + i ); triangles[index+1] = (j * (size+1) + i+1); triangles[index+2] = ((j+1) * (size+1) + i ); triangles[index+3] = ((j+1) * (size+1) + i ); triangles[index+4] = ((j ) * (size+1) + i +1 ); triangles[index+5] = ((j+1) * (size+1) + i +1 ); } } int nofTriangles = triangles.length / 3; int nofNodes = nodes.length / 3; if(nofTriangles < 1) { return null; } if(nofNodes < 1) { return null; } //System.out.println("v " + nofNodes + " t " +nofTriangles); vtkPolyData partGrid = new vtkPolyData(); partGrid.Allocate(nofTriangles, nofTriangles); vtkTriangle triangle = new vtkTriangle(); vtkIdList list = triangle.GetPointIds(); for(int i = 0; i < nofTriangles; i++) { int n0, n1, n2; n0 = triangles[3 * i]; n1 = triangles[3 * i + 1]; n2 = triangles[3 * i + 2]; // triangles(i).Get(n0, n1, n2); // if(face.orientation() != TopAbs_Orientation.FORWARD) { // int tmp = n2; n2 = n1; n1 = tmp; // } list.SetId(0, n0); list.SetId(1, n1); list.SetId(2, n2); partGrid.InsertNextCell(triangle.GetCellType(), list); } list.Delete(); triangle.Delete(); vtkPoints partPoints = new vtkPoints(); for(int i = 0; i < nofNodes; i++) { double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]}; partPoints.InsertPoint(i, xyz); } partGrid.SetPoints(partPoints); partPoints.Delete(); return partGrid; } public static void test() { TopoDS_Shape shape = null; //shape = OccTriangulator.makeCylinder(new double[]{0,0,0}, new double[]{0,1,0}, 1, 1); for (int t = 0; t < 5000; t++) { //shape = OccTriangulator.makeCylinder(new double[]{0,0,0}, new double[]{0,1,0}, 1, 1); int test = 2; if (test == 0) { vtkAssembly ass = VTKOCCTool.vtkOCCShapeToAssembly(shape); vtkPropCollection col; col = ass.GetParts(); for (int i = 0; i < col.GetNumberOfItems(); i++) { vtkProp prop = (vtkProp) col.GetItemAsObject(i); //System.out.println(prop.Print()); prop.Delete(); } col.Delete(); ass.Delete(); } else if (test == 1) { //BRepTools.clean(shape); vtkAssembly ass = new vtkAssembly(); double vol = OCCTTool.getBoundingBoxDiagonal(shape); double d = 0.001 * vol; BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,d); TopExp_Explorer expFace = new TopExp_Explorer(); for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { TopoDS_Face face = (TopoDS_Face) expFace.current(); { // TopLoc_Location Location = new TopLoc_Location(); // Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location); // if (triangulation != null) { // // int[]triangles = triangulation.triangles(); // double[]nodes = triangulation.nodes(); // int nofTriangles = triangulation.nbTriangles(); // int nofNodes = triangulation.nbNodes(); // // triangulation.delete(); // // GP_Trsf transformation = Location.transformation(); // double d_mat[] = new double[16]; // transformation.getValues(d_mat); // Matrix4d mat = new Matrix4d(d_mat); // for(int i = 0; i < nofNodes; i++) { // //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]}; // Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]); // //transformation.transforms(xyz); // mat.transform(p); // } // transformation.delete(); // } // // Location.delete(); vtkPolyData data = VTKOCCTool.createPartGrid(face); VTKOCCTool.gridToAssembly(ass, data); //data.Delete(); } face.delete(); } expFace.delete(); mesh.delete(); vtkPropCollection col; col = ass.GetParts(); for (int i = 0; i < col.GetNumberOfItems(); i++) { vtkProp prop = (vtkProp) col.GetItemAsObject(i); //System.out.println(prop.Print()); prop.Delete(); } col.Delete(); ass.Delete(); } else if (test == 2) { double[] pointStruct = new double[]{0,0,0}, dirStruct = new double[]{0,1,0}; double radius = 1.0; double height = 1.0; double[] axe = new double[6]; System.arraycopy(pointStruct, 0, axe, 0, 3); System.arraycopy(dirStruct, 0, axe, 3, 3); org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder cyl = new org.jcae.opencascade.jni.BRepPrimAPI_MakeCylinder(axe, radius, height, 2 * Math.PI); org.jcae.opencascade.jni.TopoDS_Shape tds = cyl.shape(); cyl.delete(); double vol = OCCTTool.getBoundingBoxDiagonal(tds); double d = 0.001 * vol; BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(tds,d); // TopExp_Explorer expFace = new TopExp_Explorer(); // for (expFace.init(tds, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) { // TopoDS_Face face = (TopoDS_Face) expFace.current(); // { // // } // face.delete(); // } mesh.delete(); tds.delete(); } //shape.delete(); System.out.println(t); } //shape.delete(); } }