curve.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /**
  2. * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Ludovic Autin <ludovic.autin@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { Vec3, Quat, Mat4 } from '../../mol-math/linear-algebra';
  8. import { NumberArray } from '../../mol-util/type-helpers';
  9. interface Frame {
  10. t: Vec3,
  11. r: Vec3,
  12. s: Vec3,
  13. }
  14. const a0Tmp = Vec3();
  15. const a1Tmp = Vec3();
  16. const a2Tmp = Vec3();
  17. const a3Tmp = Vec3();
  18. function CubicInterpolate(out: Vec3, y0: Vec3, y1: Vec3, y2: Vec3, y3: Vec3, mu: number): Vec3 {
  19. const mu2 = mu * mu;
  20. Vec3.sub(a0Tmp, y3, y2);
  21. Vec3.sub(a0Tmp, a0Tmp, y0);
  22. Vec3.add(a0Tmp, a0Tmp, y1);
  23. Vec3.sub(a1Tmp, y0, y1);
  24. Vec3.sub(a1Tmp, a1Tmp, a0Tmp);
  25. Vec3.sub(a2Tmp, y2, y0);
  26. Vec3.copy(a3Tmp, y1);
  27. out[0] = a0Tmp[0] * mu * mu2 + a1Tmp[0] * mu2 + a2Tmp[0] * mu + a3Tmp[0];
  28. out[1] = a0Tmp[1] * mu * mu2 + a1Tmp[1] * mu2 + a2Tmp[1] * mu + a3Tmp[1];
  29. out[2] = a0Tmp[2] * mu * mu2 + a1Tmp[2] * mu2 + a2Tmp[2] * mu + a3Tmp[2];
  30. return out;
  31. }
  32. const cp0 = Vec3();
  33. const cp1 = Vec3();
  34. const cp2 = Vec3();
  35. const cp3 = Vec3();
  36. const currentPosition = Vec3();
  37. function ResampleControlPoints(points: NumberArray, segmentLength: number) {
  38. const nP = points.length / 3;
  39. // insert a point at the end and at the begining
  40. // controlPoints.Insert(0, controlPoints[0] + (controlPoints[0] - controlPoints[1]) / 2.0f);
  41. // controlPoints.Add(controlPoints[nP - 1] + (controlPoints[nP - 1] - controlPoints[nP - 2]) / 2.0f);
  42. const resampledControlPoints: Vec3[] = [];
  43. // resampledControlPoints.Add(controlPoints[0]);
  44. // resampledControlPoints.Add(controlPoints[1]);
  45. let idx = 1;
  46. // const currentPosition = Vec3.create(points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2])
  47. Vec3.fromArray(currentPosition, points, idx * 3);
  48. let lerpValue = 0.0;
  49. // Normalize the distance between control points
  50. while (true) {
  51. if (idx + 2 >= nP) break;
  52. Vec3.fromArray(cp0, points, (idx - 1) * 3);
  53. Vec3.fromArray(cp1, points, idx * 3);
  54. Vec3.fromArray(cp2, points, (idx + 1) * 3);
  55. Vec3.fromArray(cp3, points, (idx + 2) * 3);
  56. // const cp0 = Vec3.create(points[(idx-1)*3], points[(idx-1)*3+1], points[(idx-1)*3+2]) // controlPoints[currentPointId - 1];
  57. // const cp1 = Vec3.create(points[idx*3], points[idx*3+1], points[idx*3+2]) // controlPoints[currentPointId];
  58. // const cp2 = Vec3.create(points[(idx+1)*3], points[(idx+1)*3+1], points[(idx+1)*3+2]) // controlPoints[currentPointId + 1];
  59. // const cp3 = Vec3.create(points[(idx+2)*3], points[(idx+2)*3+1], points[(idx+2)*3+2]); // controlPoints[currentPointId + 2];
  60. let found = false;
  61. for (; lerpValue <= 1; lerpValue += 0.01) {
  62. // lerp?slerp
  63. // let candidate:Vec3 = Vec3.lerp(Vec3.zero(), cp0, cp1, lerpValue);
  64. // const candidate:Vec3 = Vec3.bezier(Vec3.zero(), cp0, cp1, cp2, cp3, lerpValue);
  65. const candidate = CubicInterpolate(Vec3(), cp0, cp1, cp2, cp3, lerpValue);
  66. const d = Vec3.distance(currentPosition, candidate);
  67. if (d > segmentLength) {
  68. resampledControlPoints.push(candidate);
  69. Vec3.copy(currentPosition, candidate);
  70. found = true;
  71. break;
  72. }
  73. }
  74. if (!found) {
  75. lerpValue = 0;
  76. idx += 1;
  77. }
  78. }
  79. return resampledControlPoints;
  80. }
  81. const prevV = Vec3();
  82. const tmpV1 = Vec3();
  83. const tmpV2 = Vec3();
  84. const tmpV3 = Vec3();
  85. // easier to align to theses normals
  86. function GetSmoothNormals(points: Vec3[]) {
  87. const nP: number = points.length;
  88. const smoothNormals: Vec3[] = [];
  89. if (points.length < 3) {
  90. for (let i = 0; i < points.length; ++i)
  91. smoothNormals.push(Vec3.normalize(Vec3(), points[i]));
  92. return smoothNormals;
  93. }
  94. let p0 = points[0];
  95. let p1 = points[1];
  96. let p2 = points[2];
  97. const p21 = Vec3.sub(tmpV1, p2, p1);
  98. const p01 = Vec3.sub(tmpV2, p0, p1);
  99. const p0121 = Vec3.cross(tmpV3, p01, p21);
  100. Vec3.normalize(prevV, p0121);
  101. smoothNormals.push(Vec3.clone(prevV));
  102. for (let i = 1; i < points.length - 1; ++i) {
  103. p0 = points[i - 1];
  104. p1 = points[i];
  105. p2 = points[i + 1];
  106. const t = Vec3.normalize(tmpV1, Vec3.sub(tmpV1, p2, p0));
  107. const b = Vec3.normalize(tmpV2, Vec3.cross(tmpV2, t, prevV));
  108. const n = Vec3.normalize(Vec3(), Vec3.cross(tmpV3, t, b));
  109. Vec3.negate(n, n);
  110. Vec3.copy(prevV, n);
  111. smoothNormals.push(n);
  112. }
  113. const last = Vec3();
  114. Vec3.normalize(last, Vec3.cross(last,
  115. Vec3.sub(tmpV1, points[nP - 3], points[nP - 2]),
  116. Vec3.sub(tmpV2, points[nP - 2], points[nP - 1]))
  117. );
  118. smoothNormals.push(last);
  119. return smoothNormals;
  120. }
  121. const frameTmpV1 = Vec3();
  122. const frameTmpV2 = Vec3();
  123. const frameTmpV3 = Vec3();
  124. function getFrame(reference: Vec3, tangent: Vec3) {
  125. const t = Vec3.normalize(Vec3(), tangent);
  126. // make reference vector orthogonal to tangent
  127. const proj_r_to_t = Vec3.scale(
  128. frameTmpV1, tangent, Vec3.dot(reference, tangent) / Vec3.dot(tangent, tangent)
  129. );
  130. const r = Vec3.normalize(Vec3(), Vec3.sub(frameTmpV2, reference, proj_r_to_t));
  131. // make bitangent vector orthogonal to the others
  132. const s = Vec3.normalize(Vec3(), Vec3.cross(frameTmpV3, t, r));
  133. return { t, r, s };
  134. }
  135. const mfTmpV1 = Vec3();
  136. const mfTmpV2 = Vec3();
  137. const mfTmpV3 = Vec3();
  138. const mfTmpV4 = Vec3();
  139. const mfTmpV5 = Vec3();
  140. const mfTmpV6 = Vec3();
  141. const mfTmpV7 = Vec3();
  142. const mfTmpV8 = Vec3();
  143. const mfTmpV9 = Vec3();
  144. // easier to align to theses normals
  145. // https://github.com/bzamecnik/gpg/blob/master/rotation-minimizing-frame/rmf.py
  146. function GetMiniFrame(points: Vec3[], normals: Vec3[]) {
  147. const frames: Frame[] = [];
  148. const t0 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[1], points[0]));
  149. frames.push(getFrame(normals[0], t0));
  150. for (let i = 0; i < points.length - 2; ++i) {
  151. const t2 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[i + 2], points[i + 1]));
  152. const v1 = Vec3.sub(mfTmpV2, points[i + 1], points[i]); // this is tangeant
  153. const c1 = Vec3.dot(v1, v1);
  154. // compute r_i^L = R_1 * r_i
  155. const v1r = Vec3.scale(mfTmpV3, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].r));
  156. const ref_L_i = Vec3.sub(mfTmpV4, frames[i].r, v1r);
  157. // compute t_i^L = R_1 * t_i
  158. const v1t = Vec3.scale(mfTmpV5, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].t));
  159. const tan_L_i = Vec3.sub(mfTmpV6, frames[i].t, v1t);
  160. // # compute reflection vector of R_2
  161. const v2 = Vec3.sub(mfTmpV7, t2, tan_L_i);
  162. const c2 = Vec3.dot(v2, v2);
  163. // compute r_(i+1) = R_2 * r_i^L
  164. const v2l = Vec3.scale(mfTmpV8, v1, (2.0 / c2) * Vec3.dot(v2, ref_L_i));
  165. const ref_next = Vec3.sub(mfTmpV9, ref_L_i, v2l); // ref_L_i - (2 / c2) * v2.dot(ref_L_i) * v2
  166. frames.push(getFrame(ref_next, t2)); // frames.append(Frame(ref_next, tangents[i+1]))
  167. }
  168. return frames;
  169. }
  170. const rpTmpVec1 = Vec3();
  171. export function getMatFromResamplePoints(points: NumberArray, segmentLength: number, resample: boolean) {
  172. let new_points: Vec3[] = [];
  173. if (resample) new_points = ResampleControlPoints(points, segmentLength);
  174. else {
  175. for (let idx = 0; idx < points.length / 3; ++idx) {
  176. new_points.push(Vec3.fromArray(Vec3.zero(), points, idx * 3));
  177. }
  178. }
  179. const npoints = new_points.length;
  180. const new_normal = GetSmoothNormals(new_points);
  181. const frames = GetMiniFrame(new_points, new_normal);
  182. const limit = npoints;
  183. const transforms: Mat4[] = [];
  184. const pti = Vec3.copy(rpTmpVec1, new_points[0]);
  185. for (let i = 0; i < npoints - 2; ++i) {
  186. const pti1: Vec3 = new_points[i + 1]; // Vec3.create(points[(i+1)*3],points[(i+1)*3+1],points[(i+1)*3+2]);
  187. const d = Vec3.distance(pti, pti1);
  188. if (d >= segmentLength) {
  189. // use twist or random?
  190. const quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t); // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal
  191. const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random() * 3.60); // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();//
  192. const m = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)); // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat));
  193. // let pos:Vec3 = Vec3.add(Vec3.zero(),pti1,pti)
  194. // pos = Vec3.scale(pos,pos,1.0/2.0);
  195. // Vec3.makeRotation(Mat4.zero(),Vec3.create(0,0,1),frames[i].t);//
  196. Mat4.setTranslation(m, pti1);
  197. // let m2:Mat4 = GetTubePropertiesMatrix(pti,pti1);
  198. // let q:Quat = Quat.rotationTo(Quat.zero(), Vec3.create(0,1,0),Vec3.create(0,0,1))
  199. // m2=Mat4.mul(Mat4.identity(),Mat4.fromQuat(Mat4.zero(),q),m2);
  200. transforms.push(m);
  201. Vec3.copy(pti, pti1);
  202. }
  203. if (transforms.length >= limit) break;
  204. }
  205. return transforms;
  206. }