PageRenderTime 62ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/libTopology/src/com/graphbuilder/curve/LagrangeCurve.java

https://bitbucket.org/jorgenio/gvsig
Java | 294 lines | 147 code | 45 blank | 102 comment | 32 complexity | d9ce77ec73399830657e348ec0f39e61 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception
  1. package com.graphbuilder.curve;
  2. /**
  3. <p>The Lagrange curve passes through the control-points specified by the group-iterator.
  4. It uses a knot-vector to control when the curve passes through each control-point. That is,
  5. if there is a knot-value for every control-point, then the curve will pass through point i
  6. when the value of t is knot[i], which is an interesting property. Figure 1 is an example of
  7. this.
  8. <p><center><img align="center" src="doc-files/lagrange1.gif"/></center>
  9. <p>In addition, when there is a knot-value for every point then the base-index should be 0, and the
  10. base-length should be n-1, where n is the size of the group-iterator.
  11. <p>A knot-vector with size less than n can still be used. In this case the Lagrange curve is
  12. generated in multiple sections. This approach works better when the points are roughly equally
  13. spaced. Figure 2 is an example of this.
  14. <p><center><img align="center" src="doc-files/lagrange2.gif"/></center>
  15. <p>Lagrange curves and also be closed as shown in figures 3 &amp; 4.
  16. <p><center><img align="center" src="doc-files/lagrange3.gif"/></center>
  17. <p><center><img align="center" src="doc-files/lagrange4.gif"/></center>
  18. <p>Notes on the knot-vector, base-index and base-length. The size of the knot-vector specifies how many
  19. points are used for each section of the curve. The base-index specifies which point a section starts
  20. at. The base-index + base-length specify which point the section ends at. Once a section has been
  21. generated, the next section is generated starting from the end of the last section.
  22. */
  23. public class LagrangeCurve extends ParametricCurve {
  24. private ValueVector knotVector = new ValueVector(new double[] { 0.0, 1.0 / 3.0, 2.0 / 3.0, 1.0 }, 4);
  25. private int baseIndex = 1;
  26. private int baseLength = 1;
  27. private boolean interpolateFirst = false;
  28. private boolean interpolateLast = false;
  29. private static double[][] pt = new double[0][];
  30. /**
  31. Creates a LagrangeCurve with knot vector [0, 1/3, 2/3, 1], baseIndex == 1, baseLength == 1,
  32. interpolateFirst and interpolateLast are both false. The knot vector, baseIndex and baseLength
  33. along with the control points define the shape of curve. See the appendTo method for more information.
  34. @see #appendTo(MultiPath)
  35. */
  36. public LagrangeCurve(ControlPath cp, GroupIterator gi) {
  37. super(cp, gi);
  38. }
  39. /**
  40. Returns the base-index. The default value is 1.
  41. @see #setBaseIndex(int)
  42. */
  43. public int getBaseIndex() {
  44. return baseIndex;
  45. }
  46. /**
  47. The base-index is an index location into the knot vector such that, for each section, the curve is
  48. evaluated between [knot[baseIndex], knot[baseIndex + baseLength]].
  49. @throws IllegalArgumentException If base-index < 0.
  50. @see #getBaseIndex()
  51. */
  52. public void setBaseIndex(int b) {
  53. if (b < 0) throw new IllegalArgumentException("base index >= 0 required.");
  54. baseIndex = b;
  55. }
  56. /**
  57. Returns the base-length. The default value is 1.
  58. @see #setBaseLength(int)
  59. */
  60. public int getBaseLength() {
  61. return baseLength;
  62. }
  63. /**
  64. The base-length along with the base-index specify the interval to evaluate each section.
  65. @throws IllegalArgumentException If base-length <= 0.
  66. @see #getBaseLength()
  67. */
  68. public void setBaseLength(int b) {
  69. if (b <= 0) throw new IllegalArgumentException("base length > 0 required.");
  70. baseLength = b;
  71. }
  72. /**
  73. If baseIndex > 0 then the first control-points will only be interpolated if interpolate-first
  74. is set to true.
  75. @see #setInterpolateFirst(boolean)
  76. */
  77. public boolean getInterpolateFirst() {
  78. return interpolateFirst;
  79. }
  80. /**
  81. If baseIndex + baseLength < numKnots - 1 then the last control-points will only be interpolated if
  82. interpolate-last is set to true.
  83. @see #setInterpolateLast(boolean)
  84. */
  85. public boolean getInterpolateLast() {
  86. return interpolateLast;
  87. }
  88. /**
  89. Sets the value of the interpolateFirst flag.
  90. @see #getInterpolateFirst()
  91. */
  92. public void setInterpolateFirst(boolean b) {
  93. interpolateFirst = b;
  94. }
  95. /**
  96. Sets the value of the interpolateLast flag.
  97. @see #getInterpolateLast()
  98. */
  99. public void setInterpolateLast(boolean b) {
  100. interpolateLast = b;
  101. }
  102. /**
  103. Returns the knot-vector for this curve.
  104. @see #setKnotVector(ValueVector)
  105. */
  106. public ValueVector getKnotVector() {
  107. return knotVector;
  108. }
  109. /**
  110. Sets the knot-vector for this curve.
  111. @see #getKnotVector()
  112. @throws IllegalArgumentException If the value-vector is null.
  113. */
  114. public void setKnotVector(ValueVector v) {
  115. if (v == null)
  116. throw new IllegalArgumentException("Knot-vector cannot be null.");
  117. knotVector = v;
  118. }
  119. /**
  120. Returns a value of 1.
  121. */
  122. public int getSampleLimit() {
  123. return 1;
  124. }
  125. protected void eval(double[] p) {
  126. double t = p[p.length - 1];
  127. int n = knotVector.size();
  128. for (int i = 0; i < n; i++) {
  129. double[] q = pt[i];
  130. double L = L(t, i);
  131. for (int j = 0; j < p.length - 1; j++)
  132. p[j] += q[j] * L;
  133. }
  134. }
  135. private double L(double t, int i) {
  136. double d = 1.0;
  137. int n = knotVector.size();
  138. for (int j = 0; j < n; j++) {
  139. double e = knotVector.get(i) - knotVector.get(j);
  140. if (e != 0)
  141. d = d * ((t - knotVector.get(j)) / e);
  142. }
  143. return d;
  144. }
  145. /**
  146. For the control-points to be interpolated in order, the knot-vector values should be strictly
  147. increasing, however that is not required. The requirements are the group-iterator must be in
  148. range and baseIndex + baseLength < numKnots. As well, the number of points defined by the
  149. group-iterator must be >= numKnots, otherwise the curve does not have enough control-points
  150. to define itself. If any of these requirements are not met, then this method returns quietly.
  151. */
  152. public void appendTo(MultiPath mp) {
  153. if (!gi.isInRange(0, cp.numPoints())) return;
  154. if (baseIndex + baseLength >= knotVector.size()) return;
  155. if (pt.length < knotVector.size())
  156. pt = new double[2 * knotVector.size()][];
  157. gi.set(0, 0);
  158. boolean b = false;
  159. if (baseIndex != 0 && interpolateFirst) {
  160. for (int i = 0; i < knotVector.size(); i++) {
  161. if (!gi.hasNext()) return;
  162. pt[i] = cp.getPoint(gi.next()).getLocation();
  163. }
  164. b = doBCAA(mp, knotVector.get(0), knotVector.get(baseIndex), b);
  165. }
  166. gi.set(0, 0);
  167. int last_i = 0;
  168. int last_j = 0;
  169. while (true) {
  170. int temp_i = gi.index_i();
  171. int temp_j = gi.count_j();
  172. int index_i = 0;
  173. int count_j = 0;
  174. int i = 0;
  175. int j = 0;
  176. for (; j < knotVector.size(); j++) {
  177. if (i == baseLength) {
  178. index_i = gi.index_i();
  179. count_j = gi.count_j();
  180. }
  181. if (!gi.hasNext()) break;
  182. pt[j] = cp.getPoint(gi.next()).getLocation();
  183. i++;
  184. }
  185. if (j < knotVector.size()) {
  186. break;
  187. }
  188. else {
  189. gi.set(index_i, count_j);
  190. last_i = temp_i;
  191. last_j = temp_j;
  192. }
  193. b = doBCAA(mp, knotVector.get(baseIndex), knotVector.get(baseIndex + baseLength), b);
  194. }
  195. if (baseIndex + baseLength < knotVector.size() - 1 && interpolateLast) {
  196. gi.set(last_i, last_j);
  197. for (int i = 0; i < knotVector.size(); i++) {
  198. if (!gi.hasNext()) {
  199. System.out.println("not enough points to interpolate last");
  200. return;
  201. }
  202. pt[i] = cp.getPoint(gi.next()).getLocation();
  203. }
  204. doBCAA(mp, knotVector.get(baseIndex + baseLength), knotVector.get(knotVector.size() - 1), b);
  205. }
  206. }
  207. private boolean doBCAA(MultiPath mp, double t1, double t2, boolean b) {
  208. if (t2 < t1) {
  209. double temp = t1;
  210. t1 = t2;
  211. t2 = temp;
  212. }
  213. if (!b) {
  214. b = true;
  215. double[] d = new double[mp.getDimension() + 1];
  216. d[mp.getDimension()] = t1;
  217. eval(d);
  218. if (connect)
  219. mp.lineTo(d);
  220. else
  221. mp.moveTo(d);
  222. }
  223. BinaryCurveApproximationAlgorithm.genPts(this, t1, t2, mp);
  224. return b;
  225. }
  226. public void resetMemory() {
  227. if (pt.length > 0)
  228. pt = new double[0][];
  229. }
  230. }