/* * Project Info: http://jcae.sourceforge.net * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * (C) Copyright 2008, by EADS France */ package org.jcae.vtk; import gnu.trove.list.array.TIntArrayList; import gnu.trove.set.hash.TIntHashSet; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.map.hash.TObjectIntHashMap; import java.awt.Color; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.util.ArrayList; import org.jcae.mesh.oemm.OEMM; import vtk.vtkActor; import vtk.vtkCellCenterDepthSort; import vtk.vtkDataSet; import vtk.vtkExtractSelectedFrustum; import vtk.vtkIdTypeArray; import vtk.vtkPoints; import vtk.vtkPolyData; import vtk.vtkPolyDataMapper; /** * * @author ibarz */ public class ViewableOEMM extends Viewable implements MouseMotionListener { private final OEMM oemm; private final MeshVisuReader reader; private final vtkActor octree; private final vtkActor octreePickingActor; private boolean automaticSelection = false; private final int leafVisibleMax = 10; private final TObjectIntHashMap<LeafNode> nodeToID = new TObjectIntHashMap<LeafNode>(); private final TIntObjectHashMap<LeafNode> IDToEdgeNode = new TIntObjectHashMap<LeafNode>(); private final TIntObjectHashMap<LeafNode> IDToFreeEdgeNode = new TIntObjectHashMap<LeafNode>(); private final Node edgesNode; private final Node freeEdgesNode; private final Node octreeNode; volatile boolean rendering = false; public ViewableOEMM(OEMM oemm) { this.oemm = oemm; reader = new MeshVisuReader(oemm); edgesNode = new Node(rootNode); edgesNode.setDebugName("Edges"); freeEdgesNode = new Node(rootNode); freeEdgesNode.setDebugName("Free edges"); // Construct octree float[] nodes = reader.getNodesQuad(); vtkPoints points = Utils.createPoints(nodes); octree = new vtkActor(); vtkPolyData data = new vtkPolyData(); int[] quadsFilled = new int[nodes.length * 3]; int offset = 0; for (int i = 0; i < nodes.length - 1;) { int first = i / 3; // First quadsFilled[offset++] = 2; quadsFilled[offset++] = i / 3; ++i; quadsFilled[offset++] = i / 3; // Second quadsFilled[offset++] = 2; quadsFilled[offset++] = i / 3; ++i; quadsFilled[offset++] = i / 3; // Three quadsFilled[offset++] = 2; quadsFilled[offset++] = i / 3; ++i; quadsFilled[offset++] = i / 3; // Four quadsFilled[offset++] = 2; quadsFilled[offset++] = i / 3; ++i; quadsFilled[offset++] = first; } data.SetPoints(points); data.SetLines(Utils.createCells(quadsFilled.length / 3, quadsFilled)); vtkPolyDataMapper mapper = new vtkPolyDataMapper(); mapper.SetInputData(data); octree.SetMapper(mapper); octree.GetProperty().SetColor(0., 0., 1.); octree.PickableOff(); octree.VisibilityOn(); int[] quadsLeaf = new int[5 * 6]; int offsetLeaf = 0; for (int i = 0; i < quadsLeaf.length;) { quadsLeaf[i++] = 4; quadsLeaf[i++] = offsetLeaf++; quadsLeaf[i++] = offsetLeaf++; quadsLeaf[i++] = offsetLeaf++; quadsLeaf[i++] = offsetLeaf++; } int ID = 0; octreeNode = new Node(rootNode); octreeNode.setDebugName("Octree"); octreeNode.setManager(true); for (int i = 0; i < nodes.length;) { float[] leafNodes = new float[6 * 4 * 3]; System.arraycopy(nodes, i, leafNodes, 0, leafNodes.length); i += leafNodes.length; LeafNode.DataProvider dataLeaf = new LeafNode.DataProvider() { @Override public void unLoad() { // By default, unLoad delete datas, but // we need them in Scene.selectAllNodes } }; dataLeaf.setNodes(leafNodes); dataLeaf.setPolys(quadsLeaf.length / 5, quadsLeaf); LeafNode leaf = new LeafNode(octreeNode, dataLeaf, Color.BLUE); nodeToID.put(leaf, ID); ID++; } octreeNode.refresh(); octreeNode.setPickable(true); octreePickingActor = octreeNode.getActor(); octreePickingActor.VisibilityOff(); } public boolean isOctreeVisible() { return octree.GetVisibility() != 0; } public void setOctreeVisible(boolean octreeVisible) { octree.SetVisibility(Utils.booleanToInt(octreeVisible)); } public boolean isAutomaticSelection() { return automaticSelection; } public void setAutomaticSelection(boolean automaticSelection) { this.automaticSelection = automaticSelection; } @Override public void highlight() { Thread run = new Thread() { @Override public void run() { ViewableOEMM.this.highlightThreaded(); } }; run.start(); } public void highlightThreaded() { TIntHashSet selection; rendering = true; synchronized (selectionNode) { selection = new TIntHashSet(selectionNode.size()); for (LeafNode leaf : selectionNode) selection.add(nodeToID.get(leaf)); // Delete the nodes not selected for (int id : IDToEdgeNode.keys()) if (!selection.contains(id)) { LeafNode leaf = IDToEdgeNode.get(id); leaf.deleteData(); edgesNode.removeChild(leaf); IDToEdgeNode.remove(id); } // Delete the nodes not selected for (int id : IDToFreeEdgeNode.keys()) if (!selection.contains(id)) { LeafNode leaf = IDToFreeEdgeNode.get(id); leaf.deleteData(); freeEdgesNode.removeChild(leaf); IDToFreeEdgeNode.remove(id); } if (selection.isEmpty()) { if(!automaticSelection) render(); return; } reader.buildMeshVisu(selection.toArray()); int[] leaves = reader.getLeavesLoaded(); MeshVisuReader.MeshVisu[] meshes = reader.getMeshes(); // Add all the nodes and compute the hash set node for (int i = 0; i < leaves.length; ++i) { // If the node is already added continue if (IDToEdgeNode.containsKey(leaves[i])) continue; float[] meshNodes = meshes[i].nodes; TIntArrayList[] allEdges = new TIntArrayList[] { new TIntArrayList(meshes[i].edges.length), new TIntArrayList(meshes[i].freeEdges.length) }; ArrayList<int[]> edgesMesh = new ArrayList<int[]>(2); edgesMesh.add(meshes[i].edges); edgesMesh.add(meshes[i].freeEdges); for (int type = 0; type < 2; ++type) { int[] ones = edgesMesh.get(type); for (int j = 0; j < ones.length; j+=2) { int begin = ones[j]; int end = ones[j+1]; allEdges[type].add(2); allEdges[type].add(begin); allEdges[type].add(end); } } LeafNode.DataProvider dataEdge = new LeafNode.DataProvider(); dataEdge.setNodes(meshNodes); dataEdge.setLines(allEdges[0].toArray()); LeafNode edgeNode = new LeafNode(edgesNode, dataEdge, Color.WHITE); edgeNode.setManager(true); IDToEdgeNode.put(leaves[i], edgeNode); lockCanvas(); edgeNode.refresh(); unlockCanvas(); LeafNode.DataProvider dataFreeEdge = new LeafNode.DataProvider(); dataFreeEdge.setNodes(meshNodes); dataFreeEdge.setLines(allEdges[1].toArray()); LeafNode freeEdgeNode = new LeafNode(freeEdgesNode, dataFreeEdge, Color.RED); freeEdgeNode.setManager(true); IDToFreeEdgeNode.put(leaves[i], freeEdgeNode); lockCanvas(); freeEdgeNode.refresh(); unlockCanvas(); if(!automaticSelection) render(); } } rendering = false; } @Override public void addCanvas(Canvas canvas) { super.addCanvas(canvas); canvas.addMouseMotionListener(this); canvas.GetRenderer().AddViewProp(octree); } @Override public void removeCanvas(Canvas canvas) { super.removeCanvas(canvas); canvas.removeMouseMotionListener(this); canvas.GetRenderer().RemoveViewProp(octree); } public void mouseDragged(MouseEvent e) { if (!automaticSelection || rendering) return; Canvas canvas = Utils.retrieveCanvas(e); PickContext pickContext = new FrustumPicker(canvas, true, new Point(0, 0), new Point(canvas.getWidth(), canvas.getHeight())); performAutomaticSelection(pickContext); } public void mouseMoved(MouseEvent e) { // Do nothing } private void performAutomaticSelection(PickContext pickContext) { int [] pressPosition = pickContext.getPressPosition(); int [] releasePosition = pickContext.getReleasePosition(); Canvas canvas = pickContext.getCanvas(); vtkExtractSelectedFrustum selector = new vtkExtractSelectedFrustum(); vtkDataSet dataSet = octreePickingActor.GetMapper().GetInputAsDataSet(); selector.SetInputData(dataSet); selector.CreateFrustum(Utils.computeVerticesFrustum( pressPosition[0], pressPosition[1], releasePosition[0], releasePosition[1], canvas.GetRenderer())); selector.PreserveTopologyOff(); lockCanvas(); selector.Update(); unlockCanvas(); vtkDataSet data = (vtkDataSet) selector.GetOutput(); vtkCellCenterDepthSort sorter = new vtkCellCenterDepthSort(); sorter.SetInput(data); sorter.SetCamera(canvas.GetRenderer().GetActiveCamera()); sorter.SetMaxCellsReturned(this.leafVisibleMax); sorter.SetDirectionToFrontToBack(); lockCanvas(); sorter.InitTraversal(); unlockCanvas(); vtkIdTypeArray ids = null; boolean full = false; while ((ids = sorter.GetNextCells()) != null && !full) { int[] idsSorted = Utils.getValues(ids); vtkIdTypeArray originalCellIDs = (vtkIdTypeArray) data.GetCellData().GetArray("vtkOriginalCellIds"); for (int id : idsSorted) { int originalCell = originalCellIDs.GetValue(id); LeafNode leaf = octreeNode.getLeafNodeFromCell(originalCell); if (pickContext.addToSelectedNodes(leaf)) { // Stop if we reach the maximal number of leaves if (pickContext.getSelectedNodes().size() >= leafVisibleMax) { full = true; break; } } } } selectionChanged = true; synchronized (selectionNode) { selectionNode = pickContext.getSelectedNodes(); } manageSelection(pickContext); } @Override public void performSelection(PickContext pickContext) { int [] pressPosition = pickContext.getPressPosition(); int [] releasePosition = pickContext.getReleasePosition(); if (pressPosition[0] != releasePosition[0] || pressPosition[1] != releasePosition[1]) { // In this viewable, we want to select hidden nodes pickContext = new FrustumPicker(pickContext.getCanvas(), false, new Point(pressPosition[0], pressPosition[1]), new Point(releasePosition[0], releasePosition[1])); } octreePickingActor.VisibilityOn(); octreePickingActor.PickableOn(); super.performSelection(pickContext); octreePickingActor.VisibilityOff(); octreePickingActor.PickableOff(); } @Override protected void manageSelection(PickContext pickContext) { synchronized(selectionNode) { super.manageSelection(pickContext); } } }