[Util] Quadratics

Discussion in 'Resources' started by JBoss925, Aug 3, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    JBoss925

    Hey guys, I had to mess around with quadratics for a plugin I was working on and I decided I might as well release the code since it's a fair bit of math.:D

    Source
    Find the source on GitHub here.​
    or under everything in the thread.​
    Documentation
    As of now, documentation is above the methods in the source. Official documentation will come soon.​
    Plans
    *Add configuration serializable​
    Pull requests and change requests are much appreciated!

    CODE (open)

    Code:java
    1. package me.JBoss925.quad;
    2.  
    3. import org.bukkit.Bukkit;
    4. import org.bukkit.Location;
    5. import org.bukkit.World;
    6. import org.bukkit.block.Block;
    7. import org.bukkit.configuration.serialization.ConfigurationSerializable;
    8. import org.bukkit.entity.Player;
    9. import java.util.*;
    10.  
    11. public class Quadratic implements Cloneable, ConfigurationSerializable{
    12.  
    13. //----------------Global Variables-------------------
    14.  
    15. double a;
    16. double b;
    17. double c;
    18. double startx, endx, changeinterval;
    19. Location base;
    20. List<Location> locs;
    21. List<Block> blocks;
    22.  
    23. //---------------------------------------------------
    24.  
    25. //-----------------Constructor Possibilities------------------
    26.  
    27. public Quadratic(double a, double b, double c){
    28. this.a = a;
    29. this.b = b;
    30. this.c = c;
    31. }
    32.  
    33. public Quadratic(double a, double b, double c, double startx, double endx, double changeinterval, Location base){
    34. this.a = a;
    35. this.b = b;
    36. this.c = c;
    37. this.startx = startx;
    38. this.endx = endx;
    39. this.changeinterval = changeinterval;
    40. this.base = base;
    41. }
    42.  
    43. public Quadratic(double a, double b, double c, double startx, double endx, double changeinterval, Location base, List<Location> locs, List<Block> blocks){
    44. this.a = a;
    45. this.b = b;
    46. this.c = c;
    47. this.startx = startx;
    48. this.endx = endx;
    49. this.changeinterval = changeinterval;
    50. this.base = base;
    51. this.locs = locs;
    52. this.blocks = blocks;
    53. }
    54.  
    55. public Quadratic(double a, double b, double c, double startx, double endx, double changeinterval){
    56. this.a = a;
    57. this.b = b;
    58. this.c = c;
    59. this.startx = startx;
    60. this.endx = endx;
    61. this.changeinterval = changeinterval;
    62. }
    63.  
    64. public Quadratic(int a, int b, int c){
    65. this.a = Double.parseDouble(String.valueOf(a).concat(".0"));
    66. this.b = Double.parseDouble(String.valueOf(b).concat(".0"));
    67. this.c = Double.parseDouble(String.valueOf(c).concat(".0"));
    68. }
    69.  
    70. //----------------------------------------------------------
    71.  
    72. //-----------------Methods------------------
    73.  
    74. /**
    75.   * Used to get the y value at a single x.
    76.   *
    77.   * @param x - the x of the quadratic the y will be retrieved from
    78.   * @return - a double value of the non-coordinate-adjusted y at the given x
    79.   */
    80. public double getY(double x){
    81. double d = Math.pow(x, 2.0) * this.a;
    82. if(d == 0){
    83. d = 1.0;
    84. }
    85. d = this.b * x + d;
    86. if(d == 0){
    87. d = 1.0;
    88. }
    89. d = d + this.c;
    90. return d;
    91. }
    92.  
    93. /**
    94.   * Used to get the x intercepts of the quadratic.
    95.   *
    96.   * @return - list of doubles(2) of the non-coordinate-adjusted x intercepts of the quadratic (where y = 0)
    97.   */
    98. public List<Double> getXIntercepts(){
    99. List<Double> ds = new ArrayList<Double>();
    100. double a = this.b * -1;
    101. if(a == 0){
    102. a = 1.0;
    103. }
    104. double mod = this.a * this.c * 4;
    105. if(mod == 0){
    106. mod = 1.0;
    107. }
    108. double mod2 = this.a * 2;
    109. if(mod2 == 0){
    110. mod = 1.0;
    111. }
    112. double mod3 = Math.pow(this.b, 2.0);
    113. if(mod3 == 0){
    114. mod3 = 1.0;
    115. }
    116. if(mod3 - mod < 0){
    117. a = a + Math.sqrt(Math.abs(mod3 - mod));
    118. a = a / mod2;
    119. ds.add(a);
    120. }
    121. if(mod3 - mod >= 0){
    122. a = a + Math.sqrt(mod3 - mod);
    123. a = a / mod2;
    124. ds.add(a);
    125. }
    126. double b = this.b * -1;
    127. if(b == 0){
    128. b = 1.0;
    129. }
    130. double modb = this.a * this.c * 4;
    131. if(modb == 0){
    132. modb = 1.0;
    133. }
    134. double mod2b = this.a * 2;
    135. if(mod2b == 0){
    136. mod2b = 1.0;
    137. }
    138. double mod3b = Math.pow(this.b, 2.0);
    139. if(mod3b == 0){
    140. mod3b = 1.0;
    141. }
    142. if(mod3b - modb < 0){
    143. b = b - Math.sqrt(Math.abs(mod3b - modb));
    144. b = b / mod2b;
    145. ds.add(b);
    146. }
    147. if(mod3b - modb >= 0){
    148. b = b + Math.sqrt(mod3b - modb);
    149. b = b / mod2b;
    150. ds.add(b);
    151. }
    152. return ds;
    153. }
    154.  
    155. /**
    156.   * Used to get the non-coordinate-adjusted y values from the startx to the endx at a rate of the changeinterval.
    157.   *
    158.   * @param startx - the smallest x value that will be used to find y values
    159.   * @param endx - the largest x value that will be used to find y values
    160.   * @param changeinterval - the rate at which the x increases from startx to endx
    161.   * @return - list of doubles of the non-coordinate-adjusted y values
    162.   */
    163. public List<Double> getYValues(double startx, double endx, double changeinterval){
    164. List<Double> vals = new ArrayList<Double>();
    165. for(double x = startx; x <= endx;){
    166. double d = Math.pow(x, 2.0) * this.a;
    167. if(d == 0){
    168. d = 1.0;
    169. }
    170. d = this.b * x + d;
    171. if(d == 0){
    172. d = 1.0;
    173. }
    174. d = d + this.c;
    175. vals.add(d);
    176. x = x + changeinterval;
    177. }
    178. return vals;
    179. }
    180.  
    181. /**
    182.   * Used to get the locations of points in a quadratic.
    183.   *
    184.   * @param startx - the smallest x value that will be used to find y values
    185.   * @param endx - the largest x value that will be used to find y values
    186.   * @param changeinterval - the rate at which the x increases from startx to endx
    187.   * @param baseX - the x that is added to the non-coordinate-adjusted to find the block at a location
    188.   * @param baseY - the y that is added to the non-coordinate-adjusted to find the block at a location
    189.   * @param baseZ - the z that is added to the non-coordinate-adjusted to find the block at a location
    190.   * @param w - the world the blocks originate within
    191.   * @param rotateForZAsXAxis - boolean as to whether or not the quadratic will be rotated to be aligned with the z axis
    192.   * @return - list of locations in a coordinate-aligned quadratic
    193.   */
    194. public List<Location> getLocationsInCoordinateAlignedQuadratic(double startx, double endx, double changeinterval, double baseX, double baseY, double baseZ, World w, boolean rotateForZAsXAxis){
    195. List<Location> vals = new ArrayList<Location>();
    196. if(!rotateForZAsXAxis){
    197. for(double x = startx; x <= endx;){
    198. double d = Math.pow(x, 2.0) * this.a;
    199. d = this.b * x + d;
    200. d = d + this.c;
    201. Location loc = new Location(w, x + baseX, d + baseY, baseZ);
    202. if(!(d + baseY >= w.getMaxHeight())){
    203. vals.add(loc);
    204. }
    205. x = x + changeinterval;
    206. }
    207. }
    208. if(rotateForZAsXAxis){
    209. for(double x = startx; x <= endx;){
    210. double d = Math.pow(x, 2.0) * this.a;
    211. if(d == 0){
    212. d = 1.0;
    213. }
    214. d = this.b * x + d;
    215. if(d == 0){
    216. d = 1.0;
    217. }
    218. d = d + this.c;
    219. if(d + baseY >= w.getMaxHeight()){
    220. break;
    221. }
    222. Location loc = new Location(w, baseX, d + baseY, baseZ + x);
    223. if(!(d + baseY >= w.getMaxHeight())){
    224. vals.add(loc);
    225. }
    226. x = x + changeinterval;
    227. }
    228. }
    229. this.startx = startx;
    230. this.endx = endx;
    231. this.changeinterval = changeinterval;
    232. this.locs = vals;
    233. return vals;
    234. }
    235.  
    236. /**
    237.   * Used to find locations in a parabola that is rotated to the player's yaw.
    238.   *
    239.   * @param p - player who's yaw a location will be used to compute
    240.   * @param startx - the smallest x value that will be used to find y values
    241.   * @param endx - the largest x value that will be used to find y values
    242.   * @param changeinterval - the rate at which the x increases from startx to endx
    243.   * @return - list of locations that have been aligned with the player's yaw
    244.   */
    245. public List<Location> getLocationsInPlayerAlignedQuadratic(Player p, double startx, double endx, double changeinterval){
    246. List<Location> locs = getLocationsInCoordinateAlignedQuadratic(startx, endx, changeinterval, p.getLocation().getX(), p.getLocation().getY(), p.getLocation().getZ(), p.getWorld(), false);
    247. List<Location> newlocs = new ArrayList<Location>();
    248. Location loca = p.getLocation();
    249. Float yaw1 = loca.getYaw();
    250. double yaw = Math.toRadians(yaw1);
    251. for(Location loc : locs){
    252. double rotatedX = Math.cos(yaw) * (loc.getX() - loca.getX()) - Math.sin(yaw) * (loc.getZ()-loca.getZ()) + loca.getX();
    253. double rotatedZ = Math.sin(yaw) * (loc.getX() - loca.getX()) + Math.cos(yaw) * (loc.getZ() - loca.getZ()) + loca.getZ();
    254. newlocs.add(new Location(p.getWorld(), rotatedX, loc.getY(), rotatedZ));
    255. }
    256. this.startx = startx;
    257. this.endx = endx;
    258. this.changeinterval = changeinterval;
    259. this.locs = newlocs;
    260. return newlocs;
    261. }
    262.  
    263. /**
    264.   * Used to get all the locations within a given quadratic with regards to x and y boundaries.
    265.   * This method requires that global variables endx, startx, and locs not be null.
    266.   *
    267.   * @param ymin - the smallest y that a location can have to be added to the list of locations
    268.   * @param ymax - the largest y that a location can have to be added to the list of locations
    269.   * @return - list of locations within a given quadratic
    270.   */
    271. public List<Location> getLocationsWithinCoordinateAlignedQuadratic(double ymin, double ymax){
    272. List<Location> allLocs = new ArrayList<Location>();
    273. for(Location loc : locs){
    274. if(loc.getX() >= startx && loc.getX() <= endx){
    275. while(loc.getY() >= ymin && loc.getY() <= ymax){
    276. allLocs.add(new Location(loc.getWorld(), loc.getX(), loc.getY(), loc.getZ()));
    277. loc.setY(loc.getY() + 1.0);
    278. }
    279. }
    280. }
    281. return allLocs;
    282. }
    283.  
    284. /**
    285.   * Used to get the y value of the y intercept.
    286.   *
    287.   * @return - the y value of the y intercept(where x = 0)
    288.   */
    289. public double getYIntercept(){
    290. return this.c;
    291. }
    292.  
    293. /**
    294.   * Used to get the blocks in a quadratic aligned with the x or z axis.
    295.   *
    296.   * @param startx - the smallest x value that will be used to find y values
    297.   * @param endx - the largest x value that will be used to find y values
    298.   * @param changeinterval - the rate at which the x increases from startx to endx
    299.   * @param baseX - the x that is added to the non-coordinate-adjusted to find the block at a location
    300.   * @param baseY - the y that is added to the non-coordinate-adjusted to find the block at a location
    301.   * @param baseZ - the z that is added to the non-coordinate-adjusted to find the block at a location
    302.   * @param w - the world the blocks originate within
    303.   * @param rotateForZAsXAxis - boolean as to whether or not the quadratic will be rotated to be aligned with the z axis
    304.   * @return - list of blocks the quadratic passes through
    305.   */
    306. public List<Block> getBlocksInCoordinateAlignedQuadratic(double startx, double endx, double changeinterval, double baseX, double baseY, double baseZ, World w, boolean rotateForZAsXAxis){
    307. List<Block> vals = new ArrayList<Block>();
    308. if(!rotateForZAsXAxis){
    309. for(double x = startx; x <= endx;){
    310. double d = Math.pow(x, 2.0) * this.a;
    311. if(d == 0){
    312. d = 1.0;
    313. }
    314. d = this.b * x + d;
    315. if(d == 0){
    316. d = 1.0;
    317. }
    318. d = d + this.c;
    319. vals.add(w.getBlockAt(new Location(w, baseX + x, baseY + d, baseZ)));
    320. x = x + changeinterval;
    321. }
    322. }
    323. if(rotateForZAsXAxis){
    324. for(double x = startx; x <= endx;){
    325. double d = Math.pow(x, 2.0) * this.a;
    326. if(d == 0){
    327. d = 1.0;
    328. }
    329. d = this.b * x + d;
    330. if(d == 0){
    331. d = 1.0;
    332. }
    333. d = d + this.c;
    334. vals.add(w.getBlockAt(new Location(w, baseX, baseY + d, baseZ + x)));
    335. x = x + changeinterval;
    336. }
    337. }
    338. this.startx = startx;
    339. this.endx = endx;
    340. this.changeinterval = changeinterval;
    341. blocks = vals;
    342. return vals;
    343. }
    344.  
    345. /**
    346.   * Used to get the blocks in a quadratic aligned with the player.
    347.   *
    348.   * @param p - player who's yaw a location will be used to compute
    349.   * @param startx - the smallest x value that will be used to find y values
    350.   * @param endx - the largest x value that will be used to find y values
    351.   * @param changeinterval - the rate at which the x increases from startx to endx
    352.   * @return - list of blocks in a parabola aligned with the player
    353.   */
    354. public List<Block> getBlocksInPlayerAlignedQuadratic(Player p, double startx, double endx, double changeinterval){
    355. List<Location> locs = getLocationsInCoordinateAlignedQuadratic(startx, endx, changeinterval, p.getLocation().getX(), p.getLocation().getY(), p.getLocation().getZ(), p.getWorld(), false);
    356. List<Location> newlocs = new ArrayList<Location>();
    357. Location loca = p.getLocation();
    358. Float yaw = loca.getYaw() + 90f;
    359. if(yaw > 360){
    360. yaw = yaw - 360;
    361. }
    362. for(Location loc : locs){
    363. double rotatedX = Math.cos(yaw) * (loc.getX() - loca.getX()) - Math.sin(yaw) * (loc.getZ()-loca.getZ()) + loca.getX();
    364. double rotatedZ = Math.sin(yaw) * (loc.getX() - loca.getX()) + Math.cos(yaw) * (loc.getZ() - loca.getZ()) + loca.getZ();
    365. newlocs.add(new Location(p.getWorld(), rotatedX, loc.getY(), rotatedZ));
    366. }
    367. List<Block> blocks1 = new ArrayList<Block>();
    368. for(Location loc : newlocs){
    369. blocks1.add(p.getWorld().getBlockAt(loc));
    370. }
    371. this.startx = startx;
    372. this.endx = endx;
    373. this.changeinterval = changeinterval;
    374. blocks = blocks1;
    375. return blocks1;
    376. }
    377.  
    378. /**
    379.   * Used for rotating a list of locations about a location a given amount of degrees.
    380.   *
    381.   * @param rotatedegrees - degrees the locations will be rotated
    382.   * @param rotateAround - locations the locations will be rotated about
    383.   * @param locations - list of locations
    384.   * @return - returns a list of new locations
    385.   */
    386. public List<Location> rotateLocationsAboutYAxis(float rotatedegrees, Location rotateAround, List<Location> locations){
    387. List<Location> newlocs = new ArrayList<Location>();
    388. Location loca = new Location(rotateAround.getWorld(), rotateAround.getX(), rotateAround.getY(), rotateAround.getZ());
    389. for(Location loc : locations){
    390. double rotatedX = Math.cos(rotatedegrees) * (loc.getX() - loca.getX()) - Math.sin(rotatedegrees) * (loc.getZ()-loca.getZ()) + loca.getX();
    391. double rotatedZ = Math.sin(rotatedegrees) * (loc.getX() - loca.getX()) + Math.cos(rotatedegrees) * (loc.getZ() - loca.getZ()) + loca.getZ();
    392. newlocs.add(new Location(loca.getWorld(), rotatedX, loc.getY(), rotatedZ));
    393. }
    394. locs = newlocs;
    395. return newlocs;
    396. }
    397.  
    398. /**
    399.   * This method requires that you've used methods that set the glocal List<Location> locs and Location base or that you've set the global List<Location> locs and Location base.
    400.   * Used to rotate locations in a quadratic.
    401.   *
    402.   * @param rotatedegrees - degrees the locations will be rotated
    403.   * @return - returns a list of new locations
    404.   */
    405. public List<Location> rotateAboutYAxis(float rotatedegrees){
    406. List<Location> newlocs = new ArrayList<Location>();
    407. Location loca = new Location(base.getWorld(), base.getX(), base.getY(), base.getZ());
    408. for(Location loc : locs){
    409. double rotatedX = Math.cos(rotatedegrees) * (loc.getX() - loca.getX()) - Math.sin(rotatedegrees) * (loc.getZ()-loca.getZ()) + loca.getX();
    410. double rotatedZ = Math.sin(rotatedegrees) * (loc.getX() - loca.getX()) + Math.cos(rotatedegrees) * (loc.getZ() - loca.getZ()) + loca.getZ();
    411. newlocs.add(new Location(loca.getWorld(), rotatedX, loc.getY(), rotatedZ));
    412. }
    413. locs = newlocs;
    414. return newlocs;
    415. }
    416.  
    417. /**
    418.   * Used to rotate a quadratic about the x axis
    419.   *
    420.   * @param rotatedegrees - degrees the locations will be rotated
    421.   * @param rotateAround - locations the locations will be rotated about
    422.   * @param locations - list of locations
    423.   * @return - list of locations rotated about the X axis
    424.   */
    425. public List<Location> rotateLocationsAboutXAxis(float rotatedegrees, Location rotateAround, List<Location> locations){
    426. List<Location> newlocs = new ArrayList<Location>();
    427. Location loca = new Location(rotateAround.getWorld(), rotateAround.getX(), rotateAround.getY(), rotateAround.getZ());
    428. for(Location loc : locations){
    429. double rotatedZ = Math.cos(rotatedegrees) * (loc.getZ() - loca.getZ()) - Math.sin(rotatedegrees) * (loc.getY() - loca.getY()) + loca.getZ();
    430. double rotatedY = Math.sin(rotatedegrees) * (loc.getZ() - loca.getZ()) + Math.cos(rotatedegrees) * (loc.getY() - loca.getY()) + loca.getY();
    431. newlocs.add(new Location(loca.getWorld(), loc.getX(), rotatedY, rotatedZ));
    432. }
    433. locs = newlocs;
    434. return newlocs;
    435. }
    436.  
    437. /**
    438.   * This method the global variables locs and base not be null.
    439.   * Used to rotate a quadratic about the x axis.
    440.   *
    441.   * @param rotatedegrees - degrees the locations will be rotated
    442.   * @return - list of locations rotated about the X axis
    443.   */
    444. public List<Location> rotateAboutXAxis(float rotatedegrees){
    445. List<Location> newlocs = new ArrayList<Location>();
    446. Location loca = new Location(base.getWorld(), base.getX(), base.getY(), base.getZ());
    447. for(Location loc : locs){
    448. double rotatedY = Math.cos(rotatedegrees) * (loc.getY() - loca.getY()) - Math.sin(rotatedegrees) * (loc.getZ()-loca.getZ()) + loca.getY();
    449. double rotatedZ = Math.sin(rotatedegrees) * (loc.getY() - loca.getY()) + Math.cos(rotatedegrees) * (loc.getZ() - loca.getZ()) + loca.getZ();
    450. newlocs.add(new Location(loca.getWorld(), loc.getX(), rotatedY, rotatedZ));
    451. }
    452. locs = newlocs;
    453. return newlocs;
    454. }
    455.  
    456. /**
    457.   * Used to create a new, arbitrary instance of the quadratic.
    458.   *
    459.   * @return - A new instance of the quadratic.
    460.   */
    461. @Override
    462. public Quadratic clone() throws CloneNotSupportedException{
    463. return new Quadratic(this.a, this.b, this.c);
    464. }
    465.  
    466. @Override
    467. public Map<String, Object> serialize() {
    468. Double a = this.a;
    469. Double b = this.b;
    470. Double c = this.c;
    471. if(a == null || b == null || c == null){
    472. throw new NullPointerException("Make sure the most basic a,b,c variables are not null!");
    473. }
    474. Double startx = this.startx;
    475. Double endx = this.endx;
    476. Double changeinterval = this.changeinterval;
    477. if(startx == null || endx == null || changeinterval == null){
    478. Map<String, Object> map = new HashMap<String, Object>();
    479. map.put("a", this.a);
    480. map.put("b", this.b);
    481. map.put("c", this.c);
    482. return map;
    483. }
    484. if(this.base == null){
    485. Map<String, Object> map = new HashMap<String, Object>();
    486. map.put("a", this.a);
    487. map.put("b", this.b);
    488. map.put("c", this.c);
    489. map.put("startx", this.startx);
    490. map.put("endx", this.endx);
    491. map.put("changeInterval", this.changeinterval);
    492. return map;
    493. }
    494. if(this.locs == null){
    495. Map<String, Object> map = new HashMap<String, Object>();
    496. map.put("a", this.a);
    497. map.put("b", this.b);
    498. map.put("c", this.c);
    499. map.put("startx", this.startx);
    500. map.put("endx", this.endx);
    501. map.put("changeInterval", this.changeinterval);
    502. map.put("base", this.base);
    503. return map;
    504. }
    505. if(this.blocks == null){
    506. Map<String, Object> map = new HashMap<String, Object>();
    507. map.put("a", this.a);
    508. map.put("b", this.b);
    509. map.put("c", this.c);
    510. map.put("startx", this.startx);
    511. map.put("endx", this.endx);
    512. map.put("changeInterval", this.changeinterval);
    513. map.put("base", this.base);
    514. map.put("locs", this.locs);
    515. return map;
    516. }
    517. Map<String, Object> map = new HashMap<String, Object>();
    518. map.put("a", this.a);
    519. map.put("b", this.b);
    520. map.put("c", this.c);
    521. map.put("startx", this.startx);
    522. map.put("endx", this.endx);
    523. map.put("changeInterval", this.changeinterval);
    524. map.put("base", this.base);
    525. map.put("locs", this.locs);
    526. map.put("blocks", this.blocks);
    527. return map;
    528. }
    529.  
    530. //-------------------------------------------
    531.  
    532. }



    Post reserved in case I find something cool or for update changes.

    If you're having trouble, please feel free to ask me! Just be sure to include a stack trace and the code! I'm always happy to do some math!

    Updates
    8/4/2014: Fixed huge bug caused by not converting degrees to radians as well as added configuration serializable.​

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 9, 2016
  2. Offline

    ccrama

    What application did you use this code in?
     
  3. Offline

    JBoss925

    I used it to create a parabola that a throwable object (in game of course) would follow so as to replicate throwing with more velocity as well as a few other things.
     
    Phasesaber likes this.
  4. Offline

    bobacadodl

    Code:
     this.a = Double.parseDouble(String.valueOf(a).concat(".0"));
    wat...
     
    Bloxcraft, Zupsub and Garris0n like this.
  5. Offline

    MiniDigger

    bobacadodl How would you convert a int into an double? Cast it? Nah, don't be stupid, that would be too easy
     
  6. Offline

    JBoss925

    Lol, it's because I wanted it to return a Double not a double and there can be problems when casting to (Double) but I understand yes it's stupid. I fixed it.
     
Thread Status:
Not open for further replies.

Share This Page