package de.tud.kom.p2psim.impl.topology.movement.modularosm.movementIconVisualisation; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModelViz; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView; import de.tudarmstadt.maki.simonstrator.api.*; import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException; import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.Point2D; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * Visualises the different nodes as icons instead of these lame dots. * The icons are configured entirely in the config files. To use this visualisation * the first thing to do is specify this {@link ModularMovementIconVis} as visualisation for * your modular movement model. To add icons to the visualisation the class {@link IconMapping} is used within the tags. * You have two tags available for different kind of icons:

*

* 1. Class icons: These icons are used dependent on the class of the components the host includes. You can * add a class icon by using the <ClassIcon> tag you config and setting the fully qualified classname * of you components as object. If a host has multiple components with different specified icons, the first one will be used.

*

* 2. State icons: These icons are used dependent on the state of a host and take precedence over the class icons. You * can add them via the <StateIcon> tag. The object should be a String representing the state. When * using these types of icons, you need to set a {@link StateSelector} for this class in the config.

*

* For example usage, see the movement_social.xml config for the resourceAllocation overlay. * * @author Clemens Krug */ public class ModularMovementIconVis extends ModularMovementModelViz implements EventHandler { private HashMap pathMap; private HashMap classIconMap; private HashMap stateMap; private HashMap stateIconMap; private StateSelector stateSelector; private boolean init = false; public ModularMovementIconVis() { init(); pathMap = new HashMap<>(); classIconMap = new HashMap<>(); stateMap = new HashMap<>(); stateIconMap = new HashMap<>(); // scheduling initalization! de.tudarmstadt.maki.simonstrator.api.Event.scheduleImmediately(this, null, 0); } private void initialize() { assert !init : "ModularMovementIconVis: Was already initialized!"; VisualizationTopologyView.VisualizationInjector.getTopologyView().setShowNodes(false); for (Map.Entry e : pathMap.entrySet()) { try { Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST); classIconMap.put(e.getKey(), icon); } catch (IOException ioe) { Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue()); } } for (Map.Entry e : stateMap.entrySet()) { assert stateSelector != null : "There must be a state selector specified when using state icons!"; try { Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST); stateIconMap.put(e.getKey(), icon); } catch (IOException ioe) { Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue()); } } init = true; } @Override public void paint(Graphics g) { super.paintSuper(g); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (showAttractionPoints) { super.drawAttractionPoints(g2); } if (showNodePositions) { for (SimLocationActuator comp : movementModel .getAllLocationActuators()) { drawNodePosition(g2, comp); } } } @Override protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp) { boolean iconNotFound = true; Host host = comp.getHost(); Point2D pt = comp.getRealPosition().asPoint(); pt = new Point2D.Double(VisualizationTopologyView.VisualizationInjector.scaleValue(pt.getX()), VisualizationTopologyView.VisualizationInjector.scaleValue(pt.getY())); g2.setColor(Color.GRAY); // Check if the component has a specified state, as this would have precedence over the classIcon. if (stateSelector != null) { String state = stateSelector.getState(comp); if (stateIconMap.containsKey(state)) { Image icon = stateIconMap.get(state); int width = icon.getWidth(null); int height = icon.getHeight(null); g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null); return; } } // If not, check if there's a class icon available for (Map.Entry e : classIconMap.entrySet()) { try { host.getComponent(e.getKey()); Image icon = e.getValue(); int width = icon.getWidth(null); int height = icon.getHeight(null); g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null); iconNotFound = false; break; } catch (ComponentNotAvailableException nae) { iconNotFound = true; } } // If not, use standard visualisation if (iconNotFound) super.drawNodePosition(g2, comp); } @Override public void eventOccurred(Object content, int type) { if (type == 0) { initialize(); } } public void setClassIcon(IconMapping classIcon) { try { pathMap.put(Class.forName(classIcon.getObject()), classIcon.getIconpath()); } catch (ClassNotFoundException e) { Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Class %s not found!", classIcon.getObject()); } } public void setStateIcon(IconMapping stateIcon) { stateMap.put(stateIcon.getObject(), stateIcon.getIconpath()); } public void setStateSelector(StateSelector selector) { this.stateSelector = selector; } }