1 /*******************************************************************************
\r
2 * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.opencascade.jme;
\r
14 import java.nio.FloatBuffer;
\r
15 import java.util.ArrayList;
\r
16 import java.util.HashMap;
\r
17 import java.util.List;
\r
18 import java.util.Map;
\r
20 import javax.vecmath.Matrix4d;
\r
21 import javax.vecmath.Point3d;
\r
22 import javax.vecmath.Vector3d;
\r
23 import javax.vecmath.Vector3f;
\r
25 import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;
\r
26 import org.jcae.opencascade.jni.BRep_Tool;
\r
27 import org.jcae.opencascade.jni.GP_Trsf;
\r
28 import org.jcae.opencascade.jni.Poly_Triangulation;
\r
29 import org.jcae.opencascade.jni.TopAbs_Orientation;
\r
30 import org.jcae.opencascade.jni.TopAbs_ShapeEnum;
\r
31 import org.jcae.opencascade.jni.TopExp_Explorer;
\r
32 import org.jcae.opencascade.jni.TopLoc_Location;
\r
33 import org.jcae.opencascade.jni.TopoDS_Face;
\r
34 import org.jcae.opencascade.jni.TopoDS_Shape;
\r
35 import org.simantics.opencascade.OCCTTool;
\r
36 import org.simantics.utils.datastructures.MapList;
\r
38 import com.jme3.scene.Geometry;
\r
39 import com.jme3.scene.Mesh;
\r
40 import com.jme3.scene.Mesh.Mode;
\r
41 import com.jme3.scene.Node;
\r
42 import com.jme3.scene.Spatial;
\r
43 import com.jme3.scene.VertexBuffer.Type;
\r
44 import com.jme3.scene.mesh.IndexBuffer;
\r
48 public class JmeOCCTTool {
\r
51 public static Spatial vtkOCCShapeToAssembly(TopoDS_Shape shape) {
\r
52 double deflection = 0.001;
\r
54 if (deflection <= 0.0) {
\r
55 deflection = 0.0005;
\r
56 System.out.println("Bad value for deflection. Using: " + deflection);
\r
59 // FIXME : leaks memory!
\r
60 //BRepTools.clean(shape);
\r
62 double mass = OCCTTool.getMass(shape);
\r
64 if (mass < 1.0e-12) {
\r
65 System.out.println("Non 3D-shape detected");
\r
66 System.out.println("The cad import features are currently limited to 3D models.");
\r
69 double length = OCCTTool.getBoundingBoxDiagonal(shape);
\r
70 deflection *= length; // use relative units
\r
72 BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection);
\r
75 TopExp_Explorer expFace = new TopExp_Explorer();
\r
77 Node node = new Node();
\r
78 for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {
\r
79 TopoDS_Face face = (TopoDS_Face) expFace.current();
\r
80 Mesh partGrid = createPartGrid(face);
\r
82 if (partGrid == null)
\r
85 //gridToAssembly(assemblies, partGrid, stlSurfaceData, stlEdgeData);
\r
86 gridToAssembly(node, partGrid);
\r
92 if (faceNumber == 0) {
\r
94 .println("Cad import: error: no surface triangulation was generated.");
\r
103 public static void gridToAssembly(Node assemblies, Mesh partGrid) {
\r
104 Geometry geom = new Geometry();
\r
105 geom.setMesh(partGrid);
\r
106 assemblies.attachChild(geom);
\r
112 public static Mesh createPartGrid ( TopoDS_Face face)
\r
114 TopLoc_Location Location = new TopLoc_Location();
\r
116 Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location);
\r
118 if(triangulation == null) {
\r
120 System.out.println("Encountered empty triangulation after face");
\r
124 boolean reverse = face.orientation()==TopAbs_Orientation.REVERSED;
\r
126 int[]triangles = triangulation.triangles();
\r
127 double[]nodes = triangulation.nodes();
\r
129 int nofTriangles = triangulation.nbTriangles();
\r
130 int nofNodes = triangulation.nbNodes();
\r
132 triangulation.delete();
\r
134 if(nofTriangles < 1) {
\r
135 System.out.println("No triangles for mesh on face");
\r
141 System.out.println("No nodes for mesh on face:");
\r
146 Mesh mesh = new Mesh();
\r
148 int index[] = new int[nofTriangles*3];
\r
150 for(int i = 0; i < nofTriangles; i++)
\r
154 n0 = triangles[3 * i];
\r
155 n1 = triangles[3 * i + 1];
\r
156 n2 = triangles[3 * i + 2];
\r
158 n0 = triangles[3 * i + 2];
\r
159 n1 = triangles[3 * i + 1];
\r
160 n2 = triangles[3 * i];
\r
171 GP_Trsf transformation = Location.transformation();
\r
174 double d_mat[] = new double[16];
\r
175 transformation.getValues(d_mat);
\r
177 Matrix4d mat = new Matrix4d(d_mat);
\r
179 float vertex[] = new float[nofNodes*3];
\r
181 for(int i = 0; i < nofNodes; i++) {
\r
182 // FIXME: GP_Trsf.transform(double[]) leaks memory
\r
184 //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]};
\r
185 //transformation.transforms(xyz);
\r
186 //partPoints.InsertPoint(i, xyz);
\r
187 Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]);
\r
189 vertex[3 * i] = (float)p.x;
\r
190 vertex[3 * i+1] = (float)p.y;
\r
191 vertex[3 * i+2] = (float)p.z;
\r
194 transformation.delete();
\r
196 mesh.setBuffer(Type.Position, 3, vertex);
\r
197 mesh.setBuffer(Type.Index, 3, index);
\r
204 public static Mesh createPartGrid ( List<Double> meshPoints, List<Integer> meshTriangles)
\r
211 int nofTriangles = meshTriangles.size() / 3;
\r
212 int nofNodes = meshPoints.size() /3;
\r
215 if(nofTriangles < 1) {
\r
216 System.out.println("No triangles for mesh on face");
\r
221 System.out.println("No nodes for mesh on face:");
\r
224 Mesh mesh = new Mesh();
\r
225 //System.out.println("v " + nofNodes + " t " +nofTriangles);
\r
226 int index[] = new int[nofTriangles*3];
\r
228 for(int i = 0; i < nofTriangles; i++)
\r
231 n0 = meshTriangles.get(3 * i);
\r
232 n1 = meshTriangles.get(3 * i + 1);
\r
233 n2 = meshTriangles.get(3 * i + 2);
\r
235 index[i * 3 ] = n0;
\r
236 index[i * 3 + 1] = n1;
\r
237 index[i * 3 + 2] = n2;
\r
241 float vertex[] = new float[nofNodes*3];
\r
243 for(int i = 0; i < nofNodes; i++) {
\r
246 vertex[3 * i] = meshPoints.get(3*i).floatValue();
\r
247 vertex[3 * i+1] = meshPoints.get(3*i+1).floatValue();
\r
248 vertex[3 * i+2] = meshPoints.get(3*i+2).floatValue();
\r
251 float normal[] = calcNormals(vertex, index);
\r
254 mesh.setBuffer(Type.Position, 3, vertex);
\r
255 mesh.setBuffer(Type.Normal, 3, normal);
\r
256 mesh.setBuffer(Type.Index, 3, index);
\r
261 private static float[] calcNormals(float[] fnodes, int[] trias) {
\r
262 float nnodes[] = new float[fnodes.length];
\r
263 for (int i = 0; i < nnodes.length; i++) nnodes[i] = 0.f;
\r
264 Vector3f v1 = new Vector3f();
\r
265 Vector3f v2 = new Vector3f();
\r
266 Vector3f v3 = new Vector3f();
\r
267 Vector3f t1 = new Vector3f();
\r
268 Vector3f t2 = new Vector3f();
\r
269 Vector3f n = new Vector3f();
\r
270 for (int i = 0; i < trias.length; i+=3) {
\r
271 v1.x = fnodes[trias[i]*3];
\r
272 v1.y = fnodes[trias[i]*3+1];
\r
273 v1.z = fnodes[trias[i]*3+2];
\r
274 v2.x = fnodes[trias[i+1]*3];
\r
275 v2.y = fnodes[trias[i+1]*3+1];
\r
276 v2.z = fnodes[trias[i+1]*3+2];
\r
277 v3.x = fnodes[trias[i+2]*3];
\r
278 v3.y = fnodes[trias[i+2]*3+1];
\r
279 v3.z = fnodes[trias[i+2]*3+2];
\r
284 nnodes[trias[i]*3] += n.x;
\r
285 nnodes[trias[i]*3+1] += n.y;
\r
286 nnodes[trias[i]*3+2] += n.z;
\r
287 nnodes[trias[i+1]*3] += n.x;
\r
288 nnodes[trias[i+1]*3+1] += n.y;
\r
289 nnodes[trias[i+1]*3+2] += n.z;
\r
290 nnodes[trias[i+2]*3] += n.x;
\r
291 nnodes[trias[i+2]*3+1] += n.y;
\r
292 nnodes[trias[i+2]*3+2] += n.z;
\r
294 for (int i = 0; i < nnodes.length; i+=3) {
\r
306 public static Mesh createEdgeMesh(Mesh triMesh) {
\r
308 // list all edges in the mesh
\r
309 MapList<Integer, Integer> triEdgeIndices = new MapList<Integer, Integer>();
\r
310 for (int i = 0; i < triMesh.getTriangleCount(); i++) {
\r
311 int[] tri = new int[3];
\r
312 triMesh.getTriangle(i, tri);
\r
314 if (!triEdgeIndices.contains(tri[0], tri[1])) {
\r
315 triEdgeIndices.add(tri[0], tri[1]);
\r
317 if (!triEdgeIndices.contains(tri[1], tri[2])) {
\r
318 triEdgeIndices.add(tri[1], tri[2]);
\r
320 if (!triEdgeIndices.contains(tri[2], tri[0])) {
\r
321 triEdgeIndices.add(tri[2], tri[0]);
\r
324 // find, which edges are listed only once; those are boundaries of the mesh.
\r
325 MapList<Integer, Integer> edgeIndices = new MapList<Integer, Integer>();
\r
326 for (int s : triEdgeIndices.getKeys()) {
\r
327 for (int e : triEdgeIndices.getValues(s)) {
\r
328 if (!triEdgeIndices.contains(e, s)) {
\r
329 edgeIndices.add(s,e);
\r
330 edgeIndices.add(e,s);
\r
335 // create a new mesh, containing boundary vertices and edges of the original mesh.
\r
337 // create list of edge vertices in the original mesh
\r
338 List<Integer> vertices = new ArrayList<Integer>();
\r
339 FloatBuffer data = triMesh.getFloatBuffer(Type.Position);
\r
340 for (Integer i : edgeIndices.getKeys()) {
\r
341 List<Integer> edges = edgeIndices.getValues(i);
\r
342 if (!vertices.contains(i))
\r
344 if (!vertices.contains(edges.get(0)))
\r
345 vertices.add(edges.get(0));
\r
346 if (!vertices.contains(edges.get(1)))
\r
347 vertices.add(edges.get(1));
\r
350 // create vertices for edge mesh, and map new vertices to orignals.
\r
351 float vertex[] = new float[vertices.size() * 3];
\r
353 Map<Integer,Integer> indexMap = new HashMap<Integer, Integer>();
\r
354 for (int i : vertices) {
\r
355 vertex[i2*3] = data.get(i*3);
\r
356 vertex[i2*3+1] = data.get(i*3+1);
\r
357 vertex[i2*3+2] = data.get(i*3+2);
\r
359 indexMap.put(i, i2);
\r
364 // create line indices for the edge mesh.
\r
365 List<Integer> indices = new ArrayList<Integer>();
\r
367 for (int i = 0; i < vertices.size(); i++) {
\r
368 int s = vertices.get(i);
\r
369 List<Integer> edges = edgeIndices.getValues(s);
\r
370 for (int e : edges) {
\r
371 if (edgeIndices.contains(s, e) && indexMap.containsKey(s) && indexMap.containsKey(e)) {
\r
372 indices.add(indexMap.get(s));
\r
373 indices.add(indexMap.get(e));
\r
379 int index[] = new int[indices.size()];
\r
380 for (int i = 0; i < indices.size(); i++) {
\r
381 index[i] = indices.get(i);
\r
384 Mesh mesh = new Mesh();
\r
385 mesh.setMode(Mode.Lines);
\r
386 mesh.setBuffer(Type.Position, 3, vertex);
\r
387 mesh.setBuffer(Type.Index, 2, index);
\r
392 public static Mesh createVertexMesh(Mesh edgeMesh) {
\r
394 MapList<Integer, Integer> edgeIndices = new MapList<Integer, Integer>();
\r
395 IndexBuffer indices = edgeMesh.getIndexBuffer();
\r
396 for (int i = 0; i < indices.size(); i+=2) {
\r
397 int s = indices.get(i);
\r
398 int e = indices.get(i+1);
\r
400 if (!edgeIndices.contains(s, e)) {
\r
401 edgeIndices.add(s, e);
\r
402 edgeIndices.add(e, s);
\r
407 List<Integer> vertices = new ArrayList<Integer>();
\r
408 float data[] = edgeMesh.getFloatBuffer(Type.Position).array();
\r
409 for (Integer i : edgeIndices.getKeys()) {
\r
410 List<Integer> edges = edgeIndices.getValues(i);
\r
411 if (edges.size() != 2)
\r
414 Point3d t = new Point3d(data[i*3],data[i*3+1],data[i*3+2]);
\r
415 Vector3d v1 = new Vector3d(data[edges.get(0)*3],data[edges.get(0)*3+1],data[edges.get(0)*3+2]);
\r
416 Vector3d v2 = new Vector3d(data[edges.get(1)*3],data[edges.get(1)*3+1],data[edges.get(1)*3+2]);
\r
420 double angle = Math.PI - v1.angle(v2);
\r
421 if (angle > Math.PI/6)
\r
426 float vertex[] = new float[vertices.size() * 3];
\r
428 Map<Integer,Integer> indexMap = new HashMap<Integer, Integer>();
\r
429 for (int i : vertices) {
\r
430 vertex[i2*3] = data[i*3];
\r
431 vertex[i2*3+1] = data[i*3+1];
\r
432 vertex[i2*3+2] = data[i*3+2];
\r
434 indexMap.put(i, i2);
\r
439 int index[] = new int[vertices.size()];
\r
440 for (int i = 0; i < vertices.size(); i++) {
\r
444 Mesh mesh = new Mesh();
\r
445 mesh.setMode(Mode.Points);
\r
446 mesh.setBuffer(Type.Position, 3, vertex);
\r
447 mesh.setBuffer(Type.Index, 1, index);
\r