package au.gov.ga.earthsci.model.geometry; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import au.gov.ga.earthsci.common.color.ColorMap; import au.gov.ga.earthsci.common.color.ColorType; import au.gov.ga.earthsci.common.util.AbstractPropertyChangeBean; import au.gov.ga.earthsci.common.util.MathUtil; import au.gov.ga.earthsci.common.util.Validate; import au.gov.ga.earthsci.model.bounds.IBoundingVolume; import au.gov.ga.earthsci.model.data.IModelData; import au.gov.ga.earthsci.model.render.IModelGeometryRenderer; /** * A basic implementation of the {@link IMeshGeometry} interface that also * implements {@link IVertexColouredGeometry} and * {@link IVertexColourMappedGeometry}, allowing colour information to be stored * per-vertex (for pre-calculated colouring) or as a colour map that can be used * by a renderer to apply colour information at render time. * * @author James Navin (james.navin@ga.gov.au) */ public class BasicColouredMeshGeometry extends AbstractPropertyChangeBean implements IMeshGeometry, IVertexColouredGeometry, IVertexColourMappedGeometry, IMaskedGeometry { private final String id; private String name; private String description; private double opacity = 1.0; private IModelData vertices; private IModelData mask; private boolean zMasked; private IModelData normals; private IModelData colours; private ColorType colourType; private ColorMap colorMap; private int colouredAxis; private IModelData edges; private FaceType faceType; private IModelGeometryRenderer renderer; private IBoundingVolume bounds; private final Map<String, IModelData> dataById = new ConcurrentHashMap<String, IModelData>(); private final Map<String, IModelData> dataByKey = new ConcurrentHashMap<String, IModelData>(); public BasicColouredMeshGeometry(String id, String name, String description) { Validate.notBlank(id, "An ID is required"); //$NON-NLS-1$ this.id = id; this.name = name; this.description = description; } @Override public String getId() { return id; } @Override public String getName() { return name; } @Override public String getDescription() { return description; } @Override public IModelData getVertices() { return vertices; } public void setVertices(IModelData vertices) { updateMaps(this.vertices, vertices, VERTICES_KEY); firePropertyChange(VERTICES_EVENT_NAME, this.vertices, this.vertices = vertices); } @Override public boolean hasVertices() { return vertices != null; } @Override public IModelGeometryRenderer getRenderer() { return renderer; } @Override public void setRenderer(IModelGeometryRenderer renderer) { firePropertyChange(RENDERER_EVENT_NAME, this.renderer, this.renderer = renderer); } @Override public IModelData getDataById(String id) { return dataById.get(id); } @Override public IModelData getDataByKey(String key) { return dataByKey.get(key); } @Override public Set<String> getDataKeys() { return dataByKey.keySet(); } @Override public IModelData getVertexColour() { return colours; } public void setVertexColour(IModelData colours) { updateMaps(this.colours, colours, VERTEX_COLOUR_KEY); firePropertyChange(VERTEX_COLOUR_EVENT_NAME, this.colours, this.colours = colours); } @Override public boolean hasVertexColour() { return colours != null; } @Override public ColorType getColourType() { return colourType; } public void setColourType(ColorType colourType) { firePropertyChange(VERTEX_COLOUR_TYPE_EVENT_NAME, this.colourType, this.colourType = colourType); } @Override public IModelData getEdgeIndices() { return edges; } public void setEdgeIndices(IModelData edges) { updateMaps(this.edges, edges, EDGE_INDICES_KEY); firePropertyChange(EDGE_INDICES_EVENT_NAME, this.edges, this.edges = edges); } @Override public boolean hasEdgeIndices() { return edges != null; } @Override public FaceType getFaceType() { return faceType; } public void setFaceType(FaceType faceType) { firePropertyChange(FACE_TYPE_EVENT_NAME, this.faceType, this.faceType = faceType); } @Override public IModelData getNormals() { return normals; } @Override public boolean hasNormals() { return normals != null; } @Override public IBoundingVolume getBoundingVolume() { return bounds; } public void setBoundingVolume(IBoundingVolume bounds) { firePropertyChange(BOUNDING_VOLUME_EVENT_NAME, this.bounds, this.bounds = bounds); } @Override public boolean hasBoundingVolume() { return bounds != null; } @Override public IModelData getMask() { return mask; } public void setMask(IModelData mask) { updateMaps(this.mask, mask, MASK_KEY); firePropertyChange(MASK_EVENT_NAME, this.mask, this.mask = mask); } @Override public boolean hasMask() { return mask != null; } public void setUseZMasking(boolean use) { this.zMasked = use; } @Override public boolean useZMasking() { return zMasked; } @Override public double getOpacity() { return this.opacity; } @Override public void setOpacity(double opacity) { firePropertyChange(OPACITY_EVENT_NAME, this.opacity, this.opacity = MathUtil.clamp(opacity, 0.0, 1.0)); } @Override public ColorMap getColorMap() { return colorMap; } @Override public boolean hasColorMap() { return colorMap != null; } public void setColorMap(ColorMap map) { firePropertyChange(COLOR_MAP_EVENT_NAME, this.colorMap, this.colorMap = map); } @Override public int getColouredAxis() { return colouredAxis; } public void setColouredAxis(int axis) { this.colouredAxis = axis; } @Override public boolean isXColoured() { return getColouredAxis() == 0; } public void setXColoured() { setColouredAxis(0); } @Override public boolean isYColoured() { return getColouredAxis() == 1; } public void setYColoured() { setColouredAxis(1); } @Override public boolean isZColoured() { return getColouredAxis() == 2; } public void setZColoured() { setColouredAxis(2); } private void updateMaps(IModelData oldData, IModelData newData, String key) { removeFromMaps(oldData, key); addToMaps(oldData, key); } private void removeFromMaps(IModelData object, String key) { if (object == null) { return; } dataById.remove(object.getId()); dataByKey.remove(key); } private void addToMaps(IModelData object, String key) { if (object == null) { return; } dataById.put(object.getId(), object); dataByKey.put(key, object); } }