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 using namespace UT::Literal;
87 namespace HDK_Sample {
93 constexpr
static int theUComponent = 0;
94 constexpr
static int theVComponent = 1;
96 constexpr
static int theCurveInput = 0;
97 constexpr
static int theCrossSectionInput = 1;
100 struct CrossSectionAttribMatchData
151 sop_SweepGrid(
const sop_SweepGrid &that)
171 if (that.mySingleCrossSection)
178 sop_SweepGrid(sop_SweepGrid &&that)
198 if (that.mySingleCrossSection)
203 that.mySingleCrossSection =
true;
208 sop_SweepGrid &
operator=(
const sop_SweepGrid &that)
221 if (that.mySingleCrossSection)
241 sop_SweepGrid &
operator=(sop_SweepGrid &&that)
254 if (that.mySingleCrossSection)
259 that.mySingleCrossSection =
true;
308 myPrevCurvePrimListDataID(-1),
309 myPrevCurveTopologyDataID(-1),
310 myPrevOutputDetailID(-1),
311 myPrevCopyOrder(SOP_SweepHDKEnums::
CopyOrder::CYCLEVTX),
312 myPrevSurfaceType(SOP_SweepHDKEnums::
SurfaceType::POINTS),
313 myPrevPrimType(SOP_SweepHDKEnums::
PrimType::AUTO),
314 myPrevSurfaceShape(SOP_SweepHDKEnums::
SurfaceShape::INPUT),
316 myPrevEndCapType(SOP_SweepHDKEnums::
EndCapType::NONE),
317 myPrevEndCapDivs(-1),
318 myPrevCrossSectionPrimListDataID(-1),
319 myPrevCrossSectionTopologyDataID(-1),
320 myPrevUnrollClosedRowCol(false),
321 myPrevCloseIfNoCurveInput(false),
322 myPrevTriangularPoles(false),
323 myPrevSwapRowCol(false),
324 myPrevCrossSectCurveAttribDataId(-1),
325 myPrevCrossSectPrimAttribDataId(-1)
384 return SYSisSame<T,double>()
386 :
reinterpret_cast<const UT_Vector3T<T> *
>(myTranslatef);
396 return SYSisSame<T,double>()
398 :
reinterpret_cast<const UT_Matrix3T<T> *
>(myInverse3f);
408 return SYSisSame<T,double>()
410 :
reinterpret_cast<const UT_Matrix3T<T> *
>(myMatrix3f);
420 return SYSisSame<T,double>()
422 :
reinterpret_cast<const UT_QuaternionT<T> *
>(myQuaternionf);
445 void cook(
const CookParms &cookparms)
const override;
461 const UT_StringHolder SOP_SweepHDKVerb::theSOPTypeName(
"hdk_sweep"_sh);
483 mySopFlags.setManagesDataIDs(
true);
493 return cookMyselfAsVerb(context);
501 case 0:
return "Backbone Curves";
502 case 1:
return "Cross Section(s)";
503 default:
return "Invalid Source";
514 return (i == 0 || i == 1);
532 return SOP_SweepHDKVerb::theVerb.get();
560 namespace HDK_Sample {
563 SOP_SweepHDK::cookInputGroups(
OP_Context &context,
int alone)
570 const GU_Detail *curve_input = inputGeo(theCurveInput);
572 OP_ERROR ret = cookInputPrimitiveGroups(context, curve_group, alone,
true, 0, -1,
true,
false,
GroupCreator(curve_input));
576 const GU_Detail *cross_section_input = inputGeo(theCrossSectionInput);
578 ret = cookInputPrimitiveGroups(context, cross_section_group, alone,
true, 1, -1,
true,
false,
GroupCreator(cross_section_input));
587 const char *
const SOP_SweepHDKVerb::theDsFile = R
"THEDSFILE(
593 label "Backbone Curve Group"
596 parmtag { "script_action" "import soputils\nkwargs['geometrytype'] = (hou.geometryType.Primitives,)\nkwargs['inputindex'] = 0\nsoputils.selectGroupParm(kwargs)" }
597 parmtag { "script_action_help" "Select geometry from an available viewport.\nShift-click to turn on Select Groups." }
598 parmtag { "script_action_icon" "BUTTONS_reselect" }
601 name "crosssectiongroup"
602 cppname "CrossSectionGroup"
603 label "Cross Section Group"
606 parmtag { "script_action" "import soputils\nkwargs['geometrytype'] = (hou.geometryType.Primitives,)\nkwargs['inputindex'] = 1\nsoputils.selectGroupParm(kwargs)" }
607 parmtag { "script_action_help" "Select geometry from an available viewport.\nShift-click to turn on Select Groups." }
608 parmtag { "script_action_icon" "BUTTONS_reselect" }
617 name "surface_folder"
621 cppname "SurfaceShape"
622 label "Surface Shape"
624 default { "0" } // Default to first entry in menu, "input"
626 "input" "Second Input Cross Sections"
628 "square" "Square Tube"
634 cppname "SurfaceType"
637 default { "5" } // Default to menu entry "quads"
642 "rowcol" "Rows and Columns"
644 "quads" "Quadrilaterals"
645 "alttris" "Alternating Triangles"
646 "revtris" "Reverse Triangles"
651 label "Scale Cross Sections"
655 disablewhen "{ surfaceshape != input }"
656 hidewhen "{ surfaceshape != input }"
664 disablewhen "{ surfaceshape == input }"
665 hidewhen "{ surfaceshape == input }"
673 parmtag { "units" "m1" }
674 disablewhen "{ surfaceshape != tube }"
675 hidewhen "{ surfaceshape != tube }"
683 parmtag { "units" "m1" }
684 disablewhen "{ surfaceshape != ribbon surfaceshape != square }"
685 hidewhen "{ surfaceshape != ribbon surfaceshape != square }"
688 name "reversecrosssections"
689 cppname "ReverseCrossSections"
690 label "Reverse Cross Sections"
695 name "stretcharoundturns"
696 cppname "StretchAroundTurns"
697 label "Stretch Around Turns"
702 name "maxstretcharoundturns"
703 cppname "MaxStretchAroundTurns"
708 disablewhen "{ stretcharoundturns == 0 }"
711 name "endcaps_folder"
718 default { "0" } // Default to menu entry "none"
721 "single" "Single Polygon"
723 "sidesingle" "Side Single Polygon"
729 label "Cap Divisions"
733 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
734 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
738 name "triangularpoles"
739 cppname "TriangularPoles"
740 label "Triangular Poles"
743 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
744 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
749 label "End Cap Scale"
753 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
754 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
758 cppname "CapRoundness"
759 label "End Cap Roundness"
763 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
764 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
767 name "addendcapsgroup"
768 cppname "AddEndCapsGroup"
769 label "Add End Caps Group"
777 cppname "EndCapsGroup"
778 label "End Caps Group"
780 default { "endcaps" }
781 disablewhen "{ addendcapsgroup == 0 }"
790 label "Apply Scale Along Curve"
801 disablewhen "{ applyscale == 0 }"
802 parmtag { "rampfloatdefault" "1pos ( 0 ) 1value ( 1 ) 1interp ( linear ) 2pos ( 1 ) 2value ( 1 ) 2interp ( linear )" }
806 name "rotation_folder"
813 // NOTE: The default rotation order X,Y,Z is semi-arbitrary, but Z
814 // should probably be last, since it always needs to twist
815 // around the curve tangent. The X and Y rotations may have
816 // just been to reorient a cross-section before copying.
819 "xyz" "Pitch, Yaw, Roll"
820 "xzy" "Pitch, Roll, Yaw"
821 "yxz" "Yaw, Pitch, Roll"
822 "yzx" "Yaw, Roll, Pitch"
823 "zxy" "Roll, Pitch, Yaw"
824 "zyx" "Roll, Yaw, Pitch"
830 label "Apply Roll or Twist"
840 hidewhen "{ applyroll == 0 }"
849 hidewhen "{ applyroll == 0 }"
854 label "Partial Twist"
858 hidewhen "{ applyroll == 0 }"
866 default { "4" } // Default to "fulldistance" entry in menu
869 "distance" "Per Unit Distance"
870 "attrib" "Scale by Attribute"
871 "fulledges" "Per Full Curve by Edges"
872 "fulldistance" "Per Full Curve by Distance"
874 hidewhen "{ applyroll == 0 }"
879 label "Twist Ramp Attribute"
882 disablewhen "{ applyroll == 0 } { applyroll == 1 rollper != attrib }"
883 hidewhen "{ applyroll == 0 } { applyroll == 1 rollper != attrib }"
890 hidewhen "{ applyroll == 0 }"
905 hidewhen "{ applyyaw == 0 }"
910 label "Incremental Yaw"
914 hidewhen "{ applyyaw == 0 }"
922 default { "4" } // Default to "fulldistance" entry in menu
925 "distance" "Per Unit Distance"
926 "attrib" "Scale By Attribute"
927 "fulledges" "Per Full Curve by Edges"
928 "fulldistance" "Per Full Curve by Distance"
930 hidewhen "{ applyyaw == 0 }"
935 label "Yaw Ramp Attribute"
938 disablewhen "{ applyyaw == 0 } { applyyaw == 1 yawper != attrib }"
939 hidewhen "{ applyyaw == 0 } { applyyaw == 1 yawper != attrib }"
946 hidewhen "{ applyyaw == 0 }"
961 hidewhen "{ applypitch == 0 }"
966 label "Incremental Pitch"
970 hidewhen "{ applypitch == 0 }"
978 default { "4" } // Default to "fulldistance" entry in menu
981 "distance" "Per Unit Distance"
982 "attrib" "Scale By Attribute"
983 "fulledges" "Per Full Curve by Edges"
984 "fulldistance" "Per Full Curve by Distance"
986 hidewhen "{ applypitch == 0 }"
990 cppname "PitchAttrib"
991 label "Pitch Ramp Attribute"
994 disablewhen "{ applypitch == 0 } { applypitch == 1 pitchper != attrib }"
995 hidewhen "{ applypitch == 0 } { applypitch == 1 pitchper != attrib }"
1004 name "construction_folder"
1005 label "Construction"
1007 name "cross_sections_folder"
1008 label "Cross Sections"
1012 label "Cross Section Order"
1014 default { "1" } // Default to third entry in menu, "each"
1016 "all" "All Cross Sections At Each Curve Vertex"
1017 "each" "Each Cross Section At All Curve Vertices"
1018 "cyclevtx" "Cycle Through Cross Section Primitives per Vertex"
1019 "cyclepr" "Cycle Through Cross Section Primitives per Curve"
1020 "attrib" "Choose Cross Section Primitives by Attribute"
1022 disablewhen "{ surfaceshape != input }"
1025 name "crosssectionattrib"
1026 cppname "CrossSectionAttrib"
1027 label "Cross Section Attribute"
1029 default { "variant" }
1030 disablewhen "{ surfaceshape != input } { copyorder != attrib }"
1031 hidewhen "{ surfaceshape != input } { copyorder != attrib }"
1036 label "Primitive Type"
1038 default { "0" } // Default to menu entry "auto"
1042 "mesh" "Bilinear Mesh"
1043 "nurbs" "NURBS Surface"
1044 "bezier" "Bezier Surface"
1045 "polysoup" "Polygon Soup"
1047 disablewhen "{ surfacetype == points }"
1050 name "unrollclosedrowcol"
1051 cppname "UnrollClosedRowCol"
1052 label "Ensure Unique Seam Vertices"
1055 disablewhen "{ surfacetype == points }"
1059 cppname "SwapRowCol"
1060 label "Swap Rows and Columns"
1065 name "closeifnocurveinput"
1066 cppname "CloseIfNoCurveInput"
1067 label "Close Implicit Backbone Curve if No Curve Input"
1070 disablewhen "{ surfacetype == points } { surfacetype == rows } { hasinput(0) != 0 }"
1074 // cppname "SegDivs"
1075 // label "Segment Divisions"
1086 cppname "UpVectorType"
1087 label "Target Up Vector"
1089 default { "0" } // Default to first entry in menu, "normal"
1091 "normal" "Curve Normal"
1095 "attrib" "Attribute"
1098 disablewhen "{ tangenttype == none }"
1101 // name "usenormalup"
1102 // cppname "UseNormalUp"
1103 // label "Use Curve Normal as Up Vector (When Valid)"
1106 // disablewhen "{ tangenttype == none }"
1109 name "upvectoratstart"
1110 cppname "UpVectorAtStart"
1111 label "Target Up Vector at Start (else Average)"
1114 disablewhen "{ tangenttype == none }"
1117 name "useendupvector"
1118 cppname "UseEndUpVector"
1119 label "Use Target End Up Vector"
1122 disablewhen "{ tangenttype == none } { upvectoratstart == 0 }"
1125 name "upvectorattrib"
1126 cppname "UpVectorAttrib"
1127 label "Start Up Attribute"
1129 default { "start_up" }
1130 disablewhen "{ tangenttype == none } { upvectortype != attrib }"
1131 hidewhen "{ tangenttype == none } { upvectortype != attrib }"
1134 name "endupvectorattrib"
1135 cppname "EndUpVectorAttrib"
1136 label "End Up Attribute"
1138 default { "end_up" }
1139 disablewhen "{ tangenttype == none } { upvectortype != attrib } { useendupvector == 0 } { upvectoratstart == 0 }"
1140 hidewhen "{ tangenttype == none } { upvectortype != attrib } { useendupvector == 0 } { upvectoratstart == 0 }"
1145 label "Start Up Vector"
1148 default { "0" "1" "0" }
1149 disablewhen "{ tangenttype == none } { upvectortype != custom }"
1150 hidewhen "{ tangenttype == none } { upvectortype != custom }"
1154 cppname "EndUpVector"
1155 label "End Up Vector"
1158 default { "0" "1" "0" }
1159 disablewhen "{ tangenttype == none } { upvectortype != custom } { useendupvector == 0 } { upvectoratstart == 0 }"
1160 hidewhen "{ tangenttype == none } { upvectortype != custom } { useendupvector == 0 } { upvectoratstart == 0 }"
1164 name "tangents_folder"
1168 cppname "TangentType"
1169 label "Tangent Type"
1171 default { "0" } // Default to first entry in menu, "avgdir"
1173 "avgdir" "Average of Edge Directions"
1174 "diff" "Central Difference"
1175 "prev" "Previous Edge"
1177 "none" "Z Axis (Ignore Curve)"
1181 name "continuousclosed"
1182 cppname "ContinuousClosed"
1183 label "Make Closed Curve Orientations Continuous"
1186 disablewhen "{ tangenttype == none }"
1189 name "extrapolateendtangents"
1190 cppname "ExtrapolateEndTangents"
1191 label "Extrapolate End Tangents"
1194 disablewhen "{ tangenttype == none }"
1197 name "transformbyattribs"
1198 cppname "TransformByAttribs"
1199 label "Transform Using Curve Point Attributes"
1211 label "UVs and Attributes"
1214 label "UV Coordinates"
1217 cppname "ComputeUVs"
1223 name "overrideexistinguvs"
1224 cppname "OverrideExistingUVs"
1225 label "Override Any Existing UVs"
1228 disablewhen "{ computeuvs == 0 }"
1231 name "lengthweighteduvs"
1232 cppname "LengthWeightedUVs"
1233 label "Length-Weighted UVs"
1236 disablewhen "{ computeuvs == 0 }"
1240 cppname "NormalizeU"
1241 label "Normalize Computed Us"
1244 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1248 cppname "NormalizeV"
1249 label "Normalize Computed Vs"
1252 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1257 label "Flip Computed Us"
1260 disablewhen "{ computeuvs == 0 }"
1263 name "uvscale_folder"
1265 grouptag { "group_type" "collapsible" }
1266 parmtag { "group_default" "0" }
1274 disablewhen "{ computeuvs == 0 }"
1277 name "usemeshedgelengths"
1278 cppname "UseMeshEdgeLengths"
1279 label "Use Mesh Edge Lengths Instead of Curve Edge Lengths"
1282 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1285 name "propscalepercurve"
1286 cppname "PropScalePerCurve"
1287 label "Use Max Cross Section Length per Curve for Proportional Scale"
1290 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizeu != 1 } { normalizev != 0 }"
1294 name "uvseams_folder"
1296 grouptag { "group_type" "collapsible" }
1297 parmtag { "group_default" "0" }
1301 label "Snap U to Nearest Tile Boundary"
1304 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizeu == 1 }"
1309 label "Snap V to Nearest Tile Boundary"
1312 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizev == 1 }"
1317 name "attributes_folder"
1319 grouptag { "group_type" "collapsible" }
1320 parmtag { "group_default" "0" }
1325 name "attribsfrombackbone"
1326 cppname "AttribsFromBackbone"
1327 label "From Backbone Curves"
1329 default { "* ^P ^N ^up ^pscale ^scale ^orient ^rot ^pivot ^trans ^transform" }
1332 name "attribsfromcrosssection"
1333 cppname "AttribsFromCrossSection"
1334 label "From Cross Sections"
1340 name "output_folder"
1344 cppname "AddPointRow"
1345 label "Add Point Row Attribute"
1353 cppname "PtRowAttrib"
1354 label "Point Row Attribute"
1357 disablewhen "{ addptrow == 0 }"
1361 cppname "AddPointCol"
1362 label "Add Point Col Attribute"
1370 cppname "PtColAttrib"
1371 label "Point Col Attribute"
1374 disablewhen "{ addptcol == 0 }"
1378 cppname "AddPrimRow"
1379 label "Add Prim Row Attribute"
1386 name "primrowattrib"
1387 cppname "PrimRowAttrib"
1388 label "Prim Row Attribute"
1390 default { "primrow" }
1391 disablewhen "{ addprimrow == 0 }"
1395 cppname "AddPrimCol"
1396 label "Add Prim Col Attribute"
1403 name "primcolattrib"
1404 cppname "PrimColAttrib"
1405 label "Prim Col Attribute"
1407 default { "primcol" }
1408 disablewhen "{ addprimcol == 0 }"
1411 name "addcrosssectionnum"
1412 cppname "AddCrossSectionNum"
1413 label "Add Cross Section Num Attribute"
1420 name "crosssectionnumattrib"
1421 cppname "CrossSectionNumAttrib"
1422 label "Cross Section Num Attribute"
1424 default { "crossnum" }
1425 disablewhen "{ addcrosssectionnum == 0 }"
1429 cppname "AddCurveNum"
1430 label "Add Curve Num Attribute"
1437 name "curvenumattrib"
1438 cppname "CurveNumAttrib"
1439 label "Curve Num Attribute"
1441 default { "curvenum" }
1442 disablewhen "{ addcurvenum == 0 }"
1444 // TODO: Add option to compute vertex normals with cusp angle.
1455 using namespace SOP_SweepHDKEnums;
1456 using namespace GU_CurveFrame;
1462 template<
typename T>
1464 insertIntoIntervals(
1465 const T *
const edge_lengths,
1466 const T total_length,
1468 const exint ninsertions,
1469 exint *
const ninsertions_per_edge)
1471 UT_ASSERT(nedges >= 1 && ninsertions >= 0);
1472 exint ninsertions_so_far = 0;
1473 for (
exint i = 0; i < nedges; ++i)
1475 T portion = (total_length > 0) ? (edge_lengths[i]/total_length) : (
T(1)/
T(nedges));
1482 ki =
SYSmin(ki, ninsertions-ninsertions_so_far);
1483 ninsertions_per_edge[i] = ki;
1484 ninsertions_so_far += ki;
1486 if (ninsertions_so_far == ninsertions)
1489 struct IntervalComparator {
1490 IntervalComparator(
const T *
const edge_lengths,
const exint *
const ninsertions_per_edge) :
1491 myEdgeLengths(edge_lengths),
1492 myNInsertionsPerEdge(ninsertions_per_edge)
1497 const T nadb = myEdgeLengths[
a]*(myNInsertionsPerEdge[
b]+1);
1498 const T nbda = myEdgeLengths[
b]*(myNInsertionsPerEdge[
a]+1);
1505 return nadb < nbda || (nadb == nbda && a <
b);
1507 const T *
const myEdgeLengths;
1508 const exint *
const myNInsertionsPerEdge;
1510 IntervalComparator comparator(edge_lengths, ninsertions_per_edge);
1514 if (nedges < 20 || (ninsertions-ninsertions_so_far) < 20) {
1516 exint edge_with_largest_intervals = 0;
1517 for (
exint i = 1; i < nedges; ++i) {
1518 if (comparator(edge_with_largest_intervals, i)) {
1519 edge_with_largest_intervals = i;
1522 ++ninsertions_per_edge[edge_with_largest_intervals];
1523 ++ninsertions_so_far;
1524 }
while (ninsertions_so_far < ninsertions);
1533 for (
exint i = 0; i < nedges; ++i)
1536 exint *
const heap_end = heap_begin+nedges;
1537 std::make_heap(heap_begin, heap_end, comparator);
1542 exint edge_with_largest_intervals = heap_begin[0];
1543 ++ninsertions_per_edge[edge_with_largest_intervals];
1544 ++ninsertions_so_far;
1545 if (ninsertions_so_far == ninsertions)
1549 std::pop_heap(heap_begin, heap_end, comparator);
1550 heap_end[-1] = edge_with_largest_intervals;
1551 std::push_heap(heap_begin, heap_end, comparator);
1560 switch (sop_primtype)
1577 return (i==0) ? 0 : (n-i);
1597 if (interrupt.wasInterrupted())
1615 if (interrupt.wasInterrupted())
1619 for (
GA_Offset primoff = start; primoff <
end; ++primoff)
1640 if (!reverse || closed)
1641 vtxoff0 = vertices(0);
1643 vtxoff0 = vertices(n-1);
1645 bool local_by_length = by_length;
1646 if (local_by_length)
1667 local_by_length =
false;
1673 float cur_length = 0;
1681 const float u = cur_length/
length;
1687 if (!local_by_length)
1690 GA_Size nedges = closed ? n : (n-1);
1695 const float u = i/
float(nedges);
1704 if (reverse && closed)
1713 static GA_Offset lookupCrossSectionFromAttrib(
1714 const CrossSectionAttribMatchData *copy_order_attrib_data,
1719 if (copy_order_attrib_data->myCurveIntAttrib.isValid())
1722 const exint id = copy_order_attrib_data->myCurveIntAttrib.get(curve_offset);
1723 if (copy_order_attrib_data->myIsUsingMap) {
1729 auto &&it = copy_order_attrib_data->myIntToPrimOff.find(
id);
1730 if (it == copy_order_attrib_data->myIntToPrimOff.end()) {
1741 if (cross_section_group && !cross_section_group->
contains(cross_section_primoff)) {
1745 return cross_section_primoff;
1749 UT_ASSERT_P(copy_order_attrib_data->myCurveStrAttrib.isValid());
1750 UT_ASSERT_P(copy_order_attrib_data->myIsUsingMap);
1757 auto &&it = copy_order_attrib_data->myStrToPrimOff.find(name);
1758 if (it == copy_order_attrib_data->myStrToPrimOff.end()) {
1769 int &primitive_type,
1770 unsigned char &fallback_orderu,
1791 if (pbasisu !=
nullptr)
1798 computeCombinedCrossSectionProperties(
1802 exint num_cross_sections,
1803 exint &cross_section_nedges,
1804 bool &cross_section_closed,
1805 bool &cross_section_unrolled,
1806 bool &varying_nedges,
1808 const bool is_primtype_auto,
1809 int &primitive_type,
1810 unsigned char &fallback_orderu,
1813 if (num_cross_sections == 0)
1821 bool basis_cross_section_closed;
1822 bool basis_cross_section_unrolled;
1825 cross_section_nedges = -1;
1826 varying_nedges =
false;
1828 for (
exint cross_sectioni = 0; cross_sectioni < num_cross_sections; ++cross_sectioni)
1830 GA_Offset cross_section_primoff = *cross_section_it;
1832 if (cross_section_it.
atEnd())
1835 cross_section_it.
rewind();
1839 cross_section_primoffs.
append(cross_section_primoff);
1841 exint local_cross_section_nedges;
1842 bool local_cross_section_closed;
1843 bool local_cross_section_unrolled;
1844 bool nonempty =
getPolyProperties(cross_section_input, cross_section_vertices, local_cross_section_nedges, local_cross_section_closed, local_cross_section_unrolled);
1850 if (cross_section_nedges == -1)
1853 cross_section_closed = local_cross_section_closed;
1854 cross_section_unrolled = local_cross_section_unrolled;
1856 else if (!local_cross_section_closed)
1860 cross_section_closed =
false;
1861 cross_section_unrolled =
false;
1863 else if (local_cross_section_unrolled && cross_section_closed && !cross_section_unrolled)
1867 cross_section_unrolled =
true;
1872 bool local_varying_nedges = (cross_section_nedges != -1 && local_cross_section_nedges != cross_section_nedges);
1874 varying_nedges |= local_varying_nedges;
1877 if (is_primtype_auto)
1879 local_primtype = updateAutoPrimType(cross_section_input, cross_section_primoff, primitive_type, fallback_orderu,
nullptr);
1883 if (local_cross_section_nedges > cross_section_nedges)
1885 cross_section_nedges = local_cross_section_nedges;
1887 if (is_primtype_auto && pbasisu !=
nullptr)
1893 basis_cross_section_closed = local_cross_section_closed;
1894 basis_cross_section_unrolled = local_cross_section_unrolled;
1909 if (pbasisu !=
nullptr && *pbasisu !=
nullptr)
1914 if (basis_primtype != primitive_type ||
1915 basis_cross_section_closed != cross_section_closed ||
1916 basis_cross_section_unrolled != cross_section_unrolled)
1931 computeCombinedCrossSectionPropertiesAttrib(
1936 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
1937 exint &cross_section_nedges,
1938 bool &cross_section_closed,
1939 bool &cross_section_unrolled,
1940 bool &varying_nedges,
1942 const bool is_primtype_auto,
1943 int &primitive_type,
1944 unsigned char &fallback_orderu,
1947 exint num_vertices = curve_vertices.
size();
1948 if (num_vertices == 0)
1951 const GA_AttributeOwner curve_owner = copy_order_attrib_data->myCurveAttribOwner;
1956 bool basis_cross_section_closed;
1957 bool basis_cross_section_unrolled;
1960 cross_section_nedges = -1;
1961 varying_nedges =
false;
1963 for (
exint vtxi = 0; vtxi < num_vertices; ++vtxi)
1965 GA_Offset curve_offset = curve_vertices[vtxi];
1967 curve_offset = curve_input->
vertexPoint(curve_offset);
1968 GA_Offset cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data, curve_offset, cross_section_input, cross_section_group);
1975 cross_section_primoffs.
append(cross_section_primoff);
1977 exint local_cross_section_nedges;
1978 bool local_cross_section_closed;
1979 bool local_cross_section_unrolled;
1980 bool nonempty =
getPolyProperties(cross_section_input, cross_section_vertices, local_cross_section_nedges, local_cross_section_closed, local_cross_section_unrolled);
1986 if (cross_section_nedges == -1)
1989 cross_section_closed = local_cross_section_closed;
1990 cross_section_unrolled = local_cross_section_unrolled;
1992 else if (!local_cross_section_closed)
1996 cross_section_closed =
false;
1997 cross_section_unrolled =
false;
1999 else if (local_cross_section_unrolled && cross_section_closed && !cross_section_unrolled)
2003 cross_section_unrolled =
true;
2008 bool local_varying_nedges = (cross_section_nedges != -1 && local_cross_section_nedges != cross_section_nedges);
2010 varying_nedges |= local_varying_nedges;
2013 if (is_primtype_auto)
2015 local_primtype = updateAutoPrimType(cross_section_input, cross_section_primoff, primitive_type, fallback_orderu,
nullptr);
2019 if (local_cross_section_nedges > cross_section_nedges)
2021 cross_section_nedges = local_cross_section_nedges;
2023 if (is_primtype_auto && pbasisu !=
nullptr)
2029 basis_cross_section_closed = local_cross_section_closed;
2030 basis_cross_section_unrolled = local_cross_section_unrolled;
2045 if (pbasisu !=
nullptr && *pbasisu !=
nullptr)
2050 if (basis_primtype != primitive_type ||
2051 basis_cross_section_closed != cross_section_closed ||
2052 basis_cross_section_unrolled != cross_section_unrolled)
2065 const bool output_points_only,
2066 const bool is_primtype_auto,
2067 int &primitive_type,
2068 unsigned char &fallback_orderv,
2078 fallback_orderv = 0;
2079 if (!is_primtype_auto)
2084 if (curve_input ==
nullptr)
2088 fallback_orderv = 4;
2095 bool is_curve =
false;
2124 computeSingleGridSetup(
2128 const bool single_cross_section,
2131 exint cross_section_nedges,
2132 bool cross_section_closed,
2133 bool cross_section_unrolled,
2135 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
2136 bool varying_nedges_all_case,
2142 const bool closed_if_no_curve_input,
2146 const bool output_points_only,
2147 const bool unroll_closed_row_col,
2148 const bool is_primtype_auto,
2150 unsigned char fallback_orderu,
2151 unsigned char fallback_orderv,
2154 exint cap_divisions,
2157 sop_SweepGrid &grid_info,
2160 const bool has_col_surface_type =
2163 const bool has_row_surface_type =
2166 const bool has_rowcol_surface_type =
2167 has_col_surface_type || has_row_surface_type;
2169 const bool is_polygon_type = (!output_points_only && primitive_type ==
GA_PRIMPOLY);
2170 const bool could_add_row_seam_vertex = (has_col_surface_type || !is_polygon_type) && unroll_closed_row_col;
2171 const bool could_add_col_seam_vertex = (has_row_surface_type || !is_polygon_type) && unroll_closed_row_col;
2173 if (curve_input ==
nullptr)
2176 UT_ASSERT(cross_section_input !=
nullptr);
2178 grid_info.myCurveClosed = closed_if_no_curve_input;
2179 grid_info.myCurveUnrolled = (grid_info.myCurveClosed && could_add_row_seam_vertex);
2181 grid_info.myCurveNEdges = num_cross_sections - !grid_info.myCurveClosed;
2183 bool varying_nedges;
2185 bool is_valid_grid = computeCombinedCrossSectionProperties(
2186 cross_section_input,
2187 cross_section_group,
2190 cross_section_nedges,
2191 cross_section_closed,
2192 cross_section_unrolled,
2194 cross_section_primoffs,
2203 grid_info.myCrossSectionNEdges = cross_section_nedges;
2204 grid_info.myCrossSectionClosed = cross_section_closed;
2205 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2206 grid_info.myAllEqualNEdges = !varying_nedges;
2207 grid_info.mySingleCrossSection = (cross_section_primoffs.
size() == 1);
2208 if (grid_info.mySingleCrossSection)
2209 grid_info.myCrossSectionPrimOff = cross_section_primoffs(0);
2211 grid_info.myCrossSectionPrimOffs =
new GA_OffsetList(std::move(cross_section_primoffs));
2216 grid_info.myCurvePrimOff = curve_primoff;
2220 bool curve_unrolled;
2222 bool nonempty =
getPolyProperties(curve_input, curve_vertices, curve_nedges, curve_closed, curve_unrolled);
2228 grid_info.myCurveClosed = curve_closed;
2229 grid_info.myCurveUnrolled = curve_unrolled || (curve_closed && could_add_row_seam_vertex);
2230 grid_info.myCurveNEdges = curve_nedges;
2232 if (single_cross_section)
2235 grid_info.myCrossSectionNEdges = cross_section_nedges;
2236 grid_info.myCrossSectionClosed = cross_section_closed;
2237 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2238 grid_info.myAllEqualNEdges =
true;
2239 grid_info.mySingleCrossSection =
true;
2240 grid_info.myCrossSectionPrimOff = single_cross_section_primoff;
2245 "Other cases should have resolved to single cross section grids.");
2247 bool varying_nedges = varying_nedges_all_case;
2249 if (copy_order == CopyOrder::CYCLEVTX)
2251 exint num_cross_sections = curve_nedges + !curve_closed;
2252 bool is_valid_grid = computeCombinedCrossSectionProperties(
2253 cross_section_input,
2254 cross_section_group,
2257 cross_section_nedges,
2258 cross_section_closed,
2259 cross_section_unrolled,
2261 cross_section_primoffs,
2272 bool is_valid_grid = computeCombinedCrossSectionPropertiesAttrib(
2273 cross_section_input,
2274 cross_section_group,
2277 copy_order_attrib_data,
2278 cross_section_nedges,
2279 cross_section_closed,
2280 cross_section_unrolled,
2282 cross_section_primoffs,
2292 grid_info.myCrossSectionNEdges = cross_section_nedges;
2293 grid_info.myCrossSectionClosed = cross_section_closed;
2294 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2295 grid_info.myAllEqualNEdges = !varying_nedges;
2296 grid_info.mySingleCrossSection =
false;
2299 exint ncopies = grid_info.myCurveNEdges + !grid_info.myCurveClosed;
2300 grid_info.myCurveNEdges = (ncopies * cross_section_primoffs_all_case->
size()) - !grid_info.myCurveClosed;
2302 for (
exint copyi = 0; copyi < ncopies; ++copyi)
2304 grid_info.myCrossSectionPrimOffs->append(*cross_section_primoffs_all_case);
2309 grid_info.myCrossSectionPrimOffs =
new GA_OffsetList(std::move(cross_section_primoffs));
2314 grid_info.myHasPolygonCaps =
2315 !output_points_only &&
2317 (end_cap_type == EndCapType::SINGLE &&
2318 (!grid_info.myCurveClosed && grid_info.myCrossSectionClosed && grid_info.myCrossSectionNEdges > 1)) ||
2319 (end_cap_type == EndCapType::SIDESINGLE &&
2320 (!grid_info.myCrossSectionClosed && grid_info.myCurveClosed && grid_info.myCurveNEdges > 1))
2322 !has_rowcol_surface_type;
2325 grid_info.myUEndPoles =
false;
2327 grid_info.myUEndPoles =
2328 !output_points_only &&
2329 (end_cap_type !=
EndCapType::NONE && end_cap_type != EndCapType::SINGLE && end_cap_type != EndCapType::SIDESINGLE) &&
2330 (!grid_info.myCrossSectionClosed && grid_info.myCurveClosed) &&
2337 grid_info.myVEndPoles =
2338 !output_points_only &&
2339 (end_cap_type !=
EndCapType::NONE && end_cap_type != EndCapType::SINGLE && end_cap_type != EndCapType::SIDESINGLE) &&
2340 (!grid_info.myCurveClosed) &&
2343 if (grid_info.myUEndPoles)
2346 grid_info.myCrossSectionNEdges += 2*cap_divisions;
2349 UT_ASSERT(grid_info.myCurveNEdges >= 1);
2351 else if (grid_info.myVEndPoles)
2354 grid_info.myCurveNEdges += 2*cap_divisions;
2356 if (!grid_info.mySingleCrossSection)
2360 GA_OffsetList &primoffs = *grid_info.myCrossSectionPrimOffs;
2361 for (
exint i = 0; i < cap_divisions; ++i)
2362 new_cross_section_primoffs.
append(primoffs(0));
2363 new_cross_section_primoffs.
append(primoffs);
2364 for (
exint i = 0; i < cap_divisions; ++i)
2365 new_cross_section_primoffs.
append(primoffs.
last());
2366 primoffs = std::move(new_cross_section_primoffs);
2370 UT_ASSERT(grid_info.myCrossSectionNEdges >= 1);
2373 using PrimitiveType = sop_SweepGrid::PrimitiveType;
2374 grid_info.myPrimitiveType = PrimitiveType::POINTS;
2375 if (!output_points_only)
2377 grid_info.myPrimitiveType = PrimitiveType::POLYGON;
2379 grid_info.myPrimitiveType = PrimitiveType::POLYSOUP;
2381 grid_info.myPrimitiveType = PrimitiveType::MESH;
2383 grid_info.myPrimitiveType = PrimitiveType::NURBS;
2385 grid_info.myPrimitiveType = PrimitiveType::BEZIER;
2389 if (grid_info.myPrimitiveType != PrimitiveType::POLYGON &&
2390 (grid_info.myCurveNEdges <= 0 || grid_info.myCrossSectionNEdges <= 0))
2392 grid_info.myPrimitiveType = PrimitiveType::POLYGON;
2395 if (grid_info.myPrimitiveType == PrimitiveType::NURBS)
2397 if (fallback_orderv == 0)
2402 fallback_orderv = (is_primtype_auto && curve_input !=
nullptr) ? 2 : 4;
2404 exint curve_nvertices = grid_info.myCurveNEdges + (!grid_info.myCurveClosed || grid_info.myCurveUnrolled);
2405 if (curve_nvertices < fallback_orderv)
2409 fallback_orderv =
SYSclamp(
int(curve_nvertices), 2, 3);
2411 if (fallback_orderu == 0)
2414 fallback_orderu = (is_primtype_auto && cross_section_input !=
nullptr) ? 2 : 4;
2416 exint cross_section_nvertices = grid_info.myCrossSectionNEdges + (!grid_info.myCrossSectionClosed || grid_info.myCrossSectionUnrolled);
2417 if (cross_section_nvertices < fallback_orderu)
2421 fallback_orderu =
SYSclamp(
int(cross_section_nvertices), 2, 3);
2424 else if (grid_info.myPrimitiveType == PrimitiveType::BEZIER)
2426 if (fallback_orderv == 0)
2431 fallback_orderv = is_primtype_auto ? 2 : 4;
2433 if (grid_info.myCurveNEdges % (fallback_orderv-1) != 0)
2436 fallback_orderv = 2;
2438 if (fallback_orderu == 0)
2441 fallback_orderu = is_primtype_auto ? 2 : 4;
2443 if (grid_info.myCrossSectionNEdges % (fallback_orderu-1) != 0)
2446 fallback_orderu = 2;
2449 grid_info.myBasisOrderCrossSection = fallback_orderu;
2450 grid_info.myBasisOrderCurve = fallback_orderv;
2453 num_points = (grid_info.myCurveNEdges + !grid_info.myCurveClosed - 2*
exint(grid_info.myVEndPoles))
2454 * (grid_info.myCrossSectionNEdges + !grid_info.myCrossSectionClosed - 2*
exint(grid_info.myUEndPoles))
2455 + 2*
exint(grid_info.myVEndPoles) + 2*
exint(grid_info.myUEndPoles);
2460 template<
typename T>
2463 const sop_SweepGrid &grid_info,
2465 const bool output_points_only,
2466 const bool triangular_poles,
2467 const bool swap_row_col,
2468 const T grid_start_ptnum,
2474 grid.
myUnrollCurves = grid_info.myCurveUnrolled || grid_info.myCrossSectionUnrolled;
2477 bool is_single_grid_prim =
false;
2478 if (output_points_only)
2483 is_single_grid_prim = (grid.
myPrimitiveType != PrimitiveType::POLYGON);
2492 const exint nedgerows = swap_row_col ? grid_info.myCrossSectionNEdges : grid_info.myCurveNEdges;
2493 const exint nedgecols = swap_row_col ? grid_info.myCurveNEdges : grid_info.myCrossSectionNEdges;
2494 bool vclosed = swap_row_col ? grid_info.myCrossSectionClosed : grid_info.myCurveClosed;
2495 bool uclosed = swap_row_col ? grid_info.myCurveClosed : grid_info.myCrossSectionClosed;
2496 bool uendpoles = swap_row_col ? grid_info.myVEndPoles : grid_info.myUEndPoles;
2497 bool vendpoles = swap_row_col ? grid_info.myUEndPoles : grid_info.myVEndPoles;
2498 if (is_single_grid_prim)
2502 if (nvtxrows < 2 || nvtxcols < 2)
2504 is_single_grid_prim =
false;
2509 unsigned char orderv = swap_row_col ? grid_info.myBasisOrderCrossSection : grid_info.myBasisOrderCurve;
2510 unsigned char orderu = swap_row_col ? grid_info.myBasisOrderCurve : grid_info.myBasisOrderCrossSection;
2518 grid.
initTorus(nedgerows, nedgecols, grid_start_ptnum);
2519 else if (!uendpoles)
2520 grid.
initRowTube(nedgerows, nedgecols, grid_start_ptnum);
2525 const exint nmid_points = nedgerows*(nedgecols - 1);
2526 grid.
initRowSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2534 grid.
initColTube(nedgerows, nedgecols, grid_start_ptnum);
2539 const exint nmid_points = (nedgerows - 1)*nedgecols;
2540 grid.
initColSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2551 const exint nmid_points = (nedgerows - 1)*(nedgecols+1);
2552 grid.
initSplitColSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2559 appendPrimTypeCountPair(
2560 UT_Array<std::pair<int,exint>> &prim_type_count_pairs,
2564 if (prim_type_count_pairs.isEmpty() || prim_type_count_pairs.last().first != primtype)
2566 prim_type_count_pairs.append(std::pair<int,exint>(primtype, count));
2570 prim_type_count_pairs.last().second += count;
2583 if (!(closed_span_lengths.
size() & 1) == closed)
2584 ++closed_span_lengths.
last();
2586 closed_span_lengths.
append(1);
2593 appendSingleGridTopology(
2594 const sop_SweepGrid &grid_info,
2596 const bool output_points_only,
2597 const bool triangular_poles,
2598 const bool single_polygon_caps,
2599 const bool swap_row_col,
2601 UT_Array<std::pair<int,exint>> &prim_type_count_pairs,
2611 exint grid_start_ptnum =
exint(grid_info.myStartPtOff);
2613 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_start_ptnum, grid);
2618 if (num_grid_prims == 0)
2621 bool current_has_polygon_caps = grid_info.myHasPolygonCaps;
2622 bool is_row_cap = current_has_polygon_caps && grid.
myNoWrapV;
2623 bool is_cross_section_cap = !grid_info.myCrossSectionClosed;
2624 exint cap_count = current_has_polygon_caps ? 2 : 0;
2649 appendPrimTypeCountPair(prim_type_count_pairs, primtype, num_grid_prims + cap_count);
2653 appendPrimTypeCountPair(prim_type_count_pairs, cap_primtype, 1);
2654 appendPrimTypeCountPair(prim_type_count_pairs, primtype, num_grid_prims);
2655 appendPrimTypeCountPair(prim_type_count_pairs, cap_primtype, 1);
2658 exint cap_vertex_count = 0;
2659 if (current_has_polygon_caps)
2661 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)
2663 vertexlistsizelist.append(cap_vertex_count);
2666 appendClosedSpans(closed_span_lengths,
true);
2668 const exint old_size = vertexpointnumbers.
size();
2669 vertexpointnumbers.
bumpSize(old_size + cap_vertex_count);
2670 exint *vertexpointnumber_start = vertexpointnumbers.
getArray() + old_size;
2674 exint row = last_cap ? grid.myNumEdgeRows : 0;
2675 for (
exint col = 0; col < cap_vertex_count; ++col)
2677 exint point_col = ((last_cap != swap_row_col) != is_cross_section_cap) ? col : reverseVtx(col, cap_vertex_count,
true);
2678 vertexpointnumber_start[col] = grid.getPoint(row, point_col);
2684 exint col = last_cap ? grid.myNumEdgeCols : 0;
2685 for (
exint row = 0; row < cap_vertex_count; ++
row)
2687 exint point_row = ((last_cap != swap_row_col) != is_cross_section_cap) ? row : reverseVtx(row, cap_vertex_count,
true);
2688 vertexpointnumber_start[
row] = grid.getPoint(point_row, col);
2692 if (current_has_polygon_caps)
2695 add_polygon_cap_functor(
false);
2700 [&vertexlistsizelist,&closed_span_lengths
2706 UT_ASSERT_P(primnum >= 0 && primnum < num_grid_prims);
2707 vertexlistsizelist.append(primvtxcount);
2709 appendClosedSpans(closed_span_lengths, closed);
2712 const exint old_size = vertexpointnumbers.
size();
2713 vertexpointnumbers.
bumpSize(old_size + grid.myNumVertices);
2714 exint *vertexpointnumber_start = vertexpointnumbers.
getArray() + old_size;
2716 [vertexpointnumber_start,&grid](
exint vtxnum,
exint row,
exint col,
bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
2718 UT_ASSERT_P(vtxnum >= 0 && vtxnum < grid.myNumVertices);
2719 vertexpointnumber_start[vtxnum] = grid.getPoint(row+
exint(isrowend),col+
exint(iscolend));
2722 if (current_has_polygon_caps)
2725 add_polygon_cap_functor(
true);
2730 num_grid_prims += cap_count;
2731 num_grid_verts += 2*cap_vertex_count;
2735 initNonPolyGridPrims(
2736 const sop_SweepGrid &grid_info,
2738 const bool swap_row_col,
2748 GA_Offset primoff = grid_info.myStartPrimOff;
2749 if (grid_info.myHasPolygonCaps)
2757 const exint nvtxrows = nedgerows +
exint(!hull_wrapv);
2758 const exint nvtxcols = nedgecols +
exint(!hull_wrapu);
2765 sop_SweepGrid polygrid_info(grid_info);
2766 polygrid_info.myPrimitiveType = sop_SweepGrid::PrimitiveType::POLYGON;
2774 polygonsizes.
append(primvtxcount, 1);
2792 exint cap_vertex_count = 0;
2793 if (grid_info.myHasPolygonCaps)
2795 cap_vertex_count = !grid_info.myCurveClosed ? grid_info.myCrossSectionNEdges : grid_info.myCurveNEdges;
2797 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
2799 [&polygonvertexlist,start_vtxoff,&grid,has_endrow,has_endcol,nvtxcols](
exint vtxnum,
exint row,
exint col,
2800 bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
2817 exint soupvtxnum = row*nvtxcols + col;
2818 polygonvertexlist.append(start_vtxoff + soupvtxnum);
2829 hull->
initHullData(nvtxrows, nvtxcols, hull_wrapv, hull_wrapu);
2833 const bool is_bezier = (grid.
myPrimitiveType == PrimitiveType::BEZIER);
2834 if (!is_nurbs && !is_bezier)
2843 if (source_basisu !=
nullptr && source_basisu->
getType() != basis_type)
2844 source_basisu =
nullptr;
2845 if (source_basisv !=
nullptr && source_basisv->
getType() != basis_type)
2846 source_basisv =
nullptr;
2849 if (source_basisu !=
nullptr)
2852 basisu->copyFrom(*source_basisu);
2863 if (source_basisv !=
nullptr)
2883 bool interpolate_ends = !closed;
2884 int extra_knots = order + (closed ? (interpolate_ends ? 1 : (order - 1)) : 0);
2889 (nvertices + extra_knots),
2894 if (basisu ==
nullptr)
2896 basisu = make_nurbs_basis(nvtxcols, grid.
myBasisOrderU, hull_wrapu);
2900 if (basisv ==
nullptr)
2902 basisv = make_nurbs_basis(nvtxrows, grid.
myBasisOrderV, hull_wrapv);
2913 int extra = ((nvertices > 2 && order > 2) || (order <= 2 && closed));
2915 extra + (nvertices / (order - 1)),
2918 if (basisu ==
nullptr)
2920 basisu = make_bez_basis(nvtxcols, grid.
myBasisOrderU, hull_wrapu);
2924 if (basisv ==
nullptr)
2926 basisv = make_bez_basis(nvtxrows, grid.
myBasisOrderV, hull_wrapv);
2937 if (grid_info.myHasPolygonCaps)
2939 const bool side_caps = !grid_info.myCrossSectionClosed;
2940 const GA_Basis *cap_source_basis = (swap_row_col != side_caps) ? basisv : basisu;
2944 cap0_basis->
copyFrom(*cap_source_basis);
2945 cap1_basis->copyFrom(*cap_source_basis);
2950 cap1->setBasis(cap1_basis);
2959 exint cross_section_nedges,
2961 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
2965 const bool closed_if_no_curve_input,
2968 const bool output_points_only,
2969 const bool unroll_closed_row_col,
2970 const int primitive_type,
2972 const exint cap_divisions,
2973 const bool triangular_poles,
2974 const bool swap_row_col,
2986 if (interrupt.wasInterrupted())
2993 if (cross_section_input !=
nullptr && (
2998 exint max_num_grids = 1;
2999 if (curve_input !=
nullptr)
3004 if (curve_input !=
nullptr && (
3014 bool single_cross_section =
true;
3016 bool cross_section_closed = (cross_section_shape == SurfaceShape::TUBE || cross_section_shape == SurfaceShape::SQUARE);
3017 bool cross_section_unrolled =
false;
3019 if (cross_section_input !=
nullptr)
3022 cross_section_range = cross_section_input->
getPrimitiveRange(cross_section_group);
3024 if (ncross_sections == 0)
3034 if (single_cross_section)
3040 single_cross_section_primoff = *it;
3041 bool nonempty =
getPolyProperties(cross_section_input, single_cross_section_primoff,
3042 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3049 if (!single_cross_section || curve_input ==
nullptr)
3050 cross_section_it =
GA_Iterator(cross_section_range);
3052 const bool is_primtype_auto = !output_points_only && (primitive_type ==
GA_PRIMNONE);
3059 closed_span_lengths.
append(0);
3063 bool hassharedpoints =
true;
3064 exint total_num_points = 0;
3065 exint total_num_verts = 0;
3066 exint total_num_prims = 0;
3067 if (curve_input ==
nullptr)
3070 UT_ASSERT(cross_section_input !=
nullptr);
3074 int local_primitive_type = primitive_type;
3075 unsigned char fallback_orderu = 0;
3076 unsigned char fallback_orderv;
3080 local_primitive_type,
3085 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[0];
3087 sop_SweepGrid grid_info;
3089 bool valid_grid = computeSingleGridSetup(
3090 cross_section_input,
3091 cross_section_group,
3095 0,
false,
false, CopyOrder::CYCLEVTX,
nullptr,
false,
nullptr,
3097 closed_if_no_curve_input,
3098 surface_type, output_points_only,
3099 unroll_closed_row_col,
3101 local_primitive_type,
3102 fallback_orderu, fallback_orderv,
3106 grid_info, num_points);
3112 total_num_points = num_points;
3114 exint num_grid_prims;
3115 exint num_grid_verts;
3116 appendSingleGridTopology(
3117 grid_info, surface_type, output_points_only, triangular_poles,
3118 grid_info.myHasPolygonCaps, swap_row_col,
3119 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3120 closed_span_lengths, num_grid_prims, num_grid_verts);
3123 total_num_verts = num_grid_verts;
3124 grid_info.myStartPrimOff =
GA_Offset(0);
3125 total_num_prims = num_grid_prims;
3126 grids.
append(std::move(grid_info));
3128 else if (!single_cross_section && copy_order == CopyOrder::EACH)
3132 for (; !cross_section_it.
atEnd(); ++cross_section_it)
3134 GA_Offset cross_section_primoff = *cross_section_it;
3137 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3145 if (interrupt.wasInterrupted())
3150 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3153 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3154 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3156 int local_primitive_type = primitive_type;
3157 unsigned char fallback_orderu = 0;
3158 unsigned char fallback_orderv;
3162 local_primitive_type,
3169 if (is_primtype_auto && cross_section_input !=
nullptr)
3170 updateAutoPrimType(cross_section_input, cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3172 sop_SweepGrid grid_info;
3174 bool valid_grid = computeSingleGridSetup(
3178 cross_section_primoff,
3179 cross_section_nedges,
3180 cross_section_closed,
3181 cross_section_unrolled,
3186 curve_input, curve_primoff,
3190 unroll_closed_row_col,
3192 local_primitive_type,
3193 fallback_orderu, fallback_orderv,
3203 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3204 total_num_points += num_points;
3206 exint num_grid_prims;
3207 exint num_grid_verts;
3208 appendSingleGridTopology(
3209 grid_info, surface_type, output_points_only, triangular_poles,
3210 grid_info.myHasPolygonCaps, swap_row_col,
3211 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3212 closed_span_lengths, num_grid_prims, num_grid_verts);
3214 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3215 total_num_verts += num_grid_verts;
3216 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3217 total_num_prims += num_grid_prims;
3218 grids.
append(std::move(grid_info));
3223 else if (!single_cross_section && (copy_order == CopyOrder::CYCLEPR ||
3234 cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data,
3240 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3249 if (interrupt.wasInterrupted())
3254 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3256 if (copy_order == CopyOrder::CYCLEPR)
3258 cross_section_primoff = *cross_section_it;
3260 if (cross_section_it.
atEnd())
3262 cross_section_it.
rewind();
3268 cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data,
3269 curve_primoff, cross_section_input, cross_section_group);
3278 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3284 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3285 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3287 int local_primitive_type = primitive_type;
3288 unsigned char fallback_orderu = 0;
3289 unsigned char fallback_orderv;
3293 local_primitive_type,
3300 if (is_primtype_auto && cross_section_input !=
nullptr)
3301 updateAutoPrimType(cross_section_input, cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3303 sop_SweepGrid grid_info;
3305 bool valid_grid = computeSingleGridSetup(
3309 cross_section_primoff,
3310 cross_section_nedges,
3311 cross_section_closed,
3312 cross_section_unrolled,
3317 curve_input, curve_primoff,
3319 surface_type, output_points_only,
3320 unroll_closed_row_col,
3322 local_primitive_type,
3323 fallback_orderu, fallback_orderv,
3327 grid_info, num_points);
3332 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3333 total_num_points += num_points;
3335 exint num_grid_prims;
3336 exint num_grid_verts;
3337 appendSingleGridTopology(
3338 grid_info, surface_type, output_points_only, triangular_poles,
3339 grid_info.myHasPolygonCaps, swap_row_col,
3340 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3341 closed_span_lengths, num_grid_prims, num_grid_verts);
3343 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3344 total_num_verts += num_grid_verts;
3345 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3346 total_num_prims += num_grid_prims;
3347 grids.
append(std::move(grid_info));
3353 unsigned char fallback_orderu = 0;
3354 int cross_section_primitive_type = is_primtype_auto ?
GA_PRIMPOLY : primitive_type;
3355 bool varying_nedges_all_case =
false;
3357 const bool all_case = (!single_cross_section && copy_order ==
CopyOrder::ALL);
3358 const GA_Basis *all_case_grid_basisu =
nullptr;
3366 bool is_valid_grid = computeCombinedCrossSectionProperties(
3367 cross_section_input,
3368 cross_section_group,
3371 cross_section_nedges,
3372 cross_section_closed,
3373 cross_section_unrolled,
3374 varying_nedges_all_case,
3375 cross_section_primoffs_all_case,
3377 cross_section_primitive_type,
3379 &all_case_grid_basisu);
3390 if (interrupt.wasInterrupted())
3393 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3396 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3397 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3399 int local_primitive_type = primitive_type;
3400 unsigned char fallback_orderv;
3404 local_primitive_type,
3411 if (single_cross_section && is_primtype_auto && cross_section_input !=
nullptr)
3412 updateAutoPrimType(cross_section_input, single_cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3416 local_primitive_type = cross_section_primitive_type;
3419 if (all_case && pbasisu !=
nullptr)
3423 *pbasisu = all_case_grid_basisu;
3426 sop_SweepGrid grid_info;
3428 bool valid_grid = computeSingleGridSetup(
3429 cross_section_input,
3430 cross_section_group,
3431 single_cross_section,
3433 single_cross_section_primoff,
3434 cross_section_nedges,
3435 cross_section_closed,
3436 cross_section_unrolled,
3438 copy_order_attrib_data,
3439 varying_nedges_all_case,
3440 (cross_section_primoffs_all_case.
size() == 0) ?
nullptr : &cross_section_primoffs_all_case,
3441 curve_input, curve_primoff,
3442 closed_if_no_curve_input,
3443 surface_type, output_points_only,
3444 unroll_closed_row_col,
3446 local_primitive_type,
3447 fallback_orderu, fallback_orderv,
3451 grid_info, num_points);
3456 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3457 total_num_points += num_points;
3459 exint num_grid_prims;
3460 exint num_grid_verts;
3461 appendSingleGridTopology(
3462 grid_info, surface_type, output_points_only, triangular_poles,
3463 grid_info.myHasPolygonCaps, swap_row_col,
3464 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3465 closed_span_lengths, num_grid_prims, num_grid_verts);
3467 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3468 total_num_verts += num_grid_verts;
3469 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3470 total_num_prims += num_grid_prims;
3471 grids.
append(std::move(grid_info));
3476 if (interrupt.wasInterrupted())
3483 if (output_points_only)
3489 prim_type_count_pairs.getArray(),
3490 start_ptoff, total_num_points,
3491 vertexlistsizelist, vertexpointnumbers.
getArray(),
3508 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3510 grids[gridi].myStartPtOff += start_ptoff;
3515 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3517 grids[gridi].myStartVtxOff += start_vtxoff;
3522 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3524 grids[gridi].myStartPrimOff += start_primoff;
3532 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3534 const sop_SweepGrid &grid_info = grids[gridi];
3536 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3537 const GA_Basis *basisu = grid_basisus.
isEmpty() ?
nullptr : grid_basisus[gridi];
3538 const GA_Basis *basisv = grid_basisvs.
isEmpty() ?
nullptr : grid_basisvs[gridi];
3541 initNonPolyGridPrims(grid_info, grid, swap_row_col, basisu, basisv, output_geo);
3549 template<
typename FUNCTOR>
3551 copyVertexCrossSectionWrapper(
3553 const sop_SweepGrid &grid_info,
3554 const FUNCTOR &functor)
3558 exint cap_vertex_count = 0;
3559 if (grid_info.myHasPolygonCaps)
3566 for (
exint col = 0; col < cap_vertex_count; ++col)
3569 functor(grid_info.myStartVtxOff + col, 0, reverseVtx(col, cap_vertex_count,
true));
3577 for (
exint row = 0; row < cap_vertex_count; ++
row)
3580 functor(grid_info.myStartVtxOff + row, reverseVtx(row, cap_vertex_count,
true), 0);
3585 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
3586 auto &&functor_wrapper = [&functor,start_vtxoff](
exint vtxnum,
exint row,
exint col,
bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
3588 GA_Offset output_vtxoff = start_vtxoff + vtxnum;
3589 functor(output_vtxoff, row +
exint(isrowend), col +
exint(iscolend));
3592 if (grid_info.myHasPolygonCaps)
3599 for (
exint col = 0; col < cap_vertex_count; ++col)
3607 for (
exint row = 0; row < cap_vertex_count; ++
row)
3615 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>
3617 copyCrossSectionAttributeWrapper2(
3619 const OUTPUT_ATTRIB_T &outputh,
3620 const INPUT_ATTRIB_T &cross_sectionh,
3623 const sop_SweepGridTransformWrapper *transforms,
3624 const sop_SweepGrid &grid_info,
3625 const bool reverse_cross_sections,
3626 const bool swap_row_col,
3627 const GET_TRANSFORM_FUNCTOR &get_transform_functor,
3628 const TRANSFORM_FUNCTOR &transform_and_copy_functor,
3629 const INTERP_FUNCTOR &transform_and_interp_functor)
3632 UT_ASSERT(cross_section_owner == output_attrib_owner ||
3636 exint prev_curve_vtxi = -1;
3639 exint current_cross_section_nedges;
3640 bool current_cross_section_closed;
3641 bool current_cross_section_unrolled;
3643 auto &&functor = [&grid_info,&outputh,&cross_sectionh,
3644 cross_section_owner,
3645 &get_transform_functor,&transform_and_copy_functor,
3646 &transform_and_interp_functor,
3647 cross_section_input,
3649 reverse_cross_sections,
3652 &source_cross_section_primoff,
3653 &cross_section_vertices,
3654 ¤t_cross_section_nedges,
3655 ¤t_cross_section_closed,
3656 ¤t_cross_section_unrolled,
3659 exint num_curve_edges = grid_info.myCurveNEdges;
3660 bool is_curve_closed = grid_info.myCurveClosed;
3661 exint curve_vtxi = swap_row_col ? col :
row;
3662 exint num_cross_section_edges = grid_info.myCrossSectionNEdges;
3664 exint cross_section_vtxi = swap_row_col ? row : col;
3666 if (curve_vtxi != prev_curve_vtxi)
3671 if (output_attrib_owner ==
GA_ATTRIB_VERTEX && is_curve_closed && curve_vtxi == num_curve_edges)
3673 transform = get_transform_functor(transforms, curve_vtxi, grid_info);
3674 source_cross_section_primoff =
3675 grid_info.mySingleCrossSection ?
3676 GA_Offset(grid_info.myCrossSectionPrimOff) :
3681 cross_section_vertices = cross_section_input->getPrimitiveVertexList(source_cross_section_primoff);
3682 getPolyProperties(cross_section_input, cross_section_vertices, current_cross_section_nedges, current_cross_section_closed, current_cross_section_unrolled);
3684 prev_curve_vtxi = curve_vtxi;
3689 transform_and_copy_functor(cross_sectionh, source_cross_section_primoff, transform, outputh, output_offset);
3693 constexpr
bool is_vertex_attrib = (output_attrib_owner ==
GA_ATTRIB_VERTEX);
3695 if (current_cross_section_nedges == num_cross_section_edges)
3699 if (reverse_cross_sections)
3702 cross_section_vtxi = reverseVtx(cross_section_vtxi, current_cross_section_nedges +
exint(is_vertex_attrib || !current_cross_section_closed),
3703 !is_vertex_attrib && current_cross_section_closed);
3710 if (cross_section_vtxi == cross_section_vertices.size())
3712 if (wrap_to_invalid)
3719 vtxoff = cross_section_vertices[0];
3722 vtxoff = cross_section_vertices[cross_section_vtxi];
3724 transform_and_copy_functor(cross_sectionh, cross_section_offset, transform, outputh, output_offset);
3731 UT_ASSERT_P(num_cross_section_edges > current_cross_section_nedges);
3736 exint fine_fractions = cross_section_vtxi*current_cross_section_nedges;
3737 if (reverse_cross_sections)
3738 fine_fractions = num_cross_section_edges*current_cross_section_nedges - fine_fractions;
3739 exint current_cross_section_edge = fine_fractions / num_cross_section_edges;
3740 exint current_cross_section_fractions = fine_fractions % num_cross_section_edges;
3741 exint current_cross_section_pt = current_cross_section_fractions / current_cross_section_nedges;
3742 if (current_cross_section_pt == 0)
3746 if (current_cross_section_edge == cross_section_vertices.size())
3748 if (wrap_to_invalid)
3755 vtxoff = cross_section_vertices[0];
3758 vtxoff = cross_section_vertices[current_cross_section_edge];
3760 transform_and_copy_functor(cross_sectionh, cross_section_offset, transform, outputh, output_offset);
3768 exint current_cross_section_edge_start = (current_cross_section_edge*num_cross_section_edges + current_cross_section_nedges-1) / current_cross_section_nedges;
3769 exint current_cross_section_edge_end = ((current_cross_section_edge+1)*num_cross_section_edges + current_cross_section_nedges-1) / current_cross_section_nedges;
3770 exint current_cross_section_edge_npts = current_cross_section_edge_end - current_cross_section_edge_start;
3771 double u = double(current_cross_section_pt)/double(current_cross_section_edge_npts);
3775 UT_ASSERT_P(current_cross_section_edge != current_cross_section_nedges);
3776 exint vtxi0 = current_cross_section_edge;
3777 GA_Offset vtxoff0 = cross_section_vertices[vtxi0];
3780 if (current_cross_section_edge+1 == cross_section_vertices.size())
3782 if (wrap_to_invalid)
3789 vtxoff1 = cross_section_vertices[0];
3792 vtxoff1 = cross_section_vertices[current_cross_section_edge+1];
3798 cross_section_offset0 = vtxoff0;
3799 cross_section_offset1 = vtxoff1;
3803 cross_section_offset0 = cross_section_input->vertexPoint(vtxoff0);
3805 cross_section_offset1 = cross_section_input->vertexPoint(vtxoff1);
3807 cross_section_offset1 = vtxoff1;
3809 transform_and_interp_functor(cross_sectionh, cross_section_offset0, cross_section_offset1, u, transform, outputh, output_offset);
3818 copyVertexCrossSectionWrapper(grid, grid_info, functor);
3825 if (grid_info.myHasPolygonCaps)
3828 functor(grid_info.myStartPrimOff, 0, 0);
3831 const GA_Offset start_primoff = grid_info.myStartPrimOff +
exint(grid_info.myHasPolygonCaps);
3832 auto &&functor_wrapper = [&functor,start_primoff](
exint primnum,
exint row,
exint col,
exint primvtxcount,
bool closed)
3834 GA_Offset output_primoff = start_primoff + primnum;
3835 functor(output_primoff, row, col);
3838 if (grid_info.myHasPolygonCaps)
3855 template<
typename VALUE_T,
typename TRANSFORM_T,GA_AttributeOwner attrib_owner,
typename GET_TRANSFORM_FUNCTOR,
typename TRANSFORM_FUNCTOR,
typename INTERP_FUNCTOR>
3857 copyCrossSectionAttributeWrapper(
3862 const sop_SweepGridTransformWrapper *transforms,
3863 const sop_SweepGrid &grid_info,
3864 const bool reverse_cross_sections,
3865 const bool swap_row_col,
3866 const GET_TRANSFORM_FUNCTOR &get_transform_functor,
3867 const TRANSFORM_FUNCTOR &transform_and_copy_functor,
3868 const INTERP_FUNCTOR &transform_and_interp_functor)
3875 copyCrossSectionAttributeWrapper2<TRANSFORM_T,attrib_owner>(
3876 grid, outputh, cross_sectionh, attrib_owner,
3877 cross_section_input, transforms, grid_info,
3878 reverse_cross_sections,
3880 get_transform_functor,
3881 transform_and_copy_functor,
3882 transform_and_interp_functor);
3885 template<
typename T,GA_AttributeOwner attrib_owner>
3887 copyIntegerSingleGrid(
3891 const sop_SweepGridTransformWrapper *transforms,
3892 const sop_SweepGrid &grid_info,
3894 const bool output_points_only,
3895 const bool triangular_poles,
3896 const bool reverse_cross_sections,
3897 const bool swap_row_col)
3905 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3910 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
3915 if (tuple_size == 1)
3918 auto &&transform_and_copy = [](
3923 T value = cross_sectionh.
get(cross_section_offset);
3924 outputh.set(output_offset, value);
3926 auto &&transform_and_interp = [](
3932 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
3933 T value = cross_sectionh.
get(cross_section_offset);
3934 outputh.set(output_offset, value);
3936 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
3937 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
3938 reverse_cross_sections, swap_row_col,
3939 get_transform, transform_and_copy, transform_and_interp);
3944 auto &&transform_and_copy = [tuple_size](
3949 for (
exint component = 0; component < tuple_size; ++component)
3951 T value = cross_sectionh.
get(cross_section_offset, component);
3952 outputh.set(output_offset, component, value);
3955 auto &&transform_and_interp = [tuple_size](
3961 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
3962 for (
exint component = 0; component < tuple_size; ++component)
3964 T value = cross_sectionh.
get(cross_section_offset, component);
3965 outputh.set(output_offset, component, value);
3968 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
3969 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
3970 reverse_cross_sections, swap_row_col,
3971 get_transform, transform_and_copy, transform_and_interp);
3974 template<
typename T,GA_TypeInfo transform_type,GA_AttributeOwner attrib_owner>
3976 copyFloatSingleGrid(
3980 const sop_SweepGridTransformWrapper *transforms,
3981 const sop_SweepGrid &grid_info,
3982 const exint cross_sections_per_vertex,
3983 const exint cap_divisions,
3985 const bool output_points_only,
3986 const bool triangular_poles,
3987 const bool reverse_cross_sections,
3988 const bool swap_row_col)
3996 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3998 const exint cap_rows = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
3999 exint last_cap_start_row = -1;
4000 exint last_cap_start_transform = -1;
4001 if (cross_sections_per_vertex != 1 && cap_rows > 0)
4003 last_cap_start_row = grid_info.myCurveNEdges - cap_rows;
4004 last_cap_start_transform = (last_cap_start_row - cap_rows)/cross_sections_per_vertex + cap_rows;
4007 auto &&fix_transformi_for_all_case = [cap_rows,cross_sections_per_vertex,last_cap_start_row,last_cap_start_transform](
exint &transformi)
4013 transformi /= cross_sections_per_vertex;
4014 else if (transformi > cap_rows)
4016 if (transformi < last_cap_start_row)
4017 transformi = (transformi - cap_rows)/cross_sections_per_vertex + cap_rows;
4019 transformi = last_cap_start_transform + (transformi - last_cap_start_row);
4033 auto &&get_transform = [&
transform,cross_sections_per_vertex,&fix_transformi_for_all_case]
4034 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix4T<T>*
4037 if (cross_sections_per_vertex != 1)
4038 fix_transformi_for_all_case(transformi);
4040 transform.
setTranslates(transforms->getTranslates<T>()[transformi]);
4043 auto &&transform_and_copy = [](
4050 outputh.set(output_offset, value);
4052 auto &&transform_and_interp = [](
4062 outputh.set(output_offset, value);
4064 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix4T<T>, attrib_owner>(grid,
4065 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4066 reverse_cross_sections, swap_row_col,
4067 get_transform, transform_and_copy, transform_and_interp);
4074 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4075 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4078 if (cross_sections_per_vertex != 1)
4079 fix_transformi_for_all_case(transformi);
4080 return &transforms->getInverse3s<
T>()[transformi];
4082 auto &&transform_and_copy = [](
4089 outputh.set(output_offset, value);
4091 auto &&transform_and_interp = [](
4108 if (new_length2 != 0)
4109 value *= SYSsqrt(orig_length2/new_length2);
4110 outputh.set(output_offset, value);
4112 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4113 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4114 reverse_cross_sections, swap_row_col,
4115 get_transform, transform_and_copy, transform_and_interp);
4122 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4123 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4126 if (cross_sections_per_vertex != 1)
4127 fix_transformi_for_all_case(transformi);
4128 return &transforms->getMatrix3s<
T>()[transformi];
4130 auto &&transform_and_copy = [](
4137 outputh.set(output_offset, value);
4139 auto &&transform_and_interp = [](
4149 outputh.set(output_offset, value);
4151 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4152 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4153 reverse_cross_sections, swap_row_col,
4154 get_transform, transform_and_copy, transform_and_interp);
4161 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4162 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_QuaternionT<T>*
4165 if (cross_sections_per_vertex != 1)
4166 fix_transformi_for_all_case(transformi);
4167 return &transforms->getQuaternions<
T>()[transformi];
4169 auto &&transform_and_copy = [](
4176 outputh.set(output_offset, value);
4178 auto &&transform_and_interp = [](
4188 value = *transform *
value;
4189 outputh.set(output_offset, value);
4191 copyCrossSectionAttributeWrapper<UT_QuaternionT<T>,
UT_QuaternionT<T>, attrib_owner>(grid,
4192 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4193 reverse_cross_sections, swap_row_col,
4194 get_transform, transform_and_copy, transform_and_interp);
4199 if (tuple_size == 9)
4202 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4203 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4206 if (cross_sections_per_vertex != 1)
4207 fix_transformi_for_all_case(transformi);
4208 return &transforms->getMatrix3s<
T>()[transformi];
4210 auto &&transform_and_copy = [](
4217 outputh.set(output_offset, value);
4219 auto &&transform_and_interp = [](
4229 outputh.set(output_offset, value);
4231 copyCrossSectionAttributeWrapper<UT_Matrix3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4232 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4233 reverse_cross_sections, swap_row_col,
4234 get_transform, transform_and_copy, transform_and_interp);
4237 if (tuple_size == 16)
4242 auto &&get_transform = [&
transform,cross_sections_per_vertex,&fix_transformi_for_all_case]
4243 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix4T<T>*
4246 if (cross_sections_per_vertex != 1)
4247 fix_transformi_for_all_case(transformi);
4249 transform.
setTranslates(transforms->getTranslates<T>()[transformi]);
4252 auto &&transform_and_copy = [](
4259 outputh.set(output_offset, value);
4261 auto &&transform_and_interp = [](
4271 outputh.set(output_offset, value);
4273 copyCrossSectionAttributeWrapper<UT_Matrix4T<T>,
UT_Matrix4T<T>, attrib_owner>(grid,
4274 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4275 reverse_cross_sections, swap_row_col,
4276 get_transform, transform_and_copy, transform_and_interp);
4283 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
4289 if (tuple_size == 1)
4292 auto &&transform_and_copy = [](
4297 T value = cross_sectionh.
get(cross_section_offset);
4298 outputh.set(output_offset, value);
4300 if (is_integer_type)
4302 auto &&transform_and_interp = [](
4308 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4309 T value = cross_sectionh.
get(cross_section_offset);
4310 outputh.set(output_offset, value);
4312 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4313 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4314 reverse_cross_sections, swap_row_col,
4315 get_transform, transform_and_copy, transform_and_interp);
4319 auto &&transform_and_interp = [](
4325 const T value0 = cross_sectionh.
get(cross_section_offset0);
4326 const T value1 = cross_sectionh.
get(cross_section_offset1);
4327 T value =
SYSlerp(value0, value1, t);
4328 outputh.set(output_offset, value);
4330 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4331 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4332 reverse_cross_sections, swap_row_col,
4333 get_transform, transform_and_copy, transform_and_interp);
4337 if (tuple_size == 2 && !is_integer_type)
4340 auto &&transform_and_copy = [](
4346 outputh.set(output_offset, value);
4348 auto &&transform_and_interp = [](
4357 outputh.set(output_offset, value);
4359 copyCrossSectionAttributeWrapper<UT_Vector2T<T>,
void, attrib_owner>(grid,
4360 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4361 reverse_cross_sections, swap_row_col,
4362 get_transform, transform_and_copy, transform_and_interp);
4365 if (tuple_size == 3 && !is_integer_type)
4368 auto &&transform_and_copy = [](
4374 outputh.set(output_offset, value);
4376 auto &&transform_and_interp = [](
4385 outputh.set(output_offset, value);
4387 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
void, attrib_owner>(grid,
4388 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4389 reverse_cross_sections, swap_row_col,
4390 get_transform, transform_and_copy, transform_and_interp);
4395 auto &&transform_and_copy = [tuple_size](
4400 for (
exint component = 0; component < tuple_size; ++component)
4402 T value = cross_sectionh.
get(cross_section_offset, component);
4403 outputh.set(output_offset, component, value);
4406 if (is_integer_type)
4408 auto &&transform_and_interp = [tuple_size](
4414 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4415 for (
exint component = 0; component < tuple_size; ++component)
4417 T value = cross_sectionh.
get(cross_section_offset, component);
4418 outputh.set(output_offset, component, value);
4421 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4422 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4423 reverse_cross_sections, swap_row_col,
4424 get_transform, transform_and_copy, transform_and_interp);
4428 auto &&transform_and_interp = [tuple_size](
4434 for (
exint component = 0; component < tuple_size; ++component)
4436 const T value0 = cross_sectionh.
get(cross_section_offset0, component);
4437 const T value1 = cross_sectionh.
get(cross_section_offset1, component);
4438 T value =
SYSlerp(value0, value1, t);
4439 outputh.set(output_offset, component, value);
4442 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4443 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4444 reverse_cross_sections, swap_row_col,
4445 get_transform, transform_and_copy, transform_and_interp);
4449 template<GA_AttributeOwner attrib_owner>
4451 copyAttribSingleGrid(
4455 const sop_SweepGrid &grid_info,
4457 const bool output_points_only,
4458 const bool triangular_poles,
4459 const bool reverse_cross_sections,
4460 const bool swap_row_col)
4465 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
4468 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
4473 auto &&transform_and_copy = [](
4478 output_attrib->copy(output_offset, *cross_section_attrib, cross_section_offset);
4480 auto &&transform_and_interp = [](
4486 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4487 output_attrib->copy(output_offset, *cross_section_attrib, cross_section_offset);
4491 copyCrossSectionAttributeWrapper2<void, attrib_owner>(grid,
4492 output_attrib, cross_section_attrib, attrib_owner, cross_section_input,
nullptr, grid_info,
4493 reverse_cross_sections, swap_row_col,
4494 get_transform, transform_and_copy, transform_and_interp);
4497 static const sop_SweepGridTransformWrapper *
4498 gridOffsetTransforms(
4499 const SOP_SweepHDKCache *
const transform_cache,
4500 sop_SweepGridTransformWrapper &grid_transforms,
4503 if (transform_cache ==
nullptr)
4506 grid_transforms.
init(*transform_cache, gridi);
4508 return &grid_transforms;
4511 template<GA_AttributeOwner attrib_owner>
4513 copyCrossSectionAttrib2(
4517 const SOP_SweepHDKCache *transform_cache,
4518 const sop_SweepGrid *grids,
4520 const exint cross_sections_per_vertex,
4521 const exint cap_divisions,
4523 const bool output_points_only,
4524 const bool triangular_poles,
4525 const bool reverse_cross_sections,
4526 const bool swap_row_col)
4531 const exint PARALLEL_THRESHOLD = 2048;
4532 const bool parallel = (ngrids > 1 &&
4537 if (!output_numeric)
4544 copyAttribSingleGrid<attrib_owner>(
4545 output_attrib, cross_section_attrib, cross_section_input,
4547 surface_type, output_points_only, triangular_poles,
4548 reverse_cross_sections, swap_row_col);
4559 functor(grid_range);
4566 if (!cross_section_numeric)
4570 if (tuple_size != cross_section_numeric->
getTupleSize())
4585 sop_SweepGridTransformWrapper local_grid_transforms;
4586 if (tuple_size == 3)
4594 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4595 copyFloatSingleGrid<fpreal64,GA_TYPE_POINT,attrib_owner>(
4596 output_numeric, cross_section_numeric, cross_section_input,
4597 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4598 surface_type, output_points_only, triangular_poles,
4599 reverse_cross_sections, swap_row_col);
4606 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4607 copyFloatSingleGrid<fpreal32,GA_TYPE_POINT,attrib_owner>(
4608 output_numeric, cross_section_numeric, cross_section_input,
4609 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4610 surface_type, output_points_only, triangular_poles,
4611 reverse_cross_sections, swap_row_col);
4622 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4623 copyFloatSingleGrid<fpreal64,GA_TYPE_NORMAL,attrib_owner>(
4624 output_numeric, cross_section_numeric, cross_section_input,
4625 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4626 surface_type, output_points_only, triangular_poles,
4627 reverse_cross_sections, swap_row_col);
4634 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4635 copyFloatSingleGrid<fpreal32,GA_TYPE_NORMAL,attrib_owner>(
4636 output_numeric, cross_section_numeric, cross_section_input,
4637 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4638 surface_type, output_points_only, triangular_poles,
4639 reverse_cross_sections, swap_row_col);
4650 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4651 copyFloatSingleGrid<fpreal64,GA_TYPE_VECTOR,attrib_owner>(
4652 output_numeric, cross_section_numeric, cross_section_input,
4653 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4654 surface_type, output_points_only, triangular_poles,
4655 reverse_cross_sections, swap_row_col);
4662 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4663 copyFloatSingleGrid<fpreal32,GA_TYPE_VECTOR,attrib_owner>(
4664 output_numeric, cross_section_numeric, cross_section_input,
4665 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4666 surface_type, output_points_only, triangular_poles,
4667 reverse_cross_sections, swap_row_col);
4673 else if (tuple_size == 4)
4681 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4682 copyFloatSingleGrid<fpreal64,GA_TYPE_QUATERNION,attrib_owner>(
4683 output_numeric, cross_section_numeric, cross_section_input,
4684 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4685 surface_type, output_points_only, triangular_poles,
4686 reverse_cross_sections, swap_row_col);
4693 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4694 copyFloatSingleGrid<fpreal32,GA_TYPE_QUATERNION,attrib_owner>(
4695 output_numeric, cross_section_numeric, cross_section_input,
4696 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4697 surface_type, output_points_only, triangular_poles,
4698 reverse_cross_sections, swap_row_col);
4704 else if (tuple_size == 9 || tuple_size == 16)
4712 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4713 copyFloatSingleGrid<fpreal64,GA_TYPE_TRANSFORM,attrib_owner>(
4714 output_numeric, cross_section_numeric, cross_section_input,
4715 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4716 surface_type, output_points_only, triangular_poles,
4717 reverse_cross_sections, swap_row_col);
4724 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4725 copyFloatSingleGrid<fpreal32,GA_TYPE_TRANSFORM,attrib_owner>(
4726 output_numeric, cross_section_numeric, cross_section_input,
4727 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4728 surface_type, output_points_only, triangular_poles,
4729 reverse_cross_sections, swap_row_col);
4740 copyFloatSingleGrid<fpreal64,GA_TYPE_VOID,attrib_owner>(
4741 output_numeric, cross_section_numeric, cross_section_input,
4742 nullptr, grids[gridi], cross_sections_per_vertex, cap_divisions,
4743 surface_type, output_points_only, triangular_poles,
4744 reverse_cross_sections, swap_row_col);
4751 copyFloatSingleGrid<fpreal32,GA_TYPE_VOID,attrib_owner>(
4752 output_numeric, cross_section_numeric, cross_section_input,
4753 nullptr, grids[gridi], cross_sections_per_vertex, cap_divisions,
4754 surface_type, output_points_only, triangular_poles,
4755 reverse_cross_sections, swap_row_col);
4762 copyIntegerSingleGrid<int64,attrib_owner>(
4763 output_numeric, cross_section_numeric, cross_section_input,
4764 nullptr, grids[gridi],
4765 surface_type, output_points_only, triangular_poles,
4766 reverse_cross_sections, swap_row_col);
4773 copyIntegerSingleGrid<int32,attrib_owner>(
4774 output_numeric, cross_section_numeric, cross_section_input,
4775 nullptr, grids[gridi],
4776 surface_type, output_points_only, triangular_poles,
4777 reverse_cross_sections, swap_row_col);
4785 functor(grid_range);
4789 copyCrossSectionAttrib(
4793 const SOP_SweepHDKCache *transform_cache,
4794 const sop_SweepGrid *grids,
4796 const exint cross_sections_per_vertex,
4797 const exint cap_divisions,
4799 const bool output_points_only,
4800 const bool triangular_poles,
4801 const bool reverse_cross_sections,
4802 const bool swap_row_col)
4809 copyCrossSectionAttrib2<GA_ATTRIB_POINT>(
4810 output_attrib, cross_section_attrib, cross_section_input,
4811 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4812 surface_type, output_points_only, triangular_poles,
4813 reverse_cross_sections, swap_row_col);
4817 copyCrossSectionAttrib2<GA_ATTRIB_VERTEX>(
4818 output_attrib, cross_section_attrib, cross_section_input,
4819 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4820 surface_type, output_points_only, triangular_poles,
4821 reverse_cross_sections, swap_row_col);
4825 copyCrossSectionAttrib2<GA_ATTRIB_PRIMITIVE>(
4826 output_attrib, cross_section_attrib, cross_section_input,
4827 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4828 surface_type, output_points_only, triangular_poles,
4829 reverse_cross_sections, swap_row_col);
4833 output_attrib->
replace(*cross_section_attrib);
4837 template<
bool wrap_to_inval
id,
typename FUNCTOR>
4839 copyVertexCurveAttribWrapper(
4840 const sop_SweepGrid &grid_info,
4843 exint cap_divisions,
4844 exint cross_sections_per_vertex,
4845 const bool swap_row_col,
4846 const FUNCTOR ©_functor)
4848 const exint curve_nedges = grid_info.myCurveNEdges;
4849 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
4851 const exint cap_divs = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
4852 exint prev_vtxi = -1;
4854 exint cap_vertex_count = 0;
4855 if (grid_info.myHasPolygonCaps)
4860 cap_vertex_count = cross_section_nedges;
4865 for (
exint col = 0; col < cap_vertex_count; ++col)
4867 copy_functor(grid_info.myStartVtxOff + col, 0);
4873 cap_vertex_count = curve_nedges;
4875 for (
exint row = 0; row < cap_vertex_count; ++
row)
4877 copy_functor(grid_info.myStartVtxOff + row, row);
4882 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
4883 const bool closed_curve = grid_info.myCurveClosed;
4885 start_vtxoff, cross_sections_per_vertex, swap_row_col, closed_curve, ©_functor]
4888 exint vtxi = swap_row_col ? col :
row;
4889 vtxi +=
exint(swap_row_col ? iscolend : isrowend);
4890 if (vtxi != prev_vtxi)
4892 curve_vtxi = vtxi - cap_divs;
4893 if (cross_sections_per_vertex != 1)
4894 curve_vtxi /= cross_sections_per_vertex;
4897 else if (curve_vtxi >= num_vertices)
4900 curve_vtxi = num_vertices-1;
4901 else if (wrap_to_invalid)
4908 copy_functor(start_vtxoff + vtxnum, curve_vtxi);
4910 if (grid_info.myHasPolygonCaps)
4917 curve_vtxi = num_vertices-1;
4919 for (
exint col = 0; col < cap_vertex_count; ++col)
4921 copy_functor(cap_start_vtxoff + col, curve_vtxi);
4927 for (
exint row = 0; row < cap_vertex_count; ++
row)
4929 copy_functor(cap_start_vtxoff + row, row);
4935 template<GA_AttributeOwner attrib_owner,
bool wrap_to_inval
id=false,
typename COPY_FUNCTOR>
4940 const sop_SweepGrid *grids,
4942 const exint cross_sections_per_vertex,
4944 const bool output_points_only,
4945 const bool triangular_poles,
4946 const exint cap_divisions,
4947 const bool swap_row_col,
4948 const COPY_FUNCTOR ©_functor)
4959 const sop_SweepGrid &grid_info = grids[gridi];
4961 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
4966 copyVertexCurveAttribWrapper<wrap_to_invalid>(grid_info, grid, vertices.
size(), cap_divisions, cross_sections_per_vertex, swap_row_col,
4967 [©_functor,&vertices](
GA_Offset output_vtxoff,
exint curve_vtxi)
4970 copy_functor(output_vtxoff, curve_vtxoff);
4976 const exint cap_divs = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
4977 exint prev_vtxi = -1;
4980 &curve_ptoff, curve_input, cross_sections_per_vertex, swap_row_col, ©_functor]
4983 exint vtxi = swap_row_col ? col :
row;
4984 if (vtxi != prev_vtxi)
4986 exint curve_vtxi = vtxi - cap_divs;
4987 if (cross_sections_per_vertex != 1)
4988 curve_vtxi /= cross_sections_per_vertex;
4991 else if (curve_vtxi >= vertices.
size())
4992 curve_vtxi = vertices.
size()-1;
4993 GA_Offset curve_vtxoff = vertices(curve_vtxi);
4994 curve_ptoff = curve_input->
vertexPoint(curve_vtxoff);
4997 copy_functor(output_ptoff, curve_ptoff);
5003 const exint PARALLEL_THRESHOLD = 2048;
5022 const sop_SweepGrid *grids,
5024 const exint cross_sections_per_vertex,
5026 const bool output_points_only,
5027 const bool triangular_poles,
5028 const exint cap_divisions,
5029 const bool swap_row_col)
5036 auto &©_functor = [output_attrib,curve_attrib](
GA_Offset output_off,
GA_Offset curve_off)
5038 output_attrib->
copy(output_off, *curve_attrib, curve_off);
5040 copyCurveAttrib2<GA_ATTRIB_POINT>(
5041 output_attrib, curve_input,
5042 grids, ngrids, cross_sections_per_vertex,
5043 surface_type, output_points_only, triangular_poles, cap_divisions,
5044 swap_row_col, copy_functor);
5048 if (!output_points_only)
5050 auto &©_functor = [output_attrib,curve_attrib](
GA_Offset output_off,
GA_Offset curve_off)
5052 output_attrib->
copy(output_off, *curve_attrib, curve_off);
5054 copyCurveAttrib2<GA_ATTRIB_VERTEX>(
5055 output_attrib, curve_input,
5056 grids, ngrids, cross_sections_per_vertex,
5057 surface_type, output_points_only, triangular_poles, cap_divisions,
5058 swap_row_col, copy_functor);
5063 if (!output_points_only)
5073 const sop_SweepGrid &grid_info = grids[gridi];
5075 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
5078 const GA_Offset startprimoff = grid_info.myStartPrimOff;
5080 output_attrib->
fill(
GA_Range(output_attrib->
getIndexMap(), startprimoff, endprimoff), *curve_attrib, grid_info.myCurvePrimOff);
5084 const exint PARALLEL_THRESHOLD = 2048;
5100 output_attrib->
replace(*curve_attrib);
5112 template<
typename T,GA_AttributeOwner output_owner>
5114 copyCrossSectionUVSingleGrid(
5119 const sop_SweepGrid &grid_info,
5121 const bool is_cross_section_uv_computed,
5122 const bool reverse_cross_sections,
5123 const bool swap_row_col,
5136 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
5146 if (tuple_size == 2)
5150 auto &©_functor = [missing_input_us,&outputh,flipu,swap_row_col,uscale](
5153 const exint cross_section_vtxi = swap_row_col ? row : col;
5154 T value = (cross_section_vtxi == missing_input_us->size()) ?
T(1.0) : (*missing_input_us)[cross_section_vtxi];
5158 output_value[theUComponent] = uscale*
value;
5159 outputh.set(output_offset, output_value);
5162 copyVertexCrossSectionWrapper(grid, grid_info, copy_functor);
5166 else if (tuple_size == 3)
5170 auto &©_functor = [missing_input_us,&outputh,flipu,swap_row_col,uscale](
5173 const exint cross_section_vtxi = swap_row_col ? row : col;
5174 T value = (cross_section_vtxi == missing_input_us->size()) ?
T(1.0) : (*missing_input_us)[cross_section_vtxi];
5178 output_value[theUComponent] = uscale*
value;
5179 outputh.set(output_offset, output_value);
5182 copyVertexCrossSectionWrapper(grid, grid_info, copy_functor);
5189 if (tuple_size == 2)
5192 auto &&transform_and_copy = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5199 value = reverse_cross_sections ?
T(0.0) : T(1.0);
5201 value = cross_sectionh.get(cross_section_offset);
5204 value = T(1.0)-
value;
5205 if (is_cross_section_uv_computed)
5208 output_value[theUComponent] =
value;
5209 outputh.set(output_offset, output_value);
5211 auto &&transform_and_interp = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5218 const T value0 = cross_sectionh.get(cross_section_offset0);
5223 value1 = reverse_cross_sections ? T(0.0) : T(1.0);
5225 value1 = cross_sectionh.get(cross_section_offset1);
5227 T value =
SYSlerp(value0, value1, t);
5229 value = T(1.0)-
value;
5230 if (is_cross_section_uv_computed)
5233 output_value[theUComponent] =
value;
5234 outputh.set(output_offset, output_value);
5241 copyCrossSectionAttributeWrapper2<void, output_owner, wrap_to_invalid>(grid,
5242 outputh, cross_sectionh, cross_section_owner, cross_section_input,
nullptr, grid_info,
5243 reverse_cross_sections, swap_row_col,
5244 get_transform, transform_and_copy, transform_and_interp);
5247 if (tuple_size == 3)
5250 auto &&transform_and_copy = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5257 value = reverse_cross_sections ? T(0.0) : T(1.0);
5259 value = cross_sectionh.get(cross_section_offset);
5262 value = T(1.0)-
value;
5263 if (is_cross_section_uv_computed)
5266 output_value[theUComponent] =
value;
5267 outputh.set(output_offset, output_value);
5269 auto &&transform_and_interp = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5276 const T value0 = cross_sectionh.get(cross_section_offset0);
5281 value1 = reverse_cross_sections ? T(0.0) : T(1.0);
5283 value1 = cross_sectionh.get(cross_section_offset1);
5285 T value =
SYSlerp(value0, value1, t);
5287 value = T(1.0)-
value;
5288 if (is_cross_section_uv_computed)
5291 output_value[theUComponent] =
value;
5292 outputh.set(output_offset, output_value);
5299 copyCrossSectionAttributeWrapper2<void, output_owner, wrap_to_invalid>(grid,
5300 outputh, cross_sectionh, cross_section_owner, cross_section_input,
nullptr, grid_info,
5301 reverse_cross_sections, swap_row_col,
5302 get_transform, transform_and_copy, transform_and_interp);
5307 template<
typename T>
5312 const exint cross_section_nedges,
5313 const exint curve_row)
5316 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_nedges; ++cross_section_vtxi)
5318 exint row = curve_row;;
5319 exint col = cross_section_vtxi;
5326 return sum / cross_section_nedges;
5335 template<
typename T>
5336 static double crossSectionLength(
5340 const exint cross_section_nedges,
5341 const exint curve_row,
5345 double cross_section_length = 0;
5346 exint row = curve_row;
5353 if (dir0 !=
nullptr)
5355 T d = prevpos.
dot(*dir0);
5356 prevpos0 = prevpos - d*(*dir0);
5357 if (dir1 !=
nullptr)
5359 d = prevpos.
dot(*dir1);
5360 prevpos1 = prevpos - d*(*dir1);
5363 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_nedges; ++cross_section_vtxi)
5365 exint row = curve_row;
5366 exint col = cross_section_vtxi+1;
5372 if (dir0 !=
nullptr)
5374 T d = nextpos.
dot(*dir0);
5375 nextpos0 = nextpos - d*(*dir0);
5376 T dist0 = prevpos0.
distance(nextpos0);
5377 if (dir1 !=
nullptr)
5379 d = nextpos.
dot(*dir1);
5380 nextpos1 = nextpos - d*(*dir1);
5382 cross_section_length += 0.5f*(dist0 + prevpos1.
distance(nextpos1));
5386 cross_section_length += dist0;
5391 cross_section_length += prevpos.
distance(nextpos);
5394 if (dir0 !=
nullptr)
5396 prevpos0 = nextpos0;
5397 if (dir1 !=
nullptr)
5398 prevpos1 = nextpos1;
5401 return cross_section_length;
5404 template<
typename T,
typename FUNCTOR>
5405 static void iterateCurveEdgeLengths(
5406 const exint curve_nedges,
5407 const bool use_mesh_edge_lengths,
5409 const exint cross_section_npts,
5410 const bool swap_row_col,
5414 const sop_SweepGrid &grid_info,
5415 const exint cap_divisions,
5422 for (
exint curve_vtxi = 0; curve_vtxi < curve_nedges; ++curve_vtxi)
5424 double length_sum = 0;
5425 exint length_sum_count;
5426 if (use_mesh_edge_lengths)
5428 length_sum_count = cross_section_npts;
5429 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_npts; ++cross_section_vtxi)
5431 exint col0 = swap_row_col ? curve_vtxi : cross_section_vtxi;
5432 exint col1 = swap_row_col ? curve_vtxi+1 : cross_section_vtxi;
5433 exint row0 = swap_row_col ? cross_section_vtxi : curve_vtxi;
5434 exint row1 = swap_row_col ? cross_section_vtxi : curve_vtxi+1;
5442 length_sum_count = 1;
5443 exint orig_curve_vtxi = curve_vtxi;
5444 if (grid_info.myVEndPoles)
5447 orig_curve_vtxi -= cap_divisions;
5451 exint orig_curve_vtxi1 = (curve_vertices.
getExtraFlag() && curve_vtxi+1 == curve_nedges) ? 0 : curve_vtxi+1;
5452 if (grid_info.myVEndPoles)
5456 orig_curve_vtxi1 -= cap_divisions;
5463 functor(curve_vtxi, length_sum, length_sum_count);
5468 template<GA_AttributeOwner output_owner,
typename T>
5470 generateLengthWeightedV(
5471 const sop_SweepGrid &grid_info,
5473 const exint cross_sections_per_vertex,
5478 bool scalevasu_usingmax,
5482 bool use_mesh_edge_lengths,
5487 const exint curve_nedges = grid_info.myCurveNEdges;
5488 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
5493 exint cap_divisions = 0;
5494 if (curve_input !=
nullptr)
5497 if (grid_info.myVEndPoles)
5500 exint orig_curve_nedges = curve_vertices.
size() - 1;
5501 cap_divisions = (grid_info.myCurveNEdges - orig_curve_nedges)/2;
5504 curve_pos.
bind(curve_input->
getP());
5507 bool norm_u_unnorm_v = (ustyle == UVStyle::NORMALIZED && vstyle != UVStyle::NORMALIZED);
5508 bool special_case_u_division = (!scalevasu_usingmax && norm_u_unnorm_v);
5512 bool prevPosValid =
false;
5514 bool currPosValid =
false;
5522 double prev_cross_section_length = 0;
5523 if (special_case_u_division)
5525 if (curve_input !=
nullptr)
5529 if (curve_vertices.
size() >= 2)
5531 currPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[0]));
5532 nextPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[1]));
5533 currPosValid =
true;
5534 if (grid_info.myCurveClosed)
5538 exint last_vtxi = curve_vertices.
size() - (unrolled ? 2 : 1);
5539 prevPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[last_vtxi]));
5540 prevPosValid =
true;
5544 else if (curve_nedges >= 1 + (grid_info.myVEndPoles ? 2*cap_divisions : 0))
5548 exint start = grid_info.myVEndPoles ? cap_divisions : 0;
5549 currPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start);
5550 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start+1);
5551 currPosValid =
true;
5552 if (grid_info.myCurveClosed)
5554 prevPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, curve_nedges-1);
5555 prevPosValid =
true;
5561 dir0 = (currPos - prevPos);
5562 dir1 = (nextPos - currPos);
5565 if (length0 != 0 && length1 != 0)
5570 else if (length0 != 0 || length1 != 0)
5571 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5573 else if (currPosValid)
5575 dir1 = (nextPos - currPos);
5581 prev_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, 0, pdir0, pdir1);
5590 double max_cross_section_length = 0;
5591 if (need_max_cross_section_length)
5593 for (
exint curve_vtxi = 0; curve_vtxi <= curve_nedges; ++curve_vtxi)
5595 double cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi, dir0, dir1);
5596 max_cross_section_length =
SYSmax(cross_section_length, max_cross_section_length);
5604 double total_length_sum = 0;
5605 exint curve_npts = curve_nedges + !grid_info.myCurveClosed;
5606 exint cross_section_npts = cross_section_nedges + !grid_info.myCrossSectionClosed;
5607 iterateCurveEdgeLengths(
5609 use_mesh_edge_lengths,
5619 [&](
exint curve_vtxi,
double length_sum,
exint length_sum_count)
5621 if (special_case_u_division)
5623 bool nextPosValid =
false;
5625 if (!grid_info.myVEndPoles || (curve_vtxi >= cap_divisions && curve_vtxi < curve_npts-cap_divisions))
5627 nextPosValid =
true;
5628 if (cross_section_nedges >= 1)
5630 exint nextPosVtxi = curve_vtxi+2;
5631 exint threshold = curve_npts;
5632 if (grid_info.myVEndPoles)
5634 nextPosVtxi -= cap_divisions;
5635 threshold -= 2*cap_divisions;
5637 if (nextPosVtxi >= threshold)
5639 if (grid_info.myCurveClosed)
5640 nextPosVtxi -= curve_npts;
5642 nextPosValid =
false;
5646 if (curve_input !=
nullptr)
5649 exint next_curve_vtxi = nextPosVtxi;
5650 if (cross_sections_per_vertex != 1)
5651 next_curve_vtxi /= cross_sections_per_vertex;
5652 if (next_curve_vtxi < 0)
5653 next_curve_vtxi = 0;
5654 else if (next_curve_vtxi >= curve_vertices.
size())
5655 next_curve_vtxi = curve_vertices.
size()-1;
5656 GA_Offset curve_vtxoff = curve_vertices[next_curve_vtxi];
5658 nextPos = curve_pos.
get(curve_ptoff);
5662 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, nextPosVtxi);
5670 dir1 = (nextPos - currPos);
5672 if (length0 != 0 && length1 != 0)
5677 else if (length0 != 0 || length1 != 0)
5678 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5680 else if (length0 != 0)
5685 double next_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi+1, pdir0, pdir1);
5693 double curr_cross_section_length_avg = 0.5*(prev_cross_section_length + next_cross_section_length);
5694 if (curr_cross_section_length_avg == 0)
5699 length_sum /= (length_sum_count*curr_cross_section_length_avg);
5702 prev_cross_section_length = next_cross_section_length;
5707 length_sum /= length_sum_count;
5710 total_length_sum += length_sum;
5711 length_sums[curve_vtxi+1] = vscale*total_length_sum;
5714 UT_ASSERT_MSG(total_length_sum != 0 || (vstyle != UVStyle::NORMALIZED),
"computeGridUVScales should have fallen back to v being uniform");
5716 if (vstyle == UVStyle::NORMALIZED)
5719 length_sums[curve_nedges] = orig_vscale;
5721 for (
exint curve_vtxi = curve_nedges-1; curve_vtxi >= 0 && length_sums[curve_vtxi] > orig_vscale; ++curve_vtxi)
5723 length_sums[curve_vtxi] = orig_vscale;
5726 else if (vstyle == UVStyle::ROUNDED)
5729 double &rounded = length_sums[curve_nedges];
5733 length_sums[curve_nedges] = rounded;
5735 for (
exint curve_vtxi = curve_nedges-1; curve_vtxi >= 0 && length_sums[curve_vtxi] > rounded; ++curve_vtxi)
5737 length_sums[curve_vtxi] = rounded;
5744 exint cap_vertex_count = 0;
5750 cap_vertex_count = cross_section_nedges;
5751 for (
exint col = 0; col < cap_vertex_count; ++col)