PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java

https://gitlab.com/Skull3x/WorldEdit
Java | 160 lines | 99 code | 33 blank | 28 comment | 17 complexity | 84dcd1c6b7b76588111479bdca49e306 MD5 | raw file
  1. /*
  2. * WorldEdit, a Minecraft world manipulation toolkit
  3. * Copyright (C) sk89q <http://www.sk89q.com>
  4. * Copyright (C) WorldEdit team and contributors
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU Lesser General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  14. * for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. // $Id$
  20. package com.sk89q.worldedit.math.interpolation;
  21. import com.sk89q.worldedit.Vector;
  22. import java.util.List;
  23. import java.util.Map.Entry;
  24. import java.util.TreeMap;
  25. import java.util.logging.Logger;
  26. import static com.google.common.base.Preconditions.checkNotNull;
  27. /**
  28. * Reparametrises another interpolation function by arc length.
  29. *
  30. * <p>This is done so entities travel at roughly the same speed across
  31. * the whole route.</p>
  32. */
  33. public class ReparametrisingInterpolation implements Interpolation {
  34. private static final Logger log = Logger.getLogger(ReparametrisingInterpolation.class.getCanonicalName());
  35. private final Interpolation baseInterpolation;
  36. private double totalArcLength;
  37. private final TreeMap<Double, Double> cache = new TreeMap<Double, Double>();
  38. public ReparametrisingInterpolation(Interpolation baseInterpolation) {
  39. checkNotNull(baseInterpolation);
  40. this.baseInterpolation = baseInterpolation;
  41. }
  42. @Override
  43. public void setNodes(List<Node> nodes) {
  44. checkNotNull(nodes);
  45. baseInterpolation.setNodes(nodes);
  46. cache.clear();
  47. cache.put(0.0, 0.0);
  48. cache.put(totalArcLength = baseInterpolation.arcLength(0.0, 1.0), 1.0);
  49. }
  50. public Interpolation getBaseInterpolation() {
  51. return baseInterpolation;
  52. }
  53. @Override
  54. public Vector getPosition(double position) {
  55. if (position > 1)
  56. return null;
  57. return baseInterpolation.getPosition(arcToParameter(position));
  58. }
  59. @Override
  60. public Vector get1stDerivative(double position) {
  61. if (position > 1)
  62. return null;
  63. return baseInterpolation.get1stDerivative(arcToParameter(position)).normalize().multiply(totalArcLength);
  64. }
  65. @Override
  66. public double arcLength(double positionA, double positionB) {
  67. return baseInterpolation.arcLength(arcToParameter(positionA), arcToParameter(positionB));
  68. }
  69. private double arcToParameter(double arc) {
  70. if (cache.isEmpty())
  71. throw new IllegalStateException("Must call setNodes first.");
  72. if (arc > 1) arc = 1;
  73. arc *= totalArcLength;
  74. Entry<Double, Double> floorEntry = cache.floorEntry(arc);
  75. final double leftArc = floorEntry.getKey();
  76. final double leftParameter = floorEntry.getValue();
  77. if (leftArc == arc) {
  78. return leftParameter;
  79. }
  80. Entry<Double, Double> ceilingEntry = cache.ceilingEntry(arc);
  81. if (ceilingEntry == null) {
  82. log.warning("Error in arcToParameter: no ceiling entry for " + arc + " found!");
  83. return 0;
  84. }
  85. final double rightArc = ceilingEntry.getKey();
  86. final double rightParameter = ceilingEntry.getValue();
  87. if (rightArc == arc) {
  88. return rightParameter;
  89. }
  90. return evaluate(arc, leftArc, leftParameter, rightArc, rightParameter);
  91. }
  92. private double evaluate(double arc, double leftArc, double leftParameter, double rightArc, double rightParameter) {
  93. double midParameter = 0;
  94. for (int i = 0; i < 10; ++i) {
  95. midParameter = (leftParameter + rightParameter) * 0.5;
  96. //final double midArc = leftArc + baseInterpolation.arcLength(leftParameter, midParameter);
  97. final double midArc = baseInterpolation.arcLength(0, midParameter);
  98. cache.put(midArc, midParameter);
  99. if (midArc < leftArc) {
  100. return leftParameter;
  101. }
  102. if (midArc > rightArc) {
  103. return rightParameter;
  104. }
  105. if (Math.abs(midArc - arc) < 0.01) {
  106. return midParameter;
  107. }
  108. if (arc < midArc) {
  109. // search between left and mid
  110. rightArc = midArc;
  111. rightParameter = midParameter;
  112. }
  113. else {
  114. // search between mid and right
  115. leftArc = midArc;
  116. leftParameter = midParameter;
  117. }
  118. }
  119. return midParameter;
  120. }
  121. @Override
  122. public int getSegment(double position) {
  123. if (position > 1)
  124. return Integer.MAX_VALUE;
  125. return baseInterpolation.getSegment(arcToParameter(position));
  126. }
  127. }