52 using namespace UT::Literal;
54 namespace HDK_Sample {
56 namespace GU_CurveFrame {
58 static constexpr
float theExtremelySmallLength2 = 1e-37
f;
59 static constexpr
float theQuiteSmallRelativeLength = 1e-5
f;
60 static constexpr
float theQuiteSmallRelativeLength2 = 1e-10
f;
66 const bool stretch_using_backbone,
67 const T max_stretch_scale,
68 const T max_stretch_length_threshold,
76 T *pend_stretch_scale,
79 UT_ASSERT_MSG_P(prev_length2 > 0 && next_length2 > 0,
"This function doesn't handle zero-length edges. The caller should.");
81 if (next_length2 != 1) {
82 next_dir /= SYSsqrt(next_length2);
91 if (prev_length2 != 1) {
92 prev_dir /= SYSsqrt(prev_length2);
98 mid_dir = prev_dir + next_dir;
100 mid_length = SYSsqrt(mid_length2);
101 if (mid_length < theQuiteSmallRelativeLength) {
103 mid_dir = is_last ? prev_dir : next_dir;
106 mid_dir /= mid_length;
109 if (stretch_using_backbone) {
112 if (mid_length < max_stretch_length_threshold) {
113 stretch_scale = max_stretch_scale;
115 if (mid_length < theQuiteSmallRelativeLength) {
117 stretch_dir = is_last ? prev_dir : next_dir;
120 stretch_dir = next_dir - prev_dir;
127 stretch_scale =
SYSmin(2.0
f / mid_length, max_stretch_scale);
128 stretch_dir = next_dir - prev_dir;
131 *pend_stretch_dir = stretch_dir;
132 *pend_stretch_scale = stretch_scale;
137 switch (tangent_type) {
142 *tangent = normalize ? prev_dir : prev_edge;
145 *tangent = normalize ? next_dir : next_edge;
150 mid_dir = prev_edge + next_edge;
154 if (mid_length2 < theQuiteSmallRelativeLength2*next_length2) {
156 mid_dir = is_last ? prev_dir : next_dir;
159 mid_dir /= SYSsqrt(mid_length2);
167 UT_ASSERT_MSG(0,
"This case should have been excluded earlier.");
177 return (2*
dot(a,b))*b -
a;
189 extrapolateEndTangent(
191 const bool stretch_using_backbone,
192 const T max_stretch_scale,
193 const T max_stretch_length_threshold,
200 T *pend_stretch_scale,
201 const bool outer_edge_is_tangent)
204 T inner_length2 = inner_dir.
length2();
205 if (inner_length2 == 0) {
207 *end_tangent = outer_dir;
211 inner_dir /= SYSsqrt(inner_length2);
214 T extrapolated_length2;
218 extrapolated_edge = extrapolateVectorCircular(inner_dir, outer_dir);
219 extrapolated_length2 = 1;
220 end_edge_or_dir = outer_edge_is_tangent ? inner_dir : outer_dir;
225 extrapolated_edge = extrapolateVectorLinear(inner_edge, outer_edge);
226 extrapolated_length2 = extrapolated_edge.
length2();
227 end_edge_or_dir = outer_edge_is_tangent ? inner_edge : outer_edge;
228 end_length2 = outer_edge_is_tangent ? inner_length2 : outer_edge.
length2();
231 interpolateTangent(tangent_type,
232 stretch_using_backbone,
234 max_stretch_length_threshold,
235 is_last ? end_edge_or_dir : extrapolated_edge,
236 is_last ? extrapolated_edge : end_edge_or_dir,
237 is_last ? end_length2 : extrapolated_length2,
238 is_last ? extrapolated_length2 : end_length2,
240 end_tangent, pend_stretch_dir, pend_stretch_scale,
244 template<
typename T,
typename T2>
246 computeSingleBackboneFrames(
247 bool &rotate_using_backbone,
248 bool &stretch_using_backbone,
249 bool need_directions,
255 T &total_twist_around_loop,
262 bool extrapolate_end_tangents,
266 const bool use_nurbs_tangents,
268 T max_stretch_length_threshold,
271 const bool use_normal_vector_up,
272 const bool target_up_vector_at_start,
273 const bool continuous_closed_curves,
274 const bool use_end_target_up_vector,
278 const int ucomponent)
280 rotate_using_backbone = (rotate_using_backbone && nedges >= 1);
281 stretch_using_backbone = (stretch_using_backbone && npoints >= 3);
283 if (!rotate_using_backbone && !stretch_using_backbone && !need_directions)
289 directions.setSize(nedges);
293 T max_length_squared = 0;
294 for (
GA_Size i = 1; i < nverts; ++i)
302 if (length2 < theExtremelySmallLength2)
307 directions(i-1) = dir;
308 max_length_squared =
SYSmax(max_length_squared, length2);
311 if (closed && nverts == nedges)
317 if (length2 < theExtremelySmallLength2)
322 directions(nverts-1) = dir;
323 max_length_squared =
SYSmax(max_length_squared, length2);
326 if (!rotate_using_backbone && !stretch_using_backbone)
329 if (max_length_squared == 0)
333 rotate_using_backbone =
false;
334 stretch_using_backbone =
false;
345 GA_Size last_nonzero = directions.size()-1;
346 while (first_nonzero < last_nonzero && directions(first_nonzero).length2() == 0)
350 while (first_nonzero < last_nonzero && directions(last_nonzero).length2() == 0)
355 tangents.setSize(npoints);
356 up_vectors.setSize(npoints);
361 for (
exint i = 0; i < npoints; ++i)
366 tangents[i] = normal;
372 for (
exint i = 0; i < npoints; ++i)
381 if (first_nonzero == last_nonzero)
387 UT_Vector3T<T> dir = directions(first_nonzero) / SYSsqrt(max_length_squared);
388 tangents.constant(dir);
394 other -=
dot(other,dir)*dir;
396 if (length2 >= theQuiteSmallRelativeLength2)
397 other /= SYSsqrt(length2);
400 up_vectors.constant(other);
405 for (
exint i = 0; i < npoints; ++i)
408 other -=
dot(other,dir)*dir;
410 if (length2 >= theQuiteSmallRelativeLength2)
411 other /= SYSsqrt(length2);
414 up_vectors[i] = other;
423 for (
exint i = 0; i < npoints; ++i)
427 other -=
dot(other,dir)*dir;
429 if (length2 >= theQuiteSmallRelativeLength2)
430 other /= SYSsqrt(length2);
433 up_vectors[i] = other;
438 stretch_using_backbone =
false;
446 if (stretch_using_backbone)
448 stretch_dirs.setSizeNoInit(npoints);
457 if (instance_N.
isValid() && stretch_using_backbone)
466 if (first_nonzero == 0)
468 extrapolateEndTangent(tangent_type,
469 stretch_using_backbone, max_stretch_scale,
470 max_stretch_length_threshold,
480 if (last_nonzero == directions.size()-1)
482 extrapolateEndTangent(tangent_type,
483 stretch_using_backbone, max_stretch_scale,
484 max_stretch_length_threshold,
490 &stretch_dirs(npoints-1),
491 &stretch_scales(npoints-1),
495 else if (first_nonzero == 0 && last_nonzero == directions.size()-1)
502 stretch_using_backbone,
504 max_stretch_length_threshold,
507 directions.last().length2(),
508 directions(0).length2(),
517 GA_Size prev_nonzero = first_nonzero;
518 T prev_length2 = directions[first_nonzero].length2();
519 for (
GA_Size next_edgei = first_nonzero+1; next_edgei <= last_nonzero; ++next_edgei) {
520 T next_length2 = directions[next_edgei].length2();
521 if (next_length2 != 0)
526 stretch_using_backbone,
528 max_stretch_length_threshold,
529 directions[prev_nonzero],
530 directions[next_edgei],
535 &stretch_dirs[next_edgei],
536 &stretch_scales[next_edgei],
544 next_length2 = directions(next_edgei).length2();
545 }
while (next_edgei != last_nonzero && next_length2 == 0);
547 prev_nonzero = next_edgei;
548 prev_length2 = next_length2;
552 if (!instance_N.
isValid() && use_nurbs_tangents)
558 const bool curve_closed = curve->
isClosed();
563 for (
exint i = 0; i < nverts; ++i)
565 float u = basis->
getGreville(i,
true, curve_closed);
570 for (
exint i = 0; i < nverts; ++i)
573 float u = greville_us(i);
592 if (first_nonzero > 0) {
596 for (
GA_Size i = 0; i <= first_nonzero; ++i) {
597 tangents(i) = first_dir;
600 else if (extrapolate_end_tangents) {
601 extrapolateEndTangent(tangent_type,
602 stretch_using_backbone, max_stretch_scale,
603 max_stretch_length_threshold,
609 stretch_using_backbone ? &stretch_dirs(0) :
nullptr,
610 stretch_using_backbone ? &stretch_scales(0) :
nullptr,
615 tangents(0) = first_dir;
618 if (last_nonzero < directions.size()-1) {
620 for (
GA_Size i = last_nonzero+1; i < npoints; ++i) {
621 tangents(i) = last_dir;
624 else if (extrapolate_end_tangents) {
625 extrapolateEndTangent(tangent_type,
626 stretch_using_backbone, max_stretch_scale,
627 max_stretch_length_threshold,
629 directions(directions.size()-2),
632 &tangents(npoints-1),
633 stretch_using_backbone ? &stretch_dirs(npoints-1) :
nullptr,
634 stretch_using_backbone ? &stretch_scales(npoints-1) :
nullptr,
639 tangents(npoints-1) = last_dir;
642 else if (first_nonzero > 0 || last_nonzero < directions.size()-1) {
645 switch (tangent_type) {
648 if (first_nonzero == 1 && last_nonzero == directions.size()-1) {
649 tangents(0) = last_dir;
650 tangents(1) = first_dir;
652 else if (first_nonzero == 0 && last_nonzero == directions.size()-2) {
653 tangents.last() = last_dir;
654 tangents(0) = first_dir;
658 T cos_angle =
dot(first_dir,last_dir);
662 T full_angle = SYSacos(cos_angle);
663 GA_Size nsteps = first_nonzero + (directions.size()-1 - last_nonzero);
665 for (
GA_Size i = last_nonzero+1; i < npoints; ++i, ++
j) {
666 T part_angle = j*full_angle/nsteps;
667 tangents(i) = SYScos(part_angle)*last_dir + SYSsin(part_angle)*sin_axis;
669 for (
GA_Size i = 0; i <= first_nonzero; ++i, ++
j) {
670 T part_angle = j*full_angle/nsteps;
671 tangents(i) = SYScos(part_angle)*last_dir + SYSsin(part_angle)*sin_axis;
678 if (first_nonzero == 1 && last_nonzero == directions.size()-1) {
679 tangents(0) = last_dir;
680 tangents(1) = first_dir;
682 else if (first_nonzero == 0 && last_nonzero == directions.size()-2) {
683 tangents.last() = last_dir;
684 tangents(0) = first_dir;
688 GA_Size nsteps = first_nonzero + (directions.size()-1 - last_nonzero);
692 for (
GA_Size i = last_nonzero+1; i < npoints; ++i, ++
j) {
695 if (tangent.
length2() < 0.5f) {
698 tangent = prev_tangent;
701 prev_tangent = tangent;
703 tangents(i) = tangent;
705 for (
GA_Size i = 0; i <= first_nonzero; ++i, ++
j) {
708 if (tangent.
length2() < 0.5f) {
711 tangent = prev_tangent;
714 prev_tangent = tangent;
716 tangents(i) = tangent;
725 for (
GA_Size i = last_nonzero+1; i < npoints; ++i) {
726 tangents(i) = tangent;
728 for (
GA_Size i = 0; i <= first_nonzero; ++i) {
729 tangents(i) = tangent;
734 UT_ASSERT_MSG(0,
"This case should have been excluded earlier.");
744 stretch_using_backbone,
746 max_stretch_length_threshold,
749 directions.last().length2(),
750 directions(0).length2(),
753 stretch_using_backbone ? &stretch_dirs(0) :
nullptr,
754 stretch_using_backbone ? &stretch_scales(0) :
nullptr,
762 GA_Size prev_nonzero = first_nonzero;
763 T prev_length2 = directions(first_nonzero).length2();
764 for (
GA_Size next_edgei = first_nonzero+1; next_edgei <= last_nonzero; ++next_edgei) {
765 T next_length2 = directions(next_edgei).length2();
766 if (next_length2 != 0) {
770 stretch_using_backbone,
772 max_stretch_length_threshold,
773 directions(prev_nonzero),
774 directions(next_edgei),
778 &tangents(next_edgei),
779 stretch_using_backbone ? &stretch_dirs(next_edgei) :
nullptr,
780 stretch_using_backbone ? &stretch_scales(next_edgei) :
nullptr,
782 prev_nonzero = next_edgei;
783 prev_length2 = next_length2;
791 next_length2 = directions(next_edgei).length2();
792 }
while (next_edgei != last_nonzero && next_length2 == 0);
794 GA_Size nsteps = next_edgei - prev_nonzero - 1;
796 UT_Vector3T<T> prev_dir = directions(prev_nonzero) / SYSsqrt(prev_length2);
797 UT_Vector3T<T> next_dir = directions(next_edgei) / SYSsqrt(next_length2);
798 switch (tangent_type) {
802 tangents(next_edgei-1) = prev_dir;
803 tangents(next_edgei) = next_dir;
807 T cos_angle =
dot(next_dir,prev_dir);
811 T full_angle = SYSacos(cos_angle);
813 for (
GA_Size i = prev_nonzero+1; i <= next_edgei; ++i, ++
j) {
814 T part_angle = j*full_angle/nsteps;
815 tangents(i) = SYScos(part_angle)*prev_dir + SYSsin(part_angle)*sin_axis;
823 tangents(next_edgei-1) = prev_dir;
824 tangents(next_edgei) = next_dir;
831 for (
GA_Size i = prev_nonzero+1; i <= next_edgei; ++i, ++
j) {
834 if (tangent.
length2() < 0.5f) {
837 tangent = prev_tangent;
840 prev_tangent = tangent;
842 tangents(i) = tangent;
851 for (
GA_Size i = prev_nonzero+1; i <= next_edgei; ++i) {
852 tangents(i) = tangent;
857 UT_ASSERT_MSG(0,
"This case should have been excluded earlier.");
861 prev_nonzero = next_edgei;
862 prev_length2 = next_length2;
875 for (
exint i = 0; i < npoints; ++i)
879 other -=
dot(other,dir)*dir;
881 if (length2 >= theQuiteSmallRelativeLength2)
882 other /= SYSsqrt(length2);
885 up_vectors[i] = other;
891 if (use_normal_vector_up) {
904 double length2_max_normal = 0;
905 T length2_max_chord = 0;
906 for (
GA_Size i = 1; i < nverts-1; ++i) {
915 normal_sum +=
cross(directions(i), chord);
918 double length2 = normal_sum.
length2();
919 if (length2 > length2_max_normal) {
920 length2_max_normal = length2;
921 max_normal = normal_sum;
923 length2_max_chord =
SYSmax(length2_max_chord, chord.
length2());
926 length2_max_chord =
SYSmax(length2_max_chord, (posi-pos0).length2());
929 double small_rel_length2 = theQuiteSmallRelativeLength2*length2_max_chord;
930 double small_rel_length4 = small_rel_length2*small_rel_length2;
934 if (length2_max_normal < small_rel_length4) {
940 double length2_normal = normal_sum.
length2();
941 if (length2_normal < small_rel_length4) {
945 target_up_vector = max_normal / SYSsqrt(length2_max_normal);
949 target_up_vector = normal_sum / SYSsqrt(length2_normal);
960 up_vectors0 -=
dot(up_vectors0,tangent0)*tangent0;
962 if (length2 >= theQuiteSmallRelativeLength2) {
963 up_vectors0 /= SYSsqrt(length2);
968 up_vectors(0) = up_vectors0;
970 for (
GA_Size i = 1; i < npoints; ++i) {
979 bool failure = rotation.
dihedral(tangents(i-1), tangents(i),
false);
983 up_vectors(i) = -up_vectors(i-1);
987 up_vectors(i) = up_vectors(i-1) *
rotation;
991 up_vectors(i) -=
dot(up_vectors(i),tangents(i))*tangents(i);
995 up_vectors(i).normalize();
1002 if ((closed && continuous_closed_curves) || use_end_target_up_vector)
1006 bool skip_twist =
false;
1012 bool failure = rotation.
dihedral(tangents[npoints-1], tangents[0],
false);
1017 final_up_vector = up_vectors[npoints-1];
1022 final_up_vector = up_vectors[npoints-1] *
rotation;
1025 final_up_vector -=
dot(final_up_vector,tangents[0])*tangents[0];
1031 comparison_tangent = tangents[0];
1036 final_up_vector = up_vectors[npoints-1];
1037 comparison_tangent = tangents[npoints-1];
1041 if (closed && continuous_closed_curves)
1043 comparison_up_vector = up_vectors[0];
1048 if (use_normal_vector_up)
1051 comparison_up_vector = target_up_vector;
1054 comparison_up_vector = end_target_up_vector;
1055 comparison_up_vector -= comparison_up_vector*
dot(comparison_up_vector,comparison_tangent);
1056 T length2 = comparison_up_vector.
length2();
1058 if (length2 >= theQuiteSmallRelativeLength2)
1059 comparison_up_vector /= SYSsqrt(length2);
1074 T sin_net_twist =
dot(net_twist_vector, comparison_tangent);
1075 T cos_net_twist =
dot(final_up_vector, comparison_up_vector);
1076 net_twist = SYSatan2(sin_net_twist, cos_net_twist);
1079 if (!
SYSequalZero(net_twist, theQuiteSmallRelativeLength))
1084 for (
GA_Size i = 1; i < npoints; ++i)
1086 T reverse_twist = -i*net_twist/nedges;
1087 T s = SYSsin(reverse_twist);
1088 T c = SYScos(reverse_twist);
1090 up_vectors(i) = s*bitangent + c*up_vectors(i);
1099 double total_length = 0;
1100 for (
GA_Size i = 0; i < nedges; ++i)
1102 total_length += directions(i).length();
1107 double cur_length = 0;
1108 for (
GA_Size i = 1; i < npoints; ++i)
1110 cur_length += directions(i-1).length();
1111 T reverse_twist = -cur_length*net_twist/total_length;
1112 T s = SYSsin(reverse_twist);
1113 T c = SYScos(reverse_twist);
1115 up_vectors(i) = s*bitangent + c*up_vectors(i);
1125 if (nverts == npoints+1)
1130 ustart = roll_attrib.
get(vertices(0), ucomponent);
1131 uend = roll_attrib.
get(vertices.
last(), ucomponent);
1133 T2 uspan = (uend-ustart);
1138 for (
GA_Size i = 1; i < npoints; ++i)
1140 T2
t = roll_attrib.
get(vertices(i), ucomponent);
1142 T reverse_twist = -t*net_twist;
1143 T s = SYSsin(reverse_twist);
1144 T c = SYScos(reverse_twist);
1146 up_vectors(i) = s*bitangent + c*up_vectors(i);
1155 for (
GA_Size i = 1; i < npoints; ++i)
1157 T2 u = roll_attrib.
get(geo->
vertexPoint(vertices(i)), ucomponent);
1158 T reverse_twist = -u*net_twist;
1159 T s = SYSsin(reverse_twist);
1160 T c = SYScos(reverse_twist);
1162 up_vectors(i) = s*bitangent + c*up_vectors(i);
1167 if (closed && continuous_closed_curves)
1170 total_twist_around_loop = -net_twist;
1175 if (target_up_vector_at_start)
1216 for (
GA_Size i = 0; i < npoints; ++i) {
1217 My += up_vectors(i);
1225 double MxMx =
dot(Mx,Mx);
1226 double MxMy =
dot(Mx,My);
1227 double MyMy =
dot(My,My);
1235 double determinant = MxMx*MyMy - MxMy*MxMy;
1236 double scale2 =
SYSmax(MxMx*MxMx, MyMy*MyMy);
1248 s = (MyMy*Mxup - MxMy*Myup);
1249 c = (MxMx*Myup - MxMy*Mxup);
1250 T normalization = s*s + c*
c;
1251 if (
SYSequalZero(normalization, theExtremelySmallLength2)) {
1256 normalization =
T(1) / SYSsqrt(normalization);
1261 else if (MxMx > MyMy) {
1262 s = (Mxup >= 0) ? 1 : -1;
1267 c = (Myup >= 0) ? 1 : -1;
1275 for (
GA_Size i = 0; i < npoints; ++i) {
1277 up_vectors(i) = s*bitangent + c*up_vectors(i);
1291 if (vertices.
size() == 0) {
1295 if (vertices.
size() == 1) {
1306 nedges = vertices.
size();
1316 unrolled = (pt0 == lastpt);
1322 template<
typename T>
1324 createRotationMatrix(
1331 for (
int i = 0; i < 3; ++i)
1333 float angle = cur_angles[i];
1336 transform.
rotate(order[i], angle);
1340 template<
typename T>
1353 if (!transform_attrib.isValid())
1361 transform_attrib->hardenAllPages();
1366 if (rotate_using_backbone)
1369 T length2 = target_up_vector.
length2();
1370 if (length2 < theExtremelySmallLength2)
1373 target_up_vector.
assign(0,1,0);
1377 target_up_vector /= SYSsqrt(length2);
1382 length2 = end_target_up_vector.
length2();
1383 if (length2 < theExtremelySmallLength2)
1386 end_target_up_vector.
assign(0,1,0);
1390 end_target_up_vector /= SYSsqrt(length2);
1402 if (transform_by_instance_attribs)
1411 if (has_N && !has_up)
1413 instance_N = instance_attribs.
myN;
1416 else if (has_up && !has_N)
1418 instance_up = instance_attribs.
myUp;
1423 transform_by_instance_attribs =
false;
1428 rotate_using_backbone &= !instance_attribs.
hasNonScales();
1431 const bool use_rotation_attrib[3] =
1443 const bool varying_attrib[3] =
1463 [geo,&parms,transform_by_instance_attribs,&instance_N,&instance_up,
1464 &instance_attribs,rotate_using_backbone,target_up_vector,end_target_up_vector,
1465 &transform_attrib,&interrupt,use_rotation_attrib,rot_attrib_owner,varying_attrib,
1471 UT_SmallArray<UT_Vector3T<T>, 8*
sizeof(
UT_Vector3T<T>)> up_vectors;
1472 UT_SmallArray<UT_Vector3T<T>, 8*
sizeof(
UT_Vector3T<T>)> stretch_dirs;
1478 const bool rotate_using_parameters = !parms.
myAngles.isZero() || !parms.
myIncAngles.isZero();
1495 for (
GA_Offset primoff = start; primoff <
end; ++primoff)
1502 const GA_Size npoints = nedges + !closed;
1510 UT_Vector3T<T> local_end_target_up_vector = end_target_up_vector;
1517 T length2 = local_target_up_vector.length2();
1518 if (length2 < theExtremelySmallLength2)
1521 local_target_up_vector.assign(0,1,0);
1525 local_target_up_vector /= SYSsqrt(length2);
1534 T length2 = local_end_target_up_vector.length2();
1535 if (length2 < theExtremelySmallLength2)
1538 local_end_target_up_vector.assign(0,1,0);
1542 local_end_target_up_vector /= SYSsqrt(length2);
1546 bool local_rotate_using_backbone = rotate_using_backbone;
1552 T total_twist_around_loop = 0;
1557 bool use_nurbs_tangents =
false;
1567 bool needs_length =
false;
1568 bool needs_total_length =
false;
1569 if (rotate_using_parameters)
1575 needs_total_length =
1582 needs_length =
true;
1583 needs_total_length =
true;
1586 computeSingleBackboneFrames(
1587 local_rotate_using_backbone,
1588 local_stretch_using_backbone,
1590 directions, tangents, up_vectors,
1591 stretch_dirs, stretch_scales,
1592 total_twist_around_loop,
1593 geo, nedges, npoints, nverts, closed,
1596 primoff, vertices, use_nurbs_tangents,
1606 if (use_rotation_attrib[0] && !varying_attrib[0])
1611 if (use_rotation_attrib[1] && !varying_attrib[1])
1616 if (use_rotation_attrib[2] && !varying_attrib[2])
1624 double total_length = 0;
1625 double cur_length = 0;
1626 if (needs_total_length)
1628 for (
GA_Size i = 0; i < nedges; ++i)
1630 total_length += directions(i).length();
1636 const bool rotate_using_dangles = !local_dangles.
isZero();
1637 if (rotate_using_parameters && continuous_closed && rotate_using_dangles)
1639 for (
int axis = 0; axis < 3; ++axis)
1643 local_dangles[axis] *= nedges;
1648 local_dangles[axis] *= total_length;
1656 local_dangles.
z() -= total_twist_around_loop;
1657 total_twist_around_loop = 0;
1660 local_dangles /= (2*
M_PI);
1661 local_dangles.
x() =
SYSrint(local_dangles.
x());
1662 local_dangles.
y() =
SYSrint(local_dangles.
y());
1663 local_dangles.
z() =
SYSrint(local_dangles.
z());
1664 local_dangles *= (2*
M_PI);
1672 for (
GA_Size i = 0; i < npoints; ++i)
1683 if (rotate_using_dangles)
1685 for (
int axis = 0; axis < 3; ++axis)
1687 if (axis != 2 && local_dangles[axis] == 0)
1690 const RotationPer cur_dangle_per = local_dangle_per[axis];
1693 cur_angles[axis] += local_dangles[axis]*i;
1696 if (axis == 2 && total_twist_around_loop != 0)
1699 cur_angles.
z() -= total_twist_around_loop*
t;
1705 cur_angles[axis] += local_dangles[axis]*
t;
1709 cur_angles.
z() -= total_twist_around_loop*
t;
1713 cur_angles[axis] += local_dangles[axis]*cur_length;
1715 if (axis == 2 && total_length != 0 && total_twist_around_loop != 0)
1718 T t = (cur_length/total_length);
1719 cur_angles.
z() -= total_twist_around_loop*
t;
1726 if (total_length != 0)
1728 T t = (cur_length/total_length);
1729 cur_angles[axis] += t*local_dangles[axis];
1733 cur_angles.
z() -= total_twist_around_loop*
t;
1736 else if (use_rotation_attrib[axis] && varying_attrib[axis])
1744 if (!closed || unrolled) {
1748 ustart = parms.
myRotAttribs[axis].
get(vertices(0), curve_u_component);
1751 T uspan = (uend-ustart);
1758 cur_angles[axis] += t*local_dangles[axis];
1762 cur_angles.
z() -= total_twist_around_loop*
t;
1771 cur_angles[axis] += u*local_dangles[axis];
1775 cur_angles.
z() -= total_twist_around_loop*u;
1782 if (rotate_using_parameters)
1784 createRotationMatrix(transform, cur_angles, order);
1791 if (transform_by_instance_attribs)
1798 transform *= instance_transform;
1801 if (local_rotate_using_backbone)
1813 if (local_stretch_using_backbone)
1817 stretch_matrix.
outerproductUpdateT(stretch_scales(i)-1, stretch_dirs(i), stretch_dirs(i));
1819 transform *= stretch_matrix;
1825 const T t = (total_length != 0) ? (cur_length/total_length) :
T(i)/nedges;
1837 transform.
scale(scale);
1842 transform_attrib.set(vtxoff, transform);
1844 if (needs_length && i+1 < npoints)
1845 cur_length += directions(i).length();
1852 #define TEMPLATE_INST2(T) \
1853 template void computeCurveTransforms<T>( \
1854 const GEO_Detail *const geo, \
1855 const GA_PrimitiveGroup *curve_group, \
1856 const GA_RWHandleT<UT_Matrix4T<T>> &transform_attrib, \
1857 const CurveFrameParms<T> &parms); \
constexpr SYS_FORCE_INLINE T length2() const noexcept
void UTparallelFor(const Range &range, const Body &body, const int subscribe_ratio=2, const int min_grain_size=1, const bool force_use_task_scope=true)
SYS_FORCE_INLINE GA_Primitive * getPrimitive(GA_Offset prim_off)
SYS_FORCE_INLINE const GA_AttributeDict & pointAttribs() const
Apply angle increment to each edge on top of previous edge's rotation.
void resetScales()
Resets only the scale attributes.
virtual fpreal getGreville(int idx, bool clamp=true, bool wrap=false) const =0
Iteration over a range of elements.
SIM_API const UT_StringHolder angle
SYS_FORCE_INLINE int getPrimitiveTypeId(GA_Offset primoff) const
GA_ROHandleT< UT_Vector3T< T > > myTargetUpVectorAttrib
bool blockAdvance(GA_Offset &start, GA_Offset &end)
void setSizeNoInit(exint newsize)
SYS_FORCE_INLINE bool getExtraFlag() const
Synonym for isClosed()
bool hasNonScales() const
UT_Vector3T< T > myEndTargetUpVector
constexpr SYS_FORCE_INLINE T & z() noexcept
GLboolean GLboolean GLboolean GLboolean a
SYS_FORCE_INLINE TO_T UTverify_cast(FROM_T from)
#define UT_ASSERT_MSG_P(ZZ,...)
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Offset ptoff) const
The ptoff passed is the point offset.
void arbitraryPerp(const UT_Vector3T< T > &v)
Finds an arbitrary perpendicular to v, and sets this to it.
UT_Matrix2T< T > SYSlerp(const UT_Matrix2T< T > &v1, const UT_Matrix2T< T > &v2, S t)
SYS_FORCE_INLINE bool isClosed() const
bool myTargetUpVectorAtStart
GA_ROHandleT< T > myRotAttribs[3]
exint GA_Size
Defines the bit width for index and offset types in GA.
int myRotAttribComponent
Component of myRotAttribs being read. (default 0)
GA_ROHandleT< UT_Vector3T< T > > myEndTargetUpVectorAttrib
bool hasAnyAttribs() const
Returns true if there are any attributes bound.
UT_Vector3T< T > myAngles
#define UT_ASSERT_MSG(ZZ,...)
void rampLookup(fpreal pos, float values[4], int order=0) const
GA_API const UT_StringHolder scale
void identity()
Set the matrix to identity.
bool myExtrapolateEndTangents
#define TEMPLATE_INST2(T)
bool myContinuousClosedCurves
void rotate(UT_Vector3T< S > &axis, T theta, int norm=1)
static UT_Matrix3T< T > dihedral(UT_Vector3T< S > &a, UT_Vector3T< S > &b, UT_Vector3T< S > &c, int norm=1)
SYS_FORCE_INLINE GA_OffsetListRef getPrimitiveVertexList(GA_Offset primoff) const
void getMatrix(UT_Matrix4 &xform, const UT_Vector3 &P, GA_Offset offset, float default_pscale=1) const
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
void outerproductUpdateT(T b, const UT_Vector3T< S > &v1, const UT_Vector3T< S > &v2)
bool myUseEndTargetUpVector
Bezier or NURBS basis classes which maintain knot vectors.
GLdouble GLdouble GLint GLint order
SIM_API const UT_StringHolder rotation
UT_Vector3T< fpreal64 > UT_Vector3D
SYS_FORCE_INLINE T get(GA_Offset off, int comp=0) const
SYS_FORCE_INLINE GA_Offset vertexPoint(GA_Offset vertex) const
Given a vertex, return the point it references.
void identity()
Set the matrix to identity.
GLboolean GLboolean GLboolean b
UT_XformOrder::xyzOrder myRotationOrder
GA_API const UT_StringHolder transform
bool evaluate(fpreal u, GEO_Vertex result, GEO_AttributeHandleList &gah, int du=0, int uoffset=-1) const
fpreal32 SYSrint(fpreal32 val)
bool myStretchAroundTurns
SYS_FORCE_INLINE bool isValid() const
const GA_Basis * getBasis() const
bool SYSequalZero(const UT_Vector3T< T > &v)
ToType last() const
Return the value of the last element.
void scale(T sx, T sy, T sz, T sw=1)
void computeCurveTransforms(const GEO_Detail *const geo, const GA_PrimitiveGroup *curve_group, const GA_RWHandleT< UT_Matrix4T< T >> &transform_attrib, const CurveFrameParms< T > &parms)
void assign(T xx=0.0f, T yy=0.0f, T zz=0.0f)
Set the values of the vector components.
bool myTransformByInstanceAttribs
Use incoming N, up, rot, orient, pscale, scale, pivot, trans, transform.
void translate(T dx, T dy, T dz=0)
constexpr SYS_FORCE_INLINE bool isZero() const noexcept
bool getPolyProperties(const GEO_Detail *geometry, const GA_OffsetListRef &vertices, exint &nedges, bool &closed, bool &unrolled)
Compute an instance transform given a set of attributes.
void constant(const T &v)
Quickly set the array to a single value.
UT_Vector3T< T > myIncAngles
SYS_FORCE_INLINE GA_AttributeOwner getOwner() const
UT_Vector3T< T > myTargetUpVector
SYS_FORCE_INLINE UT_StorageMathFloat_t< T > normalize() noexcept
constexpr SYS_FORCE_INLINE T & y() noexcept
GA_Range getPrimitiveRange(const GA_PrimitiveGroup *group=0) const
Get a range of all primitives in the detail.
bool myUseCurveNormalAsTargetUp
SIM_DerVector3 cross(const SIM_DerVector3 &lhs, const SIM_DerVector3 &rhs)
void initialize(const GA_AttributeDict &dict, const UT_StringRef &N_name=GA_Names::N, const UT_StringRef &v_name=GA_Names::v)
TangentType myTangentType
constexpr T normalize(UT_FixedVector< T, D > &a) noexcept
RotationPer myIncAnglePer[3]
NOTE: myIncAnglePer[2] will also be used for ensuring closed curve continuity.
SYS_FORCE_INLINE FromType size() const
Returns the number of used elements in the list (always <= capacity())
constexpr SYS_FORCE_INLINE T & x() noexcept