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
9 * VTT Technical Research Centre of Finland - initial API and implementation
\r
10 *******************************************************************************/
\r
12 This class is combination of jCAE's classes to generate meshes from shapes.
\r
13 Faces are lisetd as individual meshes.
\r
17 jCAE stand for Java Computer Aided Engineering. Features are : Small CAD
\r
18 modeler, Finit element mesher, Plugin architecture.
\r
20 Copyright (C) 2003 Jerome Robert <jeromerobert@users.sourceforge.net>
\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
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
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
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
61 import java.util.ArrayList;
\r
62 import java.util.HashSet;
\r
64 import javax.vecmath.Matrix4d;
\r
65 import javax.vecmath.Point3d;
\r
66 import javax.vecmath.Vector3f;
\r
69 public class ViewableShapeImpl
\r
73 ArrayList<IndexedGeometry> faceMeshes =new ArrayList<IndexedGeometry>();
\r
74 ArrayList<float[]> edges=new ArrayList<float[]>();
\r
76 public ViewableShapeImpl(TopoDS_Shape g)
\r
84 public ViewableShapeImpl(TopoDS_Shape g, boolean alternative)
\r
99 public IndexedGeometry getGeometry(int i)
\r
101 return faceMeshes.get(i);
\r
104 public int numGeometries()
\r
106 return faceMeshes.size();
\r
110 public int getNumEdges() {
\r
111 return edges.size();
\r
114 public float[] getEdge(int i) {
\r
115 return edges.get(i);
\r
119 * org.jcae.viewer3d.cad.occ.OCCEdgeDomain
\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
128 double deflection = deflection(shape);
\r
129 for (explorer.init(shape, TopAbs_ShapeEnum.FACE); explorer.more(); explorer.next())
\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
137 //float error=0.01f;
\r
138 double error = deflection;
\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
146 //System.out.println("Initial triangulation of face "+face+" found.");
\r
148 while((pt==null)&(iter<meshIter)){
\r
149 //System.out.println("Triangulation failed for face "+face+". Trying other mesh parameters.");
\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
164 System.out.println("Triangulation failed for face "+face+". Mesh not generated.");
\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
174 double[] dnodes = pt.nodes();
\r
175 final int[] itriangles = pt.triangles();
\r
176 boolean useNormals = false;
\r
177 boolean useTCoord = false;
\r
179 float[] tnodes = null;
\r
180 float[] normals = null;
\r
183 tnodes = new float[dnodes.length / 3 * 2];
\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
194 GeomAPI_ProjectPointOnSurf pof = new GeomAPI_ProjectPointOnSurf(
\r
196 pof.lowerDistanceParameters(UV);
\r
197 // boolean b = GeomLib_Tool.parameters(surf, point, 0.01,
\r
199 prop.setParameters(UV[0], UV[1]);
\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
207 int index = i / 3 * 2;
\r
208 tnodes[index] = (float) UV[0];
\r
209 tnodes[index + 1] = (float) UV[1];
\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
220 if(face.orientation()==TopAbs_Orientation.REVERSED)
\r
222 flipFace(itriangles);
\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
231 geom.setNormals(normals);
\r
233 geom.setTCoordinates(tnodes);
\r
234 faceMeshes.add(geom);
\r
235 //System.out.println("Triangulation done");
\r
240 * org.jcae.viewer3d.cad.occ.OCCEdgeDomain
\r
245 private void buildFaces2(TopoDS_Shape shape) {
\r
247 TopExp_Explorer explorer = new TopExp_Explorer();
\r
248 TopLoc_Location loc = new TopLoc_Location();
\r
252 for (explorer.init(shape, TopAbs_ShapeEnum.FACE); explorer.more(); explorer.next())
\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
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
264 System.out.println("Triangulation failed for face "+face+". Using Incremental mesh");
\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
274 System.out.println("Triangulation failed for face "+face+". Trying other mesh parameters.");
\r
280 System.out.println("Triangulation failed for face "+face+". Mesh not generated.");
\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
288 double[] dnodes = pt.nodes();
\r
289 final int[] itriangles = pt.triangles();
\r
291 if(face.orientation()==TopAbs_Orientation.REVERSED)
\r
293 flipFace(itriangles);
\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
306 private float[] createFloatVertices(double dnodes[], Matrix4d m) {
\r
307 float[] fnodes=new float[dnodes.length];
\r
308 Point3d p = new Point3d();
\r
310 for(int i=0; i<dnodes.length;)
\r
316 fnodes[i++]=(float) p.x;
\r
317 fnodes[i++]=(float) p.y;
\r
318 fnodes[i++]=(float) p.z;
\r
322 private double deflection(TopoDS_Shape s) {
\r
323 Bnd_Box box = new Bnd_Box();
\r
324 BRepBndLib.add(s,box);
\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
330 return boundingBoxDeflection;
\r
333 private double edgeDeflection(TopoDS_Shape s) {
\r
334 return 0.5 * deflection(s);
\r
338 * org.jcae.viewer3d.cad.occ.OCCEdgeDomain
\r
342 private void buildEdges(TopoDS_Shape shape) {
\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
349 for (explorer.init(shape, TopAbs_ShapeEnum.EDGE); explorer.more(); explorer.next())
\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
355 if(!alreadyDone.add(e))
\r
358 double[] range = BRep_Tool.range(e);
\r
359 Geom_Curve gc = BRep_Tool.curve(e, range);
\r
363 GeomAdaptor_Curve adaptator = new GeomAdaptor_Curve(gc);
\r
364 GCPnts_UniformDeflection deflector = new GCPnts_UniformDeflection();
\r
366 deflector.initialize(adaptator, boundingBoxDeflection, range[0], range[1]);
\r
367 int npts = deflector.nbPoints();
\r
369 // Allocate one additional point at each end = parametric value 0, 1
\r
375 array = new float[size];
\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
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
397 adaptator.delete();
\r
398 deflector.delete();
\r
402 if (!BRep_Tool.degenerated(e))
\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
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
418 size = (aa.size()-2)*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
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
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
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
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
478 for (int i = 0; i < nnodes.length; i+=3) {
\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