]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.proconf.g3d.occ/src/org/simantics/proconf/g3d/occ/geometry/ViewableShapeImpl.java
194b68b2f09ec4335e9662e3c1d98c9203823d13
[simantics/3d.git] / org.simantics.proconf.g3d.occ / src / org / simantics / proconf / g3d / occ / geometry / ViewableShapeImpl.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007- VTT Technical Research Centre of Finland.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 /* \r
12    This class is combination of jCAE's classes to generate meshes from shapes.\r
13    Faces are lisetd as individual meshes.\r
14    \r
15    Marko Luukkainen\r
16    \r
17    jCAE stand for Java Computer Aided Engineering. Features are : Small CAD\r
18    modeler, Finit element mesher, Plugin architecture.\r
19 \r
20     Copyright (C) 2003 Jerome Robert <jeromerobert@users.sourceforge.net>\r
21 \r
22     This library is free software; you can redistribute it and/or\r
23     modify it under the terms of the GNU Lesser General Public\r
24     License as published by the Free Software Foundation; either\r
25     version 2.1 of the License, or (at your option) any later version.\r
26 \r
27     This library is distributed in the hope that it will be useful,\r
28     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
29     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
30     Lesser General Public License for more details.\r
31 \r
32     You should have received a copy of the GNU Lesser General Public\r
33     License along with this library; if not, write to the Free Software\r
34     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
35  */\r
36 \r
37 package org.simantics.proconf.g3d.occ.geometry;\r
38 import org.jcae.opencascade.jni.BRepBndLib;\r
39 import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;\r
40 import org.jcae.opencascade.jni.BRepTools;\r
41 import org.jcae.opencascade.jni.BRep_Tool;\r
42 import org.jcae.opencascade.jni.Bnd_Box;\r
43 import org.jcae.opencascade.jni.GCPnts_UniformDeflection;\r
44 import org.jcae.opencascade.jni.GP_Trsf;\r
45 import org.jcae.opencascade.jni.GeomAPI_ProjectPointOnSurf;\r
46 import org.jcae.opencascade.jni.GeomAdaptor_Curve;\r
47 import org.jcae.opencascade.jni.GeomLProp_SLProps;\r
48 import org.jcae.opencascade.jni.Geom_Curve;\r
49 import org.jcae.opencascade.jni.Geom_Surface;\r
50 import org.jcae.opencascade.jni.Poly_Triangulation;\r
51 import org.jcae.opencascade.jni.TopAbs_Orientation;\r
52 import org.jcae.opencascade.jni.TopAbs_ShapeEnum;\r
53 import org.jcae.opencascade.jni.TopExp_Explorer;\r
54 import org.jcae.opencascade.jni.TopLoc_Location;\r
55 import org.jcae.opencascade.jni.TopoDS_Edge;\r
56 import org.jcae.opencascade.jni.TopoDS_Face;\r
57 import org.jcae.opencascade.jni.TopoDS_Shape;\r
58 import org.jcae.opencascade.jni.TopoDS_Vertex;\r
59 \r
60 \r
61 import java.util.ArrayList;\r
62 import java.util.HashSet;\r
63 \r
64 import javax.vecmath.Matrix4d;\r
65 import javax.vecmath.Point3d;\r
66 import javax.vecmath.Vector3f;\r
67 \r
68 \r
69 public class ViewableShapeImpl \r
70 {\r
71 \r
72     \r
73     ArrayList<IndexedGeometry> faceMeshes =new ArrayList<IndexedGeometry>();\r
74     ArrayList<float[]> edges=new ArrayList<float[]>();\r
75 \r
76         public ViewableShapeImpl(TopoDS_Shape g)\r
77         {\r
78         BRepTools.clean(g);\r
79                 buildFaces(g);\r
80         buildEdges(g);\r
81                 \r
82         }\r
83     /*\r
84     public ViewableShapeImpl(TopoDS_Shape g, boolean alternative)\r
85     {\r
86         \r
87         if (alternative) \r
88             buildFaces(g);\r
89         else {\r
90             BRepTools.clean(g);\r
91             buildFaces2(g);\r
92         }\r
93             \r
94         buildEdges(g);\r
95         \r
96     }\r
97         */\r
98         \r
99         public IndexedGeometry getGeometry(int i)\r
100         {     \r
101                 return faceMeshes.get(i);\r
102         }\r
103         \r
104         public int numGeometries()\r
105         {\r
106         return faceMeshes.size();\r
107 \r
108         }       \r
109     \r
110     public int getNumEdges() {\r
111         return edges.size();\r
112     }\r
113     \r
114     public float[] getEdge(int i) {\r
115         return edges.get(i);\r
116     }\r
117     \r
118     /**\r
119      * org.jcae.viewer3d.cad.occ.OCCEdgeDomain\r
120      * @param shape\r
121      * @param geom\r
122      */\r
123     private void buildFaces(TopoDS_Shape shape) {\r
124         TopExp_Explorer explorer = new TopExp_Explorer();\r
125         TopLoc_Location loc = new TopLoc_Location();\r
126         \r
127         int meshIter=4;\r
128         double deflection = deflection(shape);\r
129         for (explorer.init(shape, TopAbs_ShapeEnum.FACE); explorer.more(); explorer.next())\r
130         {       \r
131             //System.out.println("Triangulation");\r
132             TopoDS_Shape s = explorer.current();\r
133             if (!(s instanceof TopoDS_Face)) continue; // should not happen!\r
134             TopoDS_Face face = (TopoDS_Face)s;\r
135             Poly_Triangulation pt = BRep_Tool.triangulation(face,loc);\r
136             \r
137             //float error=0.01f;\r
138             double error = deflection;\r
139             int iter=0;\r
140             // if shape was generated with program triangulation seems to be always null,\r
141             // but model is loaded from file, it may already contain triangulation\r
142             // So : in those cases can we delete existing triangulation and generate a new one ?\r
143             //if (pt == null) {\r
144                 //System.out.println("Initial triangulation of face "+face+" not found. Using Incremental mesh");\r
145             //} else {\r
146                 //System.out.println("Initial triangulation of face "+face+" found.");\r
147             //}\r
148             while((pt==null)&(iter<meshIter)){\r
149                 //System.out.println("Triangulation failed for face "+face+". Trying other mesh parameters.");\r
150                 \r
151                 // using relatif in incremental mesh would cause visible seams between faces\r
152                 BRepMesh_IncrementalMesh m = new BRepMesh_IncrementalMesh(face,error, false);\r
153                 //new BRepMesh_IncrementalMesh(face,error, false,12.0);\r
154                 pt = BRep_Tool.triangulation(face,loc);             \r
155                 error/=10;\r
156                 iter++;\r
157                 m.delete();\r
158                 \r
159             }\r
160                           \r
161             \r
162             if (pt==null)\r
163             {\r
164                 System.out.println("Triangulation failed for face "+face+". Mesh not generated.");\r
165                 continue;\r
166  \r
167             }\r
168             \r
169             GP_Trsf trsf = loc.transformation();\r
170             double[] mat = new double[16];\r
171             trsf.getValues(mat);\r
172             Matrix4d m = new Matrix4d(mat);\r
173             \r
174             double[] dnodes = pt.nodes();\r
175             final int[] itriangles = pt.triangles();   \r
176             boolean useNormals = false;\r
177             boolean useTCoord = false;\r
178             \r
179             float[] tnodes = null;\r
180             float[] normals = null;\r
181             \r
182             if (useTCoord)\r
183                 tnodes = new float[dnodes.length / 3 * 2];\r
184             if (useNormals)\r
185                 normals= new float[dnodes.length];\r
186             GeomLProp_SLProps prop = new GeomLProp_SLProps(2,0.001);\r
187             Geom_Surface surf = BRep_Tool.surface(face);\r
188             prop.setSurface(surf);\r
189             if (useTCoord || useNormals) {\r
190                 for (int i = 0; i < dnodes.length; i += 3) {\r
191                                         double UV[] = new double[2];\r
192                                         double point[] = new double[] { dnodes[i], dnodes[i + 1],\r
193                                                         dnodes[i + 2] };\r
194                                         GeomAPI_ProjectPointOnSurf pof = new GeomAPI_ProjectPointOnSurf(\r
195                                                         point, surf);\r
196                                         pof.lowerDistanceParameters(UV);\r
197                                         // boolean b = GeomLib_Tool.parameters(surf, point, 0.01,\r
198                                         // UV);\r
199                                         prop.setParameters(UV[0], UV[1]);\r
200                                         if (useNormals) {\r
201                                                 double normal[] = prop.normal();\r
202                                                 normals[i] = (float) normal[0];\r
203                                                 normals[i + 1] = (float) normal[1];\r
204                                                 normals[i + 2] = (float) normal[2];\r
205                                         }\r
206                                         if (useTCoord) {\r
207                                                 int index = i / 3 * 2;\r
208                                                 tnodes[index] = (float) UV[0];\r
209                                                 tnodes[index + 1] = (float) UV[1];\r
210                                         }\r
211                                         // System.out.println(dnodes[i]+ " " +dnodes[i+1]+ " "\r
212                                         // +dnodes[i+2]+ " " + " UV:" + UV[0] + ","+UV[1]+ " " + b);\r
213                                         // System.out.println(dnodes[i]+ " " +dnodes[i+1]+ " "\r
214                                         // +dnodes[i+2]+ " " + normals[i] + " " + normals[i+1] + " "\r
215                                         // + normals[i+2] + " UV:" + UV[0] + ","+UV[1]);\r
216                                 }\r
217             }\r
218             prop.delete();\r
219             \r
220             if(face.orientation()==TopAbs_Orientation.REVERSED)\r
221             {\r
222                 flipFace(itriangles);\r
223             }\r
224             \r
225             final float[] fnodes=createFloatVertices(dnodes, m);\r
226             IndexedGeometry geom = new IndexedGeometry();\r
227             geom.setCoordinates(fnodes);\r
228             geom.setIndices(itriangles);\r
229             geom.setNormals(calcNormals(fnodes,itriangles));\r
230             if (useNormals)\r
231                 geom.setNormals(normals);\r
232             if (useTCoord)\r
233                 geom.setTCoordinates(tnodes);\r
234             faceMeshes.add(geom);\r
235             //System.out.println("Triangulation done");\r
236         }\r
237     }\r
238     \r
239     /**\r
240      * org.jcae.viewer3d.cad.occ.OCCEdgeDomain\r
241      * @param shape\r
242      * @param geom\r
243      */\r
244     /*\r
245     private void buildFaces2(TopoDS_Shape shape) {\r
246 \r
247             TopExp_Explorer explorer = new TopExp_Explorer();\r
248             TopLoc_Location loc = new TopLoc_Location();\r
249             \r
250             int meshIter=10;\r
251                     \r
252             for (explorer.init(shape, TopAbs_ShapeEnum.FACE); explorer.more(); explorer.next())\r
253             {                       \r
254                 TopoDS_Shape s = explorer.current();\r
255                 if (!(s instanceof TopoDS_Face)) continue; // should not happen!\r
256                 TopoDS_Face face = (TopoDS_Face)s;\r
257                \r
258                 double error=0.01;\r
259                 BRepMesh_Discret mesh = new BRepMesh_Discret(0.01,face,0.1,true,true);\r
260                 Poly_Triangulation pt = BRep_Tool.triangulation(face,loc);\r
261                 //float error=0.001f*getMaxBound(s)*4;\r
262                 \r
263                 if (pt == null) {\r
264                     System.out.println("Triangulation failed for face "+face+". Using Incremental mesh");\r
265                 }\r
266                 \r
267                 int iter=0;\r
268                 while((pt==null)&(iter<meshIter)){\r
269                         BRepMesh_IncrementalMesh m = new BRepMesh_IncrementalMesh(face,error, false);\r
270                     //new BRepMesh_IncrementalMesh(face,error, true);\r
271                     pt = BRep_Tool.triangulation(face,loc);             \r
272                     error/=100;\r
273                     iter++;\r
274                     System.out.println("Triangulation failed for face "+face+". Trying other mesh parameters.");\r
275                     m.delete();\r
276                 }\r
277                 mesh.delete();\r
278                 if (pt==null)\r
279                 {\r
280                     System.out.println("Triangulation failed for face "+face+". Mesh not generated.");\r
281                     continue;\r
282                 }\r
283                 GP_Trsf trsf = loc.transformation();\r
284                 double[] mat = new double[16];\r
285                 trsf.getValues(mat);\r
286                 Matrix4d m = new Matrix4d(mat);\r
287                 \r
288                 double[] dnodes = pt.nodes();\r
289                 final int[] itriangles = pt.triangles();                        \r
290 \r
291                 if(face.orientation()==TopAbs_Orientation.REVERSED)\r
292                 {\r
293                     flipFace(itriangles);\r
294                 }\r
295                 \r
296                 final float[] fnodes=createFloatVertices(dnodes, m);\r
297                 IndexedGeometry geom = new IndexedGeometry();\r
298                 geom.setCoordinates(fnodes);\r
299                 geom.setIndices(itriangles);\r
300                 geom.setNormals(calcNormals(fnodes,itriangles));\r
301                 faceMeshes.add(geom);\r
302             }\r
303     }\r
304     */\r
305     \r
306     private float[] createFloatVertices(double dnodes[], Matrix4d m) {\r
307         float[] fnodes=new float[dnodes.length];\r
308         Point3d p = new Point3d();\r
309         \r
310         for(int i=0; i<dnodes.length;)\r
311         {\r
312             p.x = dnodes[i];\r
313             p.y = dnodes[i+1];\r
314             p.z = dnodes[i+2];\r
315             m.transform(p);\r
316             fnodes[i++]=(float) p.x;\r
317             fnodes[i++]=(float) p.y;\r
318             fnodes[i++]=(float) p.z;  \r
319         }\r
320         return fnodes;\r
321     }\r
322     private double deflection(TopoDS_Shape s) {\r
323         Bnd_Box box = new Bnd_Box(); \r
324         BRepBndLib.add(s,box);\r
325         \r
326         double[] bbox = box.get();\r
327         double boundingBoxDeflection=0.01*\r
328             Math.max(Math.max(bbox[3]-bbox[0], bbox[4]-bbox[1]), bbox[5]-bbox[2]);\r
329         box.delete();\r
330         return boundingBoxDeflection;\r
331     }\r
332     \r
333     private double edgeDeflection(TopoDS_Shape s) {\r
334         return 0.5 * deflection(s);\r
335     }\r
336     \r
337     /**\r
338      * org.jcae.viewer3d.cad.occ.OCCEdgeDomain\r
339      * @param shape\r
340      * @param geom\r
341      */\r
342     private void buildEdges(TopoDS_Shape shape) {\r
343         \r
344         \r
345         TopExp_Explorer explorer = new TopExp_Explorer();\r
346         HashSet<TopoDS_Edge> alreadyDone=new HashSet<TopoDS_Edge>();\r
347         double boundingBoxDeflection = edgeDeflection(shape);\r
348 \r
349         for (explorer.init(shape, TopAbs_ShapeEnum.EDGE); explorer.more(); explorer.next())\r
350         {\r
351             TopoDS_Shape s = explorer.current();            \r
352             if (!(s instanceof TopoDS_Edge)) continue; // should not happen!\r
353             TopoDS_Edge e = (TopoDS_Edge)s;\r
354             \r
355             if(!alreadyDone.add(e))\r
356                 continue;\r
357                         \r
358             double[] range = BRep_Tool.range(e);\r
359             Geom_Curve gc = BRep_Tool.curve(e, range);\r
360             float[] array;\r
361             if(gc!=null)\r
362             {\r
363                 GeomAdaptor_Curve adaptator = new GeomAdaptor_Curve(gc);\r
364                 GCPnts_UniformDeflection deflector = new GCPnts_UniformDeflection();\r
365 \r
366                 deflector.initialize(adaptator, boundingBoxDeflection, range[0], range[1]);\r
367                 int npts = deflector.nbPoints();\r
368                 \r
369                 // Allocate one additional point at each end  = parametric value 0, 1\r
370                 int size = 0;\r
371                 if (npts > 2)\r
372                     size = (npts-2)*2;\r
373                 size+=2;\r
374                 size*=3;\r
375                 array = new float[size];          \r
376                 int j=0;\r
377                 double[] values = adaptator.value(range[0]);\r
378                 array[j++] = (float) values[0];\r
379                 array[j++] = (float) values[1];\r
380                 array[j++] = (float) values[2];\r
381                 // All intermediary points\r
382                 for (int i=1; i<npts-1; ++i) {\r
383                     values = adaptator.value(deflector.parameter(i+1));\r
384                     array[j++] = (float) values[0];\r
385                     array[j++] = (float) values[1];\r
386                     array[j++] = (float) values[2];\r
387                     array[j++] = (float) values[0];\r
388                     array[j++] = (float) values[1];\r
389                     array[j++] = (float) values[2];\r
390                 }\r
391                 // Add last point\r
392                 values = adaptator.value(range[1]);\r
393                 array[j++] = (float) values[0];\r
394                 array[j++] = (float) values[1];\r
395                 array[j++] = (float) values[2];\r
396                 edges.add(array);\r
397                 adaptator.delete();\r
398                 deflector.delete();\r
399             }\r
400             else\r
401             {\r
402                 if (!BRep_Tool.degenerated(e))\r
403                 {\r
404                     // So, there is no curve, and the edge is not degenerated?\r
405                     // => draw lines between the vertices and ignore curvature  \r
406                     // best approximation we can do\r
407                     ArrayList<double[]> aa = new ArrayList<double[]>(); // store points here\r
408                     for (TopExp_Explorer explorer2 = new TopExp_Explorer(s, TopAbs_ShapeEnum.VERTEX);\r
409                         explorer2.more(); explorer2.next())\r
410                     {\r
411                         TopoDS_Shape sv = explorer2.current();\r
412                         if (!(sv instanceof TopoDS_Vertex)) continue; // should not happen!\r
413                         TopoDS_Vertex v = (TopoDS_Vertex)sv;\r
414                         aa.add(BRep_Tool.pnt(v));\r
415                     }\r
416                     int size = 0;\r
417                     if (aa.size() > 2)\r
418                         size = (aa.size()-2)*2;\r
419                     size+=2;\r
420                     double[] f=(double[])aa.get(0);\r
421                     array = new float[size*3];\r
422                     array[0]=(float) f[0];\r
423                     array[1]=(float) f[1];\r
424                     array[2]=(float) f[2];\r
425                     for(int i=1, j=3; i<aa.size()-1; i++)\r
426                     {\r
427                         f=aa.get(i);\r
428                         array[j++]=(float) f[0];\r
429                         array[j++]=(float) f[1];\r
430                         array[j++]=(float) f[2];\r
431                         array[j++]=(float) f[0];\r
432                         array[j++]=(float) f[1];\r
433                         array[j++]=(float) f[2];\r
434                     }\r
435                     f=aa.get(aa.size()-1);\r
436                     array[array.length-3]=(float) f[0];\r
437                     array[array.length-2]=(float) f[1];\r
438                     array[array.length-1]=(float) f[2];\r
439                     edges.add(array);\r
440                 }\r
441             }\r
442         }       \r
443     }\r
444     \r
445     private float[] calcNormals(float[] fnodes, int[] trias) {\r
446         float nnodes[] = new float[fnodes.length];\r
447         for (int i = 0; i < nnodes.length; i++) nnodes[i] = 0.f;\r
448         Vector3f v1 = new Vector3f();\r
449         Vector3f v2 = new Vector3f();\r
450         Vector3f v3 = new Vector3f();\r
451         Vector3f t1 = new Vector3f();\r
452         Vector3f t2 = new Vector3f();\r
453         Vector3f n = new Vector3f();\r
454         for (int i = 0; i < trias.length; i+=3) {\r
455             v1.x = fnodes[trias[i]*3];\r
456             v1.y = fnodes[trias[i]*3+1];\r
457             v1.z = fnodes[trias[i]*3+2];\r
458             v2.x = fnodes[trias[i+1]*3];\r
459             v2.y = fnodes[trias[i+1]*3+1];\r
460             v2.z = fnodes[trias[i+1]*3+2];\r
461             v3.x = fnodes[trias[i+2]*3];\r
462             v3.y = fnodes[trias[i+2]*3+1];\r
463             v3.z = fnodes[trias[i+2]*3+2];\r
464             t1.sub(v3, v1);\r
465             t2.sub(v2, v1);\r
466             n.cross(t2, t1);\r
467             //n.normalize();\r
468             nnodes[trias[i]*3] += n.x;\r
469             nnodes[trias[i]*3+1] += n.y;\r
470             nnodes[trias[i]*3+2] += n.z;\r
471             nnodes[trias[i+1]*3] += n.x;\r
472             nnodes[trias[i+1]*3+1] += n.y;\r
473             nnodes[trias[i+1]*3+2] += n.z;\r
474             nnodes[trias[i+2]*3] += n.x;\r
475             nnodes[trias[i+2]*3+1] += n.y;\r
476             nnodes[trias[i+2]*3+2] += n.z;\r
477         }\r
478         for (int i = 0; i < nnodes.length; i+=3) {\r
479             n.x = nnodes[i];\r
480             n.y = nnodes[i+1];\r
481             n.z = nnodes[i+2];\r
482             n.normalize();\r
483             nnodes[i] = n.x;\r
484             nnodes[i+1] = n.y;\r
485             nnodes[i+2] = n.z;\r
486         }\r
487         return nnodes;\r
488     }\r
489     \r
490     private void flipFace(int[] trias) {\r
491         int newTrias[] = new int[trias.length];\r
492         System.arraycopy(trias, 0, newTrias, 0, trias.length);\r
493         for (int i = 0; i < trias.length; i++) {\r
494             trias[i] = newTrias[trias.length - i - 1];\r
495         }\r
496     }   \r
497         \r
498 }\r