36 #include "SOP_SweepHDK.proto.h"
41 #include "../SOP_OrientAlongCurve/GU_CurveFrame.h"
42 #include "../SOP_CopyToPoints/GEO_BuildPrimitives.h"
43 #include "../SOP_CopyToPoints/GU_Copy2.h"
85 namespace HDK_Sample {
91 constexpr
static int theUComponent = 0;
92 constexpr
static int theVComponent = 1;
94 constexpr
static int theCurveInput = 0;
95 constexpr
static int theCrossSectionInput = 1;
98 struct CrossSectionAttribMatchData
149 sop_SweepGrid(
const sop_SweepGrid &that)
169 if (that.mySingleCrossSection)
176 sop_SweepGrid(sop_SweepGrid &&that)
196 if (that.mySingleCrossSection)
201 that.mySingleCrossSection =
true;
206 sop_SweepGrid &operator=(
const sop_SweepGrid &that)
219 if (that.mySingleCrossSection)
239 sop_SweepGrid &operator=(sop_SweepGrid &&that)
252 if (that.mySingleCrossSection)
257 that.mySingleCrossSection =
true;
382 return SYSisSame<T,double>()
384 :
reinterpret_cast<const UT_Vector3T<T> *
>(
myTranslatef);
394 return SYSisSame<T,double>()
396 :
reinterpret_cast<const UT_Matrix3T<T> *
>(
myInverse3f);
406 return SYSisSame<T,double>()
408 :
reinterpret_cast<const UT_Matrix3T<T> *
>(
myMatrix3f);
418 return SYSisSame<T,double>()
420 :
reinterpret_cast<const UT_QuaternionT<T> *
>(
myQuaternionf);
443 void cook(
const CookParms &cookparms)
const override;
499 case 0:
return "Backbone Curves";
500 case 1:
return "Cross Section(s)";
501 default:
return "Invalid Source";
512 return (i == 0 || i == 1);
558 namespace HDK_Sample {
591 label "Backbone Curve Group"
594 parmtag { "script_action" "import soputils\nkwargs['geometrytype'] = (hou.geometryType.Primitives,)\nkwargs['inputindex'] = 0\nsoputils.selectGroupParm(kwargs)" }
595 parmtag { "script_action_help" "Select geometry from an available viewport.\nShift-click to turn on Select Groups." }
596 parmtag { "script_action_icon" "BUTTONS_reselect" }
599 name "crosssectiongroup"
600 cppname "CrossSectionGroup"
601 label "Cross Section Group"
604 parmtag { "script_action" "import soputils\nkwargs['geometrytype'] = (hou.geometryType.Primitives,)\nkwargs['inputindex'] = 1\nsoputils.selectGroupParm(kwargs)" }
605 parmtag { "script_action_help" "Select geometry from an available viewport.\nShift-click to turn on Select Groups." }
606 parmtag { "script_action_icon" "BUTTONS_reselect" }
615 name "surface_folder"
619 cppname "SurfaceShape"
620 label "Surface Shape"
622 default { "0" } // Default to first entry in menu, "input"
624 "input" "Second Input Cross Sections"
626 "square" "Square Tube"
632 cppname "SurfaceType"
635 default { "5" } // Default to menu entry "quads"
640 "rowcol" "Rows and Columns"
642 "quads" "Quadrilaterals"
643 "alttris" "Alternating Triangles"
644 "revtris" "Reverse Triangles"
649 label "Scale Cross Sections"
653 disablewhen "{ surfaceshape != input }"
654 hidewhen "{ surfaceshape != input }"
662 disablewhen "{ surfaceshape == input }"
663 hidewhen "{ surfaceshape == input }"
671 parmtag { "units" "m1" }
672 disablewhen "{ surfaceshape != tube }"
673 hidewhen "{ surfaceshape != tube }"
681 parmtag { "units" "m1" }
682 disablewhen "{ surfaceshape != ribbon surfaceshape != square }"
683 hidewhen "{ surfaceshape != ribbon surfaceshape != square }"
686 name "reversecrosssections"
687 cppname "ReverseCrossSections"
688 label "Reverse Cross Sections"
693 name "stretcharoundturns"
694 cppname "StretchAroundTurns"
695 label "Stretch Around Turns"
700 name "maxstretcharoundturns"
701 cppname "MaxStretchAroundTurns"
706 disablewhen "{ stretcharoundturns == 0 }"
709 name "endcaps_folder"
716 default { "0" } // Default to menu entry "none"
719 "single" "Single Polygon"
721 "sidesingle" "Side Single Polygon"
727 label "Cap Divisions"
731 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
732 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
736 name "triangularpoles"
737 cppname "TriangularPoles"
738 label "Triangular Poles"
741 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
742 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
747 label "End Cap Scale"
751 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
752 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
756 cppname "CapRoundness"
757 label "End Cap Roundness"
761 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
762 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
765 name "addendcapsgroup"
766 cppname "AddEndCapsGroup"
767 label "Add End Caps Group"
775 cppname "EndCapsGroup"
776 label "End Caps Group"
778 default { "endcaps" }
779 disablewhen "{ addendcapsgroup == 0 }"
788 label "Apply Scale Along Curve"
799 disablewhen "{ applyscale == 0 }"
800 parmtag { "rampfloatdefault" "1pos ( 0 ) 1value ( 1 ) 1interp ( linear ) 2pos ( 1 ) 2value ( 1 ) 2interp ( linear )" }
804 name "rotation_folder"
811 // NOTE: The default rotation order X,Y,Z is semi-arbitrary, but Z
812 // should probably be last, since it always needs to twist
813 // around the curve tangent. The X and Y rotations may have
814 // just been to reorient a cross-section before copying.
817 "xyz" "Pitch, Yaw, Roll"
818 "xzy" "Pitch, Roll, Yaw"
819 "yxz" "Yaw, Pitch, Roll"
820 "yzx" "Yaw, Roll, Pitch"
821 "zxy" "Roll, Pitch, Yaw"
822 "zyx" "Roll, Yaw, Pitch"
828 label "Apply Roll or Twist"
838 hidewhen "{ applyroll == 0 }"
847 hidewhen "{ applyroll == 0 }"
852 label "Partial Twist"
856 hidewhen "{ applyroll == 0 }"
864 default { "4" } // Default to "fulldistance" entry in menu
867 "distance" "Per Unit Distance"
868 "attrib" "Scale by Attribute"
869 "fulledges" "Per Full Curve by Edges"
870 "fulldistance" "Per Full Curve by Distance"
872 hidewhen "{ applyroll == 0 }"
877 label "Twist Ramp Attribute"
880 disablewhen "{ applyroll == 0 } { applyroll == 1 rollper != attrib }"
881 hidewhen "{ applyroll == 0 } { applyroll == 1 rollper != attrib }"
888 hidewhen "{ applyroll == 0 }"
903 hidewhen "{ applyyaw == 0 }"
908 label "Incremental Yaw"
912 hidewhen "{ applyyaw == 0 }"
920 default { "4" } // Default to "fulldistance" entry in menu
923 "distance" "Per Unit Distance"
924 "attrib" "Scale By Attribute"
925 "fulledges" "Per Full Curve by Edges"
926 "fulldistance" "Per Full Curve by Distance"
928 hidewhen "{ applyyaw == 0 }"
933 label "Yaw Ramp Attribute"
936 disablewhen "{ applyyaw == 0 } { applyyaw == 1 yawper != attrib }"
937 hidewhen "{ applyyaw == 0 } { applyyaw == 1 yawper != attrib }"
944 hidewhen "{ applyyaw == 0 }"
959 hidewhen "{ applypitch == 0 }"
964 label "Incremental Pitch"
968 hidewhen "{ applypitch == 0 }"
976 default { "4" } // Default to "fulldistance" entry in menu
979 "distance" "Per Unit Distance"
980 "attrib" "Scale By Attribute"
981 "fulledges" "Per Full Curve by Edges"
982 "fulldistance" "Per Full Curve by Distance"
984 hidewhen "{ applypitch == 0 }"
988 cppname "PitchAttrib"
989 label "Pitch Ramp Attribute"
992 disablewhen "{ applypitch == 0 } { applypitch == 1 pitchper != attrib }"
993 hidewhen "{ applypitch == 0 } { applypitch == 1 pitchper != attrib }"
1002 name "construction_folder"
1003 label "Construction"
1005 name "cross_sections_folder"
1006 label "Cross Sections"
1010 label "Cross Section Order"
1012 default { "1" } // Default to third entry in menu, "each"
1014 "all" "All Cross Sections At Each Curve Vertex"
1015 "each" "Each Cross Section At All Curve Vertices"
1016 "cyclevtx" "Cycle Through Cross Section Primitives per Vertex"
1017 "cyclepr" "Cycle Through Cross Section Primitives per Curve"
1018 "attrib" "Choose Cross Section Primitives by Attribute"
1020 disablewhen "{ surfaceshape != input }"
1023 name "crosssectionattrib"
1024 cppname "CrossSectionAttrib"
1025 label "Cross Section Attribute"
1027 default { "variant" }
1028 disablewhen "{ surfaceshape != input } { copyorder != attrib }"
1029 hidewhen "{ surfaceshape != input } { copyorder != attrib }"
1034 label "Primitive Type"
1036 default { "0" } // Default to menu entry "auto"
1040 "mesh" "Bilinear Mesh"
1041 "nurbs" "NURBS Surface"
1042 "bezier" "Bezier Surface"
1043 "polysoup" "Polygon Soup"
1045 disablewhen "{ surfacetype == points }"
1048 name "unrollclosedrowcol"
1049 cppname "UnrollClosedRowCol"
1050 label "Ensure Unique Seam Vertices"
1053 disablewhen "{ surfacetype == points }"
1057 cppname "SwapRowCol"
1058 label "Swap Rows and Columns"
1063 name "closeifnocurveinput"
1064 cppname "CloseIfNoCurveInput"
1065 label "Close Implicit Backbone Curve if No Curve Input"
1068 disablewhen "{ surfacetype == points } { surfacetype == rows } { hasinput(0) != 0 }"
1072 // cppname "SegDivs"
1073 // label "Segment Divisions"
1084 cppname "UpVectorType"
1085 label "Target Up Vector"
1087 default { "0" } // Default to first entry in menu, "normal"
1089 "normal" "Curve Normal"
1093 "attrib" "Attribute"
1096 disablewhen "{ tangenttype == none }"
1099 // name "usenormalup"
1100 // cppname "UseNormalUp"
1101 // label "Use Curve Normal as Up Vector (When Valid)"
1104 // disablewhen "{ tangenttype == none }"
1107 name "upvectoratstart"
1108 cppname "UpVectorAtStart"
1109 label "Target Up Vector at Start (else Average)"
1112 disablewhen "{ tangenttype == none }"
1115 name "useendupvector"
1116 cppname "UseEndUpVector"
1117 label "Use Target End Up Vector"
1120 disablewhen "{ tangenttype == none } { upvectoratstart == 0 }"
1123 name "upvectorattrib"
1124 cppname "UpVectorAttrib"
1125 label "Start Up Attribute"
1127 default { "start_up" }
1128 disablewhen "{ tangenttype == none } { upvectortype != attrib }"
1129 hidewhen "{ tangenttype == none } { upvectortype != attrib }"
1132 name "endupvectorattrib"
1133 cppname "EndUpVectorAttrib"
1134 label "End Up Attribute"
1136 default { "end_up" }
1137 disablewhen "{ tangenttype == none } { upvectortype != attrib } { useendupvector == 0 } { upvectoratstart == 0 }"
1138 hidewhen "{ tangenttype == none } { upvectortype != attrib } { useendupvector == 0 } { upvectoratstart == 0 }"
1143 label "Start Up Vector"
1146 default { "0" "1" "0" }
1147 disablewhen "{ tangenttype == none } { upvectortype != custom }"
1148 hidewhen "{ tangenttype == none } { upvectortype != custom }"
1152 cppname "EndUpVector"
1153 label "End Up Vector"
1156 default { "0" "1" "0" }
1157 disablewhen "{ tangenttype == none } { upvectortype != custom } { useendupvector == 0 } { upvectoratstart == 0 }"
1158 hidewhen "{ tangenttype == none } { upvectortype != custom } { useendupvector == 0 } { upvectoratstart == 0 }"
1162 name "tangents_folder"
1166 cppname "TangentType"
1167 label "Tangent Type"
1169 default { "0" } // Default to first entry in menu, "avgdir"
1171 "avgdir" "Average of Edge Directions"
1172 "diff" "Central Difference"
1173 "prev" "Previous Edge"
1175 "none" "Z Axis (Ignore Curve)"
1179 name "continuousclosed"
1180 cppname "ContinuousClosed"
1181 label "Make Closed Curve Orientations Continuous"
1184 disablewhen "{ tangenttype == none }"
1187 name "extrapolateendtangents"
1188 cppname "ExtrapolateEndTangents"
1189 label "Extrapolate End Tangents"
1192 disablewhen "{ tangenttype == none }"
1195 name "transformbyattribs"
1196 cppname "TransformByAttribs"
1197 label "Transform Using Curve Point Attributes"
1209 label "UVs and Attributes"
1212 label "UV Coordinates"
1215 cppname "ComputeUVs"
1221 name "overrideexistinguvs"
1222 cppname "OverrideExistingUVs"
1223 label "Override Any Existing UVs"
1226 disablewhen "{ computeuvs == 0 }"
1229 name "lengthweighteduvs"
1230 cppname "LengthWeightedUVs"
1231 label "Length-Weighted UVs"
1234 disablewhen "{ computeuvs == 0 }"
1238 cppname "NormalizeU"
1239 label "Normalize Computed Us"
1242 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1246 cppname "NormalizeV"
1247 label "Normalize Computed Vs"
1250 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1255 label "Flip Computed Us"
1258 disablewhen "{ computeuvs == 0 }"
1261 name "uvscale_folder"
1263 grouptag { "group_type" "collapsible" }
1264 parmtag { "group_default" "0" }
1272 disablewhen "{ computeuvs == 0 }"
1275 name "usemeshedgelengths"
1276 cppname "UseMeshEdgeLengths"
1277 label "Use Mesh Edge Lengths Instead of Curve Edge Lengths"
1280 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1283 name "propscalepercurve"
1284 cppname "PropScalePerCurve"
1285 label "Use Max Cross Section Length per Curve for Proportional Scale"
1288 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizeu != 1 } { normalizev != 0 }"
1292 name "uvseams_folder"
1294 grouptag { "group_type" "collapsible" }
1295 parmtag { "group_default" "0" }
1299 label "Snap U to Nearest Tile Boundary"
1302 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizeu == 1 }"
1307 label "Snap V to Nearest Tile Boundary"
1310 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizev == 1 }"
1315 name "attributes_folder"
1317 grouptag { "group_type" "collapsible" }
1318 parmtag { "group_default" "0" }
1323 name "attribsfrombackbone"
1324 cppname "AttribsFromBackbone"
1325 label "From Backbone Curves"
1327 default { "* ^P ^N ^up ^pscale ^scale ^orient ^rot ^pivot ^trans ^transform" }
1330 name "attribsfromcrosssection"
1331 cppname "AttribsFromCrossSection"
1332 label "From Cross Sections"
1338 name "output_folder"
1342 cppname "AddPointRow"
1343 label "Add Point Row Attribute"
1351 cppname "PtRowAttrib"
1352 label "Point Row Attribute"
1355 disablewhen "{ addptrow == 0 }"
1359 cppname "AddPointCol"
1360 label "Add Point Col Attribute"
1368 cppname "PtColAttrib"
1369 label "Point Col Attribute"
1372 disablewhen "{ addptcol == 0 }"
1376 cppname "AddPrimRow"
1377 label "Add Prim Row Attribute"
1384 name "primrowattrib"
1385 cppname "PrimRowAttrib"
1386 label "Prim Row Attribute"
1388 default { "primrow" }
1389 disablewhen "{ addprimrow == 0 }"
1393 cppname "AddPrimCol"
1394 label "Add Prim Col Attribute"
1401 name "primcolattrib"
1402 cppname "PrimColAttrib"
1403 label "Prim Col Attribute"
1405 default { "primcol" }
1406 disablewhen "{ addprimcol == 0 }"
1409 name "addcrosssectionnum"
1410 cppname "AddCrossSectionNum"
1411 label "Add Cross Section Num Attribute"
1418 name "crosssectionnumattrib"
1419 cppname "CrossSectionNumAttrib"
1420 label "Cross Section Num Attribute"
1422 default { "crossnum" }
1423 disablewhen "{ addcrosssectionnum == 0 }"
1427 cppname "AddCurveNum"
1428 label "Add Curve Num Attribute"
1435 name "curvenumattrib"
1436 cppname "CurveNumAttrib"
1437 label "Curve Num Attribute"
1439 default { "curvenum" }
1440 disablewhen "{ addcurvenum == 0 }"
1442 // TODO: Add option to compute vertex normals with cusp angle.
1453 using namespace SOP_SweepHDKEnums;
1454 using namespace GU_CurveFrame;
1460 template<
typename T>
1462 insertIntoIntervals(
1463 const T *
const edge_lengths,
1464 const T total_length,
1466 const exint ninsertions,
1467 exint *
const ninsertions_per_edge)
1469 UT_ASSERT(nedges >= 1 && ninsertions >= 0);
1470 exint ninsertions_so_far = 0;
1471 for (
exint i = 0; i < nedges; ++i)
1473 T portion = (total_length > 0) ? (edge_lengths[i]/total_length) : (
T(1)/
T(nedges));
1480 ki =
SYSmin(ki, ninsertions-ninsertions_so_far);
1481 ninsertions_per_edge[i] = ki;
1482 ninsertions_so_far += ki;
1484 if (ninsertions_so_far == ninsertions)
1487 struct IntervalComparator {
1488 IntervalComparator(
const T *
const edge_lengths,
const exint *
const ninsertions_per_edge) :
1489 myEdgeLengths(edge_lengths),
1490 myNInsertionsPerEdge(ninsertions_per_edge)
1495 const T nadb = myEdgeLengths[
a]*(myNInsertionsPerEdge[
b]+1);
1496 const T nbda = myEdgeLengths[
b]*(myNInsertionsPerEdge[
a]+1);
1503 return nadb < nbda || (nadb == nbda && a <
b);
1505 const T *
const myEdgeLengths;
1506 const exint *
const myNInsertionsPerEdge;
1508 IntervalComparator comparator(edge_lengths, ninsertions_per_edge);
1512 if (nedges < 20 || (ninsertions-ninsertions_so_far) < 20) {
1514 exint edge_with_largest_intervals = 0;
1515 for (
exint i = 1; i < nedges; ++i) {
1516 if (comparator(edge_with_largest_intervals, i)) {
1517 edge_with_largest_intervals = i;
1520 ++ninsertions_per_edge[edge_with_largest_intervals];
1521 ++ninsertions_so_far;
1522 }
while (ninsertions_so_far < ninsertions);
1531 for (
exint i = 0; i < nedges; ++i)
1534 exint *
const heap_end = heap_begin+nedges;
1535 std::make_heap(heap_begin, heap_end, comparator);
1540 exint edge_with_largest_intervals = heap_begin[0];
1541 ++ninsertions_per_edge[edge_with_largest_intervals];
1542 ++ninsertions_so_far;
1543 if (ninsertions_so_far == ninsertions)
1547 std::pop_heap(heap_begin, heap_end, comparator);
1548 heap_end[-1] = edge_with_largest_intervals;
1549 std::push_heap(heap_begin, heap_end, comparator);
1558 switch (sop_primtype)
1575 return (i==0) ? 0 : (n-i);
1595 if (interrupt.wasInterrupted())
1613 if (interrupt.wasInterrupted())
1617 for (
GA_Offset primoff = start; primoff <
end; ++primoff)
1638 if (!reverse || closed)
1639 vtxoff0 = vertices(0);
1641 vtxoff0 = vertices(n-1);
1643 bool local_by_length = by_length;
1644 if (local_by_length)
1665 local_by_length =
false;
1671 float cur_length = 0;
1679 const float u = cur_length/
length;
1685 if (!local_by_length)
1688 GA_Size nedges = closed ? n : (n-1);
1693 const float u = i/float(nedges);
1702 if (reverse && closed)
1711 static GA_Offset lookupCrossSectionFromAttrib(
1712 const CrossSectionAttribMatchData *copy_order_attrib_data,
1717 if (copy_order_attrib_data->myCurveIntAttrib.isValid())
1720 const exint id = copy_order_attrib_data->myCurveIntAttrib.get(curve_offset);
1721 if (copy_order_attrib_data->myIsUsingMap) {
1727 auto &&it = copy_order_attrib_data->myIntToPrimOff.find(
id);
1728 if (it == copy_order_attrib_data->myIntToPrimOff.end()) {
1739 if (cross_section_group && !cross_section_group->
contains(cross_section_primoff)) {
1743 return cross_section_primoff;
1747 UT_ASSERT_P(copy_order_attrib_data->myCurveStrAttrib.isValid());
1748 UT_ASSERT_P(copy_order_attrib_data->myIsUsingMap);
1755 auto &&it = copy_order_attrib_data->myStrToPrimOff.find(name);
1756 if (it == copy_order_attrib_data->myStrToPrimOff.end()) {
1767 int &primitive_type,
1768 unsigned char &fallback_orderu,
1789 if (pbasisu !=
nullptr)
1796 computeCombinedCrossSectionProperties(
1800 exint num_cross_sections,
1801 exint &cross_section_nedges,
1802 bool &cross_section_closed,
1803 bool &cross_section_unrolled,
1804 bool &varying_nedges,
1806 const bool is_primtype_auto,
1807 int &primitive_type,
1808 unsigned char &fallback_orderu,
1811 if (num_cross_sections == 0)
1819 bool basis_cross_section_closed;
1820 bool basis_cross_section_unrolled;
1823 cross_section_nedges = -1;
1824 varying_nedges =
false;
1826 for (
exint cross_sectioni = 0; cross_sectioni < num_cross_sections; ++cross_sectioni)
1828 GA_Offset cross_section_primoff = *cross_section_it;
1830 if (cross_section_it.
atEnd())
1833 cross_section_it.
rewind();
1837 cross_section_primoffs.
append(cross_section_primoff);
1839 exint local_cross_section_nedges;
1840 bool local_cross_section_closed;
1841 bool local_cross_section_unrolled;
1842 bool nonempty =
getPolyProperties(cross_section_input, cross_section_vertices, local_cross_section_nedges, local_cross_section_closed, local_cross_section_unrolled);
1848 if (cross_section_nedges == -1)
1851 cross_section_closed = local_cross_section_closed;
1852 cross_section_unrolled = local_cross_section_unrolled;
1854 else if (!local_cross_section_closed)
1858 cross_section_closed =
false;
1859 cross_section_unrolled =
false;
1861 else if (local_cross_section_unrolled && cross_section_closed && !cross_section_unrolled)
1865 cross_section_unrolled =
true;
1870 bool local_varying_nedges = (cross_section_nedges != -1 && local_cross_section_nedges != cross_section_nedges);
1872 varying_nedges |= local_varying_nedges;
1875 if (is_primtype_auto)
1877 local_primtype = updateAutoPrimType(cross_section_input, cross_section_primoff, primitive_type, fallback_orderu,
nullptr);
1881 if (local_cross_section_nedges > cross_section_nedges)
1883 cross_section_nedges = local_cross_section_nedges;
1885 if (is_primtype_auto && pbasisu !=
nullptr)
1891 basis_cross_section_closed = local_cross_section_closed;
1892 basis_cross_section_unrolled = local_cross_section_unrolled;
1907 if (pbasisu !=
nullptr && *pbasisu !=
nullptr)
1912 if (basis_primtype != primitive_type ||
1913 basis_cross_section_closed != cross_section_closed ||
1914 basis_cross_section_unrolled != cross_section_unrolled)
1929 computeCombinedCrossSectionPropertiesAttrib(
1934 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
1935 exint &cross_section_nedges,
1936 bool &cross_section_closed,
1937 bool &cross_section_unrolled,
1938 bool &varying_nedges,
1940 const bool is_primtype_auto,
1941 int &primitive_type,
1942 unsigned char &fallback_orderu,
1945 exint num_vertices = curve_vertices.
size();
1946 if (num_vertices == 0)
1949 const GA_AttributeOwner curve_owner = copy_order_attrib_data->myCurveAttribOwner;
1954 bool basis_cross_section_closed;
1955 bool basis_cross_section_unrolled;
1958 cross_section_nedges = -1;
1959 varying_nedges =
false;
1961 for (
exint vtxi = 0; vtxi < num_vertices; ++vtxi)
1963 GA_Offset curve_offset = curve_vertices[vtxi];
1965 curve_offset = curve_input->
vertexPoint(curve_offset);
1966 GA_Offset cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data, curve_offset, cross_section_input, cross_section_group);
1973 cross_section_primoffs.
append(cross_section_primoff);
1975 exint local_cross_section_nedges;
1976 bool local_cross_section_closed;
1977 bool local_cross_section_unrolled;
1978 bool nonempty =
getPolyProperties(cross_section_input, cross_section_vertices, local_cross_section_nedges, local_cross_section_closed, local_cross_section_unrolled);
1984 if (cross_section_nedges == -1)
1987 cross_section_closed = local_cross_section_closed;
1988 cross_section_unrolled = local_cross_section_unrolled;
1990 else if (!local_cross_section_closed)
1994 cross_section_closed =
false;
1995 cross_section_unrolled =
false;
1997 else if (local_cross_section_unrolled && cross_section_closed && !cross_section_unrolled)
2001 cross_section_unrolled =
true;
2006 bool local_varying_nedges = (cross_section_nedges != -1 && local_cross_section_nedges != cross_section_nedges);
2008 varying_nedges |= local_varying_nedges;
2011 if (is_primtype_auto)
2013 local_primtype = updateAutoPrimType(cross_section_input, cross_section_primoff, primitive_type, fallback_orderu,
nullptr);
2017 if (local_cross_section_nedges > cross_section_nedges)
2019 cross_section_nedges = local_cross_section_nedges;
2021 if (is_primtype_auto && pbasisu !=
nullptr)
2027 basis_cross_section_closed = local_cross_section_closed;
2028 basis_cross_section_unrolled = local_cross_section_unrolled;
2043 if (pbasisu !=
nullptr && *pbasisu !=
nullptr)
2048 if (basis_primtype != primitive_type ||
2049 basis_cross_section_closed != cross_section_closed ||
2050 basis_cross_section_unrolled != cross_section_unrolled)
2063 const bool output_points_only,
2064 const bool is_primtype_auto,
2065 int &primitive_type,
2066 unsigned char &fallback_orderv,
2076 fallback_orderv = 0;
2077 if (!is_primtype_auto)
2082 if (curve_input ==
nullptr)
2086 fallback_orderv = 4;
2093 bool is_curve =
false;
2122 computeSingleGridSetup(
2126 const bool single_cross_section,
2129 exint cross_section_nedges,
2130 bool cross_section_closed,
2131 bool cross_section_unrolled,
2133 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
2134 bool varying_nedges_all_case,
2140 const bool closed_if_no_curve_input,
2144 const bool output_points_only,
2145 const bool unroll_closed_row_col,
2146 const bool is_primtype_auto,
2148 unsigned char fallback_orderu,
2149 unsigned char fallback_orderv,
2152 exint cap_divisions,
2155 sop_SweepGrid &grid_info,
2158 const bool has_col_surface_type =
2161 const bool has_row_surface_type =
2164 const bool has_rowcol_surface_type =
2165 has_col_surface_type || has_row_surface_type;
2167 const bool is_polygon_type = (!output_points_only && primitive_type ==
GA_PRIMPOLY);
2168 const bool could_add_row_seam_vertex = (has_col_surface_type || !is_polygon_type) && unroll_closed_row_col;
2169 const bool could_add_col_seam_vertex = (has_row_surface_type || !is_polygon_type) && unroll_closed_row_col;
2171 if (curve_input ==
nullptr)
2174 UT_ASSERT(cross_section_input !=
nullptr);
2176 grid_info.myCurveClosed = closed_if_no_curve_input;
2177 grid_info.myCurveUnrolled = (grid_info.myCurveClosed && could_add_row_seam_vertex);
2179 grid_info.myCurveNEdges = num_cross_sections - !grid_info.myCurveClosed;
2181 bool varying_nedges;
2183 bool is_valid_grid = computeCombinedCrossSectionProperties(
2184 cross_section_input,
2185 cross_section_group,
2188 cross_section_nedges,
2189 cross_section_closed,
2190 cross_section_unrolled,
2192 cross_section_primoffs,
2201 grid_info.myCrossSectionNEdges = cross_section_nedges;
2202 grid_info.myCrossSectionClosed = cross_section_closed;
2203 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2204 grid_info.myAllEqualNEdges = !varying_nedges;
2205 grid_info.mySingleCrossSection = (cross_section_primoffs.
size() == 1);
2206 if (grid_info.mySingleCrossSection)
2207 grid_info.myCrossSectionPrimOff = cross_section_primoffs(0);
2209 grid_info.myCrossSectionPrimOffs =
new GA_OffsetList(std::move(cross_section_primoffs));
2214 grid_info.myCurvePrimOff = curve_primoff;
2218 bool curve_unrolled;
2220 bool nonempty =
getPolyProperties(curve_input, curve_vertices, curve_nedges, curve_closed, curve_unrolled);
2226 grid_info.myCurveClosed = curve_closed;
2227 grid_info.myCurveUnrolled = curve_unrolled || (curve_closed && could_add_row_seam_vertex);
2228 grid_info.myCurveNEdges = curve_nedges;
2230 if (single_cross_section)
2233 grid_info.myCrossSectionNEdges = cross_section_nedges;
2234 grid_info.myCrossSectionClosed = cross_section_closed;
2235 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2236 grid_info.myAllEqualNEdges =
true;
2237 grid_info.mySingleCrossSection =
true;
2238 grid_info.myCrossSectionPrimOff = single_cross_section_primoff;
2243 "Other cases should have resolved to single cross section grids.");
2245 bool varying_nedges = varying_nedges_all_case;
2247 if (copy_order == CopyOrder::CYCLEVTX)
2249 exint num_cross_sections = curve_nedges + !curve_closed;
2250 bool is_valid_grid = computeCombinedCrossSectionProperties(
2251 cross_section_input,
2252 cross_section_group,
2255 cross_section_nedges,
2256 cross_section_closed,
2257 cross_section_unrolled,
2259 cross_section_primoffs,
2270 bool is_valid_grid = computeCombinedCrossSectionPropertiesAttrib(
2271 cross_section_input,
2272 cross_section_group,
2275 copy_order_attrib_data,
2276 cross_section_nedges,
2277 cross_section_closed,
2278 cross_section_unrolled,
2280 cross_section_primoffs,
2290 grid_info.myCrossSectionNEdges = cross_section_nedges;
2291 grid_info.myCrossSectionClosed = cross_section_closed;
2292 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2293 grid_info.myAllEqualNEdges = !varying_nedges;
2294 grid_info.mySingleCrossSection =
false;
2297 exint ncopies = grid_info.myCurveNEdges + !grid_info.myCurveClosed;
2298 grid_info.myCurveNEdges = (ncopies * cross_section_primoffs_all_case->
size()) - !grid_info.myCurveClosed;
2300 for (
exint copyi = 0; copyi < ncopies; ++copyi)
2302 grid_info.myCrossSectionPrimOffs->append(*cross_section_primoffs_all_case);
2307 grid_info.myCrossSectionPrimOffs =
new GA_OffsetList(std::move(cross_section_primoffs));
2312 grid_info.myHasPolygonCaps =
2313 !output_points_only &&
2315 (end_cap_type == EndCapType::SINGLE &&
2316 (!grid_info.myCurveClosed && grid_info.myCrossSectionClosed && grid_info.myCrossSectionNEdges > 1)) ||
2317 (end_cap_type == EndCapType::SIDESINGLE &&
2318 (!grid_info.myCrossSectionClosed && grid_info.myCurveClosed && grid_info.myCurveNEdges > 1))
2320 !has_rowcol_surface_type;
2323 grid_info.myUEndPoles =
false;
2325 grid_info.myUEndPoles =
2326 !output_points_only &&
2327 (end_cap_type !=
EndCapType::NONE && end_cap_type != EndCapType::SINGLE && end_cap_type != EndCapType::SIDESINGLE) &&
2328 (!grid_info.myCrossSectionClosed && grid_info.myCurveClosed) &&
2335 grid_info.myVEndPoles =
2336 !output_points_only &&
2337 (end_cap_type !=
EndCapType::NONE && end_cap_type != EndCapType::SINGLE && end_cap_type != EndCapType::SIDESINGLE) &&
2338 (!grid_info.myCurveClosed) &&
2341 if (grid_info.myUEndPoles)
2344 grid_info.myCrossSectionNEdges += 2*cap_divisions;
2347 UT_ASSERT(grid_info.myCurveNEdges >= 1);
2349 else if (grid_info.myVEndPoles)
2352 grid_info.myCurveNEdges += 2*cap_divisions;
2354 if (!grid_info.mySingleCrossSection)
2358 GA_OffsetList &primoffs = *grid_info.myCrossSectionPrimOffs;
2359 for (
exint i = 0; i < cap_divisions; ++i)
2360 new_cross_section_primoffs.
append(primoffs(0));
2361 new_cross_section_primoffs.
append(primoffs);
2362 for (
exint i = 0; i < cap_divisions; ++i)
2363 new_cross_section_primoffs.
append(primoffs.
last());
2364 primoffs = std::move(new_cross_section_primoffs);
2368 UT_ASSERT(grid_info.myCrossSectionNEdges >= 1);
2371 using PrimitiveType = sop_SweepGrid::PrimitiveType;
2372 grid_info.myPrimitiveType = PrimitiveType::POINTS;
2373 if (!output_points_only)
2375 grid_info.myPrimitiveType = PrimitiveType::POLYGON;
2377 grid_info.myPrimitiveType = PrimitiveType::POLYSOUP;
2379 grid_info.myPrimitiveType = PrimitiveType::MESH;
2381 grid_info.myPrimitiveType = PrimitiveType::NURBS;
2383 grid_info.myPrimitiveType = PrimitiveType::BEZIER;
2387 if (grid_info.myPrimitiveType != PrimitiveType::POLYGON &&
2388 (grid_info.myCurveNEdges <= 0 || grid_info.myCrossSectionNEdges <= 0))
2390 grid_info.myPrimitiveType = PrimitiveType::POLYGON;
2393 if (grid_info.myPrimitiveType == PrimitiveType::NURBS)
2395 if (fallback_orderv == 0)
2400 fallback_orderv = (is_primtype_auto && curve_input !=
nullptr) ? 2 : 4;
2402 exint curve_nvertices = grid_info.myCurveNEdges + (!grid_info.myCurveClosed || grid_info.myCurveUnrolled);
2403 if (curve_nvertices < fallback_orderv)
2407 fallback_orderv =
SYSclamp(
int(curve_nvertices), 2, 3);
2409 if (fallback_orderu == 0)
2412 fallback_orderu = (is_primtype_auto && cross_section_input !=
nullptr) ? 2 : 4;
2414 exint cross_section_nvertices = grid_info.myCrossSectionNEdges + (!grid_info.myCrossSectionClosed || grid_info.myCrossSectionUnrolled);
2415 if (cross_section_nvertices < fallback_orderu)
2419 fallback_orderu =
SYSclamp(
int(cross_section_nvertices), 2, 3);
2422 else if (grid_info.myPrimitiveType == PrimitiveType::BEZIER)
2424 if (fallback_orderv == 0)
2429 fallback_orderv = is_primtype_auto ? 2 : 4;
2431 if (grid_info.myCurveNEdges % (fallback_orderv-1) != 0)
2434 fallback_orderv = 2;
2436 if (fallback_orderu == 0)
2439 fallback_orderu = is_primtype_auto ? 2 : 4;
2441 if (grid_info.myCrossSectionNEdges % (fallback_orderu-1) != 0)
2444 fallback_orderu = 2;
2447 grid_info.myBasisOrderCrossSection = fallback_orderu;
2448 grid_info.myBasisOrderCurve = fallback_orderv;
2451 num_points = (grid_info.myCurveNEdges + !grid_info.myCurveClosed - 2*
exint(grid_info.myVEndPoles))
2452 * (grid_info.myCrossSectionNEdges + !grid_info.myCrossSectionClosed - 2*
exint(grid_info.myUEndPoles))
2453 + 2*
exint(grid_info.myVEndPoles) + 2*
exint(grid_info.myUEndPoles);
2458 template<
typename T>
2461 const sop_SweepGrid &grid_info,
2463 const bool output_points_only,
2464 const bool triangular_poles,
2465 const bool swap_row_col,
2466 const T grid_start_ptnum,
2472 grid.
myUnrollCurves = grid_info.myCurveUnrolled || grid_info.myCrossSectionUnrolled;
2475 bool is_single_grid_prim =
false;
2476 if (output_points_only)
2481 is_single_grid_prim = (grid.
myPrimitiveType != PrimitiveType::POLYGON);
2490 const exint nedgerows = swap_row_col ? grid_info.myCrossSectionNEdges : grid_info.myCurveNEdges;
2491 const exint nedgecols = swap_row_col ? grid_info.myCurveNEdges : grid_info.myCrossSectionNEdges;
2492 bool vclosed = swap_row_col ? grid_info.myCrossSectionClosed : grid_info.myCurveClosed;
2493 bool uclosed = swap_row_col ? grid_info.myCurveClosed : grid_info.myCrossSectionClosed;
2494 bool uendpoles = swap_row_col ? grid_info.myVEndPoles : grid_info.myUEndPoles;
2495 bool vendpoles = swap_row_col ? grid_info.myUEndPoles : grid_info.myVEndPoles;
2496 if (is_single_grid_prim)
2500 if (nvtxrows < 2 || nvtxcols < 2)
2502 is_single_grid_prim =
false;
2507 unsigned char orderv = swap_row_col ? grid_info.myBasisOrderCrossSection : grid_info.myBasisOrderCurve;
2508 unsigned char orderu = swap_row_col ? grid_info.myBasisOrderCurve : grid_info.myBasisOrderCrossSection;
2516 grid.
initTorus(nedgerows, nedgecols, grid_start_ptnum);
2517 else if (!uendpoles)
2518 grid.
initRowTube(nedgerows, nedgecols, grid_start_ptnum);
2523 const exint nmid_points = nedgerows*(nedgecols - 1);
2524 grid.
initRowSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2532 grid.
initColTube(nedgerows, nedgecols, grid_start_ptnum);
2537 const exint nmid_points = (nedgerows - 1)*nedgecols;
2538 grid.
initColSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2549 const exint nmid_points = (nedgerows - 1)*(nedgecols+1);
2550 grid.
initSplitColSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2557 appendPrimTypeCountPair(
2558 UT_Array<std::pair<int,exint>> &prim_type_count_pairs,
2562 if (prim_type_count_pairs.isEmpty() || prim_type_count_pairs.last().first != primtype)
2564 prim_type_count_pairs.append(std::pair<int,exint>(primtype, count));
2568 prim_type_count_pairs.last().second +=
count;
2581 if (!(closed_span_lengths.
size() & 1) == closed)
2582 ++closed_span_lengths.
last();
2584 closed_span_lengths.
append(1);
2591 appendSingleGridTopology(
2592 const sop_SweepGrid &grid_info,
2594 const bool output_points_only,
2595 const bool triangular_poles,
2596 const bool single_polygon_caps,
2597 const bool swap_row_col,
2599 UT_Array<std::pair<int,exint>> &prim_type_count_pairs,
2609 exint grid_start_ptnum =
exint(grid_info.myStartPtOff);
2611 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_start_ptnum, grid);
2616 if (num_grid_prims == 0)
2619 bool current_has_polygon_caps = grid_info.myHasPolygonCaps;
2620 bool is_row_cap = current_has_polygon_caps && grid.
myNoWrapV;
2621 bool is_cross_section_cap = !grid_info.myCrossSectionClosed;
2622 exint cap_count = current_has_polygon_caps ? 2 : 0;
2647 appendPrimTypeCountPair(prim_type_count_pairs, primtype, num_grid_prims + cap_count);
2651 appendPrimTypeCountPair(prim_type_count_pairs, cap_primtype, 1);
2652 appendPrimTypeCountPair(prim_type_count_pairs, primtype, num_grid_prims);
2653 appendPrimTypeCountPair(prim_type_count_pairs, cap_primtype, 1);
2656 exint cap_vertex_count = 0;
2657 if (current_has_polygon_caps)
2659 auto &&add_polygon_cap_functor = [is_row_cap,cap_vertex_count,swap_row_col,is_cross_section_cap,&grid,&vertexlistsizelist,&closed_span_lengths,&vertexpointnumbers](
bool last_cap)
2661 vertexlistsizelist.append(cap_vertex_count);
2664 appendClosedSpans(closed_span_lengths,
true);
2666 const exint old_size = vertexpointnumbers.
size();
2667 vertexpointnumbers.
bumpSize(old_size + cap_vertex_count);
2668 exint *vertexpointnumber_start = vertexpointnumbers.
getArray() + old_size;
2672 exint row = last_cap ? grid.myNumEdgeRows : 0;
2673 for (
exint col = 0; col < cap_vertex_count; ++col)
2675 exint point_col = ((last_cap != swap_row_col) != is_cross_section_cap) ? col : reverseVtx(col, cap_vertex_count,
true);
2676 vertexpointnumber_start[col] = grid.getPoint(row, point_col);
2682 exint col = last_cap ? grid.myNumEdgeCols : 0;
2683 for (
exint row = 0; row < cap_vertex_count; ++
row)
2685 exint point_row = ((last_cap != swap_row_col) != is_cross_section_cap) ? row : reverseVtx(row, cap_vertex_count,
true);
2686 vertexpointnumber_start[
row] = grid.getPoint(point_row, col);
2690 if (current_has_polygon_caps)
2693 add_polygon_cap_functor(
false);
2698 [&vertexlistsizelist,&closed_span_lengths
2704 UT_ASSERT_P(primnum >= 0 && primnum < num_grid_prims);
2705 vertexlistsizelist.append(primvtxcount);
2707 appendClosedSpans(closed_span_lengths, closed);
2710 const exint old_size = vertexpointnumbers.
size();
2711 vertexpointnumbers.
bumpSize(old_size + grid.myNumVertices);
2712 exint *vertexpointnumber_start = vertexpointnumbers.
getArray() + old_size;
2714 [vertexpointnumber_start,&grid](
exint vtxnum,
exint row,
exint col,
bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
2716 UT_ASSERT_P(vtxnum >= 0 && vtxnum < grid.myNumVertices);
2717 vertexpointnumber_start[vtxnum] = grid.getPoint(row+
exint(isrowend),col+
exint(iscolend));
2720 if (current_has_polygon_caps)
2723 add_polygon_cap_functor(
true);
2728 num_grid_prims += cap_count;
2729 num_grid_verts += 2*cap_vertex_count;
2733 initNonPolyGridPrims(
2734 const sop_SweepGrid &grid_info,
2736 const bool swap_row_col,
2746 GA_Offset primoff = grid_info.myStartPrimOff;
2747 if (grid_info.myHasPolygonCaps)
2755 const exint nvtxrows = nedgerows +
exint(!hull_wrapv);
2756 const exint nvtxcols = nedgecols +
exint(!hull_wrapu);
2763 sop_SweepGrid polygrid_info(grid_info);
2772 polygonsizes.
append(primvtxcount, 1);
2790 exint cap_vertex_count = 0;
2791 if (grid_info.myHasPolygonCaps)
2793 cap_vertex_count = !grid_info.myCurveClosed ? grid_info.myCrossSectionNEdges : grid_info.myCurveNEdges;
2795 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
2797 [&polygonvertexlist,start_vtxoff,&grid,has_endrow,has_endcol,nvtxcols](
exint vtxnum,
exint row,
exint col,
2798 bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
2815 exint soupvtxnum = row*nvtxcols + col;
2816 polygonvertexlist.append(start_vtxoff + soupvtxnum);
2827 hull->
initHullData(nvtxrows, nvtxcols, hull_wrapv, hull_wrapu);
2831 const bool is_bezier = (grid.
myPrimitiveType == PrimitiveType::BEZIER);
2832 if (!is_nurbs && !is_bezier)
2841 if (source_basisu !=
nullptr && source_basisu->
getType() != basis_type)
2842 source_basisu =
nullptr;
2843 if (source_basisv !=
nullptr && source_basisv->
getType() != basis_type)
2844 source_basisv =
nullptr;
2847 if (source_basisu !=
nullptr)
2850 basisu->copyFrom(*source_basisu);
2861 if (source_basisv !=
nullptr)
2881 bool interpolate_ends = !closed;
2882 int extra_knots = order + (closed ? (interpolate_ends ? 1 : (order - 1)) : 0);
2887 (nvertices + extra_knots),
2892 if (basisu ==
nullptr)
2894 basisu = make_nurbs_basis(nvtxcols, grid.
myBasisOrderU, hull_wrapu);
2898 if (basisv ==
nullptr)
2900 basisv = make_nurbs_basis(nvtxrows, grid.
myBasisOrderV, hull_wrapv);
2911 int extra = ((nvertices > 2 && order > 2) || (order <= 2 && closed));
2913 extra + (nvertices / (order - 1)),
2916 if (basisu ==
nullptr)
2918 basisu = make_bez_basis(nvtxcols, grid.
myBasisOrderU, hull_wrapu);
2922 if (basisv ==
nullptr)
2924 basisv = make_bez_basis(nvtxrows, grid.
myBasisOrderV, hull_wrapv);
2935 if (grid_info.myHasPolygonCaps)
2937 const bool side_caps = !grid_info.myCrossSectionClosed;
2938 const GA_Basis *cap_source_basis = (swap_row_col != side_caps) ? basisv : basisu;
2942 cap0_basis->
copyFrom(*cap_source_basis);
2943 cap1_basis->copyFrom(*cap_source_basis);
2948 cap1->setBasis(cap1_basis);
2957 exint cross_section_nedges,
2959 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
2963 const bool closed_if_no_curve_input,
2966 const bool output_points_only,
2967 const bool unroll_closed_row_col,
2968 const int primitive_type,
2970 const exint cap_divisions,
2971 const bool triangular_poles,
2972 const bool swap_row_col,
2984 if (interrupt.wasInterrupted())
2991 if (cross_section_input !=
nullptr && (
2996 exint max_num_grids = 1;
2997 if (curve_input !=
nullptr)
3002 if (curve_input !=
nullptr && (
3012 bool single_cross_section =
true;
3014 bool cross_section_closed = (cross_section_shape == SurfaceShape::TUBE || cross_section_shape == SurfaceShape::SQUARE);
3015 bool cross_section_unrolled =
false;
3017 if (cross_section_input !=
nullptr)
3020 cross_section_range = cross_section_input->
getPrimitiveRange(cross_section_group);
3022 if (ncross_sections == 0)
3032 if (single_cross_section)
3038 single_cross_section_primoff = *it;
3039 bool nonempty =
getPolyProperties(cross_section_input, single_cross_section_primoff,
3040 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3047 if (!single_cross_section || curve_input ==
nullptr)
3048 cross_section_it =
GA_Iterator(cross_section_range);
3050 const bool is_primtype_auto = !output_points_only && (primitive_type ==
GA_PRIMNONE);
3057 closed_span_lengths.
append(0);
3061 bool hassharedpoints =
true;
3062 exint total_num_points = 0;
3063 exint total_num_verts = 0;
3064 exint total_num_prims = 0;
3065 if (curve_input ==
nullptr)
3068 UT_ASSERT(cross_section_input !=
nullptr);
3072 int local_primitive_type = primitive_type;
3073 unsigned char fallback_orderu = 0;
3074 unsigned char fallback_orderv;
3078 local_primitive_type,
3083 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[0];
3085 sop_SweepGrid grid_info;
3087 bool valid_grid = computeSingleGridSetup(
3088 cross_section_input,
3089 cross_section_group,
3093 0,
false,
false, CopyOrder::CYCLEVTX,
nullptr,
false,
nullptr,
3095 closed_if_no_curve_input,
3096 surface_type, output_points_only,
3097 unroll_closed_row_col,
3099 local_primitive_type,
3100 fallback_orderu, fallback_orderv,
3104 grid_info, num_points);
3110 total_num_points = num_points;
3112 exint num_grid_prims;
3113 exint num_grid_verts;
3114 appendSingleGridTopology(
3115 grid_info, surface_type, output_points_only, triangular_poles,
3116 grid_info.myHasPolygonCaps, swap_row_col,
3117 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3118 closed_span_lengths, num_grid_prims, num_grid_verts);
3121 total_num_verts = num_grid_verts;
3122 grid_info.myStartPrimOff =
GA_Offset(0);
3123 total_num_prims = num_grid_prims;
3124 grids.
append(std::move(grid_info));
3126 else if (!single_cross_section && copy_order == CopyOrder::EACH)
3130 for (; !cross_section_it.
atEnd(); ++cross_section_it)
3132 GA_Offset cross_section_primoff = *cross_section_it;
3135 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3143 if (interrupt.wasInterrupted())
3148 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3151 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3152 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3154 int local_primitive_type = primitive_type;
3155 unsigned char fallback_orderu = 0;
3156 unsigned char fallback_orderv;
3160 local_primitive_type,
3167 if (is_primtype_auto && cross_section_input !=
nullptr)
3168 updateAutoPrimType(cross_section_input, cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3170 sop_SweepGrid grid_info;
3172 bool valid_grid = computeSingleGridSetup(
3176 cross_section_primoff,
3177 cross_section_nedges,
3178 cross_section_closed,
3179 cross_section_unrolled,
3184 curve_input, curve_primoff,
3188 unroll_closed_row_col,
3190 local_primitive_type,
3191 fallback_orderu, fallback_orderv,
3201 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3202 total_num_points += num_points;
3204 exint num_grid_prims;
3205 exint num_grid_verts;
3206 appendSingleGridTopology(
3207 grid_info, surface_type, output_points_only, triangular_poles,
3208 grid_info.myHasPolygonCaps, swap_row_col,
3209 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3210 closed_span_lengths, num_grid_prims, num_grid_verts);
3212 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3213 total_num_verts += num_grid_verts;
3214 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3215 total_num_prims += num_grid_prims;
3216 grids.
append(std::move(grid_info));
3221 else if (!single_cross_section && (copy_order == CopyOrder::CYCLEPR ||
3232 cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data,
3238 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3247 if (interrupt.wasInterrupted())
3252 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3254 if (copy_order == CopyOrder::CYCLEPR)
3256 cross_section_primoff = *cross_section_it;
3258 if (cross_section_it.
atEnd())
3260 cross_section_it.
rewind();
3266 cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data,
3267 curve_primoff, cross_section_input, cross_section_group);
3276 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3282 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3283 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3285 int local_primitive_type = primitive_type;
3286 unsigned char fallback_orderu = 0;
3287 unsigned char fallback_orderv;
3291 local_primitive_type,
3298 if (is_primtype_auto && cross_section_input !=
nullptr)
3299 updateAutoPrimType(cross_section_input, cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3301 sop_SweepGrid grid_info;
3303 bool valid_grid = computeSingleGridSetup(
3307 cross_section_primoff,
3308 cross_section_nedges,
3309 cross_section_closed,
3310 cross_section_unrolled,
3315 curve_input, curve_primoff,
3317 surface_type, output_points_only,
3318 unroll_closed_row_col,
3320 local_primitive_type,
3321 fallback_orderu, fallback_orderv,
3325 grid_info, num_points);
3330 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3331 total_num_points += num_points;
3333 exint num_grid_prims;
3334 exint num_grid_verts;
3335 appendSingleGridTopology(
3336 grid_info, surface_type, output_points_only, triangular_poles,
3337 grid_info.myHasPolygonCaps, swap_row_col,
3338 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3339 closed_span_lengths, num_grid_prims, num_grid_verts);
3341 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3342 total_num_verts += num_grid_verts;
3343 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3344 total_num_prims += num_grid_prims;
3345 grids.
append(std::move(grid_info));
3351 unsigned char fallback_orderu = 0;
3352 int cross_section_primitive_type = is_primtype_auto ?
GA_PRIMPOLY : primitive_type;
3353 bool varying_nedges_all_case =
false;
3355 const bool all_case = (!single_cross_section && copy_order ==
CopyOrder::ALL);
3356 const GA_Basis *all_case_grid_basisu =
nullptr;
3364 bool is_valid_grid = computeCombinedCrossSectionProperties(
3365 cross_section_input,
3366 cross_section_group,
3369 cross_section_nedges,
3370 cross_section_closed,
3371 cross_section_unrolled,
3372 varying_nedges_all_case,
3373 cross_section_primoffs_all_case,
3375 cross_section_primitive_type,
3377 &all_case_grid_basisu);
3388 if (interrupt.wasInterrupted())
3391 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3394 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3395 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3397 int local_primitive_type = primitive_type;
3398 unsigned char fallback_orderv;
3402 local_primitive_type,
3409 if (single_cross_section && is_primtype_auto && cross_section_input !=
nullptr)
3410 updateAutoPrimType(cross_section_input, single_cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3414 local_primitive_type = cross_section_primitive_type;
3417 if (all_case && pbasisu !=
nullptr)
3421 *pbasisu = all_case_grid_basisu;
3424 sop_SweepGrid grid_info;
3426 bool valid_grid = computeSingleGridSetup(
3427 cross_section_input,
3428 cross_section_group,
3429 single_cross_section,
3431 single_cross_section_primoff,
3432 cross_section_nedges,
3433 cross_section_closed,
3434 cross_section_unrolled,
3436 copy_order_attrib_data,
3437 varying_nedges_all_case,
3438 (cross_section_primoffs_all_case.
size() == 0) ?
nullptr : &cross_section_primoffs_all_case,
3439 curve_input, curve_primoff,
3440 closed_if_no_curve_input,
3441 surface_type, output_points_only,
3442 unroll_closed_row_col,
3444 local_primitive_type,
3445 fallback_orderu, fallback_orderv,
3449 grid_info, num_points);
3454 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3455 total_num_points += num_points;
3457 exint num_grid_prims;
3458 exint num_grid_verts;
3459 appendSingleGridTopology(
3460 grid_info, surface_type, output_points_only, triangular_poles,
3461 grid_info.myHasPolygonCaps, swap_row_col,
3462 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3463 closed_span_lengths, num_grid_prims, num_grid_verts);
3465 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3466 total_num_verts += num_grid_verts;
3467 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3468 total_num_prims += num_grid_prims;
3469 grids.
append(std::move(grid_info));
3474 if (interrupt.wasInterrupted())
3481 if (output_points_only)
3487 prim_type_count_pairs.getArray(),
3488 start_ptoff, total_num_points,
3489 vertexlistsizelist, vertexpointnumbers.
getArray(),
3506 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3508 grids[gridi].myStartPtOff += start_ptoff;
3513 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3515 grids[gridi].myStartVtxOff += start_vtxoff;
3520 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3522 grids[gridi].myStartPrimOff += start_primoff;
3530 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3532 const sop_SweepGrid &grid_info = grids[gridi];
3534 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3535 const GA_Basis *basisu = grid_basisus.
isEmpty() ?
nullptr : grid_basisus[gridi];
3536 const GA_Basis *basisv = grid_basisvs.
isEmpty() ?
nullptr : grid_basisvs[gridi];
3539 initNonPolyGridPrims(grid_info, grid, swap_row_col, basisu, basisv, output_geo);
3547 template<
typename FUNCTOR>
3549 copyVertexCrossSectionWrapper(
3551 const sop_SweepGrid &grid_info,
3552 const FUNCTOR &functor)
3556 exint cap_vertex_count = 0;
3557 if (grid_info.myHasPolygonCaps)
3564 for (
exint col = 0; col < cap_vertex_count; ++col)
3567 functor(grid_info.myStartVtxOff + col, 0, reverseVtx(col, cap_vertex_count,
true));
3575 for (
exint row = 0; row < cap_vertex_count; ++
row)
3578 functor(grid_info.myStartVtxOff + row, reverseVtx(row, cap_vertex_count,
true), 0);
3583 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
3584 auto &&functor_wrapper = [&functor,start_vtxoff](
exint vtxnum,
exint row,
exint col,
bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
3586 GA_Offset output_vtxoff = start_vtxoff + vtxnum;
3587 functor(output_vtxoff, row +
exint(isrowend), col +
exint(iscolend));
3590 if (grid_info.myHasPolygonCaps)
3597 for (
exint col = 0; col < cap_vertex_count; ++col)
3605 for (
exint row = 0; row < cap_vertex_count; ++
row)
3613 template<
typename TRANSFORM_T,GA_AttributeOwner output_attrib_owner,
bool wrap_to_inval
id=false,
typename OUTPUT_ATTRIB_T,
typename INPUT_ATTRIB_T,
typename GET_TRANSFORM_FUNCTOR,
typename TRANSFORM_FUNCTOR,
typename INTERP_FUNCTOR>
3615 copyCrossSectionAttributeWrapper2(
3617 const OUTPUT_ATTRIB_T &outputh,
3618 const INPUT_ATTRIB_T &cross_sectionh,
3621 const sop_SweepGridTransformWrapper *transforms,
3622 const sop_SweepGrid &grid_info,
3623 const bool reverse_cross_sections,
3624 const bool swap_row_col,
3625 const GET_TRANSFORM_FUNCTOR &get_transform_functor,
3626 const TRANSFORM_FUNCTOR &transform_and_copy_functor,
3627 const INTERP_FUNCTOR &transform_and_interp_functor)
3630 UT_ASSERT(cross_section_owner == output_attrib_owner ||
3634 exint prev_curve_vtxi = -1;
3637 exint current_cross_section_nedges;
3638 bool current_cross_section_closed;
3639 bool current_cross_section_unrolled;
3641 auto &&functor = [&grid_info,&outputh,&cross_sectionh,
3642 cross_section_owner,
3643 &get_transform_functor,&transform_and_copy_functor,
3644 &transform_and_interp_functor,
3645 cross_section_input,
3647 reverse_cross_sections,
3650 &source_cross_section_primoff,
3651 &cross_section_vertices,
3652 ¤t_cross_section_nedges,
3653 ¤t_cross_section_closed,
3654 ¤t_cross_section_unrolled,
3657 exint num_curve_edges = grid_info.myCurveNEdges;
3658 bool is_curve_closed = grid_info.myCurveClosed;
3659 exint curve_vtxi = swap_row_col ? col :
row;
3660 exint num_cross_section_edges = grid_info.myCrossSectionNEdges;
3662 exint cross_section_vtxi = swap_row_col ? row : col;
3664 if (curve_vtxi != prev_curve_vtxi)
3669 if (output_attrib_owner ==
GA_ATTRIB_VERTEX && is_curve_closed && curve_vtxi == num_curve_edges)
3671 transform = get_transform_functor(transforms, curve_vtxi, grid_info);
3672 source_cross_section_primoff =
3673 grid_info.mySingleCrossSection ?
3674 GA_Offset(grid_info.myCrossSectionPrimOff) :
3679 cross_section_vertices = cross_section_input->getPrimitiveVertexList(source_cross_section_primoff);
3680 getPolyProperties(cross_section_input, cross_section_vertices, current_cross_section_nedges, current_cross_section_closed, current_cross_section_unrolled);
3682 prev_curve_vtxi = curve_vtxi;
3687 transform_and_copy_functor(cross_sectionh, source_cross_section_primoff, transform, outputh, output_offset);
3691 constexpr
bool is_vertex_attrib = (output_attrib_owner ==
GA_ATTRIB_VERTEX);
3693 if (current_cross_section_nedges == num_cross_section_edges)
3697 if (reverse_cross_sections)
3700 cross_section_vtxi = reverseVtx(cross_section_vtxi, current_cross_section_nedges +
exint(is_vertex_attrib || !current_cross_section_closed),
3701 !is_vertex_attrib && current_cross_section_closed);
3708 if (cross_section_vtxi == cross_section_vertices.size())
3710 if (wrap_to_invalid)
3717 vtxoff = cross_section_vertices[0];
3720 vtxoff = cross_section_vertices[cross_section_vtxi];
3722 transform_and_copy_functor(cross_sectionh, cross_section_offset, transform, outputh, output_offset);
3729 UT_ASSERT_P(num_cross_section_edges > current_cross_section_nedges);
3734 exint fine_fractions = cross_section_vtxi*current_cross_section_nedges;
3735 if (reverse_cross_sections)
3736 fine_fractions = num_cross_section_edges*current_cross_section_nedges - fine_fractions;
3737 exint current_cross_section_edge = fine_fractions / num_cross_section_edges;
3738 exint current_cross_section_fractions = fine_fractions % num_cross_section_edges;
3739 exint current_cross_section_pt = current_cross_section_fractions / current_cross_section_nedges;
3740 if (current_cross_section_pt == 0)
3744 if (current_cross_section_edge == cross_section_vertices.size())
3746 if (wrap_to_invalid)
3753 vtxoff = cross_section_vertices[0];
3756 vtxoff = cross_section_vertices[current_cross_section_edge];
3758 transform_and_copy_functor(cross_sectionh, cross_section_offset, transform, outputh, output_offset);
3766 exint current_cross_section_edge_start = (current_cross_section_edge*num_cross_section_edges + current_cross_section_nedges-1) / current_cross_section_nedges;
3767 exint current_cross_section_edge_end = ((current_cross_section_edge+1)*num_cross_section_edges + current_cross_section_nedges-1) / current_cross_section_nedges;
3768 exint current_cross_section_edge_npts = current_cross_section_edge_end - current_cross_section_edge_start;
3769 double u = double(current_cross_section_pt)/double(current_cross_section_edge_npts);
3773 UT_ASSERT_P(current_cross_section_edge != current_cross_section_nedges);
3774 exint vtxi0 = current_cross_section_edge;
3775 GA_Offset vtxoff0 = cross_section_vertices[vtxi0];
3778 if (current_cross_section_edge+1 == cross_section_vertices.size())
3780 if (wrap_to_invalid)
3787 vtxoff1 = cross_section_vertices[0];
3790 vtxoff1 = cross_section_vertices[current_cross_section_edge+1];
3796 cross_section_offset0 = vtxoff0;
3797 cross_section_offset1 = vtxoff1;
3801 cross_section_offset0 = cross_section_input->vertexPoint(vtxoff0);
3803 cross_section_offset1 = cross_section_input->vertexPoint(vtxoff1);
3805 cross_section_offset1 = vtxoff1;
3807 transform_and_interp_functor(cross_sectionh, cross_section_offset0, cross_section_offset1, u, transform, outputh, output_offset);
3816 copyVertexCrossSectionWrapper(grid, grid_info, functor);
3823 if (grid_info.myHasPolygonCaps)
3826 functor(grid_info.myStartPrimOff, 0, 0);
3829 const GA_Offset start_primoff = grid_info.myStartPrimOff +
exint(grid_info.myHasPolygonCaps);
3830 auto &&functor_wrapper = [&functor,start_primoff](
exint primnum,
exint row,
exint col,
exint primvtxcount,
bool closed)
3832 GA_Offset output_primoff = start_primoff + primnum;
3833 functor(output_primoff, row, col);
3836 if (grid_info.myHasPolygonCaps)
3853 template<
typename VALUE_T,
typename TRANSFORM_T,GA_AttributeOwner attrib_owner,
typename GET_TRANSFORM_FUNCTOR,
typename TRANSFORM_FUNCTOR,
typename INTERP_FUNCTOR>
3855 copyCrossSectionAttributeWrapper(
3860 const sop_SweepGridTransformWrapper *transforms,
3861 const sop_SweepGrid &grid_info,
3862 const bool reverse_cross_sections,
3863 const bool swap_row_col,
3864 const GET_TRANSFORM_FUNCTOR &get_transform_functor,
3865 const TRANSFORM_FUNCTOR &transform_and_copy_functor,
3866 const INTERP_FUNCTOR &transform_and_interp_functor)
3873 copyCrossSectionAttributeWrapper2<TRANSFORM_T,attrib_owner>(
3874 grid, outputh, cross_sectionh, attrib_owner,
3875 cross_section_input, transforms, grid_info,
3876 reverse_cross_sections,
3878 get_transform_functor,
3879 transform_and_copy_functor,
3880 transform_and_interp_functor);
3883 template<
typename T,GA_AttributeOwner attrib_owner>
3885 copyIntegerSingleGrid(
3889 const sop_SweepGridTransformWrapper *transforms,
3890 const sop_SweepGrid &grid_info,
3892 const bool output_points_only,
3893 const bool triangular_poles,
3894 const bool reverse_cross_sections,
3895 const bool swap_row_col)
3903 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3908 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
3913 if (tuple_size == 1)
3916 auto &&transform_and_copy = [](
3921 T value = cross_sectionh.
get(cross_section_offset);
3922 outputh.set(output_offset, value);
3924 auto &&transform_and_interp = [](
3930 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
3931 T value = cross_sectionh.
get(cross_section_offset);
3932 outputh.set(output_offset, value);
3934 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
3935 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
3936 reverse_cross_sections, swap_row_col,
3937 get_transform, transform_and_copy, transform_and_interp);
3942 auto &&transform_and_copy = [tuple_size](
3947 for (
exint component = 0; component < tuple_size; ++component)
3949 T value = cross_sectionh.
get(cross_section_offset, component);
3950 outputh.set(output_offset, component, value);
3953 auto &&transform_and_interp = [tuple_size](
3959 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
3960 for (
exint component = 0; component < tuple_size; ++component)
3962 T value = cross_sectionh.
get(cross_section_offset, component);
3963 outputh.set(output_offset, component, value);
3966 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
3967 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
3968 reverse_cross_sections, swap_row_col,
3969 get_transform, transform_and_copy, transform_and_interp);
3972 template<
typename T,GA_TypeInfo transform_type,GA_AttributeOwner attrib_owner>
3974 copyFloatSingleGrid(
3978 const sop_SweepGridTransformWrapper *transforms,
3979 const sop_SweepGrid &grid_info,
3980 const exint cross_sections_per_vertex,
3981 const exint cap_divisions,
3983 const bool output_points_only,
3984 const bool triangular_poles,
3985 const bool reverse_cross_sections,
3986 const bool swap_row_col)
3994 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3996 const exint cap_rows = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
3997 exint last_cap_start_row = -1;
3998 exint last_cap_start_transform = -1;
3999 if (cross_sections_per_vertex != 1 && cap_rows > 0)
4001 last_cap_start_row = grid_info.myCurveNEdges - cap_rows;
4002 last_cap_start_transform = (last_cap_start_row - cap_rows)/cross_sections_per_vertex + cap_rows;
4005 auto &&fix_transformi_for_all_case = [cap_rows,cross_sections_per_vertex,last_cap_start_row,last_cap_start_transform](
exint &transformi)
4011 transformi /= cross_sections_per_vertex;
4012 else if (transformi > cap_rows)
4014 if (transformi < last_cap_start_row)
4015 transformi = (transformi - cap_rows)/cross_sections_per_vertex + cap_rows;
4017 transformi = last_cap_start_transform + (transformi - last_cap_start_row);
4031 auto &&get_transform = [&
transform,cross_sections_per_vertex,&fix_transformi_for_all_case]
4032 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix4T<T>*
4035 if (cross_sections_per_vertex != 1)
4036 fix_transformi_for_all_case(transformi);
4038 transform.
setTranslates(transforms->getTranslates<T>()[transformi]);
4041 auto &&transform_and_copy = [](
4048 outputh.set(output_offset, value);
4050 auto &&transform_and_interp = [](
4060 outputh.set(output_offset, value);
4062 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix4T<T>, attrib_owner>(grid,
4063 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4064 reverse_cross_sections, swap_row_col,
4065 get_transform, transform_and_copy, transform_and_interp);
4072 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4073 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4076 if (cross_sections_per_vertex != 1)
4077 fix_transformi_for_all_case(transformi);
4078 return &transforms->getInverse3s<
T>()[transformi];
4080 auto &&transform_and_copy = [](
4087 outputh.set(output_offset, value);
4089 auto &&transform_and_interp = [](
4106 if (new_length2 != 0)
4107 value *= SYSsqrt(orig_length2/new_length2);
4108 outputh.set(output_offset, value);
4110 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4111 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4112 reverse_cross_sections, swap_row_col,
4113 get_transform, transform_and_copy, transform_and_interp);
4120 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4121 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4124 if (cross_sections_per_vertex != 1)
4125 fix_transformi_for_all_case(transformi);
4126 return &transforms->getMatrix3s<
T>()[transformi];
4128 auto &&transform_and_copy = [](
4135 outputh.set(output_offset, value);
4137 auto &&transform_and_interp = [](
4147 outputh.set(output_offset, value);
4149 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4150 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4151 reverse_cross_sections, swap_row_col,
4152 get_transform, transform_and_copy, transform_and_interp);
4159 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4160 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_QuaternionT<T>*
4163 if (cross_sections_per_vertex != 1)
4164 fix_transformi_for_all_case(transformi);
4165 return &transforms->getQuaternions<
T>()[transformi];
4167 auto &&transform_and_copy = [](
4174 outputh.set(output_offset, value);
4176 auto &&transform_and_interp = [](
4186 value = *transform *
value;
4187 outputh.set(output_offset, value);
4189 copyCrossSectionAttributeWrapper<UT_QuaternionT<T>,
UT_QuaternionT<T>, attrib_owner>(grid,
4190 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4191 reverse_cross_sections, swap_row_col,
4192 get_transform, transform_and_copy, transform_and_interp);
4197 if (tuple_size == 9)
4200 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4201 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4204 if (cross_sections_per_vertex != 1)
4205 fix_transformi_for_all_case(transformi);
4206 return &transforms->getMatrix3s<
T>()[transformi];
4208 auto &&transform_and_copy = [](
4215 outputh.set(output_offset, value);
4217 auto &&transform_and_interp = [](
4227 outputh.set(output_offset, value);
4229 copyCrossSectionAttributeWrapper<UT_Matrix3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4230 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4231 reverse_cross_sections, swap_row_col,
4232 get_transform, transform_and_copy, transform_and_interp);
4235 if (tuple_size == 16)
4240 auto &&get_transform = [&
transform,cross_sections_per_vertex,&fix_transformi_for_all_case]
4241 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix4T<T>*
4244 if (cross_sections_per_vertex != 1)
4245 fix_transformi_for_all_case(transformi);
4247 transform.
setTranslates(transforms->getTranslates<T>()[transformi]);
4250 auto &&transform_and_copy = [](
4257 outputh.set(output_offset, value);
4259 auto &&transform_and_interp = [](
4269 outputh.set(output_offset, value);
4271 copyCrossSectionAttributeWrapper<UT_Matrix4T<T>,
UT_Matrix4T<T>, attrib_owner>(grid,
4272 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4273 reverse_cross_sections, swap_row_col,
4274 get_transform, transform_and_copy, transform_and_interp);
4281 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
4287 if (tuple_size == 1)
4290 auto &&transform_and_copy = [](
4295 T value = cross_sectionh.
get(cross_section_offset);
4296 outputh.set(output_offset, value);
4298 if (is_integer_type)
4300 auto &&transform_and_interp = [](
4306 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4307 T value = cross_sectionh.
get(cross_section_offset);
4308 outputh.set(output_offset, value);
4310 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4311 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4312 reverse_cross_sections, swap_row_col,
4313 get_transform, transform_and_copy, transform_and_interp);
4317 auto &&transform_and_interp = [](
4323 const T value0 = cross_sectionh.
get(cross_section_offset0);
4324 const T value1 = cross_sectionh.
get(cross_section_offset1);
4325 T value =
SYSlerp(value0, value1, t);
4326 outputh.set(output_offset, value);
4328 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4329 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4330 reverse_cross_sections, swap_row_col,
4331 get_transform, transform_and_copy, transform_and_interp);
4335 if (tuple_size == 2 && !is_integer_type)
4338 auto &&transform_and_copy = [](
4344 outputh.set(output_offset, value);
4346 auto &&transform_and_interp = [](
4355 outputh.set(output_offset, value);
4357 copyCrossSectionAttributeWrapper<UT_Vector2T<T>,
void, attrib_owner>(grid,
4358 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4359 reverse_cross_sections, swap_row_col,
4360 get_transform, transform_and_copy, transform_and_interp);
4363 if (tuple_size == 3 && !is_integer_type)
4366 auto &&transform_and_copy = [](
4372 outputh.set(output_offset, value);
4374 auto &&transform_and_interp = [](
4383 outputh.set(output_offset, value);
4385 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
void, attrib_owner>(grid,
4386 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4387 reverse_cross_sections, swap_row_col,
4388 get_transform, transform_and_copy, transform_and_interp);
4393 auto &&transform_and_copy = [tuple_size](
4398 for (
exint component = 0; component < tuple_size; ++component)
4400 T value = cross_sectionh.
get(cross_section_offset, component);
4401 outputh.set(output_offset, component, value);
4404 if (is_integer_type)
4406 auto &&transform_and_interp = [tuple_size](
4412 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4413 for (
exint component = 0; component < tuple_size; ++component)
4415 T value = cross_sectionh.
get(cross_section_offset, component);
4416 outputh.set(output_offset, component, value);
4419 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4420 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4421 reverse_cross_sections, swap_row_col,
4422 get_transform, transform_and_copy, transform_and_interp);
4426 auto &&transform_and_interp = [tuple_size](
4432 for (
exint component = 0; component < tuple_size; ++component)
4434 const T value0 = cross_sectionh.
get(cross_section_offset0, component);
4435 const T value1 = cross_sectionh.
get(cross_section_offset1, component);
4436 T value =
SYSlerp(value0, value1, t);
4437 outputh.set(output_offset, component, value);
4440 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4441 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4442 reverse_cross_sections, swap_row_col,
4443 get_transform, transform_and_copy, transform_and_interp);
4447 template<GA_AttributeOwner attrib_owner>
4449 copyAttribSingleGrid(
4453 const sop_SweepGrid &grid_info,
4455 const bool output_points_only,
4456 const bool triangular_poles,
4457 const bool reverse_cross_sections,
4458 const bool swap_row_col)
4463 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
4466 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
4471 auto &&transform_and_copy = [](
4476 output_attrib->copy(output_offset, *cross_section_attrib, cross_section_offset);
4478 auto &&transform_and_interp = [](
4484 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4485 output_attrib->copy(output_offset, *cross_section_attrib, cross_section_offset);
4489 copyCrossSectionAttributeWrapper2<void, attrib_owner>(grid,
4490 output_attrib, cross_section_attrib, attrib_owner, cross_section_input,
nullptr, grid_info,
4491 reverse_cross_sections, swap_row_col,
4492 get_transform, transform_and_copy, transform_and_interp);
4495 static const sop_SweepGridTransformWrapper *
4496 gridOffsetTransforms(
4497 const SOP_SweepHDKCache *
const transform_cache,
4498 sop_SweepGridTransformWrapper &grid_transforms,
4501 if (transform_cache ==
nullptr)
4504 grid_transforms.
init(*transform_cache, gridi);
4506 return &grid_transforms;
4509 template<GA_AttributeOwner attrib_owner>
4511 copyCrossSectionAttrib2(
4515 const SOP_SweepHDKCache *transform_cache,
4516 const sop_SweepGrid *grids,
4518 const exint cross_sections_per_vertex,
4519 const exint cap_divisions,
4521 const bool output_points_only,
4522 const bool triangular_poles,
4523 const bool reverse_cross_sections,
4524 const bool swap_row_col)
4529 const exint PARALLEL_THRESHOLD = 2048;
4530 const bool parallel = (ngrids > 1 &&
4535 if (!output_numeric)
4542 copyAttribSingleGrid<attrib_owner>(
4543 output_attrib, cross_section_attrib, cross_section_input,
4545 surface_type, output_points_only, triangular_poles,
4546 reverse_cross_sections, swap_row_col);
4557 functor(grid_range);
4564 if (!cross_section_numeric)
4568 if (tuple_size != cross_section_numeric->
getTupleSize())
4583 sop_SweepGridTransformWrapper local_grid_transforms;
4584 if (tuple_size == 3)
4592 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4593 copyFloatSingleGrid<fpreal64,GA_TYPE_POINT,attrib_owner>(
4594 output_numeric, cross_section_numeric, cross_section_input,
4595 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4596 surface_type, output_points_only, triangular_poles,
4597 reverse_cross_sections, swap_row_col);
4604 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4605 copyFloatSingleGrid<fpreal32,GA_TYPE_POINT,attrib_owner>(
4606 output_numeric, cross_section_numeric, cross_section_input,
4607 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4608 surface_type, output_points_only, triangular_poles,
4609 reverse_cross_sections, swap_row_col);
4620 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4621 copyFloatSingleGrid<fpreal64,GA_TYPE_NORMAL,attrib_owner>(
4622 output_numeric, cross_section_numeric, cross_section_input,
4623 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4624 surface_type, output_points_only, triangular_poles,
4625 reverse_cross_sections, swap_row_col);
4632 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4633 copyFloatSingleGrid<fpreal32,GA_TYPE_NORMAL,attrib_owner>(
4634 output_numeric, cross_section_numeric, cross_section_input,
4635 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4636 surface_type, output_points_only, triangular_poles,
4637 reverse_cross_sections, swap_row_col);
4648 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4649 copyFloatSingleGrid<fpreal64,GA_TYPE_VECTOR,attrib_owner>(
4650 output_numeric, cross_section_numeric, cross_section_input,
4651 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4652 surface_type, output_points_only, triangular_poles,
4653 reverse_cross_sections, swap_row_col);
4660 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4661 copyFloatSingleGrid<fpreal32,GA_TYPE_VECTOR,attrib_owner>(
4662 output_numeric, cross_section_numeric, cross_section_input,
4663 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4664 surface_type, output_points_only, triangular_poles,
4665 reverse_cross_sections, swap_row_col);
4671 else if (tuple_size == 4)
4679 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4680 copyFloatSingleGrid<fpreal64,GA_TYPE_QUATERNION,attrib_owner>(
4681 output_numeric, cross_section_numeric, cross_section_input,
4682 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4683 surface_type, output_points_only, triangular_poles,
4684 reverse_cross_sections, swap_row_col);
4691 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4692 copyFloatSingleGrid<fpreal32,GA_TYPE_QUATERNION,attrib_owner>(
4693 output_numeric, cross_section_numeric, cross_section_input,
4694 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4695 surface_type, output_points_only, triangular_poles,
4696 reverse_cross_sections, swap_row_col);
4702 else if (tuple_size == 9 || tuple_size == 16)
4710 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4711 copyFloatSingleGrid<fpreal64,GA_TYPE_TRANSFORM,attrib_owner>(
4712 output_numeric, cross_section_numeric, cross_section_input,
4713 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4714 surface_type, output_points_only, triangular_poles,
4715 reverse_cross_sections, swap_row_col);
4722 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4723 copyFloatSingleGrid<fpreal32,GA_TYPE_TRANSFORM,attrib_owner>(
4724 output_numeric, cross_section_numeric, cross_section_input,
4725 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4726 surface_type, output_points_only, triangular_poles,
4727 reverse_cross_sections, swap_row_col);
4738 copyFloatSingleGrid<fpreal64,GA_TYPE_VOID,attrib_owner>(
4739 output_numeric, cross_section_numeric, cross_section_input,
4740 nullptr, grids[gridi], cross_sections_per_vertex, cap_divisions,
4741 surface_type, output_points_only, triangular_poles,
4742 reverse_cross_sections, swap_row_col);
4749 copyFloatSingleGrid<fpreal32,GA_TYPE_VOID,attrib_owner>(
4750 output_numeric, cross_section_numeric, cross_section_input,
4751 nullptr, grids[gridi], cross_sections_per_vertex, cap_divisions,
4752 surface_type, output_points_only, triangular_poles,
4753 reverse_cross_sections, swap_row_col);
4760 copyIntegerSingleGrid<int64,attrib_owner>(
4761 output_numeric, cross_section_numeric, cross_section_input,
4762 nullptr, grids[gridi],
4763 surface_type, output_points_only, triangular_poles,
4764 reverse_cross_sections, swap_row_col);
4771 copyIntegerSingleGrid<int32,attrib_owner>(
4772 output_numeric, cross_section_numeric, cross_section_input,
4773 nullptr, grids[gridi],
4774 surface_type, output_points_only, triangular_poles,
4775 reverse_cross_sections, swap_row_col);
4783 functor(grid_range);
4787 copyCrossSectionAttrib(
4791 const SOP_SweepHDKCache *transform_cache,
4792 const sop_SweepGrid *grids,
4794 const exint cross_sections_per_vertex,
4795 const exint cap_divisions,
4797 const bool output_points_only,
4798 const bool triangular_poles,
4799 const bool reverse_cross_sections,
4800 const bool swap_row_col)
4807 copyCrossSectionAttrib2<GA_ATTRIB_POINT>(
4808 output_attrib, cross_section_attrib, cross_section_input,
4809 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4810 surface_type, output_points_only, triangular_poles,
4811 reverse_cross_sections, swap_row_col);
4815 copyCrossSectionAttrib2<GA_ATTRIB_VERTEX>(
4816 output_attrib, cross_section_attrib, cross_section_input,
4817 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4818 surface_type, output_points_only, triangular_poles,
4819 reverse_cross_sections, swap_row_col);
4823 copyCrossSectionAttrib2<GA_ATTRIB_PRIMITIVE>(
4824 output_attrib, cross_section_attrib, cross_section_input,
4825 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4826 surface_type, output_points_only, triangular_poles,
4827 reverse_cross_sections, swap_row_col);
4831 output_attrib->
replace(*cross_section_attrib);
4835 template<
bool wrap_to_inval
id,
typename FUNCTOR>
4837 copyVertexCurveAttribWrapper(
4838 const sop_SweepGrid &grid_info,
4841 exint cap_divisions,
4842 exint cross_sections_per_vertex,
4843 const bool swap_row_col,
4844 const FUNCTOR ©_functor)
4846 const exint curve_nedges = grid_info.myCurveNEdges;
4847 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
4849 const exint cap_divs = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
4850 exint prev_vtxi = -1;
4852 exint cap_vertex_count = 0;
4853 if (grid_info.myHasPolygonCaps)
4858 cap_vertex_count = cross_section_nedges;
4863 for (
exint col = 0; col < cap_vertex_count; ++col)
4865 copy_functor(grid_info.myStartVtxOff + col, 0);
4871 cap_vertex_count = curve_nedges;
4873 for (
exint row = 0; row < cap_vertex_count; ++
row)
4875 copy_functor(grid_info.myStartVtxOff + row, row);
4880 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
4881 const bool closed_curve = grid_info.myCurveClosed;
4883 start_vtxoff, cross_sections_per_vertex, swap_row_col, closed_curve, ©_functor]
4886 exint vtxi = swap_row_col ? col :
row;
4887 vtxi +=
exint(swap_row_col ? iscolend : isrowend);
4888 if (vtxi != prev_vtxi)
4890 curve_vtxi = vtxi - cap_divs;
4891 if (cross_sections_per_vertex != 1)
4892 curve_vtxi /= cross_sections_per_vertex;
4895 else if (curve_vtxi >= num_vertices)
4898 curve_vtxi = num_vertices-1;
4899 else if (wrap_to_invalid)
4906 copy_functor(start_vtxoff + vtxnum, curve_vtxi);
4908 if (grid_info.myHasPolygonCaps)
4915 curve_vtxi = num_vertices-1;
4917 for (
exint col = 0; col < cap_vertex_count; ++col)
4919 copy_functor(cap_start_vtxoff + col, curve_vtxi);
4925 for (
exint row = 0; row < cap_vertex_count; ++
row)
4927 copy_functor(cap_start_vtxoff + row, row);
4933 template<GA_AttributeOwner attrib_owner,
bool wrap_to_inval
id=false,
typename COPY_FUNCTOR>
4938 const sop_SweepGrid *grids,
4940 const exint cross_sections_per_vertex,
4942 const bool output_points_only,
4943 const bool triangular_poles,
4944 const exint cap_divisions,
4945 const bool swap_row_col,
4946 const COPY_FUNCTOR ©_functor)
4957 const sop_SweepGrid &grid_info = grids[gridi];
4959 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
4964 copyVertexCurveAttribWrapper<wrap_to_invalid>(grid_info, grid, vertices.
size(), cap_divisions, cross_sections_per_vertex, swap_row_col,
4965 [©_functor,&vertices](
GA_Offset output_vtxoff,
exint curve_vtxi)
4968 copy_functor(output_vtxoff, curve_vtxoff);
4974 const exint cap_divs = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
4975 exint prev_vtxi = -1;
4978 &curve_ptoff, curve_input, cross_sections_per_vertex, swap_row_col, ©_functor]
4981 exint vtxi = swap_row_col ? col :
row;
4982 if (vtxi != prev_vtxi)
4984 exint curve_vtxi = vtxi - cap_divs;
4985 if (cross_sections_per_vertex != 1)
4986 curve_vtxi /= cross_sections_per_vertex;
4989 else if (curve_vtxi >= vertices.
size())
4990 curve_vtxi = vertices.
size()-1;
4991 GA_Offset curve_vtxoff = vertices(curve_vtxi);
4992 curve_ptoff = curve_input->
vertexPoint(curve_vtxoff);
4995 copy_functor(output_ptoff, curve_ptoff);
5001 const exint PARALLEL_THRESHOLD = 2048;
5020 const sop_SweepGrid *grids,
5022 const exint cross_sections_per_vertex,
5024 const bool output_points_only,
5025 const bool triangular_poles,
5026 const exint cap_divisions,
5027 const bool swap_row_col)
5034 auto &©_functor = [output_attrib,curve_attrib](
GA_Offset output_off,
GA_Offset curve_off)
5036 output_attrib->
copy(output_off, *curve_attrib, curve_off);
5038 copyCurveAttrib2<GA_ATTRIB_POINT>(
5039 output_attrib, curve_input,
5040 grids, ngrids, cross_sections_per_vertex,
5041 surface_type, output_points_only, triangular_poles, cap_divisions,
5042 swap_row_col, copy_functor);
5046 if (!output_points_only)
5048 auto &©_functor = [output_attrib,curve_attrib](
GA_Offset output_off,
GA_Offset curve_off)
5050 output_attrib->
copy(output_off, *curve_attrib, curve_off);
5052 copyCurveAttrib2<GA_ATTRIB_VERTEX>(
5053 output_attrib, curve_input,
5054 grids, ngrids, cross_sections_per_vertex,
5055 surface_type, output_points_only, triangular_poles, cap_divisions,
5056 swap_row_col, copy_functor);
5061 if (!output_points_only)
5071 const sop_SweepGrid &grid_info = grids[gridi];
5073 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
5076 const GA_Offset startprimoff = grid_info.myStartPrimOff;
5078 output_attrib->
fill(
GA_Range(output_attrib->
getIndexMap(), startprimoff, endprimoff), *curve_attrib, grid_info.myCurvePrimOff);
5082 const exint PARALLEL_THRESHOLD = 2048;
5098 output_attrib->
replace(*curve_attrib);
5110 template<
typename T,GA_AttributeOwner output_owner>
5112 copyCrossSectionUVSingleGrid(
5117 const sop_SweepGrid &grid_info,
5119 const bool is_cross_section_uv_computed,
5120 const bool reverse_cross_sections,
5121 const bool swap_row_col,
5134 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
5144 if (tuple_size == 2)
5148 auto &©_functor = [missing_input_us,&outputh,flipu,swap_row_col,uscale](
5151 const exint cross_section_vtxi = swap_row_col ? row : col;
5152 T value = (cross_section_vtxi == missing_input_us->size()) ?
T(1.0) : (*missing_input_us)[cross_section_vtxi];
5156 output_value[theUComponent] = uscale*
value;
5157 outputh.set(output_offset, output_value);
5160 copyVertexCrossSectionWrapper(grid, grid_info, copy_functor);
5164 else if (tuple_size == 3)
5168 auto &©_functor = [missing_input_us,&outputh,flipu,swap_row_col,uscale](
5171 const exint cross_section_vtxi = swap_row_col ? row : col;
5172 T value = (cross_section_vtxi == missing_input_us->size()) ?
T(1.0) : (*missing_input_us)[cross_section_vtxi];
5176 output_value[theUComponent] = uscale*
value;
5177 outputh.set(output_offset, output_value);
5180 copyVertexCrossSectionWrapper(grid, grid_info, copy_functor);
5187 if (tuple_size == 2)
5190 auto &&transform_and_copy = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5197 value = reverse_cross_sections ?
T(0.0) : T(1.0);
5199 value = cross_sectionh.get(cross_section_offset);
5202 value = T(1.0)-
value;
5203 if (is_cross_section_uv_computed)
5206 output_value[theUComponent] =
value;
5207 outputh.set(output_offset, output_value);
5209 auto &&transform_and_interp = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5216 const T value0 = cross_sectionh.get(cross_section_offset0);
5221 value1 = reverse_cross_sections ? T(0.0) : T(1.0);
5223 value1 = cross_sectionh.get(cross_section_offset1);
5225 T value =
SYSlerp(value0, value1, t);
5227 value = T(1.0)-
value;
5228 if (is_cross_section_uv_computed)
5231 output_value[theUComponent] =
value;
5232 outputh.set(output_offset, output_value);
5239 copyCrossSectionAttributeWrapper2<void, output_owner, wrap_to_invalid>(grid,
5240 outputh, cross_sectionh, cross_section_owner, cross_section_input,
nullptr, grid_info,
5241 reverse_cross_sections, swap_row_col,
5242 get_transform, transform_and_copy, transform_and_interp);
5245 if (tuple_size == 3)
5248 auto &&transform_and_copy = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5255 value = reverse_cross_sections ? T(0.0) : T(1.0);
5257 value = cross_sectionh.get(cross_section_offset);
5260 value = T(1.0)-
value;
5261 if (is_cross_section_uv_computed)
5264 output_value[theUComponent] =
value;
5265 outputh.set(output_offset, output_value);
5267 auto &&transform_and_interp = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5274 const T value0 = cross_sectionh.get(cross_section_offset0);
5279 value1 = reverse_cross_sections ? T(0.0) : T(1.0);
5281 value1 = cross_sectionh.get(cross_section_offset1);
5283 T value =
SYSlerp(value0, value1, t);
5285 value = T(1.0)-
value;
5286 if (is_cross_section_uv_computed)
5289 output_value[theUComponent] =
value;
5290 outputh.set(output_offset, output_value);
5297 copyCrossSectionAttributeWrapper2<void, output_owner, wrap_to_invalid>(grid,
5298 outputh, cross_sectionh, cross_section_owner, cross_section_input,
nullptr, grid_info,
5299 reverse_cross_sections, swap_row_col,
5300 get_transform, transform_and_copy, transform_and_interp);
5305 template<
typename T>
5310 const exint cross_section_nedges,
5311 const exint curve_row)
5314 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_nedges; ++cross_section_vtxi)
5316 exint row = curve_row;;
5317 exint col = cross_section_vtxi;
5324 return sum / cross_section_nedges;
5333 template<
typename T>
5334 static double crossSectionLength(
5338 const exint cross_section_nedges,
5339 const exint curve_row,
5343 double cross_section_length = 0;
5344 exint row = curve_row;
5351 if (dir0 !=
nullptr)
5353 T d = prevpos.
dot(*dir0);
5354 prevpos0 = prevpos - d*(*dir0);
5355 if (dir1 !=
nullptr)
5357 d = prevpos.
dot(*dir1);
5358 prevpos1 = prevpos - d*(*dir1);
5361 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_nedges; ++cross_section_vtxi)
5363 exint row = curve_row;
5364 exint col = cross_section_vtxi+1;
5370 if (dir0 !=
nullptr)
5372 T d = nextpos.
dot(*dir0);
5373 nextpos0 = nextpos - d*(*dir0);
5374 T dist0 = prevpos0.
distance(nextpos0);
5375 if (dir1 !=
nullptr)
5377 d = nextpos.
dot(*dir1);
5378 nextpos1 = nextpos - d*(*dir1);
5380 cross_section_length += 0.5f*(dist0 + prevpos1.
distance(nextpos1));
5384 cross_section_length += dist0;
5389 cross_section_length += prevpos.
distance(nextpos);
5392 if (dir0 !=
nullptr)
5394 prevpos0 = nextpos0;
5395 if (dir1 !=
nullptr)
5396 prevpos1 = nextpos1;
5399 return cross_section_length;
5402 template<
typename T,
typename FUNCTOR>
5403 static void iterateCurveEdgeLengths(
5404 const exint curve_nedges,
5405 const bool use_mesh_edge_lengths,
5407 const exint cross_section_npts,
5408 const bool swap_row_col,
5412 const sop_SweepGrid &grid_info,
5413 const exint cap_divisions,
5420 for (
exint curve_vtxi = 0; curve_vtxi < curve_nedges; ++curve_vtxi)
5422 double length_sum = 0;
5423 exint length_sum_count;
5424 if (use_mesh_edge_lengths)
5426 length_sum_count = cross_section_npts;
5427 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_npts; ++cross_section_vtxi)
5429 exint col0 = swap_row_col ? curve_vtxi : cross_section_vtxi;
5430 exint col1 = swap_row_col ? curve_vtxi+1 : cross_section_vtxi;
5431 exint row0 = swap_row_col ? cross_section_vtxi : curve_vtxi;
5432 exint row1 = swap_row_col ? cross_section_vtxi : curve_vtxi+1;
5440 length_sum_count = 1;
5441 exint orig_curve_vtxi = curve_vtxi;
5442 if (grid_info.myVEndPoles)
5445 orig_curve_vtxi -= cap_divisions;
5449 exint orig_curve_vtxi1 = (curve_vertices.
getExtraFlag() && curve_vtxi+1 == curve_nedges) ? 0 : curve_vtxi+1;
5450 if (grid_info.myVEndPoles)
5454 orig_curve_vtxi1 -= cap_divisions;
5461 functor(curve_vtxi, length_sum, length_sum_count);
5466 template<GA_AttributeOwner output_owner,
typename T>
5468 generateLengthWeightedV(
5469 const sop_SweepGrid &grid_info,
5471 const exint cross_sections_per_vertex,
5476 bool scalevasu_usingmax,
5480 bool use_mesh_edge_lengths,
5485 const exint curve_nedges = grid_info.myCurveNEdges;
5486 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
5491 exint cap_divisions = 0;
5492 if (curve_input !=
nullptr)
5495 if (grid_info.myVEndPoles)
5498 exint orig_curve_nedges = curve_vertices.
size() - 1;
5499 cap_divisions = (grid_info.myCurveNEdges - orig_curve_nedges)/2;
5502 curve_pos.
bind(curve_input->
getP());
5506 bool special_case_u_division = (!scalevasu_usingmax && norm_u_unnorm_v);
5510 bool prevPosValid =
false;
5512 bool currPosValid =
false;
5520 double prev_cross_section_length = 0;
5521 if (special_case_u_division)
5523 if (curve_input !=
nullptr)
5527 if (curve_vertices.
size() >= 2)
5529 currPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[0]));
5530 nextPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[1]));
5531 currPosValid =
true;
5532 if (grid_info.myCurveClosed)
5536 exint last_vtxi = curve_vertices.
size() - (unrolled ? 2 : 1);
5537 prevPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[last_vtxi]));
5538 prevPosValid =
true;
5542 else if (curve_nedges >= 1 + (grid_info.myVEndPoles ? 2*cap_divisions : 0))
5546 exint start = grid_info.myVEndPoles ? cap_divisions : 0;
5547 currPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start);
5548 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start+1);
5549 currPosValid =
true;
5550 if (grid_info.myCurveClosed)
5552 prevPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, curve_nedges-1);
5553 prevPosValid =
true;
5559 dir0 = (currPos - prevPos);
5560 dir1 = (nextPos - currPos);
5563 if (length0 != 0 && length1 != 0)
5568 else if (length0 != 0 || length1 != 0)
5569 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5571 else if (currPosValid)
5573 dir1 = (nextPos - currPos);
5579 prev_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, 0, pdir0, pdir1);
5588 double max_cross_section_length = 0;
5589 if (need_max_cross_section_length)
5591 for (
exint curve_vtxi = 0; curve_vtxi <= curve_nedges; ++curve_vtxi)
5593 double cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi, dir0, dir1);
5594 max_cross_section_length =
SYSmax(cross_section_length, max_cross_section_length);
5602 double total_length_sum = 0;
5603 exint curve_npts = curve_nedges + !grid_info.myCurveClosed;
5604 exint cross_section_npts = cross_section_nedges + !grid_info.myCrossSectionClosed;
5605 iterateCurveEdgeLengths(
5607 use_mesh_edge_lengths,
5617 [&](
exint curve_vtxi,
double length_sum,
exint length_sum_count)
5619 if (special_case_u_division)
5621 bool nextPosValid =
false;
5623 if (!grid_info.myVEndPoles || (curve_vtxi >= cap_divisions && curve_vtxi < curve_npts-cap_divisions))
5625 nextPosValid =
true;
5626 if (cross_section_nedges >= 1)
5628 exint nextPosVtxi = curve_vtxi+2;
5629 exint threshold = curve_npts;
5630 if (grid_info.myVEndPoles)
5632 nextPosVtxi -= cap_divisions;
5633 threshold -= 2*cap_divisions;
5635 if (nextPosVtxi >= threshold)
5637 if (grid_info.myCurveClosed)
5638 nextPosVtxi -= curve_npts;
5640 nextPosValid =
false;
5644 if (curve_input !=
nullptr)
5647 exint next_curve_vtxi = nextPosVtxi;
5648 if (cross_sections_per_vertex != 1)
5649 next_curve_vtxi /= cross_sections_per_vertex;
5650 if (next_curve_vtxi < 0)
5651 next_curve_vtxi = 0;
5652 else if (next_curve_vtxi >= curve_vertices.
size())
5653 next_curve_vtxi = curve_vertices.
size()-1;
5654 GA_Offset curve_vtxoff = curve_vertices[next_curve_vtxi];
5656 nextPos = curve_pos.
get(curve_ptoff);
5660 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, nextPosVtxi);
5668 dir1 = (nextPos - currPos);
5670 if (length0 != 0 && length1 != 0)
5675 else if (length0 != 0 || length1 != 0)
5676 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5678 else if (length0 != 0)
5683 double next_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi+1, pdir0, pdir1);
5691 double curr_cross_section_length_avg = 0.5*(prev_cross_section_length + next_cross_section_length);
5692 if (curr_cross_section_length_avg == 0)
5697 length_sum /= (length_sum_count*curr_cross_section_length_avg);
5700 prev_cross_section_length = next_cross_section_length;