package classes; import com.google.gson.annotations.Expose; import interfaces.GraphEditable; import interfaces.IGraphedElement; import ui.model.Model; import ui.view.IndexTranslator; import java.awt.*; import java.awt.geom.Point2D; import java.awt.geom.Point2D.Double; 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 IGraphedElement, 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 */ @Expose private boolean flexible; /** Flexibility (meaning the actual */ @Expose private float flexibleEnergyAvailable; /** Place where the Object is Stored */ @Expose private Pair saving; /** ID */ @Expose private int id; //private static final int DEFAULT_GRAPH_LENGTH=100; //private int graphLength=DEFAULT_GRAPH_LENGTH; Unimplementable due to former developer's dark magic. /* * 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 stretch; /** * 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(String eleName, int amount, float energy, Model model) { this(eleName, amount, energy, IdCounterElem.nextId(),model); } /** * same as standard constructor, but with already given id (so the counter is not increased twice) */ public HolonElement(String eleName, int amount, float energy, int id, Model model){ setLocalPeriod(model==null? IGraphedElement.STANDARD_GRAPH_ACCURACY : model.getGraphIterations()); setStretching(IGraphedElement.STRETCH_BY_DEFAULT); setEleName(eleName); setAmount(amount); setEnergyPerElement(energy); setActive(true); System.out.println("heiNEW"); setGraphPoints(new LinkedList<>()); initGraphPoints(); sampleGraph(); setId(id); setFlexibleEnergyAvailable(0); setFlexible(false); } /** * Create a copy of the HolonElement given each one a new ID. * * @param element element to copy */ public HolonElement(HolonElement element) { setLocalPeriod(element.getLocalPeriod()); setStretching(element.isStretching()); setEleName(element.getEleName()); setLocalPeriod(element.getLocalPeriod()); setAmount(element.getAmount()); setEnergyPerElement(element.getEnergyPerElement()); setActive(element.isActive()); setGraphPoints(new LinkedList<>()); System.out.println("hei"); for (Point2D.Double p : element.getGraphPoints()) { this.graphPoints.add(new Point2D.Double(p.getX(), p.getY())); } sampleGraph(); setSaving(null); setId(IdCounterElem.nextId()); setFlexibleEnergyAvailable(0); setFlexible(false); } public String getObjName() { return objName; } public void setObjName(String objName) { this.objName = objName; } /** * Get the energyPerElement currently(at given time step) available */ public float getAvailableEnergyAt(int timestep) { System.out.println("getAvailableEnergyAt"); return amount * energyPerElement * this.curveSample[IndexTranslator.getEffectiveIndex(this, timestep)]; } /** * 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; } /** * 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; } /** * 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 getOverallEnergy() { float totalEnergy = amount * energyPerElement; return totalEnergy; } /** * Get the energyPerElement value at a selected time x. * * @param timestep int * @return energyPerElement value */ public float getOverallEnergyAtTimeStep(int timestep) { if (flexible) { return ((float) amount) * energyPerElement; } else { return ((float) amount) * energyPerElement * curveSample[IndexTranslator.getEffectiveIndex(this, timestep)]; } } /** * Get the flexibleEnergyAvailable of an element */ public float getFlexibleEnergyAvailablePerElement() { return this.flexibleEnergyAvailable; } /** * Set the flexibleEnergyAvailable of an element */ public void setFlexibleEnergyAvailable(float energy) { this.flexibleEnergyAvailable = energy; } /** * Get the flexibleEnergyAvailable of an element */ public boolean isFlexible() { return this.flexible; } /** * Set the flexibleEnergyAvailable of an element, ~switches energyPerElement and flexible energyPerElement */ public void setFlexible(boolean b) { // if flexibleEnergyAvailable was set to true if (b && !this.flexible) { this.flexible = b; // move energyPerElement to flexibleEnergyAvailable (becomes the possible-to-use energyPerElement) if (getEnergyPerElement() != 0) { setFlexibleEnergyAvailable(getEnergyPerElement()); setEnergyPerElement(0); } } else if (!b && this.flexible) { this.flexible = b; // move the energyPerElement to actually used energyPerElement and set flexible amount to 0 if (getFlexibleEnergyAvailablePerElement() != 0) { setEnergyPerElement(getFlexibleEnergyAvailablePerElement()); } setFlexibleEnergyAvailable(0); } } /** * 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(", amount=").append(amount) .append(", active=").append(active) .append(", flexible=").append(flexible) .append(", energyPerElement used=").append(energyPerElement) .append(", flexible energyPerElement available=").append(flexibleEnergyAvailable); sb.append("]"); return sb.toString(); } @Override public void setLocalPeriod(int period) { localPeriod=period; } @Override public int getLocalPeriod() { return localPeriod; } @Override public boolean isStretching() { return stretch; } @Override public void setStretching(boolean stretch) { this.stretch=stretch; } public void initGraphPoints() { graphPoints.clear(); graphPoints.add(new Point2D.Double(0,1.0)); graphPoints.add(new Point2D.Double(1,1.0)); } public LinkedList getGraphPoints() { return graphPoints; } public void setGraphPoints(LinkedList testGraphPoints) { this.graphPoints = testGraphPoints; } @Override public Graphtype getGraphType() { return Graphtype.doubleGraph; } @Override public LinkedList getStateGraph() { return getGraphPoints(); } 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; } 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; } 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; } @Override public void sampleGraph() { curveSample = sampleGraph(100); } @Override public void reset() { initGraphPoints(); sampleGraph(); } }