1 /*******************************************************************************
\r
2 * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.opencascade.vtk;
\r
14 import java.util.ArrayList;
\r
15 import java.util.Collection;
\r
16 import java.util.List;
\r
18 import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;
\r
19 import org.jcae.opencascade.jni.TopAbs_ShapeEnum;
\r
20 import org.jcae.opencascade.jni.TopExp_Explorer;
\r
21 import org.jcae.opencascade.jni.TopoDS_Face;
\r
22 import org.jcae.opencascade.jni.TopoDS_Shape;
\r
23 import org.simantics.opencascade.OCCTTool;
\r
24 import org.simantics.utils.datastructures.Pair;
\r
25 import org.simantics.utils.threads.AWTThread;
\r
26 import org.simantics.utils.threads.ThreadUtils;
\r
28 import vtk.vtkActor;
\r
29 import vtk.vtkAlgorithmOutput;
\r
30 import vtk.vtkCleanPolyData;
\r
31 import vtk.vtkDataSetMapper;
\r
32 import vtk.vtkFeatureEdges;
\r
33 import vtk.vtkGlyph3D;
\r
34 import vtk.vtkPanel;
\r
35 import vtk.vtkPolyData;
\r
36 import vtk.vtkPolyDataMapper;
\r
37 import vtk.vtkPolyDataNormals;
\r
38 import vtk.vtkPolyDataSilhouette;
\r
39 import vtk.vtkProp3D;
\r
40 import vtk.vtkProperty;
\r
41 import vtk.vtkRenderer;
\r
42 import vtk.vtkSphereSource;
\r
44 public class vtkSolidObject {
\r
46 public static double deflection = 0.001;
\r
48 public static double featureAngle = 30;
\r
49 public static boolean computeNormals = true;
\r
50 public static boolean cleanPart = false;
\r
51 public static boolean mergePoints = false;
\r
53 private vtkPanel panel;
\r
54 private TopoDS_Shape shape;
\r
56 private List<vtkProp3D> actors = new ArrayList<vtkProp3D>(2);
\r
58 private List<vtkProp3D> solid = new ArrayList<vtkProp3D>(1);
\r
59 private List<vtkProp3D> edges = new ArrayList<vtkProp3D>(1);
\r
60 private vtkActor silhouette = null;
\r
62 private boolean errors = false;
\r
64 public vtkSolidObject(vtkPanel panel,TopoDS_Shape shape) {
\r
69 public void visualizeSolid(boolean showEdges, boolean showVertices) {
\r
70 visualizeSolid(true, showEdges, showVertices);
\r
73 public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices) {
\r
74 visualizeSolid(showFaces, showEdges, showVertices, false);
\r
77 public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices, boolean showSilhouette) {
\r
80 Pair<vtkPolyData, Boolean> res = createSolidMesh(shape);
\r
85 vtkPolyData data = res.first;
\r
89 solid.add(createActor(data));
\r
92 vtkActor edge = createEdgesActor(data);
\r
95 actors.add(createVerticesActor(edge));
\r
98 if (showSilhouette) {
\r
99 silhouette = createSilhouette(panel.GetRenderer(), data);
\r
101 actors.addAll(solid);
\r
102 actors.addAll(edges);
\r
103 if (silhouette != null)
\r
104 actors.add(silhouette);
\r
109 public void visualizeFaces(boolean showEdges, boolean showVertices) {
\r
112 Collection<vtkPolyData> datas = createFaceMeshes(shape);
\r
113 for (vtkPolyData data : datas) {
\r
114 if (data == null) {
\r
119 solid.add(createActor(data));
\r
122 vtkActor edgesActor = createEdgesActor(data);
\r
123 edges.add(edgesActor);
\r
124 if (showVertices) {
\r
125 actors.add(createVerticesActor(edgesActor));
\r
130 actors.addAll(solid);
\r
131 actors.addAll(edges);
\r
136 public boolean hasErrors() {
\r
140 public List<vtkProp3D> getActors() {
\r
141 assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());
\r
145 public List<vtkProp3D> getSolid() {
\r
146 assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());
\r
150 public List<vtkProp3D> getEdges() {
\r
151 assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());
\r
155 public vtkActor getSilhouette() {
\r
156 assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());
\r
160 public void showActorsAWT() {
\r
161 assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());
\r
162 vtkRenderer ren = panel.GetRenderer();
\r
163 for (vtkProp3D act : actors) {
\r
168 public void showActors() {
\r
169 ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
\r
172 public void run() {
\r
178 public void clearActorsAWT() {
\r
179 assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());
\r
180 if (actors.size() == 0)
\r
182 vtkRenderer ren = panel.GetRenderer();
\r
183 for (vtkProp3D act : actors) {
\r
184 if (act.GetVTKId() != 0) {
\r
185 ren.RemoveActor(act);
\r
194 private void clearActorsAWT(List<vtkProp3D> actors) {
\r
195 assert (Thread.currentThread() == AWTThread.getThreadAccess().getThread());
\r
197 if (actors.size() == 0)
\r
199 vtkRenderer ren = panel.GetRenderer();
\r
201 for (vtkProp3D act : actors) {
\r
202 if (act.GetVTKId() != 0) {
\r
203 ren.RemoveActor(act);
\r
210 public void clearActors() {
\r
211 if (actors.size() == 0)
\r
213 final List<vtkProp3D> temp = new ArrayList<vtkProp3D>(actors.size());
\r
214 temp.addAll(actors);
\r
218 ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
\r
221 public void run() {
\r
222 clearActorsAWT(temp);
\r
227 public void dispose() {
\r
228 if (shape != null) {
\r
235 public void delete() {
\r
236 if (shape != null) {
\r
243 private static double TOLERANCE = 0.01;
\r
245 public static Pair<vtkPolyData, Boolean> createSolidMesh(TopoDS_Shape shape) {
\r
247 boolean success = true;
\r
249 double volume = OCCTTool.getBoundingBoxDiagonal(shape);
\r
250 if (volume < TOLERANCE)
\r
253 BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume);
\r
255 TopExp_Explorer expFace = new TopExp_Explorer();
\r
257 List<Double> meshPoints = new ArrayList<Double>();
\r
258 List<Integer> meshTriangles = new ArrayList<Integer>();
\r
259 for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {
\r
260 TopoDS_Face face = (TopoDS_Face) expFace.current();
\r
261 if (!OCCTTool.appendToMesh(face, meshPoints, meshTriangles))
\r
265 if (meshPoints.size() == 0 || meshTriangles.size() == 0)
\r
268 vtkPolyData data = VTKOCCTool.createPartGrid(meshPoints, meshTriangles);
\r
273 return new Pair<vtkPolyData, Boolean>(data, success);
\r
276 public static Collection<vtkPolyData> createFaceMeshes(TopoDS_Shape shape) {
\r
278 double volume = OCCTTool.getBoundingBoxDiagonal(shape);
\r
279 Collection<vtkPolyData> faces = new ArrayList<vtkPolyData>();
\r
281 if (volume > TOLERANCE) {
\r
283 BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume);
\r
285 TopExp_Explorer expFace = new TopExp_Explorer();
\r
288 for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {
\r
289 TopoDS_Face face = (TopoDS_Face) expFace.current();
\r
290 vtkPolyData data = VTKOCCTool.createPartGrid(face);
\r
304 public static vtkActor createActor(vtkPolyData partGrid) {
\r
307 vtkDataSetMapper partMapper = new vtkDataSetMapper();
\r
309 vtkCleanPolyData partCleaner = null;
\r
312 partCleaner = new vtkCleanPolyData();
\r
313 partCleaner.SetInput(partGrid);
\r
315 partCleaner.PointMergingOn();
\r
317 partCleaner.PointMergingOff();
\r
321 if (computeNormals)
\r
323 vtkPolyDataNormals partNormals = new vtkPolyDataNormals();
\r
327 vtkAlgorithmOutput out = partCleaner.GetOutputPort();
\r
328 partNormals.SetInputConnection(out);
\r
331 else partNormals.SetInput(partGrid);
\r
333 partNormals.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called
\r
334 vtkAlgorithmOutput out = partNormals.GetOutputPort();
\r
335 partMapper.SetInputConnection(out);
\r
337 partNormals.Delete();
\r
342 vtkAlgorithmOutput out = partCleaner.GetOutputPort();
\r
343 partMapper.SetInputConnection(out); // metoda 2, ne tak pekne, viz http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681
\r
346 else partMapper.SetInput(partGrid); // metoda 1, ne tak pekne stinovani, viz: http://www.codeguru.com/cpp/g-m/opengl/article.php/c2681
\r
348 partMapper.ScalarVisibilityOn();
\r
350 vtkActor partActor = new vtkActor();
\r
351 // partActor.SetPickable(1);
\r
352 vtkProperty prop = partActor.GetProperty();
\r
353 prop.SetColor(1, 1, 0);
\r
355 partActor.SetMapper(partMapper);
\r
357 partMapper.Delete();
\r
360 partCleaner.Delete();
\r
365 public static vtkActor createEdgesActor(vtkPolyData partGrid) {
\r
366 vtkCleanPolyData partCleaner = null;
\r
370 partCleaner = new vtkCleanPolyData();
\r
371 partCleaner.SetInput(partGrid);
\r
373 partCleaner.PointMergingOn();
\r
375 partCleaner.PointMergingOff();
\r
379 vtkFeatureEdges partEdges = new vtkFeatureEdges();
\r
381 vtkAlgorithmOutput out = partCleaner.GetOutputPort();
\r
382 partEdges.SetInputConnection(out);
\r
385 else partEdges.SetInput(partGrid);
\r
386 // partEdges.SetFeatureAngle(featureAngle); // this do not have to be neccesarily called
\r
387 partEdges.FeatureEdgesOn();
\r
388 partEdges.BoundaryEdgesOn();
\r
389 partEdges.NonManifoldEdgesOn();
\r
390 partEdges.ManifoldEdgesOn();
\r
392 vtkDataSetMapper partEdgesMapper = new vtkDataSetMapper();
\r
393 vtkAlgorithmOutput out = partEdges.GetOutputPort();
\r
394 partEdgesMapper.SetInputConnection(out);
\r
396 partEdgesMapper.SetResolveCoincidentTopologyToPolygonOffset();
\r
397 partEdgesMapper.ScalarVisibilityOff();
\r
399 vtkActor partEdgesActor = new vtkActor();
\r
401 vtkProperty prop = partEdgesActor.GetProperty();
\r
402 prop.SetColor(0, 0, 0);
\r
403 prop.SetLineWidth(2.0);
\r
405 partEdgesActor.SetMapper(partEdgesMapper);
\r
407 partEdgesMapper.Delete();
\r
408 partEdges.Delete();
\r
411 partCleaner.Delete();
\r
413 return partEdgesActor;
\r
416 public static vtkActor createVerticesActor(vtkActor partEdgesActor) {
\r
417 vtkDataSetMapper partEdgesMapper = (vtkDataSetMapper) partEdgesActor.GetMapper();
\r
418 vtkAlgorithmOutput out = partEdgesMapper.GetInputConnection(0, 0);
\r
419 vtkFeatureEdges partEdges = (vtkFeatureEdges)out.GetProducer();
\r
421 vtkActor edgePointsActor = createVerticesActor(partEdges);
\r
423 partEdges.Delete();
\r
425 partEdgesMapper.Delete();
\r
426 return edgePointsActor;
\r
429 public static vtkActor createVerticesActor(vtkFeatureEdges partEdges) {
\r
430 EdgePointsFilter edgePoints = new EdgePointsFilter();
\r
433 vtkAlgorithmOutput out = partEdges.GetOutputPort();
\r
434 edgePoints.SetInputConnection(out);
\r
437 vtkSphereSource sphereSource = new vtkSphereSource();
\r
438 vtkGlyph3D glyph3D = new vtkGlyph3D();
\r
439 out = sphereSource.GetOutputPort();
\r
440 glyph3D.SetSourceConnection(out);
\r
443 out = edgePoints.GetOutputPort();
\r
444 glyph3D.SetInputConnection(out);
\r
447 glyph3D.SetScaleFactor(0.03);
\r
451 vtkPolyDataMapper partEdgePointsMapper = new vtkPolyDataMapper();
\r
452 out = glyph3D.GetOutputPort();
\r
453 partEdgePointsMapper.SetInputConnection(out);
\r
456 vtkActor edgePointsActor = new vtkActor();
\r
458 vtkProperty prop = edgePointsActor.GetProperty();
\r
459 prop.SetColor(0, 0, 1);
\r
461 edgePointsActor.SetMapper(partEdgePointsMapper);
\r
463 edgePointsActor.PickableOn();
\r
466 partEdgePointsMapper.Delete();
\r
467 edgePoints.Delete();
\r
468 sphereSource.Delete();
\r
470 return edgePointsActor;
\r
473 public static vtkActor createSilhouette(vtkRenderer ren, vtkPolyData data) {
\r
476 vtkPolyDataSilhouette silhouette = new vtkPolyDataSilhouette();
\r
478 silhouette.SetInput(data);
\r
479 silhouette.SetCamera(ren.GetActiveCamera());
\r
480 silhouette.SetEnableFeatureAngle(0);
\r
481 vtkPolyDataMapper mapper = new vtkPolyDataMapper();
\r
483 mapper.SetInputConnection(silhouette.GetOutputPort());
\r
485 vtkActor actor = new vtkActor();
\r
486 actor.SetMapper(mapper);
\r
488 actor.GetProperty().SetColor(0,0,1);
\r
489 actor.GetProperty().SetLineWidth(6);
\r