HolonElement.java 12 KB

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