--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007- VTT Technical Research Centre of Finland.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+/* \r
+ This class is combination of jCAE's classes to generate meshes from shapes.\r
+ Faces are lisetd as individual meshes.\r
+ \r
+ Marko Luukkainen\r
+ \r
+ jCAE stand for Java Computer Aided Engineering. Features are : Small CAD\r
+ modeler, Finit element mesher, Plugin architecture.\r
+\r
+ Copyright (C) 2003 Jerome Robert <jeromerobert@users.sourceforge.net>\r
+\r
+ This library is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU Lesser General Public\r
+ License as published by the Free Software Foundation; either\r
+ version 2.1 of the License, or (at your option) any later version.\r
+\r
+ This library is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ Lesser General Public License for more details.\r
+\r
+ You should have received a copy of the GNU Lesser General Public\r
+ License along with this library; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+ */\r
+\r
+package org.simantics.proconf.g3d.occ.geometry;\r
+import org.jcae.opencascade.jni.BRepBndLib;\r
+import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;\r
+import org.jcae.opencascade.jni.BRepTools;\r
+import org.jcae.opencascade.jni.BRep_Tool;\r
+import org.jcae.opencascade.jni.Bnd_Box;\r
+import org.jcae.opencascade.jni.GCPnts_UniformDeflection;\r
+import org.jcae.opencascade.jni.GP_Trsf;\r
+import org.jcae.opencascade.jni.GeomAPI_ProjectPointOnSurf;\r
+import org.jcae.opencascade.jni.GeomAdaptor_Curve;\r
+import org.jcae.opencascade.jni.GeomLProp_SLProps;\r
+import org.jcae.opencascade.jni.Geom_Curve;\r
+import org.jcae.opencascade.jni.Geom_Surface;\r
+import org.jcae.opencascade.jni.Poly_Triangulation;\r
+import org.jcae.opencascade.jni.TopAbs_Orientation;\r
+import org.jcae.opencascade.jni.TopAbs_ShapeEnum;\r
+import org.jcae.opencascade.jni.TopExp_Explorer;\r
+import org.jcae.opencascade.jni.TopLoc_Location;\r
+import org.jcae.opencascade.jni.TopoDS_Edge;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.jcae.opencascade.jni.TopoDS_Vertex;\r
+\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashSet;\r
+\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3f;\r
+\r
+\r
+public class ViewableShapeImpl \r
+{\r
+\r
+ \r
+ ArrayList<IndexedGeometry> faceMeshes =new ArrayList<IndexedGeometry>();\r
+ ArrayList<float[]> edges=new ArrayList<float[]>();\r
+\r
+ public ViewableShapeImpl(TopoDS_Shape g)\r
+ {\r
+ BRepTools.clean(g);\r
+ buildFaces(g);\r
+ buildEdges(g);\r
+ \r
+ }\r
+ /*\r
+ public ViewableShapeImpl(TopoDS_Shape g, boolean alternative)\r
+ {\r
+ \r
+ if (alternative) \r
+ buildFaces(g);\r
+ else {\r
+ BRepTools.clean(g);\r
+ buildFaces2(g);\r
+ }\r
+ \r
+ buildEdges(g);\r
+ \r
+ }\r
+ */\r
+ \r
+ public IndexedGeometry getGeometry(int i)\r
+ { \r
+ return faceMeshes.get(i);\r
+ }\r
+ \r
+ public int numGeometries()\r
+ {\r
+ return faceMeshes.size();\r
+\r
+ } \r
+ \r
+ public int getNumEdges() {\r
+ return edges.size();\r
+ }\r
+ \r
+ public float[] getEdge(int i) {\r
+ return edges.get(i);\r
+ }\r
+ \r
+ /**\r
+ * org.jcae.viewer3d.cad.occ.OCCEdgeDomain\r
+ * @param shape\r
+ * @param geom\r
+ */\r
+ private void buildFaces(TopoDS_Shape shape) {\r
+ TopExp_Explorer explorer = new TopExp_Explorer();\r
+ TopLoc_Location loc = new TopLoc_Location();\r
+ \r
+ int meshIter=4;\r
+ double deflection = deflection(shape);\r
+ for (explorer.init(shape, TopAbs_ShapeEnum.FACE); explorer.more(); explorer.next())\r
+ { \r
+ //System.out.println("Triangulation");\r
+ TopoDS_Shape s = explorer.current();\r
+ if (!(s instanceof TopoDS_Face)) continue; // should not happen!\r
+ TopoDS_Face face = (TopoDS_Face)s;\r
+ Poly_Triangulation pt = BRep_Tool.triangulation(face,loc);\r
+ \r
+ //float error=0.01f;\r
+ double error = deflection;\r
+ int iter=0;\r
+ // if shape was generated with program triangulation seems to be always null,\r
+ // but model is loaded from file, it may already contain triangulation\r
+ // So : in those cases can we delete existing triangulation and generate a new one ?\r
+ //if (pt == null) {\r
+ //System.out.println("Initial triangulation of face "+face+" not found. Using Incremental mesh");\r
+ //} else {\r
+ //System.out.println("Initial triangulation of face "+face+" found.");\r
+ //}\r
+ while((pt==null)&(iter<meshIter)){\r
+ //System.out.println("Triangulation failed for face "+face+". Trying other mesh parameters.");\r
+ \r
+ // using relatif in incremental mesh would cause visible seams between faces\r
+ BRepMesh_IncrementalMesh m = new BRepMesh_IncrementalMesh(face,error, false);\r
+ //new BRepMesh_IncrementalMesh(face,error, false,12.0);\r
+ pt = BRep_Tool.triangulation(face,loc); \r
+ error/=10;\r
+ iter++;\r
+ m.delete();\r
+ \r
+ }\r
+ \r
+ \r
+ if (pt==null)\r
+ {\r
+ System.out.println("Triangulation failed for face "+face+". Mesh not generated.");\r
+ continue;\r
+ \r
+ }\r
+ \r
+ GP_Trsf trsf = loc.transformation();\r
+ double[] mat = new double[16];\r
+ trsf.getValues(mat);\r
+ Matrix4d m = new Matrix4d(mat);\r
+ \r
+ double[] dnodes = pt.nodes();\r
+ final int[] itriangles = pt.triangles(); \r
+ boolean useNormals = false;\r
+ boolean useTCoord = false;\r
+ \r
+ float[] tnodes = null;\r
+ float[] normals = null;\r
+ \r
+ if (useTCoord)\r
+ tnodes = new float[dnodes.length / 3 * 2];\r
+ if (useNormals)\r
+ normals= new float[dnodes.length];\r
+ GeomLProp_SLProps prop = new GeomLProp_SLProps(2,0.001);\r
+ Geom_Surface surf = BRep_Tool.surface(face);\r
+ prop.setSurface(surf);\r
+ if (useTCoord || useNormals) {\r
+ for (int i = 0; i < dnodes.length; i += 3) {\r
+ double UV[] = new double[2];\r
+ double point[] = new double[] { dnodes[i], dnodes[i + 1],\r
+ dnodes[i + 2] };\r
+ GeomAPI_ProjectPointOnSurf pof = new GeomAPI_ProjectPointOnSurf(\r
+ point, surf);\r
+ pof.lowerDistanceParameters(UV);\r
+ // boolean b = GeomLib_Tool.parameters(surf, point, 0.01,\r
+ // UV);\r
+ prop.setParameters(UV[0], UV[1]);\r
+ if (useNormals) {\r
+ double normal[] = prop.normal();\r
+ normals[i] = (float) normal[0];\r
+ normals[i + 1] = (float) normal[1];\r
+ normals[i + 2] = (float) normal[2];\r
+ }\r
+ if (useTCoord) {\r
+ int index = i / 3 * 2;\r
+ tnodes[index] = (float) UV[0];\r
+ tnodes[index + 1] = (float) UV[1];\r
+ }\r
+ // System.out.println(dnodes[i]+ " " +dnodes[i+1]+ " "\r
+ // +dnodes[i+2]+ " " + " UV:" + UV[0] + ","+UV[1]+ " " + b);\r
+ // System.out.println(dnodes[i]+ " " +dnodes[i+1]+ " "\r
+ // +dnodes[i+2]+ " " + normals[i] + " " + normals[i+1] + " "\r
+ // + normals[i+2] + " UV:" + UV[0] + ","+UV[1]);\r
+ }\r
+ }\r
+ prop.delete();\r
+ \r
+ if(face.orientation()==TopAbs_Orientation.REVERSED)\r
+ {\r
+ flipFace(itriangles);\r
+ }\r
+ \r
+ final float[] fnodes=createFloatVertices(dnodes, m);\r
+ IndexedGeometry geom = new IndexedGeometry();\r
+ geom.setCoordinates(fnodes);\r
+ geom.setIndices(itriangles);\r
+ geom.setNormals(calcNormals(fnodes,itriangles));\r
+ if (useNormals)\r
+ geom.setNormals(normals);\r
+ if (useTCoord)\r
+ geom.setTCoordinates(tnodes);\r
+ faceMeshes.add(geom);\r
+ //System.out.println("Triangulation done");\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * org.jcae.viewer3d.cad.occ.OCCEdgeDomain\r
+ * @param shape\r
+ * @param geom\r
+ */\r
+ /*\r
+ private void buildFaces2(TopoDS_Shape shape) {\r
+\r
+ TopExp_Explorer explorer = new TopExp_Explorer();\r
+ TopLoc_Location loc = new TopLoc_Location();\r
+ \r
+ int meshIter=10;\r
+ \r
+ for (explorer.init(shape, TopAbs_ShapeEnum.FACE); explorer.more(); explorer.next())\r
+ { \r
+ TopoDS_Shape s = explorer.current();\r
+ if (!(s instanceof TopoDS_Face)) continue; // should not happen!\r
+ TopoDS_Face face = (TopoDS_Face)s;\r
+ \r
+ double error=0.01;\r
+ BRepMesh_Discret mesh = new BRepMesh_Discret(0.01,face,0.1,true,true);\r
+ Poly_Triangulation pt = BRep_Tool.triangulation(face,loc);\r
+ //float error=0.001f*getMaxBound(s)*4;\r
+ \r
+ if (pt == null) {\r
+ System.out.println("Triangulation failed for face "+face+". Using Incremental mesh");\r
+ }\r
+ \r
+ int iter=0;\r
+ while((pt==null)&(iter<meshIter)){\r
+ BRepMesh_IncrementalMesh m = new BRepMesh_IncrementalMesh(face,error, false);\r
+ //new BRepMesh_IncrementalMesh(face,error, true);\r
+ pt = BRep_Tool.triangulation(face,loc); \r
+ error/=100;\r
+ iter++;\r
+ System.out.println("Triangulation failed for face "+face+". Trying other mesh parameters.");\r
+ m.delete();\r
+ }\r
+ mesh.delete();\r
+ if (pt==null)\r
+ {\r
+ System.out.println("Triangulation failed for face "+face+". Mesh not generated.");\r
+ continue;\r
+ }\r
+ GP_Trsf trsf = loc.transformation();\r
+ double[] mat = new double[16];\r
+ trsf.getValues(mat);\r
+ Matrix4d m = new Matrix4d(mat);\r
+ \r
+ double[] dnodes = pt.nodes();\r
+ final int[] itriangles = pt.triangles(); \r
+\r
+ if(face.orientation()==TopAbs_Orientation.REVERSED)\r
+ {\r
+ flipFace(itriangles);\r
+ }\r
+ \r
+ final float[] fnodes=createFloatVertices(dnodes, m);\r
+ IndexedGeometry geom = new IndexedGeometry();\r
+ geom.setCoordinates(fnodes);\r
+ geom.setIndices(itriangles);\r
+ geom.setNormals(calcNormals(fnodes,itriangles));\r
+ faceMeshes.add(geom);\r
+ }\r
+ }\r
+ */\r
+ \r
+ private float[] createFloatVertices(double dnodes[], Matrix4d m) {\r
+ float[] fnodes=new float[dnodes.length];\r
+ Point3d p = new Point3d();\r
+ \r
+ for(int i=0; i<dnodes.length;)\r
+ {\r
+ p.x = dnodes[i];\r
+ p.y = dnodes[i+1];\r
+ p.z = dnodes[i+2];\r
+ m.transform(p);\r
+ fnodes[i++]=(float) p.x;\r
+ fnodes[i++]=(float) p.y;\r
+ fnodes[i++]=(float) p.z; \r
+ }\r
+ return fnodes;\r
+ }\r
+ private double deflection(TopoDS_Shape s) {\r
+ Bnd_Box box = new Bnd_Box(); \r
+ BRepBndLib.add(s,box);\r
+ \r
+ double[] bbox = box.get();\r
+ double boundingBoxDeflection=0.01*\r
+ Math.max(Math.max(bbox[3]-bbox[0], bbox[4]-bbox[1]), bbox[5]-bbox[2]);\r
+ box.delete();\r
+ return boundingBoxDeflection;\r
+ }\r
+ \r
+ private double edgeDeflection(TopoDS_Shape s) {\r
+ return 0.5 * deflection(s);\r
+ }\r
+ \r
+ /**\r
+ * org.jcae.viewer3d.cad.occ.OCCEdgeDomain\r
+ * @param shape\r
+ * @param geom\r
+ */\r
+ private void buildEdges(TopoDS_Shape shape) {\r
+ \r
+ \r
+ TopExp_Explorer explorer = new TopExp_Explorer();\r
+ HashSet<TopoDS_Edge> alreadyDone=new HashSet<TopoDS_Edge>();\r
+ double boundingBoxDeflection = edgeDeflection(shape);\r
+\r
+ for (explorer.init(shape, TopAbs_ShapeEnum.EDGE); explorer.more(); explorer.next())\r
+ {\r
+ TopoDS_Shape s = explorer.current(); \r
+ if (!(s instanceof TopoDS_Edge)) continue; // should not happen!\r
+ TopoDS_Edge e = (TopoDS_Edge)s;\r
+ \r
+ if(!alreadyDone.add(e))\r
+ continue;\r
+ \r
+ double[] range = BRep_Tool.range(e);\r
+ Geom_Curve gc = BRep_Tool.curve(e, range);\r
+ float[] array;\r
+ if(gc!=null)\r
+ {\r
+ GeomAdaptor_Curve adaptator = new GeomAdaptor_Curve(gc);\r
+ GCPnts_UniformDeflection deflector = new GCPnts_UniformDeflection();\r
+\r
+ deflector.initialize(adaptator, boundingBoxDeflection, range[0], range[1]);\r
+ int npts = deflector.nbPoints();\r
+ \r
+ // Allocate one additional point at each end = parametric value 0, 1\r
+ int size = 0;\r
+ if (npts > 2)\r
+ size = (npts-2)*2;\r
+ size+=2;\r
+ size*=3;\r
+ array = new float[size]; \r
+ int j=0;\r
+ double[] values = adaptator.value(range[0]);\r
+ array[j++] = (float) values[0];\r
+ array[j++] = (float) values[1];\r
+ array[j++] = (float) values[2];\r
+ // All intermediary points\r
+ for (int i=1; i<npts-1; ++i) {\r
+ values = adaptator.value(deflector.parameter(i+1));\r
+ array[j++] = (float) values[0];\r
+ array[j++] = (float) values[1];\r
+ array[j++] = (float) values[2];\r
+ array[j++] = (float) values[0];\r
+ array[j++] = (float) values[1];\r
+ array[j++] = (float) values[2];\r
+ }\r
+ // Add last point\r
+ values = adaptator.value(range[1]);\r
+ array[j++] = (float) values[0];\r
+ array[j++] = (float) values[1];\r
+ array[j++] = (float) values[2];\r
+ edges.add(array);\r
+ adaptator.delete();\r
+ deflector.delete();\r
+ }\r
+ else\r
+ {\r
+ if (!BRep_Tool.degenerated(e))\r
+ {\r
+ // So, there is no curve, and the edge is not degenerated?\r
+ // => draw lines between the vertices and ignore curvature \r
+ // best approximation we can do\r
+ ArrayList<double[]> aa = new ArrayList<double[]>(); // store points here\r
+ for (TopExp_Explorer explorer2 = new TopExp_Explorer(s, TopAbs_ShapeEnum.VERTEX);\r
+ explorer2.more(); explorer2.next())\r
+ {\r
+ TopoDS_Shape sv = explorer2.current();\r
+ if (!(sv instanceof TopoDS_Vertex)) continue; // should not happen!\r
+ TopoDS_Vertex v = (TopoDS_Vertex)sv;\r
+ aa.add(BRep_Tool.pnt(v));\r
+ }\r
+ int size = 0;\r
+ if (aa.size() > 2)\r
+ size = (aa.size()-2)*2;\r
+ size+=2;\r
+ double[] f=(double[])aa.get(0);\r
+ array = new float[size*3];\r
+ array[0]=(float) f[0];\r
+ array[1]=(float) f[1];\r
+ array[2]=(float) f[2];\r
+ for(int i=1, j=3; i<aa.size()-1; i++)\r
+ {\r
+ f=aa.get(i);\r
+ array[j++]=(float) f[0];\r
+ array[j++]=(float) f[1];\r
+ array[j++]=(float) f[2];\r
+ array[j++]=(float) f[0];\r
+ array[j++]=(float) f[1];\r
+ array[j++]=(float) f[2];\r
+ }\r
+ f=aa.get(aa.size()-1);\r
+ array[array.length-3]=(float) f[0];\r
+ array[array.length-2]=(float) f[1];\r
+ array[array.length-1]=(float) f[2];\r
+ edges.add(array);\r
+ }\r
+ }\r
+ } \r
+ }\r
+ \r
+ private float[] calcNormals(float[] fnodes, int[] trias) {\r
+ float nnodes[] = new float[fnodes.length];\r
+ for (int i = 0; i < nnodes.length; i++) nnodes[i] = 0.f;\r
+ Vector3f v1 = new Vector3f();\r
+ Vector3f v2 = new Vector3f();\r
+ Vector3f v3 = new Vector3f();\r
+ Vector3f t1 = new Vector3f();\r
+ Vector3f t2 = new Vector3f();\r
+ Vector3f n = new Vector3f();\r
+ for (int i = 0; i < trias.length; i+=3) {\r
+ v1.x = fnodes[trias[i]*3];\r
+ v1.y = fnodes[trias[i]*3+1];\r
+ v1.z = fnodes[trias[i]*3+2];\r
+ v2.x = fnodes[trias[i+1]*3];\r
+ v2.y = fnodes[trias[i+1]*3+1];\r
+ v2.z = fnodes[trias[i+1]*3+2];\r
+ v3.x = fnodes[trias[i+2]*3];\r
+ v3.y = fnodes[trias[i+2]*3+1];\r
+ v3.z = fnodes[trias[i+2]*3+2];\r
+ t1.sub(v3, v1);\r
+ t2.sub(v2, v1);\r
+ n.cross(t2, t1);\r
+ //n.normalize();\r
+ nnodes[trias[i]*3] += n.x;\r
+ nnodes[trias[i]*3+1] += n.y;\r
+ nnodes[trias[i]*3+2] += n.z;\r
+ nnodes[trias[i+1]*3] += n.x;\r
+ nnodes[trias[i+1]*3+1] += n.y;\r
+ nnodes[trias[i+1]*3+2] += n.z;\r
+ nnodes[trias[i+2]*3] += n.x;\r
+ nnodes[trias[i+2]*3+1] += n.y;\r
+ nnodes[trias[i+2]*3+2] += n.z;\r
+ }\r
+ for (int i = 0; i < nnodes.length; i+=3) {\r
+ n.x = nnodes[i];\r
+ n.y = nnodes[i+1];\r
+ n.z = nnodes[i+2];\r
+ n.normalize();\r
+ nnodes[i] = n.x;\r
+ nnodes[i+1] = n.y;\r
+ nnodes[i+2] = n.z;\r
+ }\r
+ return nnodes;\r
+ }\r
+ \r
+ private void flipFace(int[] trias) {\r
+ int newTrias[] = new int[trias.length];\r
+ System.arraycopy(trias, 0, newTrias, 0, trias.length);\r
+ for (int i = 0; i < trias.length; i++) {\r
+ trias[i] = newTrias[trias.length - i - 1];\r
+ }\r
+ } \r
+ \r
+}\r