package ui.view; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.GeneralPath; import java.util.ArrayList; import javax.swing.JPanel; import classes.AbstractCpsObject; import classes.CpsUpperNode; import classes.HolonElement; import classes.HolonObject; import classes.HolonSwitch; import classes.SubNet; import classes.TrackedDataSet; import ui.controller.Control; import ui.model.Model; public class StatisticGraph extends JPanel { /** * */ private static final long serialVersionUID = 1L; // Maximum y Value float maximum = 0; // is the Simulation running? private boolean isSimRunning; // model and controller private Model model; private Control controller; // Graphics2D private Graphics2D g2; GeneralPath path = new GeneralPath(); // Data private ArrayList dataSets = new ArrayList<>(); /** * Constructor. * * @param model * the Model * @param control * the Controller */ public StatisticGraph(final Model model, Control control) { this.controller = control; this.model = model; this.setBackground(Color.WHITE); } /** * Paints all Components on the Canvas. * * @param g * Graphics * */ public void paintComponent(Graphics g) { super.paintComponent(g); // Graphics2D init g2 = (Graphics2D) g; RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHints(rh); // Paint the Grid g2.setStroke(new BasicStroke(0)); g2.setColor(Color.BLACK); for (int i = 0; i <= this.getWidth(); i += 10) { g2.drawLine(i, 0, i, this.getHeight()); } for (int i = 0; i <= this.getHeight(); i += 5) { g2.drawLine(0, i, this.getWidth(), i); } isSimRunning = true; // if sim is on if (isSimRunning) { g2.setStroke(new BasicStroke(3)); // Calculate the Maximum calcMaximum(); // Calculate values for each set and add them addValues(); // Create Paths and draw them for (TrackedDataSet set : dataSets) { path.reset(); switch (set.getProperty()) { case TrackedDataSet.CONSUMPTION: case TrackedDataSet.PRODUCTION: case TrackedDataSet.ACTIVATED_ELEMENTS: case TrackedDataSet.TOTAL_PRODUCTION: case TrackedDataSet.TOTAL_CONSUMPTION: case TrackedDataSet.AMOUNT_HOLONS: case TrackedDataSet.GROUP_CONSUMPTION: case TrackedDataSet.GROUP_PRODUCTION: case TrackedDataSet.AMOUNT_CLOSED_SWITCHES: case TrackedDataSet.AVG_AMOUNT_OBJECTS_IN_HOLONS: case TrackedDataSet.AVG_AMOUNT_ELEMENTS_IN_HOLONS: case TrackedDataSet.AVG_AMOUNT_PRODUCERS_IN_HOLONS: case TrackedDataSet.AVG_CONSUMED_ENERGY_IN_HOLONS: case TrackedDataSet.AVG_WASTED_ENERGY_IN_HOLONS: case TrackedDataSet.AMOUNT_BROKEN_EDGES: case TrackedDataSet.AVG_AMOUNT_CLOSED_SWITCHES_IN_HOLONS: case TrackedDataSet.AVG_AMOUNT_ACTIVE_ELEMENTS_IN_HOLONS: case TrackedDataSet.AVG_AMOUNT_INACTIVE_ELEMENTS_IN_HOLONS: case TrackedDataSet.AVG_PRODUCED_ENERGY_IN_HOLONS: createPathFloats(set); break; case TrackedDataSet.ON_OFF: createPathBooleans(set); break; case TrackedDataSet.PERCENT_SUPPLIED: case TrackedDataSet.PERCENT_NOT_SUPPLIED: case TrackedDataSet.PERCENT_PARTIAL_SUPPLIED: case TrackedDataSet.RATIO_PRODUCERS_CONSUMERS: createPathPercent(set); break; default: break; } g2.setColor(set.getColor()); g2.draw(path); } } } /** * Add an Object to the Graph if the maximum has not reached yet. * * @param obj * the Object to add */ public void addObject(TrackedDataSet set) { dataSets.add(set); } /** * Removes an Object from the Graph. * * @param id * the id of the Object to remove */ public void removeObject(int id) { dataSets.remove(id); } /** * converts the number to fit the canvas. * * @param d * the number to convert * @return the converted number */ public double convertToCanvasY(float d) { return Math.abs((this.getHeight() - (d * (this.getHeight() / maximum)))); } /** * Does take into account which timestep is watched, calculates the max * values. * * @return the currentEnergy */ public float getEnergyAtCurrentTimeStep(HolonObject obj) { float temp = 0; for (HolonElement e : obj.getElements()) { if (e.getActive()) { temp = temp + e.getEnergyAt()[model.getCurIteration()]; } } return temp; } /** * Calculate the Max Value of the Graph */ public void calcMaximum() { maximum = 0; for (TrackedDataSet set : dataSets) { float val = 0; switch (set.getProperty()) { case TrackedDataSet.CONSUMPTION: for (HolonElement h : ((HolonObject) set.getCpsObject()).getElements()) { if (h.getEnergy() < 0) { val += h.getEnergy() * h.getAmount(); } } val *= -1; break; case TrackedDataSet.PRODUCTION: for (HolonElement h : ((HolonObject) set.getCpsObject()).getElements()) { if (h.getEnergy() > 0) { val += h.getEnergy() * h.getAmount(); } } break; case TrackedDataSet.ACTIVATED_ELEMENTS: for (HolonElement h : ((HolonObject) set.getCpsObject()).getElements()) { val += h.getAmount(); } break; case TrackedDataSet.ON_OFF: val = 1; break; case TrackedDataSet.TOTAL_PRODUCTION: val = getMaxTotalProduction(model.getObjectsOnCanvas()); break; case TrackedDataSet.TOTAL_CONSUMPTION: val = getMaxTotalConsumption(model.getObjectsOnCanvas()); val *= -1; break; case TrackedDataSet.PERCENT_SUPPLIED: case TrackedDataSet.PERCENT_NOT_SUPPLIED: case TrackedDataSet.PERCENT_PARTIAL_SUPPLIED: val = 1; break; case TrackedDataSet.GROUP_PRODUCTION: val = getMaxTotalProduction(((CpsUpperNode) set.getCpsObject()).getNodes()); break; case TrackedDataSet.GROUP_CONSUMPTION: val = getMaxTotalConsumption(((CpsUpperNode) set.getCpsObject()).getNodes()); val *= -1; break; case TrackedDataSet.AMOUNT_HOLONS: val = controller.getSimManager().getSubNets().size(); for (int i = 0; i < model.getCurIteration(); i++) { if (val < set.getValues()[i]) { val = set.getValues()[i]; } } break; case TrackedDataSet.AMOUNT_CLOSED_SWITCHES: val = model.getSwitches().size(); break; case TrackedDataSet.AVG_AMOUNT_OBJECTS_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { if (val < sub.getObjects().size()) { val = sub.getObjects().size(); } } break; case TrackedDataSet.AVG_AMOUNT_ELEMENTS_IN_HOLONS: case TrackedDataSet.AVG_AMOUNT_ACTIVE_ELEMENTS_IN_HOLONS: case TrackedDataSet.AVG_AMOUNT_INACTIVE_ELEMENTS_IN_HOLONS: float eCount = 0; for (SubNet sub : controller.getSimManager().getSubNets()) { for (HolonObject obj : sub.getObjects()) { eCount += obj.getElements().size(); } if (val < eCount) { val = eCount; } eCount = 0; } break; case TrackedDataSet.AVG_AMOUNT_PRODUCERS_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { if (val < sub.getObjects().size()) { val = sub.getObjects().size(); } } break; case TrackedDataSet.AVG_CONSUMED_ENERGY_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { float tempVal = -getMaxTotalConsumption(new ArrayList(sub.getObjects())); if (val < tempVal) { val = tempVal; } } break; case TrackedDataSet.AVG_WASTED_ENERGY_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { float tempVal = getMaxTotalProduction(new ArrayList(sub.getObjects())); if (val < tempVal) { val = tempVal; } } break; case TrackedDataSet.AMOUNT_BROKEN_EDGES: for (SubNet sub : controller.getSimManager().getSubNets()) { val += sub.getSwitches().size(); } break; case TrackedDataSet.RATIO_PRODUCERS_CONSUMERS: val = 1; break; case TrackedDataSet.AVG_AMOUNT_CLOSED_SWITCHES_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { float tempVal = sub.getSwitches().size(); if (val < tempVal) { val = tempVal; } } break; case TrackedDataSet.AVG_PRODUCED_ENERGY_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { float tempVal = getMaxTotalProduction(new ArrayList(sub.getObjects())); if (val < tempVal) { val = tempVal; } } break; default: maximum = 0; break; } if (val > maximum) { maximum = val; } } ((StatisticGraphPanel) this.getParent()).setMaximumLabel(maximum); } /** * Add the Current Values to each set */ private void addValues() { for (TrackedDataSet set : dataSets) { float val = 0; switch (set.getProperty()) { case TrackedDataSet.CONSUMPTION: for (HolonElement h : ((HolonObject) set.getCpsObject()).getElements()) { if (h.getEnergy() < 0 && h.getActive()) { val += Math.abs(h.getEnergyAt()[model.getCurIteration()]) * h.getAmount(); } set.setValAt(val, model.getCurIteration()); } break; case TrackedDataSet.PRODUCTION: for (HolonElement h : ((HolonObject) set.getCpsObject()).getElements()) { if (h.getEnergy() > 0 && h.getActive()) { val += Math.abs(h.getEnergyAt()[model.getCurIteration()]) * h.getAmount(); } set.setValAt(val, model.getCurIteration()); } break; case TrackedDataSet.ACTIVATED_ELEMENTS: for (HolonElement h : ((HolonObject) set.getCpsObject()).getElements()) { if (h.getActive()) { val += h.getAmount(); } set.setValAt(val, model.getCurIteration()); } break; case TrackedDataSet.ON_OFF: if (((HolonSwitch) set.getCpsObject()).getManualMode()) { if (((HolonSwitch) set.getCpsObject()).getActiveManual()) { set.setValAt(1, model.getCurIteration()); } else { set.setValAt(0, model.getCurIteration()); } } else { if (((HolonSwitch) set.getCpsObject()).getActiveAt()[model.getCurIteration()]) { set.setValAt(1, model.getCurIteration()); } else { set.setValAt(0, model.getCurIteration()); } } break; case TrackedDataSet.TOTAL_PRODUCTION: set.setValAt(getTotalProductionAt(model.getObjectsOnCanvas(), model.getCurIteration()), model.getCurIteration()); break; case TrackedDataSet.TOTAL_CONSUMPTION: set.setValAt(-getTotalConsumptionAt(model.getObjectsOnCanvas(), model.getCurIteration()), model.getCurIteration()); break; case TrackedDataSet.PERCENT_SUPPLIED: set.setValAt(getPercentState(model.getObjectsOnCanvas(), HolonObject.SUPPLIED), model.getCurIteration()); break; case TrackedDataSet.PERCENT_NOT_SUPPLIED: set.setValAt(getPercentState(model.getObjectsOnCanvas(), HolonObject.NOT_SUPPLIED), model.getCurIteration()); break; case TrackedDataSet.PERCENT_PARTIAL_SUPPLIED: set.setValAt(getPercentState(model.getObjectsOnCanvas(), HolonObject.PARTIALLY_SUPPLIED), model.getCurIteration()); break; case TrackedDataSet.GROUP_PRODUCTION: set.setValAt( getTotalProductionAt(((CpsUpperNode) set.getCpsObject()).getNodes(), model.getCurIteration()), model.getCurIteration()); break; case TrackedDataSet.GROUP_CONSUMPTION: set.setValAt( -getTotalConsumptionAt(((CpsUpperNode) set.getCpsObject()).getNodes(), model.getCurIteration()), model.getCurIteration()); break; case TrackedDataSet.AMOUNT_HOLONS: set.setValAt(controller.getSimManager().getSubNets().size(), model.getCurIteration()); break; case TrackedDataSet.AMOUNT_CLOSED_SWITCHES: for (HolonSwitch s : model.getSwitches()) { if (s.getState(model.getCurIteration())) { val++; } } set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_AMOUNT_OBJECTS_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { val += sub.getObjects().size(); } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_AMOUNT_ELEMENTS_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { for (HolonObject obj : sub.getObjects()) { val += obj.getElements().size(); } } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_AMOUNT_PRODUCERS_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { for (HolonObject obj : sub.getObjects()) { if (obj.getCurrentEnergyAtTimeStep(model.getCurIteration()) > 0) { val++; } } } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_CONSUMED_ENERGY_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { val += -getTotalConsumptionAt(new ArrayList(sub.getObjects()), model.getCurIteration()); } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_WASTED_ENERGY_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { val += (getTotalProductionAt(new ArrayList(sub.getObjects()), model.getCurIteration()) + getTotalConsumptionAt(new ArrayList(sub.getObjects()), model.getCurIteration())); } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AMOUNT_BROKEN_EDGES: for (SubNet sub : controller.getSimManager().getSubNets()) { for (HolonSwitch s : sub.getSwitches()) { if (s.getState()) { val++; } } } set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.RATIO_PRODUCERS_CONSUMERS: float prod = 0; float cons = 0; for (SubNet sub : controller.getSimManager().getSubNets()) { for (HolonObject obj : sub.getObjects()) { if (obj.getCurrentEnergyAtTimeStep(model.getCurIteration()) > 0) { prod++; } else if (obj.getCurrentEnergyAtTimeStep(model.getCurIteration()) < 0) { cons++; } } } val = prod / (prod + cons); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_AMOUNT_CLOSED_SWITCHES_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { val += sub.getSwitches().size(); } val /=controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_AMOUNT_ACTIVE_ELEMENTS_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { for (HolonObject obj : sub.getObjects()) { for (HolonElement ele: obj.getElements()) { if (ele.getActive()) { val++; } } } } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_AMOUNT_INACTIVE_ELEMENTS_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { for (HolonObject obj : sub.getObjects()) { for (HolonElement ele: obj.getElements()) { if (!ele.getActive()) { val++; } } } } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; case TrackedDataSet.AVG_PRODUCED_ENERGY_IN_HOLONS: for (SubNet sub : controller.getSimManager().getSubNets()) { val += getTotalProductionAt(new ArrayList(sub.getObjects()), model.getCurIteration()); } val /= controller.getSimManager().getSubNets().size(); set.setValAt(val, model.getCurIteration()); break; default: break; } } } /** * create Path with floats * * @param set */ private void createPathFloats(TrackedDataSet set) { boolean init = true; path.moveTo(0, 0); for (int i = 0; i < model.getCurIteration(); i++) { if (init && set.getValues()[i] != -1) { path.moveTo(i * this.getWidth() / model.getIterations() - 1, convertToCanvasY(set.getValues()[i])); init = false; } if (!init) { if (set.getValues()[i + 1] != -1) { path.lineTo((i + 1) * this.getWidth() / model.getIterations(), convertToCanvasY(set.getValues()[i + 1])); } else { break; } } } } /** * create Path with booleans(0 and 1) * * @param set */ private void createPathBooleans(TrackedDataSet set) { boolean init = true; for (int i = 0; i < model.getCurIteration(); i++) { if (init && set.getValues()[i] != -1) { path.moveTo(i * this.getWidth() / model.getIterations() - 1, convertToCanvasY((float) (set.getValues()[i] * maximum))); init = false; } if (!init) { if (set.getValues()[i + 1] != -1) { path.lineTo((i + 1) * this.getWidth() / model.getIterations(), convertToCanvasY((float) (set.getValues()[i + 1] * maximum))); } else { break; } } } } /** * create Path for percent values * * @param set */ private void createPathPercent(TrackedDataSet set) { boolean init = true; path.moveTo(0, 0); for (int i = 0; i < model.getCurIteration(); i++) { if (init && set.getValues()[i] != -1) { path.moveTo(i * this.getWidth() / model.getIterations() - 1, convertToCanvasY(set.getValues()[i] * maximum)); init = false; } if (!init) { if (set.getValues()[i + 1] != -1) { path.lineTo((i + 1) * this.getWidth() / model.getIterations(), convertToCanvasY(set.getValues()[i + 1] * maximum)); } else { break; } } } } /** * get the max total production of the given Objects * * @param objects * List of Objects */ private float getMaxTotalProduction(ArrayList objects) { float val = 0; for (AbstractCpsObject obj : objects) { if (obj instanceof HolonObject) { for (HolonElement ele : ((HolonObject) obj).getElements()) { if (ele.getEnergy() > 0) { val += ele.getEnergy() * ele.getAmount(); } } } else if (obj instanceof CpsUpperNode) { val += getMaxTotalProduction(((CpsUpperNode) obj).getNodes()); } } return val; } /** * get the max total consumption of the given Objects * * @param objects * List of Objects */ private float getMaxTotalConsumption(ArrayList objects) { float val = 0; for (AbstractCpsObject obj : objects) { if (obj instanceof HolonObject) { for (HolonElement ele : ((HolonObject) obj).getElements()) { if (ele.getEnergy() < 0) { val += ele.getEnergy() * ele.getAmount(); } } } else if (obj instanceof CpsUpperNode) { val += getMaxTotalConsumption(((CpsUpperNode) obj).getNodes()); } } return val; } /** * get the max total production of the given Objects * * @param objects * List of Objects * @param tStep */ private float getTotalProductionAt(ArrayList objects, int tStep) { float val = 0; for (AbstractCpsObject obj : objects) { if (obj instanceof HolonObject) { for (HolonElement ele : ((HolonObject) obj).getElements()) { if (ele.getEnergyAt()[tStep] > 0 && ele.getActive()) { val += ele.getEnergyAt()[tStep] * ele.getAmount(); } } } else if (obj instanceof CpsUpperNode) { val += getTotalProductionAt(((CpsUpperNode) obj).getNodes(), tStep); } } return val; } /** * get the total consumption of the given Objects at the given timestep * * @param objects * List of Objects * @param tStep */ private float getTotalConsumptionAt(ArrayList objects, int tStep) { float val = 0; for (AbstractCpsObject obj : objects) { if (obj instanceof HolonObject) { for (HolonElement ele : ((HolonObject) obj).getElements()) { if (ele.getEnergyAt()[tStep] < 0 && ele.getActive()) { val += ele.getEnergyAt()[tStep] * ele.getAmount(); } } } else if (obj instanceof CpsUpperNode) { val += getTotalConsumptionAt(((CpsUpperNode) obj).getNodes(), tStep); } } return val; } /** * get the Percentage of how many objects with the given state are in the * given List * * @param objects * List of Objects */ private float getPercentState(ArrayList objects, int state) { float count = controller.getNumberHolonObjects(objects); float stateObjectss = controller.getNumberStateObjects(objects, state); return stateObjectss / count; } public ArrayList getDataSets() { return dataSets; } }