]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java
git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@22282 ac1ea38d-2e2b...
[simantics/3d.git] / org.simantics.g3d.occ / src / org / simantics / proconf / g3d / occ / geometry / ViewableShapeImpl.java
diff --git a/org.simantics.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java b/org.simantics.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java
new file mode 100644 (file)
index 0000000..194b68b
--- /dev/null
@@ -0,0 +1,498 @@
+/*******************************************************************************\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