-/*******************************************************************************\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