package classes; import com.google.gson.annotations.Expose; import interfaces.GraphEditable; import interfaces.LocalMode; import ui.controller.FlexManager; import ui.view.IndexTranslator; import java.awt.*; import java.awt.geom.Point2D; import java.awt.geom.Point2D.Double; import java.util.ArrayList; import java.util.LinkedList; import java.util.ListIterator; /** * The class "HolonElement" represents any possible element that can be added to * a CpsObject (such as TV (consumer) or any energyPerElement source/producer). * * @author Gruppe14 */ public class HolonElement implements LocalMode, GraphEditable{ /** Points of new TestGraph * Represent the Graph * the X component from a Point is period from 0..1 * the Y component from a Point is the percentage from 0..1 * */ private LinkedList graphPoints; /** Name of the object, e.g. House, 1 */ @Expose private String objName; /** Name of the gadget, e.g. TV */ @Expose private String eleName; /** Amount of same elements */ @Expose private int amount; /** Currently used energy per element (- indicates consumation of energy, + indicates production of energy)*/ @Expose private float energyPerElement; /** Whether the gadget is active or not (currently uses/produces the energy in energyPerElement) */ @Expose private boolean active; /** Gives us whether this element is flexible and can flexibly use any part of the energy in flexibleEnergyAvailable */ public HolonObject parentObject; @Expose private Priority priority; public enum Priority { Essential, High, Medium , Low } /** Place where the Object is Stored */ @Expose private Pair saving; /** ID */ @Expose private int id; public java.util.List flexList = new ArrayList(); /* * Energy at each point of the graph with 100 predefined points. At the * beginning, it starts with all values at energyPerElement. * If switched to flexible, this represents the maximum of usable energy */ private float[] curveSample; @Expose private int localPeriod; @Expose private boolean isUsingLocalPeriod; /** * Create a new HolonElement with a user-defined name, amount of the same * element, energyPerElement and corresponding model. * * @param eleName String * @param amount int * @param energy float * @param model Model */ public HolonElement(HolonObject parentObject, String eleName, int amount, float energy) { this(parentObject, eleName, amount, energy, IdCounterElem.nextId()); } /** * same as standard constructor, but with already given id (so the counter is not increased twice) */ public HolonElement(HolonObject parentObject, String eleName, int amount, float energy, int id){ this.parentObject = parentObject; setUseLocalPeriod(false); setEleName(eleName); setAmount(amount); setEnergyPerElement(energy); setActive(true); setGraphPoints(new LinkedList<>()); initGraphPoints(); sampleGraph(); setId(id); this.priority = Priority.Low; } /** * Create a copy of the HolonElement given each one a new ID. * * @param element element to copy */ public HolonElement(HolonElement element) { this.parentObject = element.parentObject; this.priority = element.getPriority(); setLocalPeriod(element.getLocalPeriod()); setUseLocalPeriod(element.isUsingLocalPeriod()); setEleName(element.getEleName()); setLocalPeriod(element.getLocalPeriod()); setAmount(element.getAmount()); setEnergyPerElement(element.getEnergyPerElement()); setActive(element.isActive()); setGraphPoints(new LinkedList<>()); for (Point2D.Double p : element.getGraphPoints()) { this.graphPoints.add(new Point2D.Double(p.getX(), p.getY())); } sampleGraph(); setSaving(null); setId(IdCounterElem.nextId()); } public String getObjName() { return objName; } public void setObjName(String objName) { this.objName = objName; } /** * Get the user-defined Name. * * @return the name String */ public String getEleName() { return eleName; } /** * Set the name to any new name. * * @param name the name to set */ public void setEleName(String name) { this.eleName = name; } /** * Get the actual amount of Elements in the selected Object. * * @return the amount int */ public int getAmount() { return amount; } /** * Set the amount of the Element in the selected Object. * * @param amount the amount to set */ public void setAmount(int amount) { this.amount = amount; } /** * Get the energyPerElement value of the selected Element. * * @return the energyPerElement */ public float getEnergyPerElement() { return energyPerElement; } public Priority getPriority() { return priority; } public void setPriority(Priority priority) { this.priority = priority; } /** * Check the HolonElemnet is a Producer * @return true when the energy used be each element is higher then 0 */ public boolean isProducer() { return (energyPerElement > 0); } /** * Check the HolonElemnet is a Consumer * @return true when the energy used be each element is lower then 0 */ public boolean isConsumer() { return (energyPerElement < 0); } /** * Set the energyPerElement value of the selected Element. * * @param energyPerElement the energyPerElement to set */ public void setEnergyPerElement(float energyPerElement) { this.energyPerElement = energyPerElement; } /** * Get the Status of the Element (see description of variables). * * @return the active */ public boolean isActive() { return active; } public boolean isOn(FlexManager flexManager) { //return (flexManager.isAFlexInUseOfHolonElement(this))?!active:active; //Bool logic XOR return flexManager.isAFlexInUseOfHolonElement(this) ^ active; } public boolean isFlexActive(FlexManager flexManager) { return flexManager.isAFlexInUseOfHolonElement(this); } /** * Set the Status of the Element (see description of variables). * * @param active the active to set */ public void setActive(boolean active) { this.active = active; } /** * Multiply the amount of gadgets, given by the user, and the * consumption/production. If the switch isWorking is turned off for on * gadget, the energyPerElement of this gadget have to be subtracted. * * @return totalEnergy (actual) */ public float getMaximumEnergy() { return amount * energyPerElement; } /** * Get the energyPerElement value at a selected time x. * * @param timestep int * @return energyPerElement value */ public float getOverallEnergyAtTimeStep(int timestep) { return ((float) amount) * energyPerElement * curveSample[IndexTranslator.getEffectiveIndex(this, timestep)]; } /** * Get the energyPerElement currently(at given time step) available */ public float getEnergyAtTimeStep(int timestep) { return amount * energyPerElement * this.curveSample[IndexTranslator.getEffectiveIndex(this, timestep)]; } /** * Get the Id of the selected HolonElement. * * @return id the id */ public int getId() { return id; } /** * Set the ID of the HolonElement (one time only). * * @param id the id */ public void setId(int id) { this.id = id; } /** * @return the saving */ public Pair getSaving() { return saving; } /** * @param saving the saving to set */ public void setSaving(Pair saving) { this.saving = saving; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[HolonElement: "); sb.append("id=").append(id) .append(", eleName=").append(eleName) .append(", parentName=").append(parentObject.getName()) .append(", amount=").append(amount) .append(", active=").append(active) .append(", energyPerElement used=").append(energyPerElement); sb.append("]"); return sb.toString(); } /** * Initialize the {@link HolonElement#graphPoints} List with the normal 2 Points at 100%. */ private void initGraphPoints() { graphPoints.clear(); graphPoints.add(new Point2D.Double(0,1.0)); graphPoints.add(new Point2D.Double(1,1.0)); } /** * Getter for the graphPoint List. * @return {@link HolonElement#graphPoints} */ public LinkedList getGraphPoints() { return graphPoints; } /** * Setter for the graphPoint List. * @param testGraphPoints is new {@link HolonElement#graphPoints} */ public void setGraphPoints(LinkedList testGraphPoints) { this.graphPoints = testGraphPoints; } //interfaces.GraphEditable @Override public Graphtype getGraphType() { return Graphtype.doubleGraph; } @Override public LinkedList getStateGraph() { return getGraphPoints(); } @Override public void sampleGraph() { curveSample = sampleGraph(100); } @Override public void reset() { initGraphPoints(); sampleGraph(); } /** * Generate out of the Graph Points a array of floats that represent the Curve at each sample position. The Values are in the Range [0,1]. * e.g. 0.0 represent: "0%" , 0.34 represent: 34% 1.0 represent: "100%" * @param sampleLength amount of samplePositions. The positions are equidistant on the Range[0,1]. * @return the float array of samplepoints. */ private float[] sampleGraph(int sampleLength) { ListIterator iter = this.graphPoints.listIterator(); Point.Double before = iter.next(); Point.Double after = iter.next(); float [] sampleCurve = new float[sampleLength]; for(int i = 0; i after.x) { before = after; after = iter.next(); } //t to determine how many percentage the graphX is to the next Point needed to calc Bezier //inverseLerp(valueBetween, min, max) (valueBetween - min) / (max - min) // e.g. old.x = 0.4, actual.x = 0.8 and graphX = 0.6 then t is 0.5 double t = (after.x -before.x > 0)? (graphX - before.x) / (after.x -before.x) : 0.0; sampleCurve[i] = (float) getYBetweenTwoPoints(t, before, after); } return sampleCurve; } /** * Helper method for {@link HolonElement#sampleGraph(int)}. *

* Its get the start and Endposition and calculate the Points in between for the Bezi�r Curve. * Then its get the Y Value a.k.a. the percentage from the curve at the X value t. * @param t is in Range [0,1] and represent how much the X value is traverse along the Curve between the two Points. * @param start is the start Point of the Curve. * @param end is the end Point of the Curve. * @return the percentage from the Curve at the X Value based on t. */ private double getYBetweenTwoPoints(double t, Point.Double start, Point.Double end) { double mitte = (start.x + end.x)* 0.5; Point.Double bezier = getBezierPoint(t, start, new Point.Double(mitte, start.y), new Point.Double(mitte, end.y), end); return bezier.y; } /** * Helper method for {@link HolonElement#getYBetweenTwoPoints(double, Point.Double, Point.Double)}. *

* A Method for a normal Cubic Bezier Curve. A Cubic Bezier curve has four control points. * @param t is in Range [0,1] how much it traverse along the curve. * @param p0 StartPoint * @param p1 ControlPoint * @param p2 ControlPoint * @param p3 EndPoint * @return the BezierPosition at t. */ private Point.Double getBezierPoint(double t, Point.Double p0, Point.Double p1,Point.Double p2,Point.Double p3) { /* * Calculate Bezi�r: * B(t) = (1-t)^3 * P0 + 3*(1-t)^2 * t * P1 + 3*(1-t)*t^2 * P2 + t^3 * P3 , 0 < t < 1 * * Source: //http://www.theappguruz.com/blog/bezier-curve-in-games */ Point.Double bezier = new Point.Double(); double OneSubT = 1-t; double OneSubT2 = Math.pow(OneSubT, 2); double OneSubT3 = Math.pow(OneSubT, 3); double t2 = Math.pow(t , 2); double t3 = Math.pow(t , 3); bezier.x = OneSubT3 * p0.x + 3 * OneSubT2 * t * p1.x + 3 * OneSubT * t2 * p2.x + t3 * p3.x; bezier.y = OneSubT3 * p0.y + 3 * OneSubT2 * t * p1.y + 3 * OneSubT * t2 * p2.y + t3 * p3.y; return bezier; } //interfaces.LocalMode @Override public void setLocalPeriod(int period) { localPeriod=period; } @Override public int getLocalPeriod() { return localPeriod; } @Override public boolean isUsingLocalPeriod() { return isUsingLocalPeriod; } @Override public void setUseLocalPeriod(boolean state) { this.isUsingLocalPeriod=state; } }