/*
* 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-2009, by EADS France
*/
package org.jcae.vtk;
import java.awt.Color;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.jcae.vtk.AbstractNode.ActorCustomiser;
import org.jcae.vtk.AbstractNode.MapperCustomiser;
import org.jcae.vtk.LeafNode.DataProvider;
import vtk.vtkActor;
import vtk.vtkPainterPolyDataMapper;
import vtk.vtkProperty;
/**
* TODO : the beams are stored in the polydata with the scalar
* UNVProvider.OTHERS_GROUP wich can make a bug of color. It can make a bug for
* the selection in jcae because this group doesn't really exist. Find an
* example of .unv to check this feature.
* @author Julian Ibarz
*/
public class ViewableMesh extends Viewable
{
private static class BeamNodeWrapper
{
public LeafNode beams, vertexBeams;
}
private ViewMode viewMode = ViewMode.WIRED;
private final Map<String, LeafNode> groupToTrias = new HashMap<String, LeafNode>();
private final Map<LeafNode, String> triasToNode = new HashMap<LeafNode, String>();
private final Map<String, BeamNodeWrapper> groupToBeams = new HashMap<String, BeamNodeWrapper>();
private final Map<LeafNode, String> beamsToNode = new HashMap<LeafNode, String>();
private int currentColorID;
private final Palette palette;
private boolean beamVertVisible = true;
private final static MapperCustomiser MAPPER_CUSTOMIZER = new MapperCustomiser() {
@Override
public void customiseMapper(vtkPainterPolyDataMapper mapper)
{
Utils.setPolygonOffset(mapper, Utils.getOffsetFactor(),
Utils.getOffsetValue()*2);
}
};
private final static MapperCustomiser MAPPER_CUSTOMIZER_S = new MapperCustomiser() {
@Override
public void customiseMapper(vtkPainterPolyDataMapper mapper)
{
Utils.setPolygonOffset(mapper, Utils.getOffsetFactor(),
Utils.getOffsetValue());
}
};
/**
* It explain how the mesh is displayed :
* _ FILLED means the mesh is not in wired mode but the selection remains filled ;
* _ WIRED means the mesh is wired.
*/
public enum ViewMode { FILLED, WIRED }
public ViewableMesh()
{
this(new Palette(Integer.MAX_VALUE));
}
public ViewableMesh(Map<String, LeafNode.DataProvider> triangles)
{
this();
addTriangles(triangles);
}
public ViewableMesh(Palette palette)
{
rootNode.setSelectionActorCustomiser(new SelectionActorCustomiser()
{
@Override
public void customiseActor(vtkActor actor)
{
super.customiseActor(actor);
vtkProperty p = actor.GetProperty();
p.EdgeVisibilityOn();
p.LightingOff();
p.SetEdgeColor(0.4, 0.4, 0.4);
}
});
rootNode.setMapperCustomiser(MAPPER_CUSTOMIZER);
rootNode.setSelectionMapperCustomiser(MAPPER_CUSTOMIZER_S);
setViewMode(viewMode);
currentColorID = 0;
this.palette = palette;
}
/**
* @param mesh a map associating group id to DataProvider. If dataprovider
* is null the group is removed from the viewable.
*/
public void addTriangles(Map<String, LeafNode.DataProvider> mesh)
{
for (Entry<String, LeafNode.DataProvider> group : mesh.entrySet())
{
LeafNode groupNode = groupToTrias.get(group.getKey());
if(group.getValue() == null && groupNode != null)
{
rootNode.removeChild(groupNode);
groupToTrias.remove(group.getKey());
triasToNode.remove(groupNode);
}
else if(group.getValue() != null && groupNode == null)
{
// Warning: Do *not* replace colorManager.getColor() by
// selectionColor here, some ColorManager may have a
// different behavior!
groupNode = new LeafNode(rootNode, group.getValue(),
getColor(group.getKey()));
groupNode.setManager(true);
groupNode.setPickable(true);
groupToTrias.put(group.getKey(), groupNode);
triasToNode.put(groupNode, group.getKey());
}
else if(group.getValue() != null && groupNode != null)
{
groupNode.setDataProvider(group.getValue());
}
}
rootNode.refresh();
}
public Collection<String> getTriaGroups()
{
return Collections.unmodifiableCollection(groupToTrias.keySet());
}
public Collection<LeafNode> getTriaNodes()
{
return Collections.unmodifiableCollection(groupToTrias.values());
}
public Collection<String> getBeamGroups()
{
return Collections.unmodifiableCollection(groupToBeams.keySet());
}
/** ensure that beams and trias in the same groups have the same color */
private Color getColor(String groupid)
{
BeamNodeWrapper aa = groupToBeams.get(groupid);
LeafNode a = aa == null ? null : groupToBeams.get(groupid).beams;
if(a != null)
return a.getColor();
a = groupToTrias.get(groupid);
if(a != null)
return a.getColor();
return palette.getColor(currentColorID++);
}
private DataProvider createVertices(final DataProvider value) {
DataProvider toReturn = new DataProvider()
{
@Override
public void load() {
if(value.getNodes().length == 0)
value.load();
setNodes(value.getNodes());
int n = nodes.length / 3;
int[] vert = new int[2*n];
for(int i = 0; i<n; i++)
{
vert[2*i] = 1;
vert[2*i+1] = i;
}
setVertices(vert);
}
};
return toReturn;
}
public void addBeams(Map<String, LeafNode.DataProvider> beams)
{
for (Entry<String, LeafNode.DataProvider> group : beams.entrySet())
{
BeamNodeWrapper groupNode = groupToBeams.get(group.getKey());
if(group.getValue() == null && groupNode != null)
{
rootNode.removeChild(groupNode.beams);
if(groupNode.vertexBeams != null)
rootNode.removeChild(groupNode.vertexBeams);
groupToBeams.remove(group.getKey());
beamsToNode.remove(groupNode.beams);
}
else if(group.getValue() != null && groupNode == null)
{
BeamNodeWrapper bnw = new BeamNodeWrapper();
final LeafNode fgn = new LeafNode(rootNode, group.getValue(),
getColor(group.getKey()));
fgn.setActorCustomiser(new ActorCustomiser() {
public void customiseActor(vtkActor actor) {
vtkProperty p = actor.GetProperty();
Utils.vtkPropertySetColor(p, fgn.getColor());
p.SetLineWidth(2.0);
}
});
fgn.setManager(true);
fgn.setPickable(true);
bnw.beams = fgn;
if(beamVertVisible)
{
final LeafNode vertexNode = new LeafNode(rootNode, createVertices(group.getValue()), Color.WHITE);
vertexNode.setActorCustomiser(new ActorCustomiser() {
public void customiseActor(vtkActor actor) {
actor.GetProperty().SetPointSize(3.0);
}
});
vertexNode.setManager(true);
vertexNode.setPickable(false);
bnw.vertexBeams = vertexNode;
}
groupToBeams.put(group.getKey(), bnw);
beamsToNode.put(fgn, group.getKey());
}
else if(group.getValue() != null && groupNode != null)
{
groupNode.beams.setDataProvider(group.getValue());
if(groupNode.vertexBeams != null)
groupNode.vertexBeams.setDataProvider(
createVertices(group.getValue()));
}
}
rootNode.refresh();
}
public boolean isBeamVertVisible() {
return beamVertVisible;
}
public void setBeamVertVisible(boolean beamVertVisible) {
this.beamVertVisible = beamVertVisible;
}
public void selectSelectionNodes() {
for (LeafNode n :rootNode.getLeaves())
n.unselect();
for (LeafNode n : selectionNode)
if (n!=null)
n.select();
}
public ViewMode getViewMode()
{
return viewMode;
}
public void setViewMode(ViewMode viewMode)
{
this.viewMode = viewMode;
final int wired = (viewMode == ViewMode.WIRED) ? 1 : 0;
rootNode.setActorCustomiser(new AbstractNode.ActorCustomiser()
{
@Override
public void customiseActor(vtkActor actor)
{
vtkProperty p = actor.GetProperty();
p.LightingOff();
p.SetEdgeVisibility(wired);
p.SetEdgeColor(0.2, 0.2, 0.2);
}
});
rootNode.refresh();
render();
}
/**
* Return the selection of the different ids groups
* @return
*/
public String[] getSelection()
{
String[] selectionGroups = new String[selectionNode.size()];
int i = 0;
for (LeafNode leaf : selectionNode)
{
selectionGroups[i] = triasToNode.get(leaf);
i++;
}
return selectionGroups;
}
/**
* Set the new selection.
* Be careful, the listeners of change selection will not be informed.
* The function verify if the group is loaded or not. If the group is not loaded
* it is removed from the selection.
*
* @param selection
*/
public void setSelection(String[] selection)
{
selectionNode.clear();
for (String id : selection)
{
LeafNode n = groupToTrias.get(id);
if(n != null)
selectionNode.add(n);
}
}
}