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)
5753 outputh.
set(grid_info.myStartVtxOff + col, theVComponent, 0);
5759 cap_vertex_count = curve_nedges;
5763 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
5770 exint curve_vtxi = swap_row_col ? col :
row;
5771 curve_vtxi +=
exint(swap_row_col ? iscolend : isrowend);
5772 outputh.
set(start_vtxoff + vtxnum, theVComponent, length_sums[curve_vtxi]);
5778 const GA_Offset start_ptoff = grid_info.myStartPtOff;
5782 exint curve_vtxi = swap_row_col ? col :
row;
5783 outputh.
set(start_ptoff + ptnum, theVComponent, length_sums[curve_vtxi]);
5793 for (
exint col = 0; col < cap_vertex_count; ++col)
5795 outputh.
set(cap_start_vtxoff + col, theVComponent, length_sums[curve_nedges]);
5806 template<GA_AttributeOwner output_owner,
typename T>
5809 const sop_SweepGrid &grid_info,
5815 const exint curve_nedges = grid_info.myCurveNEdges;
5816 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
5819 exint cap_vertex_count = 0;
5825 cap_vertex_count = cross_section_nedges;
5826 for (
exint col = 0; col < cap_vertex_count; ++col)
5828 outputh.
set(grid_info.myStartVtxOff + col, theVComponent, 0);
5834 cap_vertex_count = curve_nedges;
5839 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
5840 const T recip_curve_nedges = (curve_nedges == 0) ? T(0.0) : (vscale/curve_nedges);
5847 exint curve_vtxi = swap_row_col ? col :
row;
5848 curve_vtxi +=
exint(swap_row_col ? iscolend : isrowend);
5849 outputh.
set(start_vtxoff + vtxnum, theVComponent, T(curve_vtxi)*recip_curve_nedges);
5855 const GA_Offset start_ptoff = grid_info.myStartPtOff;
5859 exint curve_vtxi = swap_row_col ? col :
row;
5860 outputh.
set(start_ptoff + ptnum, theVComponent, T(curve_vtxi)*recip_curve_nedges);
5870 for (
exint col = 0; col < cap_vertex_count; ++col)
5872 outputh.
set(cap_start_vtxoff + col, theVComponent, vscale);
5887 const sop_SweepGrid &grid_info,
5889 const bool swap_row_col,
5890 const exint cross_sections_per_vertex,
5891 const exint cap_divisions,
5894 const bool use_mesh_edge_lengths,
5895 const bool scalevasu_usingmax,
5897 bool &fallback_to_uniform_v)
5899 fallback_to_uniform_v =
false;
5901 const exint curve_nedges = grid_info.myCurveNEdges;
5902 const exint curve_npts = curve_nedges + !grid_info.myCurveClosed;
5903 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
5904 exint cross_section_npts = cross_section_nedges + !grid_info.myCrossSectionClosed;
5912 bool prevPosValid =
false;
5914 bool currPosValid =
false;
5916 if (curve_input !=
nullptr)
5918 curve_pos.bind(curve_input->
getP());
5922 if (curve_vertices.size() >= 2)
5924 currPos = curve_pos.get(curve_input->
vertexPoint(curve_vertices[0]));
5925 nextPos = curve_pos.get(curve_input->
vertexPoint(curve_vertices[1]));
5926 currPosValid =
true;
5927 if (grid_info.myCurveClosed)
5930 bool unrolled = !curve_vertices.getExtraFlag();
5931 exint last_vtxi = curve_vertices.size() - (unrolled ? 2 : 1);
5932 prevPos = curve_pos.get(curve_input->
vertexPoint(curve_vertices[last_vtxi]));
5933 prevPosValid =
true;
5937 else if (curve_nedges >= 1 + (grid_info.myVEndPoles ? 2*cap_divisions : 0))
5941 exint start = grid_info.myVEndPoles ? cap_divisions : 0;
5942 currPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start);
5943 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start+1);
5944 currPosValid =
true;
5945 if (grid_info.myCurveClosed)
5947 prevPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, curve_nedges-1);
5948 prevPosValid =
true;
5960 dir0 = (currPos - prevPos);
5961 dir1 = (nextPos - currPos);
5964 if (length0 != 0 && length1 != 0)
5969 else if (length0 != 0 || length1 != 0)
5970 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5972 else if (currPosValid)
5974 dir1 = (nextPos - currPos);
5980 double prev_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, 0, pdir0, pdir1);
5987 double curve_length = 0;
5988 double curve_length_per_cross_section_length_sum = 0;
5989 double cross_section_length_sum = prev_cross_section_length;
5990 exint cross_section_length_count = 1;
5991 double cross_section_length_max = prev_cross_section_length;
5992 iterateCurveEdgeLengths(
5994 use_mesh_edge_lengths,
6004 [&](
exint curve_vtxi,
double length_sum,
exint length_sum_count)
6006 double curr_curve_length = (length_sum/length_sum_count);
6007 curve_length += curr_curve_length;
6009 bool nextPosValid =
false;
6011 if (!grid_info.myVEndPoles || (curve_vtxi >= cap_divisions && curve_vtxi < curve_npts-cap_divisions))
6013 nextPosValid =
true;
6014 if (cross_section_nedges >= 1)
6016 exint nextPosVtxi = curve_vtxi+2;
6017 exint threshold = curve_npts;
6018 if (grid_info.myVEndPoles)
6020 nextPosVtxi -= cap_divisions;
6021 threshold -= 2*cap_divisions;
6023 if (nextPosVtxi >= threshold)
6025 if (grid_info.myCurveClosed)
6026 nextPosVtxi -= curve_npts;
6028 nextPosValid =
false;
6032 if (curve_input !=
nullptr)
6035 exint next_curve_vtxi = nextPosVtxi;
6036 if (cross_sections_per_vertex != 1)
6037 next_curve_vtxi /= cross_sections_per_vertex;
6038 if (next_curve_vtxi < 0)
6039 next_curve_vtxi = 0;
6040 else if (next_curve_vtxi >= curve_vertices.size())
6041 next_curve_vtxi = curve_vertices.size()-1;
6042 GA_Offset curve_vtxoff = curve_vertices[next_curve_vtxi];
6044 nextPos = curve_pos.get(curve_ptoff);
6048 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, nextPosVtxi);
6056 dir1 = (nextPos - currPos);
6058 if (length0 != 0 && length1 != 0)
6063 else if (length0 != 0 || length1 != 0)
6064 pdir0 = (length0 != 0) ? &dir0 : &dir1;
6066 else if (length0 != 0)
6071 double next_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi+1, pdir0, pdir1);
6080 double curr_cross_section_length_avg = 0.5*(prev_cross_section_length + next_cross_section_length);
6081 if (curr_cross_section_length_avg != 0)
6086 curve_length_per_cross_section_length_sum += (curr_curve_length/curr_cross_section_length_avg);
6089 if (curve_vtxi+1 != curve_nedges || !grid_info.myCurveClosed)
6091 cross_section_length_max =
SYSmax(next_cross_section_length, cross_section_length_max);
6092 cross_section_length_sum += next_cross_section_length;
6093 ++cross_section_length_count;
6094 prev_cross_section_length = next_cross_section_length;
6097 double cross_section_length_avg = (cross_section_length_sum/cross_section_length_count);
6101 if (ustyle == UVStyle::NORMALIZED)
6105 if (vstyle == UVStyle::NORMALIZED)
6108 if (curve_length == 0)
6109 fallback_to_uniform_v =
true;
6111 uvscale[1] /= curve_length;
6117 if ((scalevasu_usingmax && cross_section_length_max == 0) || (!scalevasu_usingmax && curve_length_per_cross_section_length_sum == 0))
6120 fallback_to_uniform_v =
true;
6122 else if (vstyle == UVStyle::FULL)
6124 if (scalevasu_usingmax)
6125 uvscale[1] /= cross_section_length_max;
6135 if (scalevasu_usingmax)
6137 if (curve_length == 0)
6140 fallback_to_uniform_v =
true;
6144 double rounded =
SYSrint(uvscale[1]*curve_length/cross_section_length_max);
6147 uvscale[1] = rounded/curve_length;
6152 UT_ASSERT(curve_length_per_cross_section_length_sum != 0);
6153 double rounded =
SYSrint(uvscale[1]*curve_length_per_cross_section_length_sum);
6156 uvscale[1] = rounded/curve_length_per_cross_section_length_sum;
6161 else if (ustyle == UVStyle::FULL)
6165 uvscale[0] *= cross_section_length_avg;
6167 if (vstyle == UVStyle::NORMALIZED)
6170 if (curve_length == 0)
6172 fallback_to_uniform_v =
true;
6176 uvscale[0] /= curve_length;
6177 uvscale[1] /= curve_length;
6180 else if (vstyle == UVStyle::FULL)
6189 if (curve_length == 0)
6192 fallback_to_uniform_v =
true;
6196 double old_vscale = uvscale[1];
6197 double rounded =
SYSrint(old_vscale*curve_length);
6200 uvscale[1] = rounded/curve_length;
6201 uvscale[0] *= (uvscale[1]/old_vscale);
6214 if (vstyle == UVStyle::NORMALIZED)
6216 if (curve_length == 0)
6218 double rounded =
SYSrint(cross_section_length_avg*uvscale[0]);
6221 uvscale[0] = rounded;
6222 fallback_to_uniform_v =
true;
6226 double rounded =
SYSrint(cross_section_length_avg*uvscale[0]/curve_length);
6229 uvscale[0] = rounded;
6230 uvscale[1] /= curve_length;
6235 const double old_uscale = cross_section_length_avg*uvscale[0];
6236 uvscale[0] =
SYSrint(old_uscale);
6240 if (vstyle == UVStyle::FULL)
6242 if (old_uscale != 0)
6243 uvscale[1] *= (uvscale[0]/old_uscale);
6248 if (curve_length == 0)
6251 fallback_to_uniform_v =
true;
6255 double rounded =
SYSrint(curve_length*uvscale[1]);
6258 uvscale[1] = rounded/curve_length;
6267 template<GA_AttributeOwner output_owner>
6269 copyUVAttribPairPtOrVtx(
6275 const sop_SweepGrid *grids,
6277 const exint cross_sections_per_vertex,
6279 const bool output_points_only,
6280 const bool triangular_poles,
6281 const exint cap_divisions,
6282 const bool reverse_cross_sections,
6283 const bool swap_row_col,
6285 const bool length_weighted_uvs,
6288 const bool use_mesh_edge_lengths,
6289 const bool scalevasu_usingmax,
6293 const exint PARALLEL_THRESHOLD = 2048;
6294 const bool parallel = (ngrids > 1 &&
6304 const bool is_cross_section_uv_computed = cross_section_attrib ==
nullptr || cross_section_attrib->
isDetached();
6307 UT_ASSERT((cross_section_attrib !=
nullptr) != (missing_input_us !=
nullptr));
6315 const sop_SweepGrid &grid_info = grids[gridi];
6317 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
6319 bool fallback_to_uniform_v =
false;
6321 if (length_weighted_uvs && (is_cross_section_uv_computed || curve_attrib ==
nullptr))
6324 grid_uvscale = computeGridUVScales(
6326 cross_section_input,
6330 cross_sections_per_vertex,
6333 use_mesh_edge_lengths,
6336 fallback_to_uniform_v);
6339 UT_ASSERT((cross_section_attrib !=
nullptr) != (missing_input_us !=
nullptr));
6342 copyCrossSectionUVSingleGrid<fpreal64,output_owner>(
6343 output_attrib, cross_section_attrib, cross_section_owner, cross_section_input,
6344 grid_info, grid, is_cross_section_uv_computed,
6345 reverse_cross_sections, swap_row_col, flipu, grid_uvscale[0],
6350 copyCrossSectionUVSingleGrid<fpreal32,output_owner>(
6351 output_attrib, cross_section_attrib, cross_section_owner, cross_section_input,
6352 grid_info, grid, is_cross_section_uv_computed,
6353 reverse_cross_sections, swap_row_col, flipu, grid_uvscale[0],
6357 if (curve_attrib ==
nullptr)
6366 if (length_weighted_uvs && !fallback_to_uniform_v)
6367 generateLengthWeightedV<output_owner>(grid_info, grid, cross_sections_per_vertex, outputh, pos, ustyle, vstyle,
6368 scalevasu_usingmax, grid_uvscale[1], uvscale[1], swap_row_col, use_mesh_edge_lengths, curve_input);
6370 generateUniformV<output_owner>(grid_info, grid, outputh, swap_row_col, grid_uvscale[1]);
6376 if (length_weighted_uvs && !fallback_to_uniform_v)
6377 generateLengthWeightedV<output_owner>(grid_info, grid, cross_sections_per_vertex, outputh, pos, ustyle, vstyle,
6378 scalevasu_usingmax,
float(grid_uvscale[1]),
float(uvscale[1]), swap_row_col, use_mesh_edge_lengths, curve_input);
6380 generateUniformV<output_owner>(grid_info, grid, outputh, swap_row_col,
float(grid_uvscale[1]));
6390 functor(grid_range);
6400 outputh.
set(output_off, theVComponent,
GAisValid(curve_off) ? curveh.get(curve_off) : 1.0);
6402 copyCurveAttrib2<output_owner,true>(
6403 output_attrib, curve_input,
6404 grids, ngrids, cross_sections_per_vertex,
6405 surface_type, output_points_only, triangular_poles, cap_divisions,
6406 swap_row_col, copy_functor);
6414 outputh.
set(output_off, theVComponent,
GAisValid(curve_off) ? curveh.get(curve_off) : 1.0f);
6416 copyCurveAttrib2<output_owner,true>(
6417 output_attrib, curve_input,
6418 grids, ngrids, cross_sections_per_vertex,
6419 surface_type, output_points_only, triangular_poles, cap_divisions,
6420 swap_row_col, copy_functor);
6431 auto &©_functor = [&outputh,&curveh,curve_input](
GA_Offset output_off,
GA_Offset curve_vtxoff)
6437 value = curveh.get(curve_off);
6441 outputh.
set(output_off, theVComponent, value);
6443 copyCurveAttrib2<output_owner,true>(
6444 output_attrib, curve_input,
6445 grids, ngrids, cross_sections_per_vertex,
6446 surface_type, output_points_only, triangular_poles, cap_divisions,
6447 swap_row_col, copy_functor);
6453 auto &©_functor = [&outputh,&curveh,curve_input](
GA_Offset output_off,
GA_Offset curve_vtxoff)
6459 value = curveh.get(curve_off);
6463 outputh.
set(output_off, theVComponent, value);
6465 copyCurveAttrib2<output_owner,true>(
6466 output_attrib, curve_input,
6467 grids, ngrids, cross_sections_per_vertex,
6468 surface_type, output_points_only, triangular_poles, cap_divisions,
6469 swap_row_col, copy_functor);
6481 const sop_SweepGrid *grids,
6483 const exint cross_sections_per_vertex,
6485 const bool output_points_only,
6486 const bool triangular_poles,
6487 const exint cap_divisions,
6488 const bool reverse_cross_sections,
6489 const bool swap_row_col,
6491 const bool length_weighted_uvs,
6494 const bool use_mesh_edge_lengths,
6495 const bool scalevasu_usingmax,
6522 copyUVAttribPairPtOrVtx<GA_ATTRIB_POINT>(
6524 cross_section_attrib,
6525 cross_section_input,
6529 cross_sections_per_vertex,
6534 reverse_cross_sections,
6537 length_weighted_uvs,
6539 use_mesh_edge_lengths,
6546 if (output_points_only)
6553 copyUVAttribPairPtOrVtx<GA_ATTRIB_VERTEX>(
6555 cross_section_attrib,
6556 cross_section_input,
6560 cross_sections_per_vertex,
6565 reverse_cross_sections,
6568 length_weighted_uvs,
6570 use_mesh_edge_lengths,
6582 const exint PARALLEL_THRESHOLD = 2048;
6583 const bool parallel = (ngrids > 1 &&
6605 const sop_SweepGrid &grid_info = grids[gridi];
6607 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
6609 copyCrossSectionUVSingleGrid<fpreal64,GA_ATTRIB_PRIMITIVE>(
6611 grid_info, grid,
false,
6612 reverse_cross_sections, swap_row_col, flipu, uvscale[0]);
6614 if (curveh.isValid() && outputh.
isValid() && outputh.getTupleSize() >= 2)
6616 const double v = curveh.get(grid_info.myCurvePrimOff);
6621 outputh.
set(grid_info.myStartPrimOff + primnum, theVComponent, v);
6632 const sop_SweepGrid &grid_info = grids[gridi];
6634 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
6636 copyCrossSectionUVSingleGrid<fpreal32,GA_ATTRIB_PRIMITIVE>(
6638 grid_info, grid,
false,
6639 reverse_cross_sections, swap_row_col, flipu, uvscale[0]);
6641 if (curveh.isValid() && outputh.
isValid() && outputh.getTupleSize() >= 2)
6643 const float v = curveh.get(grid_info.myCurvePrimOff);
6648 outputh.
set(grid_info.myStartPrimOff + primnum, theVComponent, v);
6659 functor(grid_range);
6668 case SurfaceType::ROWS:
6670 case SurfaceType::COLS:
6672 case SurfaceType::ROWCOL:
6674 case SurfaceType::QUADS:
6676 case SurfaceType::TRIS:
6678 case SurfaceType::REVTRIS:
6680 case SurfaceType::ALTTRIS:
6683 case SurfaceType::POINTS:
6690 copySurfaceAttributes(
6695 const exint cross_sections_per_vertex,
6696 const UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &cross_section_attribs,
6697 const UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &curve_attribs,
6698 const UT_Array<std::pair<std::pair<const GA_ATINumeric*,const GA_ATINumeric*>,
GA_ATINumeric*>> &uv_attribs,
6699 const SOP_SweepHDKCache *
const transform_cache,
6701 const bool output_points_only,
6702 const bool triangular_poles,
6703 const exint cap_divisions,
6704 const bool reverse_cross_sections,
6705 const bool swap_row_col,
6706 const exint uv_attrib_index,
6708 const bool length_weighted_uvs,
6711 const bool use_mesh_edge_lengths,
6712 const bool scalevasu_usingmax,
6717 if (interrupt.wasInterrupted())
6721 for (
exint attribi = 0; attribi < cross_section_attribs.size(); ++attribi)
6723 if (interrupt.wasInterrupted())
6726 const GA_Attribute *cross_section_attrib = cross_section_attribs[attribi].first;
6727 GA_Attribute *output_attrib = cross_section_attribs[attribi].second;
6728 copyCrossSectionAttrib(
6730 cross_section_attrib,
6731 cross_section_input,
6734 cross_sections_per_vertex, cap_divisions,
6735 surface_type, output_points_only, triangular_poles,
6736 reverse_cross_sections, swap_row_col);
6740 for (
exint attribi = 0; attribi < curve_attribs.size(); ++attribi)
6742 if (interrupt.wasInterrupted())
6745 const GA_Attribute *curve_attrib = curve_attribs[attribi].first;
6746 GA_Attribute *output_attrib = curve_attribs[attribi].second;
6752 cross_sections_per_vertex,
6753 surface_type, output_points_only, triangular_poles,
6754 cap_divisions, swap_row_col);
6758 for (
exint attribi = 0; attribi < uv_attribs.size(); ++attribi)
6760 if (interrupt.wasInterrupted())
6763 const GA_ATINumeric *cross_section_attrib = uv_attribs[attribi].first.first;
6764 const GA_ATINumeric *curve_attrib = uv_attribs[attribi].first.second;
6768 cross_section_attrib,
6769 cross_section_input,
6773 cross_sections_per_vertex,
6774 surface_type, output_points_only, triangular_poles,
6776 reverse_cross_sections, swap_row_col,
6777 (uv_attrib_index == attribi) ? missing_input_us :
nullptr,
6778 length_weighted_uvs,
6780 use_mesh_edge_lengths,
6782 (uv_attrib_index == attribi) && flipu,
6789 static void setupCrossSectionAttribs(
6790 SOP_SweepHDKCache *sopcache,
6792 const SOP_SweepHDKParms &sopparms,
6793 bool &same_cross_section_data,
6799 UT_ASSERT_MSG(cross_section_input && curve_input,
"Copy order only makes sense if both inputs are present.");
6801 CrossSectionAttribMatchData ©_order_attrib_data = sopcache->myCrossSectionAttribMatchData;
6806 const UT_StringHolder &cross_section_attrib_name = sopparms.getCrossSectionAttrib();
6817 bool string_missing_error_case =
false;
6821 same_cross_section_data &= (sopcache->myPrevCrossSectCurveAttribDataId == new_curve_data_id);
6822 sopcache->myPrevCrossSectCurveAttribDataId = new_curve_data_id;
6824 copy_order_attrib_data.myCurveAttribOwner = curve_attrib->
getOwner();
6828 copy_order_attrib_data.myCurveIntAttrib.bind(curve_attrib);
6829 if (!copy_order_attrib_data.myCurveIntAttrib.isValid()) {
6830 copy_order_attrib_data.myCurveStrAttrib.bind(curve_attrib);
6831 if (!copy_order_attrib_data.myCurveStrAttrib.isValid()) {
6833 curve_attrib =
nullptr;
6837 if (!cross_section_name_attrib.isValid()) {
6839 curve_attrib =
nullptr;
6840 copy_order_attrib_data.myCurveStrAttrib.clear();
6841 string_missing_error_case =
true;
6845 const int64 new_cross_section_data_id = cross_section_name_attrib->getDataId();
6846 const bool same_map = (sopcache->myPrevCrossSectPrimAttribDataId == new_cross_section_data_id);
6847 same_cross_section_data &= same_map;
6848 sopcache->myPrevCrossSectPrimAttribDataId = new_cross_section_data_id;
6849 copy_order_attrib_data.myIsUsingMap =
true;
6854 copy_order_attrib_data.myIntToPrimOff.destroy();
6855 copy_order_attrib_data.myStrToPrimOff.destroy();
6861 for (
GA_Offset primoff = start; primoff <
end; ++primoff) {
6873 copy_order_attrib_data.myStrToPrimOff.insert(name, primoff);
6882 if (!cross_section_id_attrib.isValid()) {
6884 copy_order_attrib_data.myIsUsingMap =
false;
6885 same_cross_section_data &= (sopcache->myPrevCrossSectPrimAttribDataId == -1);
6886 sopcache->myPrevCrossSectPrimAttribDataId = -1;
6889 copy_order_attrib_data.myIntToPrimOff.destroy();
6890 copy_order_attrib_data.myStrToPrimOff.destroy();
6894 copy_order_attrib_data.myIsUsingMap =
true;
6895 const int64 new_cross_section_data_id = cross_section_id_attrib->getDataId();
6896 const bool same_map = (sopcache->myPrevCrossSectPrimAttribDataId == new_cross_section_data_id);
6897 same_cross_section_data &= same_map;
6898 sopcache->myPrevCrossSectPrimAttribDataId = new_cross_section_data_id;
6903 copy_order_attrib_data.myIntToPrimOff.destroy();
6904 copy_order_attrib_data.myStrToPrimOff.destroy();
6910 for (
GA_Offset primoff = start; primoff <
end; ++primoff) {
6911 exint id = cross_section_id_attrib.get(primoff);
6920 copy_order_attrib_data.myIntToPrimOff.insert(
id, primoff);
6927 if (!curve_attrib) {
6930 if (!string_missing_error_case)
6931 buf.
sprintf(
"Curve input geometry doesn't have an integer or string attribute named \"%s\" for selecting cross section primitives.", cross_section_attrib_name.
c_str());
6933 buf.
sprintf(
"Cross section doesn't have a primitive string attribute named \"%s\" for selecting cross section primitives,", cross_section_attrib_name.
c_str());
6937 copy_order = CopyOrder::CYCLEVTX;
6938 same_cross_section_data = (sopcache->myPrevCopyOrder == copy_order);
6939 sopcache->myPrevCrossSectCurveAttribDataId = -1;
6940 sopcache->myPrevCrossSectPrimAttribDataId = -1;
6941 copy_order_attrib_data.myIntToPrimOff.destroy();
6942 copy_order_attrib_data.myStrToPrimOff.destroy();
6947 static void removeUnnecessarySweepAttribs(
6958 attribs_to_delete.
append(attrib);
6960 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
6969 attribs_to_delete.
clear();
6973 attribs_to_delete.
append(attrib);
6975 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
6984 attribs_to_delete.
clear();
6987 attribs_to_delete.
append(attrib);
6989 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
6998 attribs_to_delete.
clear();
7001 attribs_to_delete.
append(attrib);
7003 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
7010 edge_groups_to_delete.
append(it.group());
7012 for (
exint i = 0, n = edge_groups_to_delete.
size(); i <
n; ++i)
7018 static void setupSweepTransferAttribs(
7024 UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &cross_section_attribs,
7025 UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &curve_attribs,
7026 UT_Array<std::pair<std::pair<const GA_ATINumeric*,const GA_ATINumeric*>,
GA_ATINumeric*>> &uv_attribs,
7027 exint &uv_attrib_index,
7028 const bool compute_uvs,
7029 const bool override_existing_uvs)
7036 UT_ASSERT(compute_uvs || !override_existing_uvs);
7037 uv_attrib_index = -1;
7043 if (cross_section_input)
7049 auto &&clone_attrib_functor = [&cross_section_attribs,&uv_attribs,&uv_attrib_index,&
filter,output_geo,
7050 curve_input,&curve_filter,override_existing_uvs,compute_uvs](
const GA_Attribute *attrib)
7052 if (!filter.match(attrib))
7059 const bool isuv = point_or_vertex &&
7062 if ((compute_uvs && override_existing_uvs) && isuv)
7078 GA_Attribute *new_attribute = output_geo->getAttributes().cloneAttribute(
7079 output_owner, attrib->
getName(),
7083 uv_attribs.append(std::make_pair(
7091 if (isuv && compute_uvs)
7095 GA_Attribute *new_attribute = output_geo->getAttributes().cloneAttribute(
7100 uv_attrib_index = uv_attribs.size();
7101 uv_attribs.append(std::make_pair(
7113 new_attribute = output_geo->getAttributes().cloneAttribute(
7121 output_geo->getElementGroupTable(owner).newGroup(attrib->
getName()));
7125 cross_section_attribs.append(std::make_pair(attrib, new_attribute));
7141 auto &&clone_attrib_functor = [&curve_attribs,&uv_attribs,&uv_attrib_index,&curve_filter,output_geo,
7142 cross_section_input,override_existing_uvs,compute_uvs](
const GA_Attribute *attrib)
7144 if (!curve_filter.match(attrib))
7153 if (cross_section_input)
7156 output_geo->findAttribute(owner, attrib->
getScope(), attrib->
getName());
7167 old_attrib = output_geo->findAttribute(
7176 const bool isuv = point_or_vertex &&
7179 if ((compute_uvs && override_existing_uvs) && isuv)
7187 if (isuv && compute_uvs)
7191 GA_Attribute *new_attribute = output_geo->getAttributes().cloneAttribute(
7196 uv_attrib_index = uv_attribs.size();
7197 uv_attribs.append(std::make_pair(
7208 new_attribute = output_geo->getAttributes().cloneAttribute(
7216 output_geo->getElementGroupTable(owner).newGroup(attrib->
getName()));
7220 curve_attribs.append(std::make_pair(attrib, new_attribute));
7230 .forEachAttribute(clone_attrib_functor);
7260 centre = 0.5*(p0+p1);
7269 UT_Vector3D new_normal = *out_normal -
dot(*out_normal, diff)*diff;
7272 *out_normal = new_normal;
7281 for (
exint i = 2; i <
n; ++i)
7290 covariance_matrix.
zero();
7293 pdiff = p1 - pos_avg;
7295 for (
exint i = 2; i <
n; ++i)
7298 pdiff = p - pos_avg;
7301 const double row_length2s[] = {
7302 covariance_matrix[0].length2(),
7303 covariance_matrix[1].length2(),
7304 covariance_matrix[2].length2()
7306 const int maxrow = SYSargmax(
7310 if (row_length2s[maxrow] == 0)
7318 UT_Vector3D maxrow_vec = covariance_matrix[maxrow];
7323 double maxrow_vec_eigen2 = (maxrow_vec*covariance_matrix).length2();
7324 double other_dir0_eigen2 = (other_dir0*covariance_matrix).length2();
7325 double other_dir1_eigen2 = (other_dir1*covariance_matrix).length2();
7328 if (other_dir0_eigen2+other_dir1_eigen2 < 1e-8*maxrow_vec_eigen2)
7330 pdiff = p0 - pos_avg;
7331 double min_from_avg = pdiff.
dot(maxrow_vec);
7332 double max_from_avg = min_from_avg;
7333 pdiff = p1 - pos_avg;
7334 double d = pdiff.
dot(maxrow_vec);
7335 min_from_avg =
SYSmin(min_from_avg, d);
7336 max_from_avg =
SYSmax(max_from_avg, d);
7337 for (
exint i = 2; i <
n; ++i)
7340 pdiff = p - pos_avg;
7341 d = pdiff.
dot(maxrow_vec);
7342 min_from_avg =
SYSmin(min_from_avg, d);
7343 max_from_avg =
SYSmax(max_from_avg, d);
7346 radius = 0.5*(max_from_avg - min_from_avg);
7347 centre = pos_avg + 0.5*(min_from_avg + max_from_avg);
7350 UT_Vector3D new_normal = *out_normal -
dot(*out_normal, maxrow_vec)*maxrow_vec;
7353 *out_normal = new_normal;
7361 for (
exint i = 2; i <
n; ++i)
7364 normal +=
cross(pprev-p0, pnext-p0);
7369 if (normal.length2() == 0)
7374 double max_distance2 =
distance2(centre, p0);
7375 for (
exint i = 1; i <
n; ++i)
7380 radius = SYSsqrt(max_distance2);
7385 double min_normal_dot = 0;
7386 double max_normal_dot = 0;
7387 for (
exint i = 1; i <
n; ++i)
7390 double dot = (p-p0).
dot(normal);
7391 min_normal_dot =
SYSmin(dot, min_normal_dot);
7392 max_normal_dot =
SYSmax(dot, max_normal_dot);
7396 double mid_normal_dot = 0.5*(min_normal_dot+max_normal_dot);
7402 tangent1 =
cross(normal, tangent0);
7408 for (
exint i = 1; i <
n; ++i)
7416 radius = SYSsqrt(radius2);
7420 centre = p0 + (normal*mid_normal_dot + tangent0*centre2d[0] + tangent1*centre2d[1]);
7426 if (out_normal->
dot(normal) < 0)
7427 *out_normal = -normal;
7429 *out_normal = normal;
7434 sopPrescaleTranslate(
7446 pret[0]*transform0[0][0] + pret[1]*transform0[1][0] + pret[2]*transform0[2][0] + transform0[3][0],
7447 pret[0]*transform0[0][1] + pret[1]*transform0[1][1] + pret[2]*transform0[2][1] + transform0[3][1],
7448 pret[0]*transform0[0][2] + pret[1]*transform0[1][2] + pret[2]*transform0[2][2] + transform0[3][2]
7452 scale*transform0[0][0], scale*transform0[0][1], scale*transform0[0][2], scale*transform0[0][3],
7453 scale*transform0[1][0], scale*transform0[1][1], scale*transform0[1][2], scale*transform0[1][3],
7454 scale*transform0[2][0], scale*transform0[2][1], scale*transform0[2][2], scale*transform0[2][3],
7455 t[0], t[1], t[2], 1.0
7462 const exint cap_divisions,
7470 scaled_z_dir = -scaled_z_dir;
7480 ztranslate = scaled_z_dir;
7484 const double scale_portion = double(capi)/double(cap_divisions);
7485 const double ztranslate_portion = 1.0 - scale_portion;
7491 const double theta =
M_PI_2*ztranslate_portion;
7492 const double scale_round = SYScos(theta);
7493 const double ztranslate_round = SYSsin(theta);
7500 const double scale_pointed = scale_portion;
7501 const double ztranslate_pointed = ztranslate_portion;
7504 double ztranslate_scalar;
7507 scale =
SYSlerp(scale_pointed, scale_round, roundness);
7508 ztranslate_scalar =
SYSlerp(ztranslate_pointed, ztranslate_round, roundness);
7510 else if (roundness == 0)
7512 scale = scale_pointed;
7513 ztranslate_scalar = ztranslate_pointed;
7523 scale =
SYSlerp(scale_pointed, 1.0-ztranslate_round, -roundness);
7524 ztranslate_scalar =
SYSlerp(ztranslate_pointed, 1.0-scale_round, -roundness);
7526 ztranslate = ztranslate_scalar*scaled_z_dir;
7528 return sopPrescaleTranslate(scale, centre, ztranslate, transform0);
7532 sopAllEndCapTransforms(
7533 const sop_SweepGrid &grid,
7534 const SOP_SweepHDKParms &sopparms,
7538 const exint num_vertices,
7541 bool use_cross_section_normal_for_z)
7543 const exint cap_divisions = sopparms.getCapDivs();
7554 if (grid.mySingleCrossSection && !
GAisValid(grid.myCrossSectionPrimOff))
7562 else if (grid.mySingleCrossSection)
7569 sopBoundingTube(cross_section_input, primoff, radius, centre,
7570 use_cross_section_normal_for_z ? &normal :
nullptr);
7573 centres[0] = centre;
7574 centres[1] = centre;
7575 if (use_cross_section_normal_for_z)
7577 normals[0] = normal;
7578 normals[1] = normal;
7583 GA_Offset primoff0 = (*grid.myCrossSectionPrimOffs)[0];
7584 GA_Offset primoff1 = grid.myCrossSectionPrimOffs->last();
7586 if (use_cross_section_normal_for_z && grid.myCrossSectionPrimOffs->size() >= 2*cap_divisions+1)
7591 sopBoundingTube(cross_section_input, primoff0, radius, centreA,
nullptr);
7592 sopBoundingTube(cross_section_input, (*grid.myCrossSectionPrimOffs)[cap_divisions+1], radius, centreB,
nullptr);
7593 normals[0] = centreA-centreB;
7595 sopBoundingTube(cross_section_input, primoff1, radius, centreA,
nullptr);
7596 sopBoundingTube(cross_section_input, (*grid.myCrossSectionPrimOffs)[grid.myCrossSectionPrimOffs->size()-2-cap_divisions], radius, centreB,
nullptr);
7597 normals[1] = centreB-centreA;
7600 sopBoundingTube(cross_section_input, primoff0, radii[0], centres[0],
7601 use_cross_section_normal_for_z ? &normals[0] :
nullptr);
7602 sopBoundingTube(cross_section_input, primoff1, radii[1], centres[1],
7603 use_cross_section_normal_for_z ? &normals[1] :
nullptr);
7605 if (use_cross_section_normal_for_z)
7615 const double cap_scale = sopparms.getCapScale();
7616 const double cap_roundness = sopparms.getCapRoundness();
7619 for (
exint i = 0; i < cap_divisions; ++i)
7621 const exint row = i;
7624 centres[0], (cap_scale*radii[0])*normals[0],
7625 cap_roundness, transform0);
7632 for (
exint i = 0; i < cap_divisions; ++i)
7636 const exint row = cap_divisions+num_vertices+i;
7638 cap_divisions-1-i, cap_divisions,
7639 centres[1], (-cap_scale*radii[1])*normals[1],
7640 cap_roundness, transform1);
7648 void SOP_SweepHDKVerb::cook(
const CookParms &cookparms)
const
7667 using namespace GU_Copy;
7676 auto &&sopparms = cookparms.
parms<SOP_SweepHDKParms>();
7683 const GU_Detail *
const cross_section_input =
7684 (sopparms.getSurfaceShape() == SurfaceShape::INPUT)
7685 ? cookparms.
inputGeo(theCrossSectionInput)
7690 if (!cookparms.
inputGeo(theCrossSectionInput) && !curve_input)
7693 output_geo->clearAndDestroy();
7697 if (!cross_section_input && (sopparms.getSurfaceShape() == SurfaceShape::INPUT))
7700 output_geo->clearAndDestroy();
7703 if (!curve_input && (sopparms.getSurfaceShape() != SurfaceShape::INPUT))
7706 output_geo->clearAndDestroy();
7717 if (sopparms.getCurveGroup().isstring())
7719 curve_group = group_manager.parsePrimitiveGroups(
7720 sopparms.getCurveGroup(),
7723 if (curve_group ==
nullptr)
7725 curve_group_list = curve_input->getPrimitiveMap().getOffsetFromIndexList();
7733 curve_group_list.setTrivialRange(curve_group_list.size(),
start, end-
start);
7739 if (cross_section_input)
7741 if (sopparms.getCrossSectionGroup().isstring())
7743 cross_section_group = group_manager.parsePrimitiveGroups(
7744 sopparms.getCrossSectionGroup(),
7747 if (cross_section_group ==
nullptr)
7757 cross_section_group_list.setTrivialRange(cross_section_group_list.size(),
start, end-
start);
7770 CopyOrder copy_order = (cross_section_input && curve_input) ? sopparms.getCopyOrder() : CopyOrder::CYCLEVTX;
7771 bool same_cross_section_data = (sopcache->myPrevCopyOrder == copy_order);
7775 setupCrossSectionAttribs(
7776 sopcache, cookparms, sopparms,
7777 same_cross_section_data, copy_order,
7778 cross_section_input, curve_input,
7779 cross_section_group);
7785 removeUnnecessarySweepAttribs(output_geo);
7792 bool need_to_build_surface =
true;
7794 const bool same_output_geo_as_last_cook =
7795 (output_geo->getUniqueId() == sopcache->myPrevOutputDetailID);
7796 int64 new_curve_prim_list_data_id = (curve_input ? curve_input->getPrimitiveList().getDataId() : -1);
7797 int64 new_curve_topology_data_id = (curve_input ? curve_input->getTopology().getDataId() : -1);
7798 if (same_output_geo_as_last_cook)
7800 const bool same_input_curves =
7801 (new_curve_prim_list_data_id == sopcache->myPrevCurvePrimListDataID) &&
7802 (new_curve_topology_data_id == sopcache->myPrevCurveTopologyDataID) &&
7803 (curve_group_list.size() == sopcache->myPrevCurveGroup.size()) &&
7804 (curve_group_list.isEqual(sopcache->myPrevCurveGroup, 0, curve_group_list.size()));
7806 bool same_surface_parms =
7807 (sopparms.getSurfaceType() == sopcache->myPrevSurfaceType) &&
7808 (sopparms.getUnrollClosedRowCol() == sopcache->myPrevUnrollClosedRowCol) &&
7809 (sopparms.getPrimType() == sopcache->myPrevPrimType) &&
7810 (sopparms.getEndCapType() == sopcache->myPrevEndCapType) &&
7811 (sopparms.getCapDivs() == sopcache->myPrevEndCapDivs) &&
7812 (sopparms.getTriangularPoles() == sopcache->myPrevTriangularPoles) &&
7813 (sopparms.getSwapRowCol() == sopcache->myPrevSwapRowCol);
7814 if (same_surface_parms)
7816 if (cross_section_input && sopcache->myPrevSurfaceShape == SurfaceShape::INPUT)
7818 same_surface_parms =
7819 (sopcache->myPrevSurfaceShape == SurfaceShape::INPUT) &&
7820 (sopcache->myPrevCloseIfNoCurveInput == sopparms.getCloseIfNoCurveInput()) &&
7821 same_cross_section_data &&
7823 (cross_section_input->
getTopology().
getDataId() == sopcache->myPrevCrossSectionTopologyDataID) &&
7824 (cross_section_group_list.size() == sopcache->myPrevCrossSectionGroup.size()) &&
7825 (cross_section_group_list.isEqual(sopcache->myPrevCrossSectionGroup, 0, cross_section_group_list.size()));
7829 same_surface_parms =
7830 (sopparms.getSurfaceShape() == sopcache->myPrevSurfaceShape) &&
7831 (sopparms.getCols() == sopcache->myPrevCols);
7838 if (same_input_curves && same_surface_parms)
7839 need_to_build_surface =
false;
7842 sopcache->myPrevOutputDetailID = output_geo->getUniqueId();
7843 sopcache->myPrevCurvePrimListDataID = new_curve_prim_list_data_id;
7844 sopcache->myPrevCurveTopologyDataID = new_curve_topology_data_id;
7845 sopcache->myPrevCurveGroup = std::move(curve_group_list);
7846 sopcache->myPrevSurfaceType = sopparms.getSurfaceType();
7847 sopcache->myPrevUnrollClosedRowCol = sopparms.getUnrollClosedRowCol();
7848 sopcache->myPrevPrimType = sopparms.getPrimType();
7849 sopcache->myPrevCloseIfNoCurveInput = sopparms.getCloseIfNoCurveInput();
7850 sopcache->myPrevSurfaceShape = sopparms.getSurfaceShape();
7851 sopcache->myPrevCols = (cross_section_input && sopcache->myPrevSurfaceShape == SurfaceShape::INPUT) ? -1 : sopparms.getCols();
7852 sopcache->myPrevEndCapType = sopparms.getEndCapType();
7853 sopcache->myPrevEndCapDivs = sopparms.getCapDivs();
7854 sopcache->myPrevTriangularPoles = sopparms.getTriangularPoles();
7855 sopcache->myPrevSwapRowCol = sopparms.getSwapRowCol();
7856 sopcache->myPrevCrossSectionPrimListDataID = cross_section_input ? cross_section_input->
getPrimitiveList().
getDataId() : -1;
7857 sopcache->myPrevCrossSectionTopologyDataID = cross_section_input ? cross_section_input->
getTopology().
getDataId() : -1;
7858 sopcache->myPrevCrossSectionGroup = std::move(cross_section_group_list);
7859 sopcache->myPrevCopyOrder = copy_order;
7862 const CrossSectionAttribMatchData *copy_order_attrib_data = (copy_order ==
CopyOrder::ATTRIB) ? &sopcache->myCrossSectionAttribMatchData :
nullptr;
7864 GEO_SurfaceType surface_type = sweepSurfaceToGeoSurface(sopparms.getSurfaceType());
7865 bool output_points_only = (sopparms.getSurfaceType() == SurfaceType::POINTS);
7866 exint cap_divisions =
7867 (sopparms.getEndCapType() ==
EndCapType::NONE || sopparms.getEndCapType() == EndCapType::SINGLE || sopparms.getEndCapType() == EndCapType::SIDESINGLE) ? 0 : sopparms.getCapDivs();
7869 if (need_to_build_surface)
7871 bool finished = createGrids(
7872 cross_section_input, cross_section_group,
7873 sopparms.getSurfaceShape(),
7874 sopparms.getCols() * ((sopparms.getSurfaceShape() == SurfaceShape::SQUARE) ? 4 : 1),
7875 copy_order, copy_order_attrib_data,
7876 curve_input, curve_group,
7877 sopparms.getCloseIfNoCurveInput(),
7878 surface_type, output_points_only, sopparms.getUnrollClosedRowCol(),
7879 sopParmToPrimType(sopparms.getPrimType()),
7880 sopparms.getEndCapType(), cap_divisions,
7881 sopparms.getTriangularPoles(),
7882 sopparms.getSwapRowCol(),
7897 exint uv_attrib_index = -1;
7899 setupSweepTransferAttribs(output_geo,
7900 cross_section_input, sopparms.getAttribsFromCrossSection(),
7901 curve_input, sopparms.getAttribsFromBackbone(),
7902 cross_section_attribs,
7906 sopparms.getComputeUVs(),
7907 sopparms.getComputeUVs() && sopparms.getOverrideExistingUVs());
7919 if (sopparms.getComputeUVs())
7921 if (cross_section_input)
7924 if (!sopparms.getOverrideExistingUVs())
7927 if (!input_uv_attrib.
isValid())
7932 if (!input_uv_attrib.
isValid() || sopparms.getOverrideExistingUVs())
7936 detached_cross_section_uv =
7939 rw_uv_attrib.
bind(detached_cross_section_uv.get());
7945 computeCurveUVs(cross_section_input, cross_section_group, rw_uv_attrib, sopparms.getLengthWeightedUVs(), sopparms.getReverseCrossSections());
7947 if (uv_attrib_index >= 0)
7950 uv_attribs[uv_attrib_index].first.first = rw_uv_attrib.
getAttribute();
7957 uv_attrib_index = uv_attribs.size();
7958 uv_attribs.append(std::make_pair(std::make_pair(rw_uv_attrib.
getAttribute(), (
const GA_ATINumeric*)
nullptr), output_attrib));
7965 exint nedgecols = sopparms.getCols();
7966 if (sopparms.getSurfaceShape() == SurfaceShape::SQUARE)
7968 bool closed = (sopparms.getSurfaceShape() == SurfaceShape::TUBE || sopparms.getSurfaceShape() == SurfaceShape::SQUARE);
7969 exint nvertices = nedgecols + !closed;
7971 for (
exint i = 0; i < nvertices; ++i)
7973 missing_input_us[i] = double(i)/double(nedgecols);
7976 if (uv_attrib_index < 0)
7983 uv_attrib_index = uv_attribs.size();
7984 uv_attribs.append(std::make_pair(std::make_pair((
const GA_ATINumeric*)
nullptr, (
const GA_ATINumeric*)
nullptr), output_attrib));
7994 if (!sopparms.getOverrideExistingUVs())
7997 if (!input_uv_attrib.
isValid())
8002 if (!input_uv_attrib.
isValid() || sopparms.getOverrideExistingUVs())
8007 curve_uv_deleter.reset(detached_uv_attrib);
8008 rw_uv_attrib.
bind(detached_uv_attrib);
8014 computeCurveUVs(curve_input, curve_group, rw_uv_attrib, sopparms.getLengthWeightedUVs());
8016 if (uv_attrib_index >= 0)
8019 uv_attribs[uv_attrib_index].first.second = rw_uv_attrib.
getAttribute();
8025 uv_attrib_index = uv_attribs.size();
8026 uv_attribs.append(std::make_pair(std::make_pair((
const GA_ATINumeric*)
nullptr, rw_uv_attrib.
getAttribute()), output_attrib));
8034 bool closed = sopparms.getCloseIfNoCurveInput();
8035 exint nedgecols = num_cross_sections - !closed;
8037 bool length_weighted_uvs = sopparms.getLengthWeightedUVs();
8038 if (length_weighted_uvs)
8046 exint cross_section_i = 0;
8047 double total_distance = 0;
8048 for (; !cross_section_it.
atEnd(); ++cross_section_it)
8054 for (
exint i = 0; i <
n; ++i)
8057 centroid += pos_attrib.get(ptoff);
8062 if (cross_section_i == 0)
8064 first_centroid = centroid;
8071 missing_input_us[cross_section_i] = total_distance;
8074 prev_centroid = centroid;
8079 double distance = first_centroid.distance(prev_centroid);
8083 if (total_distance == 0)
8086 length_weighted_uvs =
false;
8090 for (
exint i = 0, n = missing_input_us.
size(); i <
n; ++i)
8092 missing_input_us[i] /= total_distance;
8098 if (!length_weighted_uvs)
8101 for (
exint i = 0; i < num_cross_sections; ++i)
8103 missing_input_us[i] = double(i)/double(nedgecols);
8110 const bool computing_uvs = (uv_attrib_index >= 0);
8118 exint total_transforms = 0;
8119 if (curve_input !=
nullptr)
8127 curve_input->createDetachedTupleAttribute(
8129 GA_RWHandleM4D transform_attrib(detached_transform_attrib.get());
8134 parms.myExtrapolateEndTangents = sopparms.getExtrapolateEndTangents();
8135 parms.myTransformByInstanceAttribs = sopparms.getTransformByAttribs();
8139 const bool applypitch = sopparms.getApplyPitch();
8140 const bool applyyaw = sopparms.getApplyYaw();
8141 const bool applyroll = sopparms.getApplyRoll();
8143 applypitch ? SYSdegToRad(sopparms.getPitch()) : 0.0,
8144 applyyaw ? SYSdegToRad(sopparms.getYaw()) : 0.0,
8145 applyroll ? SYSdegToRad(sopparms.getRoll()) : 0.0);
8146 parms.myAngles = angles;
8148 applypitch ? SYSdegToRad(sopparms.getIncPitch()) : 0.0,
8149 applyyaw ? SYSdegToRad(sopparms.getIncYaw()) : 0.0,
8150 applyroll ? SYSdegToRad(sopparms.getIncRoll() + 360.0*sopparms.getFullTwists()) : 0.0);
8151 parms.myIncAngles = incangles;
8163 parms.myRotAttribs[0].bind(curve_input->findAttribute(sopparms.getPitchAttrib(), search_order, 4));
8165 parms.myRotAttribs[1].bind(curve_input->findAttribute(sopparms.getYawAttrib(), search_order, 4));
8167 parms.myRotAttribs[2].bind(curve_input->findAttribute(sopparms.getRollAttrib(), search_order, 4));
8171 switch (sopparms.getUpVectorType())
8179 parms.myTargetUpVectorAttrib.bind(curve_input, GA_ATTRIB_PRIMITIVE, sopparms.getUpVectorAttrib());
8180 if (!parms.myTargetUpVectorAttrib.isValid())
8182 parms.myTargetUpVectorAttrib.bind(curve_input,
GA_ATTRIB_DETAIL, sopparms.getUpVectorAttrib());
8184 if (parms.myTargetUpVectorAttrib.isValid() && parms.myTargetUpVectorAttrib->getOwner() ==
GA_ATTRIB_DETAIL)
8187 parms.myTargetUpVector = parms.myTargetUpVectorAttrib.get(
GA_DETAIL_OFFSET);
8188 parms.myTargetUpVectorAttrib.clear();
8192 if (!parms.myTargetUpVectorAttrib.isValid())
8200 case UpVectorType::CUSTOM: parms.myTargetUpVector = sopparms.getUpVector();
break;
8202 parms.myUseCurveNormalAsTargetUp = (sopparms.getUpVectorType() == UpVectorType::NORMAL);
8203 parms.myTargetUpVectorAtStart = sopparms.getUpVectorAtStart();
8204 parms.myContinuousClosedCurves = sopparms.getContinuousClosed();
8206 if (parms.myTargetUpVectorAtStart && sopparms.getUseEndUpVector())
8208 parms.myUseEndTargetUpVector =
true;
8211 parms.myEndTargetUpVectorAttrib.bind(curve_input, GA_ATTRIB_PRIMITIVE, sopparms.getEndUpVectorAttrib());
8212 if (!parms.myEndTargetUpVectorAttrib.isValid())
8214 parms.myEndTargetUpVectorAttrib.bind(curve_input,
GA_ATTRIB_DETAIL, sopparms.getEndUpVectorAttrib());
8216 if (parms.myEndTargetUpVectorAttrib.isValid() && parms.myEndTargetUpVectorAttrib->getOwner() ==
GA_ATTRIB_DETAIL)
8219 parms.myEndTargetUpVector = parms.myEndTargetUpVectorAttrib.get(
GA_DETAIL_OFFSET);
8220 parms.myEndTargetUpVectorAttrib.clear();
8224 if (!parms.myEndTargetUpVectorAttrib.isValid())
8226 cookparms.
sopAddWarning(
SOP_MESSAGE,
"End target up vector attribute not found; defaulting to no end target up vector.");
8227 parms.myUseEndTargetUpVector =
false;
8232 else if (sopparms.getUpVectorType() == UpVectorType::CUSTOM)
8234 parms.myEndTargetUpVector = sopparms.getEndUpVector();
8238 parms.myEndTargetUpVector = parms.myTargetUpVector;
8242 parms.myNormalizeScales =
false;
8244 if (sopparms.getSurfaceShape() == SurfaceShape::INPUT)
8245 parms.myUniformScale = sopparms.getScale();
8246 else if (sopparms.getSurfaceShape() == SurfaceShape::TUBE)
8247 parms.myUniformScale = sopparms.getRadius();
8249 parms.myUniformScale = 0.5*sopparms.getWidth();
8251 if(sopparms.getApplyScale())
8252 parms.myScaleRamp = sopparms.getScaleRamp().get();
8254 parms.myStretchAroundTurns = sopparms.getStretchAroundTurns();
8255 parms.myMaxStretchScale = sopparms.getMaxStretchAroundTurns();
8260 total_transforms = 0;
8261 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8263 const sop_SweepGrid &grid = grids[gridi];
8264 total_transforms += grid.myCurveNEdges + !grid.myCurveClosed;
8266 sopcache->myGridTransformStarts.reset(
new exint[grids.
size()]);
8267 sopcache->clearTransformArrays();
8268 sopcache->myTransformMatrices3D.reset(
new UT_Matrix3D[total_transforms]);
8269 sopcache->myTransformTranslates3D.reset(
new UT_Vector3D[total_transforms]);
8270 sopcache->myTransformCacheSize = total_transforms;
8271 exint *grid_transform_starts = sopcache->myGridTransformStarts.get();
8272 UT_Matrix3D *transform_matrix3ds = sopcache->myTransformMatrices3D.get();
8273 UT_Vector3D *transform_translate3ds = sopcache->myTransformTranslates3D.get();
8274 exint current_transform_start = 0;
8275 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8277 const sop_SweepGrid &grid = grids[gridi];
8278 grid_transform_starts[gridi] = current_transform_start;
8279 current_transform_start += grid.myCurveNEdges + !grid.myCurveClosed;
8282 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8284 const sop_SweepGrid &grid = grids[gridi];
8286 const GA_Offset curve_primoff = grid.myCurvePrimOff;
8287 const GA_OffsetListRef vertices = curve_input->getPrimitiveVertexList(curve_primoff);
8292 (curve_input->vertexPoint(vertices(0)) == curve_input->vertexPoint(vertices.
last()));
8294 if (vertices.
size() == 1)
8298 curve_unrolled =
false;
8304 const exint grid_transform_start = grid_transform_starts[gridi];
8305 UT_Matrix3D *grid_matrix3ds = transform_matrix3ds + grid_transform_start;
8306 UT_Vector3D *grid_translate3ds = transform_translate3ds + grid_transform_start;
8309 const exint row_start = grid.myVEndPoles ? cap_divisions : 0;
8310 for (
exint i = 0; i < num_vertices; ++i)
8312 const UT_Matrix4D transform = transform_attrib.get(vertices(i));
8313 UT_ASSERT(grid_transform_start+row_start+i < total_transforms);
8314 grid_matrix3ds[row_start+i] =
UT_Matrix3D(transform);
8318 if (grid.myVEndPoles)
8322 const UT_Matrix4D transform0 = transform_attrib.get(vtxoff0);
8323 const UT_Matrix4D transform1 = transform_attrib.get(vtxoff1);
8325 sopAllEndCapTransforms(
8326 grid, sopparms, cross_section_input,
8327 transform0, transform1, num_vertices,
8328 grid_matrix3ds, grid_translate3ds,
8333 else if (grids.
size() == 1 && grids[0].myVEndPoles)
8337 const sop_SweepGrid &grid = grids[0];
8340 total_transforms = grid.myCurveNEdges + !grid.myCurveClosed;
8341 exint num_vertices = total_transforms - 2*cap_divisions;
8343 sopcache->myGridTransformStarts.reset(
new exint[1]);
8344 sopcache->clearTransformArrays();
8345 sopcache->myTransformMatrices3D.reset(
new UT_Matrix3D[total_transforms]);
8346 sopcache->myTransformTranslates3D.reset(
new UT_Vector3D[total_transforms]);
8347 sopcache->myTransformCacheSize = total_transforms;
8348 exint *grid_transform_starts = sopcache->myGridTransformStarts.get();
8349 UT_Matrix3D *grid_matrix3ds = sopcache->myTransformMatrices3D.get();
8350 UT_Vector3D *grid_translate3ds = sopcache->myTransformTranslates3D.get();
8351 grid_transform_starts[0] = 0;
8354 for (
exint i = 0; i < num_vertices; ++i)
8356 UT_ASSERT(cap_divisions+i < total_transforms);
8357 grid_matrix3ds[cap_divisions+i].
identity();
8358 grid_translate3ds[cap_divisions+i] =
UT_Vector3D(0,0,0);
8362 sopAllEndCapTransforms(
8363 grid, sopparms, cross_section_input,
8364 identity, identity, num_vertices,
8365 grid_matrix3ds, grid_translate3ds,
8370 sopcache->clearTransformArrays();
8377 needed_transforms[i] =
false;
8379 for (
exint attribi = 0, nattribs = cross_section_attribs.size(); attribi < nattribs; ++attribi)
8381 GA_Attribute *output_attrib = cross_section_attribs[attribi].second;
8383 if (output_numeric ==
nullptr)
8390 using namespace NeededTransforms;
8395 needed_transforms[
matrix3f] |= !double_precision;
8396 needed_transforms[
translate3f] |= !double_precision;
8400 needed_transforms[
matrix3f] |= !double_precision;
8404 needed_transforms[
inverse3d] |= double_precision;
8405 needed_transforms[
inverse3f] |= !double_precision;
8409 needed_transforms[
quaterniond] |= double_precision;
8410 needed_transforms[
quaternionf] |= !double_precision;
8414 needed_transforms[
matrix3f] |= !double_precision;
8425 const SOP_SweepHDKCache *transform_cache = (sopcache->myTransformCacheSize != 0) ? sopcache :
nullptr;
8436 if (!cross_section_input)
8440 output_geo->getP()->bumpDataId();
8445 const exint cross_section_nedges = sopparms.getCols();
8446 if (sopparms.getSurfaceShape() == SurfaceShape::TUBE)
8448 cross_section_positions.
setSize(cross_section_nedges);
8449 if (cross_section_nedges == 1)
8451 cross_section_positions[0].assign(1,0,0);
8455 cross_section_positions[0].assign(1,0,0);
8456 for (
exint cross_sectioni = 1; cross_sectioni < cross_section_nedges; ++cross_sectioni)
8458 exint tcross_sectioni = cross_sectioni;
8459 if (sopparms.getReverseCrossSections())
8460 tcross_sectioni = reverseVtx(cross_sectioni, cross_section_nedges,
true);
8461 double t = double(tcross_sectioni)/double(cross_section_nedges);
8471 double theta = (2.0*
M_PI)*t;
8472 double c = SYScos(theta);
8473 double s = SYSsin(theta);
8479 cross_section_positions[cross_sectioni] =
v;
8483 else if (sopparms.getSurfaceShape() == SurfaceShape::RIBBON)
8485 cross_section_positions.setSize(cross_section_nedges+1);
8488 double x0 = (sopparms.getReverseCrossSections() ? 1 : -1);
8490 cross_section_positions[0].assign(x0, 0, 0);
8491 for (
exint cross_sectioni = 1; cross_sectioni < cross_section_nedges; ++cross_sectioni)
8493 double t = double(cross_sectioni)/double(cross_section_nedges);
8495 cross_section_positions[cross_sectioni] =
UT_Vector3D(x,0,0);
8497 cross_section_positions.last().assign(x1,0,0);
8501 UT_ASSERT(sopparms.getSurfaceShape() == SurfaceShape::SQUARE);
8503 cross_section_positions.setSize(4*cross_section_nedges);
8512 if (!sopparms.getReverseCrossSections())
8513 UTswap(corners[1], corners[3]);
8516 for (
exint big_edgei = 0; big_edgei < 4; ++big_edgei)
8519 cross_section_positions[arrayi].assign(corners[big_edgei][0], corners[big_edgei][1], 0);
8523 UT_Vector2D next = corners[(big_edgei==3) ? 0 : (big_edgei+1)];
8524 for (
exint small_edgei = 1; small_edgei < cross_section_nedges; ++small_edgei, ++arrayi)
8526 double t = double(small_edgei)/double(cross_section_nedges);
8528 cross_section_positions[arrayi].assign(pos2d[0], pos2d[1], 0);
8543 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
8544 const sop_SweepGrid &grid_info = grids[gridi];
8546 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8548 const bool swap_row_col = sopparms.getSwapRowCol();
8549 exint prev_vtxi = -1;
8550 auto&& functor = [&prev_vtxi,&cross_section_positions,swap_row_col,grid_transforms,&
transform,&outputP]
8553 const exint curve_vtxi = swap_row_col ? col :
row;
8554 if (curve_vtxi != prev_vtxi)
8556 transform =
UT_Matrix4D(grid_transforms->getMatrix3s<
double>()[curve_vtxi]);
8557 transform.setTranslates(grid_transforms->getTranslates<
double>()[curve_vtxi]);
8558 prev_vtxi = curve_vtxi;
8563 const exint cross_section_vtxi = swap_row_col ? row : col;
8564 const UT_Vector3D &cross_section_pos = cross_section_positions[cross_section_vtxi];
8565 outputP.set(output_offset, (cross_section_pos * transform));
8572 const exint PARALLEL_THRESHOLD = 2048;
8573 if (ngrids > 1 && output_geo->getNumPoints() >= PARALLEL_THRESHOLD)
8576 outputP->hardenAllPages();
8586 exint num_cross_sections;
8587 if (cross_section_group !=
nullptr)
8589 num_cross_sections = cross_section_group->
entries();
8591 else if (cross_section_input !=
nullptr)
8597 num_cross_sections = 1;
8600 const UVStyle ustyle = (!computing_uvs || !sopparms.getLengthWeightedUVs() || sopparms.getNormalizeU()) ?
8601 UVStyle::NORMALIZED :
8602 (sopparms.getWrapU() ? UVStyle::ROUNDED : UVStyle::FULL);
8603 const UVStyle vstyle = (!computing_uvs || !sopparms.getLengthWeightedUVs() || sopparms.getNormalizeV()) ?
8604 UVStyle::NORMALIZED :
8605 (sopparms.getWrapV() ? UVStyle::ROUNDED : UVStyle::FULL);
8607 bool finished = copySurfaceAttributes(
8608 output_geo, curve_input, cross_section_input,
8610 cross_section_attribs,
8611 curve_attribs, uv_attribs,
8613 surface_type, output_points_only, sopparms.getTriangularPoles(), cap_divisions,
8614 sopparms.getReverseCrossSections(), sopparms.getSwapRowCol(),
8616 (!missing_input_us.
isEmpty()) ? &missing_input_us :
nullptr,
8617 sopparms.getLengthWeightedUVs(),
8619 (curve_input ==
nullptr) || sopparms.getUseMeshEdgeLengths(),
8620 sopparms.getPropScalePerCurve(),
8621 computing_uvs && sopparms.getFlipU(),
8622 sopparms.getUVScale());
8634 if (sopparms.getAddPointRow() && sopparms.getPtRowAttrib().isstring())
8639 if (attrib.isValid())
8641 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8643 const sop_SweepGrid &grid_info = grids[gridi];
8645 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8649 attrib.set(output_ptoff, ptrow);
8654 if (sopparms.getAddPointCol() && sopparms.getPtColAttrib().isstring())
8659 if (attrib.isValid())
8661 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8663 const sop_SweepGrid &grid_info = grids[gridi];
8665 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8669 attrib.set(output_ptoff, ptcol);
8674 if (sopparms.getAddPrimRow() && sopparms.getPrimRowAttrib().isstring())
8679 if (attrib.isValid())
8681 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8683 const sop_SweepGrid &grid_info = grids[gridi];
8685 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8687 GA_Offset grid_start_primoff = grid_info.myStartPrimOff;
8688 if (grid_info.myHasPolygonCaps)
8691 attrib.set(grid_start_primoff, 0);
8692 ++grid_start_primoff;
8698 attrib.set(grid_start_primoff + primnum, primrow);
8701 if (grid_info.myHasPolygonCaps)
8704 attrib.set(grid_start_primoff + grid.
myNumPrimitives, grid_info.myCurveNEdges);
8709 if (sopparms.getAddPrimCol() && sopparms.getPrimColAttrib().isstring())
8714 if (attrib.isValid())
8716 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8718 const sop_SweepGrid &grid_info = grids[gridi];
8720 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8722 GA_Offset grid_start_primoff = grid_info.myStartPrimOff;
8723 if (grid_info.myHasPolygonCaps)
8726 attrib.set(grid_start_primoff, 0);
8727 ++grid_start_primoff;
8733 attrib.set(grid_start_primoff + primnum, primcol);
8736 if (grid_info.myHasPolygonCaps)
8744 if (sopparms.getAddCurveNum() && sopparms.getCurveNumAttrib().isstring())
8749 if (attrib.isValid())
8751 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8753 const sop_SweepGrid &grid_info = grids[gridi];
8755 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8758 exint curve_number = (curve_input !=
nullptr) ?
exint(curve_input->primitiveIndex(grid_info.myCurvePrimOff)) : 0;
8762 attrib.set(output_ptoff, curve_number);
8767 if (sopparms.getAddCrossSectionNum() && sopparms.getCrossSectionNumAttrib().isstring())
8770 const UT_StringHolder &attribname = sopparms.getCrossSectionNumAttrib();
8772 if (attrib.isValid())
8774 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8776 const sop_SweepGrid &grid_info = grids[gridi];
8778 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8780 if (cross_section_input !=
nullptr)
8784 GA_Offset source_cross_section_primoff =
8785 grid_info.mySingleCrossSection ?
8786 GA_Offset(grid_info.myCrossSectionPrimOff) :
8787 (*grid_info.myCrossSectionPrimOffs)[ptrow];
8789 exint cross_section_number = cross_section_input->
primitiveIndex(source_cross_section_primoff);
8791 attrib.set(output_ptoff, cross_section_number);
8799 attrib.set(output_ptoff, 0);
8805 if (sopparms.getAddEndCapsGroup() && sopparms.getEndCapsGroup().isstring())
8812 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8814 const sop_SweepGrid &grid_info = grids[gridi];
8816 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8818 GA_Offset grid_start_primoff = grid_info.myStartPrimOff;
8819 if (grid_info.myHasPolygonCaps)
8825 else if (grid_info.myVEndPoles)
8828 exint last_cap_start_vtxi = grid_info.myCurveNEdges - cap_divisions;
8829 const bool swap_row_col = sopparms.getSwapRowCol();
8833 exint curve_vtxi = swap_row_col ? primcol : primrow;
8834 if (curve_vtxi < cap_divisions || curve_vtxi >= last_cap_start_vtxi)
8836 group->
addOffset(grid_start_primoff + primnum);
8849 sopcache->clearTransformArrays();
static PRM_ChoiceList primGroupMenu
void destroyPrimitiveGroup(GA_PrimitiveGroup *g)
void initColTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
constexpr SYS_FORCE_INLINE T length2() const noexcept
SYS_FORCE_INLINE void bumpDataId()
SYS_FORCE_INLINE const GA_Detail & getDetail() const
SYS_FORCE_INLINE void forEachAttribute(FUNCTOR &&functor) const
static SYS_FORCE_INLINE bool isType(const GA_Attribute *attrib)
Definition of a geometry attribute.
UT_Matrix4T< fpreal64 > UT_Matrix4D
GLenum GLuint GLenum GLsizei const GLchar * buf
void UTparallelFor(const Range &range, const Body &body, const int subscribe_ratio=2, const int min_grain_size=1, const bool force_use_task_scope=true)
constexpr SYS_FORCE_INLINE T dot(const UT_Vector3T &b) const noexcept
Data has no numeric representation.
#define SYS_STATIC_ASSERT(expr)
int setUBasis(GA_Basis *ub)
SYS_FORCE_INLINE GA_Primitive * getPrimitive(GA_Offset prim_off)
SYS_FORCE_INLINE const GA_AttributeDict & pointAttribs() const
FromType append(ToType value)
Add a single entry (may grow array)
const GA_IndexMap & getPrimitiveMap() const
GA_DataId getDataId() const
unsigned char myBasisOrderU
Iteration over a range of elements.
static SYS_FORCE_INLINE bool isType(const GA_Attribute *attrib)
int setVBasis(GA_Basis *vb)
void setChoiceListPtr(const UT_StringRef &name, PRM_ChoiceList *list)
UT_ErrorSeverity sopAddWarning(int code, const char *msg=0, const UT_SourceLocation *loc=0) const
GOP_GroupParse::GroupCreator GroupCreator
static GA_AttributeFilter selectAnd(const GA_AttributeFilter &f0, const GA_AttributeFilter &f1, bool single_match=false)
void newSopOperator(OP_OperatorTable *table)
SYS_FORCE_INLINE int getPrimitiveTypeId(GA_Offset primoff) const
Class which stores the default values for a GA_Attribute.
T distance3d(const UT_Vector3T< T > &p1, const UT_Vector3T< T > &p2)
Compute the distance between two points.
bool myPrevCloseIfNoCurveInput
getFileOption("OpenEXR:storage") storage
bool mySingleCrossSection
bool isValid() const
Test to see whether the iterator is valid.
GA_API const UT_StringHolder uv
bool myFirstRowIfNotWrapped
static GA_AttributeFilter selectPublic(bool include_noninternal_groups=true)
Select public scope attributes and non-internal groups.
SYS_FORCE_INLINE const GA_IndexMap & getIndexMap() const
SYS_FORCE_INLINE void colVecMult(const UT_Matrix3F &m)
GA_OffsetListType< GA_Size > GA_OffsetList
GA_OffsetList is a map from index to offset.
UT_Vector2T< fpreal64 > UT_Vector2D
#define UT_ASSERT_LEVEL_PARANOID
bool blockAdvance(GA_Offset &start, GA_Offset &end)
GLsizei const GLfloat * value
GA_Size entries() const overridefinal
Will return the number of primary elements.
bool myPrevUnrollClosedRowCol
void setSizeNoInit(exint newsize)
void clearAndDestroy()
Clear all the points/primitives out of this detail.
UT_Vector3T< float > UT_Vector3
SYS_FORCE_INLINE bool getExtraFlag() const
Synonym for isClosed()
fpreal64 distance2(const UT_VectorD &v1, const UT_VectorD &v2)
Distance squared (L2) aka quadrance.
GA_DataId getDataId() const
Return the data ID for the topology attributes.
SYS_FORCE_INLINE void initHullData(int rows, int cols, bool wrapv, bool wrapu)
GA_Attribute * getP()
Convenience method to access the P attribute.
SYS_FORCE_INLINE const char * buffer() const
GLboolean GLboolean GLboolean GLboolean a
bool myCurvesIfBasisRowCol
void reverse(I begin, I end)
SYS_FORCE_INLINE GA_AttributeScope getScope() const
GLuint GLsizei GLsizei * length
~SOP_SweepHDKCache() override
void setCapacity(exint new_capacity)
void destroyVertexGroup(GA_VertexGroup *g)
GA_EdgeGroupTable & edgeGroups()
SYS_FORCE_INLINE TO_T UTverify_cast(FROM_T from)
bool myFirstColIfNotWrapped
bool addOperator(OP_Operator *op, std::ostream *err=nullptr)
Standard user attribute level.
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Offset ptoff) const
The ptoff passed is the point offset.
void arbitraryPerp(const UT_Vector3T< T > &v)
Finds an arbitrary perpendicular to v, and sets this to it.
UT_Matrix2T< T > SYSlerp(const UT_Matrix2T< T > &v1, const UT_Matrix2T< T > &v2, S t)
UT_UniquePtr< exint[]> myGridTransformStarts
GA_ROHandleS myCurveStrAttrib
SOP_SweepHDKEnums::SurfaceShape myPrevSurfaceShape
We'll use NONE to represent using the cross section input.
bool shouldInterpretAsTexCoord(bool allow_float2=false) const
void appendPolygons(const GA_PolyCounts &sizes, const GA_OffsetList &vertices)
SYS_FORCE_INLINE bool GAisValid(GA_Size v)
CrossSectionAttribMatchData myCrossSectionAttribMatchData
void setSize(exint newsize)
exint GA_Size
Defines the bit width for index and offset types in GA.
GA_OffsetList myPrevCurveGroup
GA_ATINumeric * getAttribute() const
This is the SOP class definition.
#define GA_INVALID_OFFSET
void bumpSize(exint newsize)
GA_Size countPrimitiveType(const GA_PrimitiveTypeId &type) const
UT_ErrorSeverity sopAddError(int code, const char *msg=0, const UT_SourceLocation *loc=0) const
GA_GroupTable::iterator< GA_EdgeGroup > beginTraverse() const
A range of elements in an index-map.
bool myCrossSectionClosed
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
SYS_FORCE_INLINE const UT_StringHolder & getName() const
const char * inputLabel(unsigned idx) const override
These are the labels that appear when hovering over the inputs.
#define UT_ASSERT_MSG(ZZ,...)
virtual bool fill(const GA_Range &destrange, GA_Offset srci)
virtual bool copyFrom(const GA_Basis &b, bool compatible=false)
SYS_FORCE_INLINE void outerproductUpdate(T b, const UT_Vector3F &v1, const UT_Vector3F &v2)
GA_API const UT_StringHolder scale
exint myCrossSectionPrimOff
UT_Array< sop_SweepGrid > myGrids
SYS_FORCE_INLINE GA_Index primitiveIndex(GA_Offset offset) const
Given a primitive's data offset, return its index.
int64 myPrevCrossSectionPrimListDataID
GA_ROHandleID myCurveIntAttrib
Constructs a PRM_Template list from an embedded .ds file or an istream.
void identity()
Set the matrix to identity.
IMATH_NAMESPACE::V2f float
void bind(const GA_Detail *gdp, GA_AttributeOwner owner, const UT_StringRef &name, int minsize=1)
GA_Iterator begin() const
SOP_SweepHDKEnums::CopyOrder myPrevCopyOrder
void GUiterateGridPrimitives(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
exint myCrossSectionNEdges
virtual void replace(const GA_Attribute &src)=0
GA_OffsetList * myCrossSectionPrimOffs
SYS_FORCE_INLINE GA_Offset appendPointBlock(GA_Size npoints)
Append new points, returning the first offset of the contiguous block.
constexpr SYS_FORCE_INLINE void negate() noexcept
PRM_Template * templates() const
UT_ArrayStringMap< GA_Offset > myStrToPrimOff
static SYS_FORCE_INLINE GA_ATINumeric * cast(GA_Attribute *attrib)
SOP_SweepHDKEnums::PrimType myPrevPrimType
SYS_FORCE_INLINE GA_OffsetListRef getPrimitiveVertexList(GA_Offset primoff) const
virtual GA_BASIS_TYPE getType() const =0
Return the type of the basis.
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
GEO_API GA_Offset GEObuildPrimitives(GEO_Detail *detail, const std::pair< int, exint > *primtype_count_pairs, const GA_Offset init_startpt, const GA_Size npoints_per_copy, const GA_PolyCounts &vertexlistsizelist, const INT_T *vertexpointnumbers, const bool hassharedpoints, const exint *closed_span_lengths, const exint ncopies=1)
UT_Vector3T< T > SYSclamp(const UT_Vector3T< T > &v, const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
void GUiterateGridVertices(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
GA_AttributeSet & getAttributes()
SOP_NodeCache * allocCache() const override
Bezier or NURBS basis classes which maintain knot vectors.
NURBS basis classes which maintain knot vectors.
SOP_NodeParms * allocParms() const override
GU_API void computeCurveTransforms(const GEO_Detail *const geo, const GA_PrimitiveGroup *curve_group, const GA_RWHandleT< UT_Matrix4T< T >> &transform_attrib, const CurveFrameParms< T > &parms)
SYS_FORCE_INLINE GA_ATINumericUPtr createDetachedTupleAttribute(GA_AttributeOwner owner, GA_Storage storage, int tuple_size, const GA_Defaults &defaults=GA_Defaults(0.0f), const GA_AttributeOptions *attribute_options=nullptr) const
GLdouble GLdouble GLint GLint order
UT::ArrayMap< exint, GA_Offset > myIntToPrimOff
SYS_FORCE_INLINE const char * c_str() const
UT_Vector3T< fpreal64 > UT_Vector3D
SYS_FORCE_INLINE T get(GA_Offset off, int comp=0) const
SYS_FORCE_INLINE GA_Offset vertexPoint(GA_Offset vertex) const
Given a vertex, return the point it references.
void identity()
Set the matrix to identity.
int64 myPrevCrossSectCurveAttribDataId
SYS_API fpreal32 SYSfloor(fpreal32 val)
bool myPrevTriangularPoles
GLuint const GLchar * name
SYS_FORCE_INLINE GA_DataId getDataId() const
UT_API T UTboundingCircle(const T *coords, exint n, T *centre_out=nullptr)
Returns radius squared.
SYS_FORCE_INLINE const GA_Attribute * findAttribute(GA_AttributeScope scope, const UT_StringRef &name, const GA_AttributeOwner search_order[], int search_size) const
OP_ERROR cookMySop(OP_Context &context) override
Since this SOP implements a verb, cookMySop just delegates to the verb.
SYS_FORCE_INLINE bool destroyEdgeGroup(const UT_StringRef &name)
GLboolean GLboolean GLboolean b
GA_Size GA_Index
Define the strictness of GA_Offset/GA_Index.
GA_API const UT_StringHolder transform
void GUiterateGridPoints(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
void initColSphere(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1), INT_TYPE start_mid_pt=INT_TYPE(2))
SYS_FORCE_INLINE const GA_AttributeDict & getDict(GA_AttributeOwner owner) const
Raw access to the GA_AttributeDict for a particular owner.
GEO_SurfaceType mySurfaceType
bool contains(const GA_Primitive *prim) const
fpreal32 SYSrint(fpreal32 val)
GLenum GLenum GLsizei void * table
static UT_XformOrder::xyzOrder getRotOrder(int xyz)
Translate a XYZ parameter menu index into the UT_XformOrder type.
int64 myPrevCurvePrimListDataID
bool myLastRowIfNotWrapped
UT_UniquePtr< GA_Attribute > GA_AttributeUPtr
void setTranslates(const UT_Vector3T< S > &translates)
SYS_FORCE_INLINE const GA_AttributeDict & attribs() const
GA_Topology & getTopology()
static PRM_Template * buildTemplates()
int sprintf(const char *fmt,...) SYS_PRINTF_CHECK_ATTRIBUTE(2
UT_QuaternionT< T > interpolate(const UT_QuaternionT< T > &target, T t, T b=0.0f) const
Interpolates between this quat (t==0) and the target (t==1)
SYS_FORCE_INLINE const GA_Attribute * findPrimitiveAttribute(GA_AttributeScope s, const UT_StringRef &name) const
int64 myPrevCrossSectPrimAttribDataId
INT_TYPE getPoint(exint row, exint col) const
SYS_FORCE_INLINE bool isValid() const
const GA_Basis * getBasis() const
ToType last() const
Return the value of the last element.
bool myLastColIfNotWrapped
GU_API void GUcomputeTransformTypeCaches(GU_PointTransformCache *cache, exint num_target_points, bool transforms_changed, const bool needed_transforms[NeededTransforms::num_needed_transforms])
PrimitiveType myPrimitiveType
SYS_FORCE_INLINE GA_Size getNumVertices() const
Return the number verticies in the entire detail.
Data represents a quaternion. Token "quaternion".
void hardenAllPages(GA_Offset start_offset=GA_Offset(0), GA_Offset end_offset=GA_INVALID_OFFSET) override
Harden data pages.
bool myCrossSectionUnrolled
SOP_SweepHDKEnums::SurfaceType myPrevSurfaceType
static GA_AttributeFilter selectByPattern(const char *pattern)
SYS_FORCE_INLINE GA_TypeInfo getTypeInfo() const
SYS_FORCE_INLINE void set(GA_Offset off, const T &val) const
SYS_FORCE_INLINE GA_Index indexSize() const
SYS_FORCE_INLINE GA_Offset primitiveOffset(GA_Index index) const
Given a primitive's index (in append order), return its data offset.
GA_Size getEntries() const
Get an accurate count of the entries in the range.
virtual bool copy(GA_Offset desti, GA_Offset srci)
Data represents a normal vector. Token "normal".
LeafData & operator=(const LeafData &)=delete
SYS_FORCE_INLINE const GA_AttributeDict & primitiveAttribs() const
void append(GA_Size size, GA_Size count=1)
void destroyPointGroup(GA_PointGroup *g)
int setBasis(GA_Basis *ub)
unsigned char myBasisOrderCrossSection
int64 myPrevOutputDetailID
static const char *const theDsFile
This is the parameter interface string, below.
SYS_FORCE_INLINE GA_Size getNumPrimitives() const
Return the number of primitives.
GA_AttributeOwner myCurveAttribOwner
Data represents a direction vector. Token "vector".
const GU_Detail * inputGeo(exint idx) const
const GA_PrimitiveList & getPrimitiveList() const
int64 myPrevCurveTopologyDataID
SOP_NodeCache * cache() const
void constant(const T &v)
Quickly set the array to a single value.
constexpr SYS_FORCE_INLINE T distance(const UT_Vector3T &b) const noexcept
UT_StringHolder name() const override
Data represents a position in space. Token "point".
SYS_FORCE_INLINE GA_AttributeOwner getOwner() const
Container class for all geometry.
static const SOP_NodeVerb::Register< SOP_SweepHDKVerb > theVerb
int64 myPrevCrossSectionTopologyDataID
void zero()
Set the matrix to zero.
SYS_FORCE_INLINE UT_StorageMathFloat_t< T > normalize() noexcept
GLenum GLenum GLsizei void * row
void bind(GA_Detail *gdp, GA_AttributeOwner owner, const UT_StringRef &name, int minsize=1)
static const UT_StringHolder theSOPTypeName
GA_OffsetList myPrevCrossSectionGroup
SYS_FORCE_INLINE GA_Offset vertexOffset(GA_Index index) const
Given a vertex's index (in append order), return its data offset.
SIM_API const UT_StringHolder distance
void clear()
Resets list to an empty list.
SYS_FORCE_INLINE void setTypeInfo(GA_TypeInfo type)
void initRowSphere(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1), INT_TYPE start_mid_pt=INT_TYPE(2))
GA_Range getPrimitiveRange(const GA_PrimitiveGroup *group=0) const
Get a range of all primitives in the detail.
CookMode cookMode(const SOP_NodeParms *parms) const override
virtual void hardenAllPages(GA_Offset start_offset=GA_Offset(0), GA_Offset end_offset=GA_INVALID_OFFSET)=0
void destroyAttribute(GA_AttributeOwner owner, GA_AttributeScope scope, const UT_StringRef &name, const GA_AttributeFilter *filter=0)
void bumpDataIdsForAddOrRemove(bool added_or_removed_points, bool added_or_removed_vertices, bool added_or_removed_primitives)
PrimitiveType myPrimitiveType
Bezier basis classes which maintain knot vectors.
void initRowTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
SOP_SweepHDKEnums::EndCapType myPrevEndCapType
static GA_Basis * newSpecies(GA_BASIS_TYPE type)
Data represents a transform matrix. Token "matrix".
void initTorus(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
SIM_DerVector3 cross(const SIM_DerVector3 &lhs, const SIM_DerVector3 &rhs)
GA_Basis * getUBasis() const
GU_API bool getPolyProperties(const GEO_Detail *geometry, const GA_OffsetListRef &vertices, exint &nedges, bool &closed, bool &unrolled)
SYS_FORCE_INLINE void addOffset(GA_Offset ai)
static OP_Node * myConstructor(OP_Network *net, const char *name, OP_Operator *op)
GU_DetailHandle & gdh() const
The initial state of gdh depends on the cookMode()
GA_OffsetList getOffsetFromIndexList() const
TangentType myTangentType
bool fullBlockAdvance(GA_Offset &start, GA_Offset &end)
SYS_FORCE_INLINE bool isstring() const
unsigned char myBasisOrderCurve
int getOrder() const
Return the order of the basis.
SYS_FORCE_INLINE FromType size() const
Returns the number of used elements in the list (always <= capacity())
unsigned char myBasisOrderV
void getTranslates(UT_Vector3T< S > &translates) const
void initSingleGrid(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
SOP_SweepHDK(OP_Network *net, const char *name, OP_Operator *op)
SYS_FORCE_INLINE const GA_AttributeDict & vertexAttribs() const
void setSurfaceType(GEO_SurfaceType t)
UT_Matrix3T< fpreal64 > UT_Matrix3D
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
void initSplitColSphere(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0), INT_TYPE end_pt=INT_TYPE(1), INT_TYPE start_mid_pt=INT_TYPE(2))
bool isEmpty() const
Returns true iff there are no occupied elements in the array.
GA_Storage getStorage() const
GA_Basis * getVBasis() const
int isRefInput(unsigned i) const override