HolonElement.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. package holeg.model;
  2. import com.google.gson.annotations.Expose;
  3. import com.google.gson.annotations.SerializedName;
  4. import holeg.interfaces.TimelineDependent;
  5. import holeg.model.Flexibility.FlexState;
  6. import holeg.ui.controller.IndexTranslator;
  7. import holeg.ui.model.IdCounter;
  8. import holeg.ui.model.IdCounter.CounterType;
  9. import holeg.utility.Vector2Float;
  10. import java.util.ArrayList;
  11. import java.util.LinkedList;
  12. import java.util.ListIterator;
  13. import java.util.AbstractMap.SimpleEntry;
  14. import java.util.logging.Logger;
  15. /**
  16. * The class "HolonElement" represents any possible element that can be added to
  17. * a CpsObject (such as TV (consumer) or any energyPerElement source/producer).
  18. *
  19. * @author Gruppe14
  20. */
  21. public class HolonElement implements TimelineDependent{
  22. private static final Logger log = Logger.getLogger(HolonElement.class.getName());
  23. /*
  24. * MODEL
  25. */
  26. /** Owner of the Element */
  27. public HolonObject parentObject;
  28. /** Points of new TestGraph
  29. * Represent the Graph
  30. * the X component from a Point is period from 0..1
  31. * the Y component from a Point is the percentage from 0..1
  32. * */
  33. private LinkedList<Vector2Float> graphPoints;
  34. /** Name of the gadget, e.g. TV */
  35. @Expose
  36. @SerializedName(value = "name", alternate = "eleName")
  37. private String name;
  38. /** Amount of same elements */
  39. @Expose
  40. @SerializedName(value = "energy", alternate = "energyPerElement")
  41. private float energy;
  42. /** Whether the gadget is active or not (currently uses/produces the energy in energyPerElement) */
  43. @Expose
  44. public boolean active;
  45. /** Gives us whether this element is flexible and can flexibly use any part of the energy in flexibleEnergyAvailable */
  46. public enum Priority {
  47. Low, Medium, High, Essential
  48. }
  49. @Expose
  50. public Priority priority = Priority.Low;
  51. /** Place where the Object is Stored */
  52. @Expose
  53. private SimpleEntry<String, String> saving;
  54. /** ID */
  55. @Expose
  56. private int id;
  57. public java.util.List<Flexibility> flexList = new ArrayList<Flexibility>();
  58. /*
  59. * Energy at each point of the graph with 100 predefined points. At the
  60. * beginning, it starts with all values at energyPerElement.
  61. * If switched to flexible, this represents the maximum of usable energy
  62. */
  63. private float[] curveSample;
  64. @Expose
  65. private int localPeriod;
  66. @Expose
  67. private boolean isUsingLocalPeriod;
  68. /**
  69. * Create a new HolonElement with a user-defined name, amount of the same
  70. * element, energyPerElement and corresponding model.
  71. *
  72. * @param eleName String
  73. * @param amount int
  74. * @param energy float
  75. * @param model Model
  76. */
  77. //TODO(Tom2021-12-20): constructor should be remade
  78. public HolonElement(HolonObject parentObject, String eleName, float energy) {
  79. this(parentObject, eleName, energy, IdCounter.nextId(CounterType.Element));
  80. }
  81. /**
  82. * same as standard constructor, but with already given id (so the counter is not increased twice)
  83. */
  84. public HolonElement(HolonObject parentObject, String eleName, float energy, int id){
  85. this.parentObject = parentObject;
  86. setUseLocalPeriod(false);
  87. setName(eleName);
  88. setEnergy(energy);
  89. this.active = true;
  90. setGraphPoints(new LinkedList<>());
  91. initGraphPoints();
  92. sampleGraph();
  93. this.id = id;
  94. }
  95. /**
  96. * Create a copy of the HolonElement given each one a new ID.
  97. *
  98. * @param element element to copy
  99. */
  100. public HolonElement(HolonElement element) {
  101. this.parentObject = element.parentObject;
  102. this.priority = element.getPriority();
  103. setLocalPeriod(element.getLocalPeriod());
  104. setUseLocalPeriod(element.isUsingLocalPeriod());
  105. setName(element.getName());
  106. setLocalPeriod(element.getLocalPeriod());
  107. setEnergy(element.getEnergy());
  108. this.active = element.active;
  109. setGraphPoints(new LinkedList<>());
  110. for (Vector2Float p : element.getGraphPoints()) {
  111. this.graphPoints.add(new Vector2Float(p));
  112. }
  113. sampleGraph();
  114. setSaving(null);
  115. this.id = IdCounter.nextId(CounterType.Element);
  116. }
  117. public int getId() {
  118. return id;
  119. }
  120. /**
  121. * Get the user-defined Name.
  122. *
  123. * @return the name String
  124. */
  125. public String getName() {
  126. return name;
  127. }
  128. /**
  129. * Set the name to any new name.
  130. *
  131. * @param name the name to set
  132. */
  133. public void setName(String name) {
  134. this.name = name;
  135. }
  136. /**
  137. * Get the energyPerElement value of the selected Element.
  138. *
  139. * @return the energyPerElement
  140. */
  141. public float getEnergy() {
  142. return energy;
  143. }
  144. /**
  145. * Set the energyPerElement value of the selected Element.
  146. *
  147. * @param energyPerElement the energyPerElement to set
  148. */
  149. public void setEnergy(float energyPerElement) {
  150. log.finest(this.energy + " -> " + energyPerElement);
  151. this.energy = energyPerElement;
  152. }
  153. /**
  154. * Check the HolonElemnet is a Producer
  155. * @return true when the energy used be each element is higher then 0
  156. */
  157. public boolean isProducer()
  158. {
  159. return (energy > 0);
  160. }
  161. /**
  162. * Check the HolonElemnet is a Consumer
  163. * @return true when the energy used be each element is lower then 0
  164. */
  165. public boolean isConsumer()
  166. {
  167. return (energy < 0);
  168. }
  169. public Priority getPriority() {
  170. return priority;
  171. }
  172. public void setPriority(Priority priority) {
  173. this.priority = priority;
  174. }
  175. /**
  176. * @return the saving
  177. */
  178. public SimpleEntry<String, String> getSaving() {
  179. return saving;
  180. }
  181. /**
  182. * @param saving the saving to set
  183. */
  184. public void setSaving(SimpleEntry<String, String> saving) {
  185. this.saving = saving;
  186. }
  187. public String toString() {
  188. StringBuilder sb = new StringBuilder();
  189. sb.append("[HolonElement: ");
  190. sb.append("id=").append(id)
  191. .append(", eleName=").append(name)
  192. .append(", parentName=").append(parentObject.getName())
  193. .append(", active=").append(active)
  194. .append(", energyPerElement used=").append(energy);
  195. sb.append("]");
  196. return sb.toString();
  197. }
  198. /**
  199. * Initialize the {@link HolonElement#graphPoints} List with the normal 2 Points at 100%.
  200. */
  201. private void initGraphPoints()
  202. {
  203. graphPoints.clear();
  204. graphPoints.add(new Vector2Float(0f,1.0f));
  205. graphPoints.add(new Vector2Float(1f,1.0f));
  206. }
  207. /**
  208. * Getter for the graphPoint List.
  209. * @return {@link HolonElement#graphPoints}
  210. */
  211. public LinkedList<Vector2Float> getGraphPoints() {
  212. return graphPoints;
  213. }
  214. /**
  215. * Setter for the graphPoint List.
  216. * @param testGraphPoints is new {@link HolonElement#graphPoints}
  217. */
  218. public void setGraphPoints(LinkedList<Vector2Float> graphPoints) {
  219. this.graphPoints = graphPoints;
  220. }
  221. //interfaces.GraphEditable
  222. @Override
  223. public GraphType getGraphType() {
  224. return GraphType.doubleGraph;
  225. }
  226. @Override
  227. public LinkedList<Vector2Float> getStateGraph() {
  228. return getGraphPoints();
  229. }
  230. @Override
  231. public void sampleGraph() {
  232. curveSample = sampleGraph(100);
  233. }
  234. @Override
  235. public void reset() {
  236. initGraphPoints();
  237. sampleGraph();
  238. }
  239. /**
  240. * 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].
  241. * e.g. 0.0 represent: "0%" , 0.34 represent: 34% 1.0 represent: "100%"
  242. * @param sampleLength amount of samplePositions. The positions are equidistant on the Range[0,1].
  243. * @return the float array of samplepoints.
  244. */
  245. private float[] sampleGraph(int sampleLength)
  246. {
  247. ListIterator<Vector2Float> iter = this.graphPoints.listIterator();
  248. Vector2Float before = iter.next();
  249. Vector2Float after = iter.next();
  250. float [] sampleCurve = new float[sampleLength];
  251. for(int i = 0; i<sampleLength ; i++)
  252. {
  253. double graphX = (double)i / (double) (sampleLength - 1); //from 0.0 to 1.0
  254. if(graphX > after.x)
  255. {
  256. before = after;
  257. after = iter.next();
  258. }
  259. //t to determine how many percentage the graphX is to the next Point needed to calc Bezier
  260. //inverseLerp(valueBetween, min, max) (valueBetween - min) / (max - min)
  261. // e.g. old.x = 0.4, actual.x = 0.8 and graphX = 0.6 then t is 0.5
  262. double t = (after.x -before.x > 0)? (graphX - before.x) / (after.x -before.x) : 0.0;
  263. sampleCurve[i] = (float) getYBetweenTwoPoints(t, before, after);
  264. }
  265. return sampleCurve;
  266. }
  267. /**
  268. * Helper method for {@link HolonElement#sampleGraph(int)}.
  269. * <p>
  270. * Its get the start and Endposition and calculate the Points in between for the Bezi�r Curve.
  271. * Then its get the Y Value a.k.a. the percentage from the curve at the X value t.
  272. * @param t is in Range [0,1] and represent how much the X value is traverse along the Curve between the two Points.
  273. * @param start is the start Point of the Curve.
  274. * @param end is the end Point of the Curve.
  275. * @return the percentage from the Curve at the X Value based on t.
  276. */
  277. private double getYBetweenTwoPoints(double t, Vector2Float start, Vector2Float end) {
  278. float mitte = (start.x + end.x)* 0.5f;
  279. Vector2Float bezier = getBezierPoint(t, start, new Vector2Float(mitte, start.y), new Vector2Float(mitte, end.y), end);
  280. return bezier.y;
  281. }
  282. /**
  283. * Helper method for {@link HolonElement#getYBetweenTwoPoints(double, Vector2Float, Vector2Float)}.
  284. * <p>
  285. * A Method for a normal Cubic Bezier Curve. A Cubic Bezier curve has four control points.
  286. * @param t is in Range [0,1] how much it traverse along the curve.
  287. * @param p0 StartPoint
  288. * @param p1 ControlPoint
  289. * @param p2 ControlPoint
  290. * @param p3 EndPoint
  291. * @return the BezierPosition at t.
  292. */
  293. private Vector2Float getBezierPoint(double t, Vector2Float p0, Vector2Float p1,Vector2Float p2,Vector2Float p3) {
  294. /*
  295. * Calculate Bezi�r:
  296. * B(t) = (1-t)^3 * P0 + 3*(1-t)^2 * t * P1 + 3*(1-t)*t^2 * P2 + t^3 * P3 , 0 < t < 1
  297. *
  298. * Source: //http://www.theappguruz.com/blog/bezier-curve-in-games
  299. */
  300. Vector2Float bezier = new Vector2Float();
  301. double OneSubT = 1-t;
  302. double OneSubT2 = Math.pow(OneSubT, 2);
  303. double OneSubT3 = Math.pow(OneSubT, 3);
  304. double t2 = Math.pow(t , 2);
  305. double t3 = Math.pow(t , 3);
  306. bezier.x = (float)(OneSubT3 * p0.x + 3 * OneSubT2 * t * p1.x + 3 * OneSubT * t2 * p2.x + t3 * p3.x);
  307. bezier.y = (float)(OneSubT3 * p0.y + 3 * OneSubT2 * t * p1.y + 3 * OneSubT * t2 * p2.y + t3 * p3.y);
  308. return bezier;
  309. }
  310. //interfaces.LocalMode
  311. @Override
  312. public void setLocalPeriod(int period) {
  313. localPeriod=period;
  314. }
  315. @Override
  316. public int getLocalPeriod() {
  317. return localPeriod;
  318. }
  319. @Override
  320. public boolean isUsingLocalPeriod() {
  321. return isUsingLocalPeriod;
  322. }
  323. @Override
  324. public void setUseLocalPeriod(boolean state) {
  325. this.isUsingLocalPeriod=state;
  326. }
  327. /*
  328. * STATE
  329. */
  330. private float actualEnergy = 0;
  331. //TODO(Tom2021-12-1): public -> package
  332. public void calculateState(int timestep) {
  333. flexList.forEach(flex -> flex.calculateState(timestep));
  334. float energyWhenActive = energy * this.curveSample[IndexTranslator.getEffectiveIndex(this, timestep)];
  335. actualEnergy = isOn() ? energyWhenActive : 0;
  336. }
  337. /**
  338. * Get the energyPerElement currently(at given time step) available
  339. */
  340. public float calculateExpectedEnergyAtTimeStep(int timestep) {
  341. float energyWhenActive = energy * this.curveSample[IndexTranslator.getEffectiveIndex(this, timestep)];
  342. return active ? energyWhenActive : 0;
  343. }
  344. public float getActualEnergy() {
  345. return actualEnergy;
  346. }
  347. public boolean isOn() {
  348. //return isFlexActive()?!active:active;
  349. //Bool logic XOR
  350. return isFlexActive() ^ active;
  351. }
  352. public boolean isFlexActive() {
  353. return flexList.stream().anyMatch(flex -> flex.getState() == FlexState.IN_USE || flex.getState() == FlexState.ON_COOLDOWN);
  354. }
  355. }