curve-segment.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /**
  2. * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Vec3 } from '../../../../../mol-math/linear-algebra';
  7. import { NumberArray } from '../../../../../mol-util/type-helpers';
  8. import { lerp } from '../../../../../mol-math/interpolate';
  9. // avoiding namespace lookup improved performance in Chrome (Aug 2020)
  10. const v3fromArray = Vec3.fromArray;
  11. const v3toArray = Vec3.toArray;
  12. const v3normalize = Vec3.normalize;
  13. const v3sub = Vec3.sub;
  14. const v3spline = Vec3.spline;
  15. const v3slerp = Vec3.slerp;
  16. const v3copy = Vec3.copy;
  17. const v3cross = Vec3.cross;
  18. const v3orthogonalize = Vec3.orthogonalize;
  19. const v3matchDirection = Vec3.matchDirection;
  20. export interface CurveSegmentState {
  21. curvePoints: NumberArray,
  22. tangentVectors: NumberArray,
  23. normalVectors: NumberArray,
  24. binormalVectors: NumberArray,
  25. widthValues: NumberArray,
  26. heightValues: NumberArray,
  27. linearSegments: number
  28. }
  29. export interface CurveSegmentControls {
  30. secStrucFirst: boolean, secStrucLast: boolean
  31. p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3,
  32. d12: Vec3, d23: Vec3
  33. }
  34. export function createCurveSegmentState(linearSegments: number): CurveSegmentState {
  35. const n = linearSegments + 1;
  36. const pn = n * 3;
  37. return {
  38. curvePoints: new Float32Array(pn),
  39. tangentVectors: new Float32Array(pn),
  40. normalVectors: new Float32Array(pn),
  41. binormalVectors: new Float32Array(pn),
  42. widthValues: new Float32Array(n),
  43. heightValues: new Float32Array(n),
  44. linearSegments
  45. };
  46. }
  47. export function interpolateCurveSegment(state: CurveSegmentState, controls: CurveSegmentControls, tension: number, shift: number) {
  48. interpolatePointsAndTangents(state, controls, tension, shift);
  49. interpolateNormals(state, controls);
  50. }
  51. const tanA = Vec3();
  52. const tanB = Vec3();
  53. const curvePoint = Vec3();
  54. export function interpolatePointsAndTangents(state: CurveSegmentState, controls: CurveSegmentControls, tension: number, shift: number) {
  55. const { curvePoints, tangentVectors, linearSegments } = state;
  56. const { p0, p1, p2, p3, p4, secStrucFirst, secStrucLast } = controls;
  57. const shift1 = 1 - shift;
  58. const tensionBeg = secStrucFirst ? 0.5 : tension;
  59. const tensionEnd = secStrucLast ? 0.5 : tension;
  60. for (let j = 0; j <= linearSegments; ++j) {
  61. const t = j * 1.0 / linearSegments;
  62. if (t < shift1) {
  63. const te = lerp(tensionBeg, tension, t);
  64. v3spline(curvePoint, p0, p1, p2, p3, t + shift, te);
  65. v3spline(tanA, p0, p1, p2, p3, t + shift + 0.01, tensionBeg);
  66. v3spline(tanB, p0, p1, p2, p3, t + shift - 0.01, tensionBeg);
  67. } else {
  68. const te = lerp(tension, tensionEnd, t);
  69. v3spline(curvePoint, p1, p2, p3, p4, t - shift1, te);
  70. v3spline(tanA, p1, p2, p3, p4, t - shift1 + 0.01, te);
  71. v3spline(tanB, p1, p2, p3, p4, t - shift1 - 0.01, te);
  72. }
  73. v3toArray(curvePoint, curvePoints, j * 3);
  74. v3normalize(tangentVec, v3sub(tangentVec, tanA, tanB));
  75. v3toArray(tangentVec, tangentVectors, j * 3);
  76. }
  77. }
  78. const tmpNormal = Vec3();
  79. const tangentVec = Vec3();
  80. const normalVec = Vec3();
  81. const binormalVec = Vec3();
  82. const prevNormal = Vec3();
  83. const firstTangentVec = Vec3();
  84. const lastTangentVec = Vec3();
  85. const firstNormalVec = Vec3();
  86. const lastNormalVec = Vec3();
  87. /**
  88. * Populate normalVectors by interpolating from firstDirection to lastDirection with
  89. * resulting vector perpendicular to tangentVectors and binormalVectors
  90. */
  91. export function interpolateNormals(state: CurveSegmentState, controls: CurveSegmentControls) {
  92. const { curvePoints, tangentVectors, normalVectors, binormalVectors } = state;
  93. const { d12: firstDirection, d23: lastDirection } = controls;
  94. const n = curvePoints.length / 3;
  95. v3fromArray(firstTangentVec, tangentVectors, 0);
  96. v3fromArray(lastTangentVec, tangentVectors, (n - 1) * 3);
  97. v3orthogonalize(firstNormalVec, firstTangentVec, firstDirection);
  98. v3orthogonalize(lastNormalVec, lastTangentVec, lastDirection);
  99. v3matchDirection(lastNormalVec, lastNormalVec, firstNormalVec);
  100. v3copy(prevNormal, firstNormalVec);
  101. for (let i = 0; i < n; ++i) {
  102. const t = i === 0 ? 0 : 1 / (n - i);
  103. v3fromArray(tangentVec, tangentVectors, i * 3);
  104. v3orthogonalize(normalVec, tangentVec, v3slerp(tmpNormal, prevNormal, lastNormalVec, t));
  105. v3toArray(normalVec, normalVectors, i * 3);
  106. v3copy(prevNormal, normalVec);
  107. v3normalize(binormalVec, v3cross(binormalVec, tangentVec, normalVec));
  108. v3toArray(binormalVec, binormalVectors, i * 3);
  109. }
  110. }
  111. export function interpolateSizes(state: CurveSegmentState, w0: number, w1: number, w2: number, h0: number, h1: number, h2: number, shift: number) {
  112. const { widthValues, heightValues, linearSegments } = state;
  113. const shift1 = 1 - shift;
  114. for (let i = 0; i <= linearSegments; ++i) {
  115. const t = i * 1.0 / linearSegments;
  116. if (t < shift1) {
  117. widthValues[i] = lerp(w0, w1, t + shift);
  118. heightValues[i] = lerp(h0, h1, t + shift);
  119. } else {
  120. widthValues[i] = lerp(w1, w2, t - shift1);
  121. heightValues[i] = lerp(h1, h2, t - shift1);
  122. }
  123. }
  124. }