HolonElement.java 11 KB

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