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);
502 case 0:
return "Backbone Curves";
503 case 1:
return "Cross Section(s)";
504 default:
return "Invalid Source";
516 return (i == 0 || i == 1);
534 return SOP_SweepHDKVerb::theVerb.get();
562 namespace HDK_Sample {
565 SOP_SweepHDK::cookInputGroups(
OP_Context &context,
int alone)
572 const GU_Detail *curve_input = inputGeo(theCurveInput);
574 OP_ERROR ret = cookInputPrimitiveGroups(context, curve_group, alone,
true, 0, -1,
true,
false,
GroupCreator(curve_input));
578 const GU_Detail *cross_section_input = inputGeo(theCrossSectionInput);
580 ret = cookInputPrimitiveGroups(context, cross_section_group, alone,
true, 1, -1,
true,
false,
GroupCreator(cross_section_input));
589 const char *
const SOP_SweepHDKVerb::theDsFile = R
"THEDSFILE(
595 label "Backbone Curve Group"
598 parmtag { "script_action" "import soputils\nkwargs['geometrytype'] = (hou.geometryType.Primitives,)\nkwargs['inputindex'] = 0\nsoputils.selectGroupParm(kwargs)" }
599 parmtag { "script_action_help" "Select geometry from an available viewport.\nShift-click to turn on Select Groups." }
600 parmtag { "script_action_icon" "BUTTONS_reselect" }
603 name "crosssectiongroup"
604 cppname "CrossSectionGroup"
605 label "Cross Section Group"
608 parmtag { "script_action" "import soputils\nkwargs['geometrytype'] = (hou.geometryType.Primitives,)\nkwargs['inputindex'] = 1\nsoputils.selectGroupParm(kwargs)" }
609 parmtag { "script_action_help" "Select geometry from an available viewport.\nShift-click to turn on Select Groups." }
610 parmtag { "script_action_icon" "BUTTONS_reselect" }
619 name "surface_folder"
623 cppname "SurfaceShape"
624 label "Surface Shape"
626 default { "0" } // Default to first entry in menu, "input"
628 "input" "Second Input Cross Sections"
630 "square" "Square Tube"
636 cppname "SurfaceType"
639 default { "5" } // Default to menu entry "quads"
644 "rowcol" "Rows and Columns"
646 "quads" "Quadrilaterals"
647 "alttris" "Alternating Triangles"
648 "revtris" "Reverse Triangles"
653 label "Scale Cross Sections"
657 disablewhen "{ surfaceshape != input }"
658 hidewhen "{ surfaceshape != input }"
666 disablewhen "{ surfaceshape == input }"
667 hidewhen "{ surfaceshape == input }"
675 parmtag { "units" "m1" }
676 disablewhen "{ surfaceshape != tube }"
677 hidewhen "{ surfaceshape != tube }"
685 parmtag { "units" "m1" }
686 disablewhen "{ surfaceshape != ribbon surfaceshape != square }"
687 hidewhen "{ surfaceshape != ribbon surfaceshape != square }"
690 name "reversecrosssections"
691 cppname "ReverseCrossSections"
692 label "Reverse Cross Sections"
697 name "stretcharoundturns"
698 cppname "StretchAroundTurns"
699 label "Stretch Around Turns"
704 name "maxstretcharoundturns"
705 cppname "MaxStretchAroundTurns"
710 disablewhen "{ stretcharoundturns == 0 }"
713 name "endcaps_folder"
720 default { "0" } // Default to menu entry "none"
723 "single" "Single Polygon"
725 "sidesingle" "Side Single Polygon"
731 label "Cap Divisions"
735 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
736 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
740 name "triangularpoles"
741 cppname "TriangularPoles"
742 label "Triangular Poles"
745 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
746 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
751 label "End Cap Scale"
755 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
756 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
760 cppname "CapRoundness"
761 label "End Cap Roundness"
765 disablewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
766 hidewhen "{ endcaptype == none } { endcaptype == single } { endcaptype == sidesingle }"
769 name "addendcapsgroup"
770 cppname "AddEndCapsGroup"
771 label "Add End Caps Group"
779 cppname "EndCapsGroup"
780 label "End Caps Group"
782 default { "endcaps" }
783 disablewhen "{ addendcapsgroup == 0 }"
792 label "Apply Scale Along Curve"
803 disablewhen "{ applyscale == 0 }"
804 parmtag { "rampfloatdefault" "1pos ( 0 ) 1value ( 1 ) 1interp ( linear ) 2pos ( 1 ) 2value ( 1 ) 2interp ( linear )" }
808 name "rotation_folder"
815 // NOTE: The default rotation order X,Y,Z is semi-arbitrary, but Z
816 // should probably be last, since it always needs to twist
817 // around the curve tangent. The X and Y rotations may have
818 // just been to reorient a cross-section before copying.
821 "xyz" "Pitch, Yaw, Roll"
822 "xzy" "Pitch, Roll, Yaw"
823 "yxz" "Yaw, Pitch, Roll"
824 "yzx" "Yaw, Roll, Pitch"
825 "zxy" "Roll, Pitch, Yaw"
826 "zyx" "Roll, Yaw, Pitch"
832 label "Apply Roll or Twist"
842 hidewhen "{ applyroll == 0 }"
851 hidewhen "{ applyroll == 0 }"
856 label "Partial Twist"
860 hidewhen "{ applyroll == 0 }"
868 default { "4" } // Default to "fulldistance" entry in menu
871 "distance" "Per Unit Distance"
872 "attrib" "Scale by Attribute"
873 "fulledges" "Per Full Curve by Edges"
874 "fulldistance" "Per Full Curve by Distance"
876 hidewhen "{ applyroll == 0 }"
881 label "Twist Ramp Attribute"
884 disablewhen "{ applyroll == 0 } { applyroll == 1 rollper != attrib }"
885 hidewhen "{ applyroll == 0 } { applyroll == 1 rollper != attrib }"
892 hidewhen "{ applyroll == 0 }"
907 hidewhen "{ applyyaw == 0 }"
912 label "Incremental Yaw"
916 hidewhen "{ applyyaw == 0 }"
924 default { "4" } // Default to "fulldistance" entry in menu
927 "distance" "Per Unit Distance"
928 "attrib" "Scale By Attribute"
929 "fulledges" "Per Full Curve by Edges"
930 "fulldistance" "Per Full Curve by Distance"
932 hidewhen "{ applyyaw == 0 }"
937 label "Yaw Ramp Attribute"
940 disablewhen "{ applyyaw == 0 } { applyyaw == 1 yawper != attrib }"
941 hidewhen "{ applyyaw == 0 } { applyyaw == 1 yawper != attrib }"
948 hidewhen "{ applyyaw == 0 }"
963 hidewhen "{ applypitch == 0 }"
968 label "Incremental Pitch"
972 hidewhen "{ applypitch == 0 }"
980 default { "4" } // Default to "fulldistance" entry in menu
983 "distance" "Per Unit Distance"
984 "attrib" "Scale By Attribute"
985 "fulledges" "Per Full Curve by Edges"
986 "fulldistance" "Per Full Curve by Distance"
988 hidewhen "{ applypitch == 0 }"
992 cppname "PitchAttrib"
993 label "Pitch Ramp Attribute"
996 disablewhen "{ applypitch == 0 } { applypitch == 1 pitchper != attrib }"
997 hidewhen "{ applypitch == 0 } { applypitch == 1 pitchper != attrib }"
1006 name "construction_folder"
1007 label "Construction"
1009 name "cross_sections_folder"
1010 label "Cross Sections"
1014 label "Cross Section Order"
1016 default { "1" } // Default to third entry in menu, "each"
1018 "all" "All Cross Sections At Each Curve Vertex"
1019 "each" "Each Cross Section At All Curve Vertices"
1020 "cyclevtx" "Cycle Through Cross Section Primitives per Vertex"
1021 "cyclepr" "Cycle Through Cross Section Primitives per Curve"
1022 "attrib" "Choose Cross Section Primitives by Attribute"
1024 disablewhen "{ surfaceshape != input }"
1027 name "crosssectionattrib"
1028 cppname "CrossSectionAttrib"
1029 label "Cross Section Attribute"
1031 default { "variant" }
1032 disablewhen "{ surfaceshape != input } { copyorder != attrib }"
1033 hidewhen "{ surfaceshape != input } { copyorder != attrib }"
1038 label "Primitive Type"
1040 default { "0" } // Default to menu entry "auto"
1044 "mesh" "Bilinear Mesh"
1045 "nurbs" "NURBS Surface"
1046 "bezier" "Bezier Surface"
1047 "polysoup" "Polygon Soup"
1049 disablewhen "{ surfacetype == points }"
1052 name "unrollclosedrowcol"
1053 cppname "UnrollClosedRowCol"
1054 label "Ensure Unique Seam Vertices"
1057 disablewhen "{ surfacetype == points }"
1061 cppname "SwapRowCol"
1062 label "Swap Rows and Columns"
1067 name "closeifnocurveinput"
1068 cppname "CloseIfNoCurveInput"
1069 label "Close Implicit Backbone Curve if No Curve Input"
1072 disablewhen "{ surfacetype == points } { surfacetype == rows } { hasinput(0) != 0 }"
1076 // cppname "SegDivs"
1077 // label "Segment Divisions"
1088 cppname "UpVectorType"
1089 label "Target Up Vector"
1091 default { "0" } // Default to first entry in menu, "normal"
1093 "normal" "Curve Normal"
1097 "attrib" "Attribute"
1100 disablewhen "{ tangenttype == none }"
1103 // name "usenormalup"
1104 // cppname "UseNormalUp"
1105 // label "Use Curve Normal as Up Vector (When Valid)"
1108 // disablewhen "{ tangenttype == none }"
1111 name "upvectoratstart"
1112 cppname "UpVectorAtStart"
1113 label "Target Up Vector at Start (else Average)"
1116 disablewhen "{ tangenttype == none }"
1119 name "useendupvector"
1120 cppname "UseEndUpVector"
1121 label "Use Target End Up Vector"
1124 disablewhen "{ tangenttype == none } { upvectoratstart == 0 }"
1127 name "upvectorattrib"
1128 cppname "UpVectorAttrib"
1129 label "Start Up Attribute"
1131 default { "start_up" }
1132 disablewhen "{ tangenttype == none } { upvectortype != attrib }"
1133 hidewhen "{ tangenttype == none } { upvectortype != attrib }"
1136 name "endupvectorattrib"
1137 cppname "EndUpVectorAttrib"
1138 label "End Up Attribute"
1140 default { "end_up" }
1141 disablewhen "{ tangenttype == none } { upvectortype != attrib } { useendupvector == 0 } { upvectoratstart == 0 }"
1142 hidewhen "{ tangenttype == none } { upvectortype != attrib } { useendupvector == 0 } { upvectoratstart == 0 }"
1147 label "Start Up Vector"
1150 default { "0" "1" "0" }
1151 disablewhen "{ tangenttype == none } { upvectortype != custom }"
1152 hidewhen "{ tangenttype == none } { upvectortype != custom }"
1156 cppname "EndUpVector"
1157 label "End Up Vector"
1160 default { "0" "1" "0" }
1161 disablewhen "{ tangenttype == none } { upvectortype != custom } { useendupvector == 0 } { upvectoratstart == 0 }"
1162 hidewhen "{ tangenttype == none } { upvectortype != custom } { useendupvector == 0 } { upvectoratstart == 0 }"
1166 name "tangents_folder"
1170 cppname "TangentType"
1171 label "Tangent Type"
1173 default { "0" } // Default to first entry in menu, "avgdir"
1175 "avgdir" "Average of Edge Directions"
1176 "diff" "Central Difference"
1177 "prev" "Previous Edge"
1179 "none" "Z Axis (Ignore Curve)"
1183 name "continuousclosed"
1184 cppname "ContinuousClosed"
1185 label "Make Closed Curve Orientations Continuous"
1188 disablewhen "{ tangenttype == none }"
1191 name "extrapolateendtangents"
1192 cppname "ExtrapolateEndTangents"
1193 label "Extrapolate End Tangents"
1196 disablewhen "{ tangenttype == none }"
1199 name "transformbyattribs"
1200 cppname "TransformByAttribs"
1201 label "Transform Using Curve Point Attributes"
1213 label "UVs and Attributes"
1216 label "UV Coordinates"
1219 cppname "ComputeUVs"
1225 name "overrideexistinguvs"
1226 cppname "OverrideExistingUVs"
1227 label "Override Any Existing UVs"
1230 disablewhen "{ computeuvs == 0 }"
1233 name "lengthweighteduvs"
1234 cppname "LengthWeightedUVs"
1235 label "Length-Weighted UVs"
1238 disablewhen "{ computeuvs == 0 }"
1242 cppname "NormalizeU"
1243 label "Normalize Computed Us"
1246 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1250 cppname "NormalizeV"
1251 label "Normalize Computed Vs"
1254 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1259 label "Flip Computed Us"
1262 disablewhen "{ computeuvs == 0 }"
1265 name "uvscale_folder"
1267 grouptag { "group_type" "collapsible" }
1268 parmtag { "group_default" "0" }
1276 disablewhen "{ computeuvs == 0 }"
1279 name "usemeshedgelengths"
1280 cppname "UseMeshEdgeLengths"
1281 label "Use Mesh Edge Lengths Instead of Curve Edge Lengths"
1284 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 }"
1287 name "propscalepercurve"
1288 cppname "PropScalePerCurve"
1289 label "Use Max Cross Section Length per Curve for Proportional Scale"
1292 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizeu != 1 } { normalizev != 0 }"
1296 name "uvseams_folder"
1298 grouptag { "group_type" "collapsible" }
1299 parmtag { "group_default" "0" }
1303 label "Snap U to Nearest Tile Boundary"
1306 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizeu == 1 }"
1311 label "Snap V to Nearest Tile Boundary"
1314 disablewhen "{ computeuvs == 0 } { lengthweighteduvs == 0 } { normalizev == 1 }"
1319 name "attributes_folder"
1321 grouptag { "group_type" "collapsible" }
1322 parmtag { "group_default" "0" }
1327 name "attribsfrombackbone"
1328 cppname "AttribsFromBackbone"
1329 label "From Backbone Curves"
1331 default { "* ^P ^N ^up ^pscale ^scale ^orient ^rot ^pivot ^trans ^transform" }
1334 name "attribsfromcrosssection"
1335 cppname "AttribsFromCrossSection"
1336 label "From Cross Sections"
1342 name "output_folder"
1346 cppname "AddPointRow"
1347 label "Add Point Row Attribute"
1355 cppname "PtRowAttrib"
1356 label "Point Row Attribute"
1359 disablewhen "{ addptrow == 0 }"
1363 cppname "AddPointCol"
1364 label "Add Point Col Attribute"
1372 cppname "PtColAttrib"
1373 label "Point Col Attribute"
1376 disablewhen "{ addptcol == 0 }"
1380 cppname "AddPrimRow"
1381 label "Add Prim Row Attribute"
1388 name "primrowattrib"
1389 cppname "PrimRowAttrib"
1390 label "Prim Row Attribute"
1392 default { "primrow" }
1393 disablewhen "{ addprimrow == 0 }"
1397 cppname "AddPrimCol"
1398 label "Add Prim Col Attribute"
1405 name "primcolattrib"
1406 cppname "PrimColAttrib"
1407 label "Prim Col Attribute"
1409 default { "primcol" }
1410 disablewhen "{ addprimcol == 0 }"
1413 name "addcrosssectionnum"
1414 cppname "AddCrossSectionNum"
1415 label "Add Cross Section Num Attribute"
1422 name "crosssectionnumattrib"
1423 cppname "CrossSectionNumAttrib"
1424 label "Cross Section Num Attribute"
1426 default { "crossnum" }
1427 disablewhen "{ addcrosssectionnum == 0 }"
1431 cppname "AddCurveNum"
1432 label "Add Curve Num Attribute"
1439 name "curvenumattrib"
1440 cppname "CurveNumAttrib"
1441 label "Curve Num Attribute"
1443 default { "curvenum" }
1444 disablewhen "{ addcurvenum == 0 }"
1446 // TODO: Add option to compute vertex normals with cusp angle.
1457 using namespace SOP_SweepHDKEnums;
1458 using namespace GU_CurveFrame;
1464 template<
typename T>
1466 insertIntoIntervals(
1467 const T *
const edge_lengths,
1468 const T total_length,
1470 const exint ninsertions,
1471 exint *
const ninsertions_per_edge)
1473 UT_ASSERT(nedges >= 1 && ninsertions >= 0);
1474 exint ninsertions_so_far = 0;
1475 for (
exint i = 0; i < nedges; ++i)
1477 T portion = (total_length > 0) ? (edge_lengths[i]/total_length) : (
T(1)/
T(nedges));
1484 ki =
SYSmin(ki, ninsertions-ninsertions_so_far);
1485 ninsertions_per_edge[i] = ki;
1486 ninsertions_so_far += ki;
1488 if (ninsertions_so_far == ninsertions)
1491 struct IntervalComparator {
1492 IntervalComparator(
const T *
const edge_lengths,
const exint *
const ninsertions_per_edge) :
1493 myEdgeLengths(edge_lengths),
1494 myNInsertionsPerEdge(ninsertions_per_edge)
1499 const T nadb = myEdgeLengths[
a]*(myNInsertionsPerEdge[
b]+1);
1500 const T nbda = myEdgeLengths[
b]*(myNInsertionsPerEdge[
a]+1);
1507 return nadb < nbda || (nadb == nbda && a <
b);
1509 const T *
const myEdgeLengths;
1510 const exint *
const myNInsertionsPerEdge;
1512 IntervalComparator comparator(edge_lengths, ninsertions_per_edge);
1516 if (nedges < 20 || (ninsertions-ninsertions_so_far) < 20) {
1518 exint edge_with_largest_intervals = 0;
1519 for (
exint i = 1; i < nedges; ++i) {
1520 if (comparator(edge_with_largest_intervals, i)) {
1521 edge_with_largest_intervals = i;
1524 ++ninsertions_per_edge[edge_with_largest_intervals];
1525 ++ninsertions_so_far;
1526 }
while (ninsertions_so_far < ninsertions);
1535 for (
exint i = 0; i < nedges; ++i)
1538 exint *
const heap_end = heap_begin+nedges;
1539 std::make_heap(heap_begin, heap_end, comparator);
1544 exint edge_with_largest_intervals = heap_begin[0];
1545 ++ninsertions_per_edge[edge_with_largest_intervals];
1546 ++ninsertions_so_far;
1547 if (ninsertions_so_far == ninsertions)
1551 std::pop_heap(heap_begin, heap_end, comparator);
1552 heap_end[-1] = edge_with_largest_intervals;
1553 std::push_heap(heap_begin, heap_end, comparator);
1562 switch (sop_primtype)
1579 return (i==0) ? 0 : (n-i);
1599 if (interrupt.wasInterrupted())
1617 if (interrupt.wasInterrupted())
1621 for (
GA_Offset primoff = start; primoff <
end; ++primoff)
1642 if (!reverse || closed)
1643 vtxoff0 = vertices(0);
1645 vtxoff0 = vertices(n-1);
1647 bool local_by_length = by_length;
1648 if (local_by_length)
1669 local_by_length =
false;
1675 float cur_length = 0;
1683 const float u = cur_length/
length;
1689 if (!local_by_length)
1692 GA_Size nedges = closed ? n : (n-1);
1697 const float u = i/
float(nedges);
1706 if (reverse && closed)
1715 static GA_Offset lookupCrossSectionFromAttrib(
1716 const CrossSectionAttribMatchData *copy_order_attrib_data,
1721 if (copy_order_attrib_data->myCurveIntAttrib.isValid())
1724 const exint id = copy_order_attrib_data->myCurveIntAttrib.get(curve_offset);
1725 if (copy_order_attrib_data->myIsUsingMap) {
1731 auto &&it = copy_order_attrib_data->myIntToPrimOff.find(
id);
1732 if (it == copy_order_attrib_data->myIntToPrimOff.end()) {
1743 if (cross_section_group && !cross_section_group->
contains(cross_section_primoff)) {
1747 return cross_section_primoff;
1751 UT_ASSERT_P(copy_order_attrib_data->myCurveStrAttrib.isValid());
1752 UT_ASSERT_P(copy_order_attrib_data->myIsUsingMap);
1759 auto &&it = copy_order_attrib_data->myStrToPrimOff.find(name);
1760 if (it == copy_order_attrib_data->myStrToPrimOff.end()) {
1771 int &primitive_type,
1772 unsigned char &fallback_orderu,
1793 if (pbasisu !=
nullptr)
1800 computeCombinedCrossSectionProperties(
1804 exint num_cross_sections,
1805 exint &cross_section_nedges,
1806 bool &cross_section_closed,
1807 bool &cross_section_unrolled,
1808 bool &varying_nedges,
1810 const bool is_primtype_auto,
1811 int &primitive_type,
1812 unsigned char &fallback_orderu,
1815 if (num_cross_sections == 0)
1823 bool basis_cross_section_closed;
1824 bool basis_cross_section_unrolled;
1827 cross_section_nedges = -1;
1828 varying_nedges =
false;
1830 for (
exint cross_sectioni = 0; cross_sectioni < num_cross_sections; ++cross_sectioni)
1832 GA_Offset cross_section_primoff = *cross_section_it;
1834 if (cross_section_it.
atEnd())
1837 cross_section_it.
rewind();
1841 cross_section_primoffs.
append(cross_section_primoff);
1843 exint local_cross_section_nedges;
1844 bool local_cross_section_closed;
1845 bool local_cross_section_unrolled;
1846 bool nonempty =
getPolyProperties(cross_section_input, cross_section_vertices, local_cross_section_nedges, local_cross_section_closed, local_cross_section_unrolled);
1852 if (cross_section_nedges == -1)
1855 cross_section_closed = local_cross_section_closed;
1856 cross_section_unrolled = local_cross_section_unrolled;
1858 else if (!local_cross_section_closed)
1862 cross_section_closed =
false;
1863 cross_section_unrolled =
false;
1865 else if (local_cross_section_unrolled && cross_section_closed && !cross_section_unrolled)
1869 cross_section_unrolled =
true;
1874 bool local_varying_nedges = (cross_section_nedges != -1 && local_cross_section_nedges != cross_section_nedges);
1876 varying_nedges |= local_varying_nedges;
1879 if (is_primtype_auto)
1881 local_primtype = updateAutoPrimType(cross_section_input, cross_section_primoff, primitive_type, fallback_orderu,
nullptr);
1885 if (local_cross_section_nedges > cross_section_nedges)
1887 cross_section_nedges = local_cross_section_nedges;
1889 if (is_primtype_auto && pbasisu !=
nullptr)
1895 basis_cross_section_closed = local_cross_section_closed;
1896 basis_cross_section_unrolled = local_cross_section_unrolled;
1911 if (pbasisu !=
nullptr && *pbasisu !=
nullptr)
1916 if (basis_primtype != primitive_type ||
1917 basis_cross_section_closed != cross_section_closed ||
1918 basis_cross_section_unrolled != cross_section_unrolled)
1933 computeCombinedCrossSectionPropertiesAttrib(
1938 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
1939 exint &cross_section_nedges,
1940 bool &cross_section_closed,
1941 bool &cross_section_unrolled,
1942 bool &varying_nedges,
1944 const bool is_primtype_auto,
1945 int &primitive_type,
1946 unsigned char &fallback_orderu,
1949 exint num_vertices = curve_vertices.
size();
1950 if (num_vertices == 0)
1953 const GA_AttributeOwner curve_owner = copy_order_attrib_data->myCurveAttribOwner;
1958 bool basis_cross_section_closed;
1959 bool basis_cross_section_unrolled;
1962 cross_section_nedges = -1;
1963 varying_nedges =
false;
1965 for (
exint vtxi = 0; vtxi < num_vertices; ++vtxi)
1967 GA_Offset curve_offset = curve_vertices[vtxi];
1969 curve_offset = curve_input->
vertexPoint(curve_offset);
1970 GA_Offset cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data, curve_offset, cross_section_input, cross_section_group);
1977 cross_section_primoffs.
append(cross_section_primoff);
1979 exint local_cross_section_nedges;
1980 bool local_cross_section_closed;
1981 bool local_cross_section_unrolled;
1982 bool nonempty =
getPolyProperties(cross_section_input, cross_section_vertices, local_cross_section_nedges, local_cross_section_closed, local_cross_section_unrolled);
1988 if (cross_section_nedges == -1)
1991 cross_section_closed = local_cross_section_closed;
1992 cross_section_unrolled = local_cross_section_unrolled;
1994 else if (!local_cross_section_closed)
1998 cross_section_closed =
false;
1999 cross_section_unrolled =
false;
2001 else if (local_cross_section_unrolled && cross_section_closed && !cross_section_unrolled)
2005 cross_section_unrolled =
true;
2010 bool local_varying_nedges = (cross_section_nedges != -1 && local_cross_section_nedges != cross_section_nedges);
2012 varying_nedges |= local_varying_nedges;
2015 if (is_primtype_auto)
2017 local_primtype = updateAutoPrimType(cross_section_input, cross_section_primoff, primitive_type, fallback_orderu,
nullptr);
2021 if (local_cross_section_nedges > cross_section_nedges)
2023 cross_section_nedges = local_cross_section_nedges;
2025 if (is_primtype_auto && pbasisu !=
nullptr)
2031 basis_cross_section_closed = local_cross_section_closed;
2032 basis_cross_section_unrolled = local_cross_section_unrolled;
2047 if (pbasisu !=
nullptr && *pbasisu !=
nullptr)
2052 if (basis_primtype != primitive_type ||
2053 basis_cross_section_closed != cross_section_closed ||
2054 basis_cross_section_unrolled != cross_section_unrolled)
2067 const bool output_points_only,
2068 const bool is_primtype_auto,
2069 int &primitive_type,
2070 unsigned char &fallback_orderv,
2080 fallback_orderv = 0;
2081 if (!is_primtype_auto)
2086 if (curve_input ==
nullptr)
2090 fallback_orderv = 4;
2097 bool is_curve =
false;
2126 computeSingleGridSetup(
2130 const bool single_cross_section,
2133 exint cross_section_nedges,
2134 bool cross_section_closed,
2135 bool cross_section_unrolled,
2137 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
2138 bool varying_nedges_all_case,
2144 const bool closed_if_no_curve_input,
2148 const bool output_points_only,
2149 const bool unroll_closed_row_col,
2150 const bool is_primtype_auto,
2152 unsigned char fallback_orderu,
2153 unsigned char fallback_orderv,
2156 exint cap_divisions,
2159 sop_SweepGrid &grid_info,
2162 const bool has_col_surface_type =
2165 const bool has_row_surface_type =
2168 const bool has_rowcol_surface_type =
2169 has_col_surface_type || has_row_surface_type;
2171 const bool is_polygon_type = (!output_points_only && primitive_type ==
GA_PRIMPOLY);
2172 const bool could_add_row_seam_vertex = (has_col_surface_type || !is_polygon_type) && unroll_closed_row_col;
2173 const bool could_add_col_seam_vertex = (has_row_surface_type || !is_polygon_type) && unroll_closed_row_col;
2175 if (curve_input ==
nullptr)
2178 UT_ASSERT(cross_section_input !=
nullptr);
2180 grid_info.myCurveClosed = closed_if_no_curve_input;
2181 grid_info.myCurveUnrolled = (grid_info.myCurveClosed && could_add_row_seam_vertex);
2183 grid_info.myCurveNEdges = num_cross_sections - !grid_info.myCurveClosed;
2185 bool varying_nedges;
2187 bool is_valid_grid = computeCombinedCrossSectionProperties(
2188 cross_section_input,
2189 cross_section_group,
2192 cross_section_nedges,
2193 cross_section_closed,
2194 cross_section_unrolled,
2196 cross_section_primoffs,
2205 grid_info.myCrossSectionNEdges = cross_section_nedges;
2206 grid_info.myCrossSectionClosed = cross_section_closed;
2207 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2208 grid_info.myAllEqualNEdges = !varying_nedges;
2209 grid_info.mySingleCrossSection = (cross_section_primoffs.
size() == 1);
2210 if (grid_info.mySingleCrossSection)
2211 grid_info.myCrossSectionPrimOff = cross_section_primoffs(0);
2213 grid_info.myCrossSectionPrimOffs =
new GA_OffsetList(std::move(cross_section_primoffs));
2218 grid_info.myCurvePrimOff = curve_primoff;
2222 bool curve_unrolled;
2224 bool nonempty =
getPolyProperties(curve_input, curve_vertices, curve_nedges, curve_closed, curve_unrolled);
2230 grid_info.myCurveClosed = curve_closed;
2231 grid_info.myCurveUnrolled = curve_unrolled || (curve_closed && could_add_row_seam_vertex);
2232 grid_info.myCurveNEdges = curve_nedges;
2234 if (single_cross_section)
2237 grid_info.myCrossSectionNEdges = cross_section_nedges;
2238 grid_info.myCrossSectionClosed = cross_section_closed;
2239 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2240 grid_info.myAllEqualNEdges =
true;
2241 grid_info.mySingleCrossSection =
true;
2242 grid_info.myCrossSectionPrimOff = single_cross_section_primoff;
2247 "Other cases should have resolved to single cross section grids.");
2249 bool varying_nedges = varying_nedges_all_case;
2251 if (copy_order == CopyOrder::CYCLEVTX)
2253 exint num_cross_sections = curve_nedges + !curve_closed;
2254 bool is_valid_grid = computeCombinedCrossSectionProperties(
2255 cross_section_input,
2256 cross_section_group,
2259 cross_section_nedges,
2260 cross_section_closed,
2261 cross_section_unrolled,
2263 cross_section_primoffs,
2274 bool is_valid_grid = computeCombinedCrossSectionPropertiesAttrib(
2275 cross_section_input,
2276 cross_section_group,
2279 copy_order_attrib_data,
2280 cross_section_nedges,
2281 cross_section_closed,
2282 cross_section_unrolled,
2284 cross_section_primoffs,
2294 grid_info.myCrossSectionNEdges = cross_section_nedges;
2295 grid_info.myCrossSectionClosed = cross_section_closed;
2296 grid_info.myCrossSectionUnrolled = cross_section_unrolled || (cross_section_closed && could_add_col_seam_vertex);
2297 grid_info.myAllEqualNEdges = !varying_nedges;
2298 grid_info.mySingleCrossSection =
false;
2301 exint ncopies = grid_info.myCurveNEdges + !grid_info.myCurveClosed;
2302 grid_info.myCurveNEdges = (ncopies * cross_section_primoffs_all_case->
size()) - !grid_info.myCurveClosed;
2304 for (
exint copyi = 0; copyi < ncopies; ++copyi)
2306 grid_info.myCrossSectionPrimOffs->append(*cross_section_primoffs_all_case);
2311 grid_info.myCrossSectionPrimOffs =
new GA_OffsetList(std::move(cross_section_primoffs));
2316 grid_info.myHasPolygonCaps =
2317 !output_points_only &&
2319 (end_cap_type == EndCapType::SINGLE &&
2320 (!grid_info.myCurveClosed && grid_info.myCrossSectionClosed && grid_info.myCrossSectionNEdges > 1)) ||
2321 (end_cap_type == EndCapType::SIDESINGLE &&
2322 (!grid_info.myCrossSectionClosed && grid_info.myCurveClosed && grid_info.myCurveNEdges > 1))
2324 !has_rowcol_surface_type;
2327 grid_info.myUEndPoles =
false;
2329 grid_info.myUEndPoles =
2330 !output_points_only &&
2331 (end_cap_type !=
EndCapType::NONE && end_cap_type != EndCapType::SINGLE && end_cap_type != EndCapType::SIDESINGLE) &&
2332 (!grid_info.myCrossSectionClosed && grid_info.myCurveClosed) &&
2339 grid_info.myVEndPoles =
2340 !output_points_only &&
2341 (end_cap_type !=
EndCapType::NONE && end_cap_type != EndCapType::SINGLE && end_cap_type != EndCapType::SIDESINGLE) &&
2342 (!grid_info.myCurveClosed) &&
2345 if (grid_info.myUEndPoles)
2348 grid_info.myCrossSectionNEdges += 2*cap_divisions;
2351 UT_ASSERT(grid_info.myCurveNEdges >= 1);
2353 else if (grid_info.myVEndPoles)
2356 grid_info.myCurveNEdges += 2*cap_divisions;
2358 if (!grid_info.mySingleCrossSection)
2362 GA_OffsetList &primoffs = *grid_info.myCrossSectionPrimOffs;
2363 for (
exint i = 0; i < cap_divisions; ++i)
2364 new_cross_section_primoffs.
append(primoffs(0));
2365 new_cross_section_primoffs.
append(primoffs);
2366 for (
exint i = 0; i < cap_divisions; ++i)
2367 new_cross_section_primoffs.
append(primoffs.
last());
2368 primoffs = std::move(new_cross_section_primoffs);
2372 UT_ASSERT(grid_info.myCrossSectionNEdges >= 1);
2375 using PrimitiveType = sop_SweepGrid::PrimitiveType;
2376 grid_info.myPrimitiveType = PrimitiveType::POINTS;
2377 if (!output_points_only)
2379 grid_info.myPrimitiveType = PrimitiveType::POLYGON;
2381 grid_info.myPrimitiveType = PrimitiveType::POLYSOUP;
2383 grid_info.myPrimitiveType = PrimitiveType::MESH;
2385 grid_info.myPrimitiveType = PrimitiveType::NURBS;
2387 grid_info.myPrimitiveType = PrimitiveType::BEZIER;
2391 if (grid_info.myPrimitiveType != PrimitiveType::POLYGON &&
2392 (grid_info.myCurveNEdges <= 0 || grid_info.myCrossSectionNEdges <= 0))
2394 grid_info.myPrimitiveType = PrimitiveType::POLYGON;
2397 if (grid_info.myPrimitiveType == PrimitiveType::NURBS)
2399 if (fallback_orderv == 0)
2404 fallback_orderv = (is_primtype_auto && curve_input !=
nullptr) ? 2 : 4;
2406 exint curve_nvertices = grid_info.myCurveNEdges + (!grid_info.myCurveClosed || grid_info.myCurveUnrolled);
2407 if (curve_nvertices < fallback_orderv)
2411 fallback_orderv =
SYSclamp(
int(curve_nvertices), 2, 3);
2413 if (fallback_orderu == 0)
2416 fallback_orderu = (is_primtype_auto && cross_section_input !=
nullptr) ? 2 : 4;
2418 exint cross_section_nvertices = grid_info.myCrossSectionNEdges + (!grid_info.myCrossSectionClosed || grid_info.myCrossSectionUnrolled);
2419 if (cross_section_nvertices < fallback_orderu)
2423 fallback_orderu =
SYSclamp(
int(cross_section_nvertices), 2, 3);
2426 else if (grid_info.myPrimitiveType == PrimitiveType::BEZIER)
2428 if (fallback_orderv == 0)
2433 fallback_orderv = is_primtype_auto ? 2 : 4;
2435 if (grid_info.myCurveNEdges % (fallback_orderv-1) != 0)
2438 fallback_orderv = 2;
2440 if (fallback_orderu == 0)
2443 fallback_orderu = is_primtype_auto ? 2 : 4;
2445 if (grid_info.myCrossSectionNEdges % (fallback_orderu-1) != 0)
2448 fallback_orderu = 2;
2451 grid_info.myBasisOrderCrossSection = fallback_orderu;
2452 grid_info.myBasisOrderCurve = fallback_orderv;
2455 num_points = (grid_info.myCurveNEdges + !grid_info.myCurveClosed - 2*
exint(grid_info.myVEndPoles))
2456 * (grid_info.myCrossSectionNEdges + !grid_info.myCrossSectionClosed - 2*
exint(grid_info.myUEndPoles))
2457 + 2*
exint(grid_info.myVEndPoles) + 2*
exint(grid_info.myUEndPoles);
2462 template<
typename T>
2465 const sop_SweepGrid &grid_info,
2467 const bool output_points_only,
2468 const bool triangular_poles,
2469 const bool swap_row_col,
2470 const T grid_start_ptnum,
2476 grid.
myUnrollCurves = grid_info.myCurveUnrolled || grid_info.myCrossSectionUnrolled;
2479 bool is_single_grid_prim =
false;
2480 if (output_points_only)
2485 is_single_grid_prim = (grid.
myPrimitiveType != PrimitiveType::POLYGON);
2494 const exint nedgerows = swap_row_col ? grid_info.myCrossSectionNEdges : grid_info.myCurveNEdges;
2495 const exint nedgecols = swap_row_col ? grid_info.myCurveNEdges : grid_info.myCrossSectionNEdges;
2496 bool vclosed = swap_row_col ? grid_info.myCrossSectionClosed : grid_info.myCurveClosed;
2497 bool uclosed = swap_row_col ? grid_info.myCurveClosed : grid_info.myCrossSectionClosed;
2498 bool uendpoles = swap_row_col ? grid_info.myVEndPoles : grid_info.myUEndPoles;
2499 bool vendpoles = swap_row_col ? grid_info.myUEndPoles : grid_info.myVEndPoles;
2500 if (is_single_grid_prim)
2504 if (nvtxrows < 2 || nvtxcols < 2)
2506 is_single_grid_prim =
false;
2511 unsigned char orderv = swap_row_col ? grid_info.myBasisOrderCrossSection : grid_info.myBasisOrderCurve;
2512 unsigned char orderu = swap_row_col ? grid_info.myBasisOrderCurve : grid_info.myBasisOrderCrossSection;
2520 grid.
initTorus(nedgerows, nedgecols, grid_start_ptnum);
2521 else if (!uendpoles)
2522 grid.
initRowTube(nedgerows, nedgecols, grid_start_ptnum);
2527 const exint nmid_points = nedgerows*(nedgecols - 1);
2528 grid.
initRowSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2536 grid.
initColTube(nedgerows, nedgecols, grid_start_ptnum);
2541 const exint nmid_points = (nedgerows - 1)*nedgecols;
2542 grid.
initColSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2553 const exint nmid_points = (nedgerows - 1)*(nedgecols+1);
2554 grid.
initSplitColSphere(nedgerows, nedgecols, grid_start_ptnum, grid_start_ptnum+1+nmid_points, grid_start_ptnum+1);
2561 appendPrimTypeCountPair(
2562 UT_Array<std::pair<int,exint>> &prim_type_count_pairs,
2566 if (prim_type_count_pairs.isEmpty() || prim_type_count_pairs.last().first != primtype)
2568 prim_type_count_pairs.append(std::pair<int,exint>(primtype, count));
2572 prim_type_count_pairs.last().second += count;
2585 if (!(closed_span_lengths.
size() & 1) == closed)
2586 ++closed_span_lengths.
last();
2588 closed_span_lengths.
append(1);
2595 appendSingleGridTopology(
2596 const sop_SweepGrid &grid_info,
2598 const bool output_points_only,
2599 const bool triangular_poles,
2600 const bool single_polygon_caps,
2601 const bool swap_row_col,
2603 UT_Array<std::pair<int,exint>> &prim_type_count_pairs,
2613 exint grid_start_ptnum =
exint(grid_info.myStartPtOff);
2615 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_start_ptnum, grid);
2620 if (num_grid_prims == 0)
2623 bool current_has_polygon_caps = grid_info.myHasPolygonCaps;
2624 bool is_row_cap = current_has_polygon_caps && grid.
myNoWrapV;
2625 bool is_cross_section_cap = !grid_info.myCrossSectionClosed;
2626 exint cap_count = current_has_polygon_caps ? 2 : 0;
2651 appendPrimTypeCountPair(prim_type_count_pairs, primtype, num_grid_prims + cap_count);
2655 appendPrimTypeCountPair(prim_type_count_pairs, cap_primtype, 1);
2656 appendPrimTypeCountPair(prim_type_count_pairs, primtype, num_grid_prims);
2657 appendPrimTypeCountPair(prim_type_count_pairs, cap_primtype, 1);
2660 exint cap_vertex_count = 0;
2661 if (current_has_polygon_caps)
2663 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)
2665 vertexlistsizelist.append(cap_vertex_count);
2668 appendClosedSpans(closed_span_lengths,
true);
2670 const exint old_size = vertexpointnumbers.
size();
2671 vertexpointnumbers.
bumpSize(old_size + cap_vertex_count);
2672 exint *vertexpointnumber_start = vertexpointnumbers.
getArray() + old_size;
2676 exint row = last_cap ? grid.myNumEdgeRows : 0;
2677 for (
exint col = 0; col < cap_vertex_count; ++col)
2679 exint point_col = ((last_cap != swap_row_col) != is_cross_section_cap) ? col : reverseVtx(col, cap_vertex_count,
true);
2680 vertexpointnumber_start[col] = grid.getPoint(row, point_col);
2686 exint col = last_cap ? grid.myNumEdgeCols : 0;
2687 for (
exint row = 0; row < cap_vertex_count; ++
row)
2689 exint point_row = ((last_cap != swap_row_col) != is_cross_section_cap) ? row : reverseVtx(row, cap_vertex_count,
true);
2690 vertexpointnumber_start[
row] = grid.getPoint(point_row, col);
2694 if (current_has_polygon_caps)
2697 add_polygon_cap_functor(
false);
2702 [&vertexlistsizelist,&closed_span_lengths
2708 UT_ASSERT_P(primnum >= 0 && primnum < num_grid_prims);
2709 vertexlistsizelist.append(primvtxcount);
2711 appendClosedSpans(closed_span_lengths, closed);
2714 const exint old_size = vertexpointnumbers.
size();
2715 vertexpointnumbers.
bumpSize(old_size + grid.myNumVertices);
2716 exint *vertexpointnumber_start = vertexpointnumbers.
getArray() + old_size;
2718 [vertexpointnumber_start,&grid](
exint vtxnum,
exint row,
exint col,
bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
2720 UT_ASSERT_P(vtxnum >= 0 && vtxnum < grid.myNumVertices);
2721 vertexpointnumber_start[vtxnum] = grid.getPoint(row+
exint(isrowend),col+
exint(iscolend));
2724 if (current_has_polygon_caps)
2727 add_polygon_cap_functor(
true);
2732 num_grid_prims += cap_count;
2733 num_grid_verts += 2*cap_vertex_count;
2737 initNonPolyGridPrims(
2738 const sop_SweepGrid &grid_info,
2740 const bool swap_row_col,
2750 GA_Offset primoff = grid_info.myStartPrimOff;
2751 if (grid_info.myHasPolygonCaps)
2759 const exint nvtxrows = nedgerows +
exint(!hull_wrapv);
2760 const exint nvtxcols = nedgecols +
exint(!hull_wrapu);
2767 sop_SweepGrid polygrid_info(grid_info);
2768 polygrid_info.myPrimitiveType = sop_SweepGrid::PrimitiveType::POLYGON;
2776 polygonsizes.
append(primvtxcount, 1);
2794 exint cap_vertex_count = 0;
2795 if (grid_info.myHasPolygonCaps)
2797 cap_vertex_count = !grid_info.myCurveClosed ? grid_info.myCrossSectionNEdges : grid_info.myCurveNEdges;
2799 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
2801 [&polygonvertexlist,start_vtxoff,&grid,has_endrow,has_endcol,nvtxcols](
exint vtxnum,
exint row,
exint col,
2802 bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
2819 exint soupvtxnum = row*nvtxcols + col;
2820 polygonvertexlist.append(start_vtxoff + soupvtxnum);
2831 hull->
initHullData(nvtxrows, nvtxcols, hull_wrapv, hull_wrapu);
2835 const bool is_bezier = (grid.
myPrimitiveType == PrimitiveType::BEZIER);
2836 if (!is_nurbs && !is_bezier)
2845 if (source_basisu !=
nullptr && source_basisu->
getType() != basis_type)
2846 source_basisu =
nullptr;
2847 if (source_basisv !=
nullptr && source_basisv->
getType() != basis_type)
2848 source_basisv =
nullptr;
2851 if (source_basisu !=
nullptr)
2854 basisu->copyFrom(*source_basisu);
2865 if (source_basisv !=
nullptr)
2885 bool interpolate_ends = !closed;
2886 int extra_knots = order + (closed ? (interpolate_ends ? 1 : (order - 1)) : 0);
2891 (nvertices + extra_knots),
2896 if (basisu ==
nullptr)
2898 basisu = make_nurbs_basis(nvtxcols, grid.
myBasisOrderU, hull_wrapu);
2902 if (basisv ==
nullptr)
2904 basisv = make_nurbs_basis(nvtxrows, grid.
myBasisOrderV, hull_wrapv);
2915 int extra = ((nvertices > 2 && order > 2) || (order <= 2 && closed));
2917 extra + (nvertices / (order - 1)),
2920 if (basisu ==
nullptr)
2922 basisu = make_bez_basis(nvtxcols, grid.
myBasisOrderU, hull_wrapu);
2926 if (basisv ==
nullptr)
2928 basisv = make_bez_basis(nvtxrows, grid.
myBasisOrderV, hull_wrapv);
2939 if (grid_info.myHasPolygonCaps)
2941 const bool side_caps = !grid_info.myCrossSectionClosed;
2942 const GA_Basis *cap_source_basis = (swap_row_col != side_caps) ? basisv : basisu;
2946 cap0_basis->
copyFrom(*cap_source_basis);
2947 cap1_basis->copyFrom(*cap_source_basis);
2952 cap1->setBasis(cap1_basis);
2961 exint cross_section_nedges,
2963 const CrossSectionAttribMatchData *
const copy_order_attrib_data,
2967 const bool closed_if_no_curve_input,
2970 const bool output_points_only,
2971 const bool unroll_closed_row_col,
2972 const int primitive_type,
2974 const exint cap_divisions,
2975 const bool triangular_poles,
2976 const bool swap_row_col,
2988 if (interrupt.wasInterrupted())
2995 if (cross_section_input !=
nullptr && (
3000 exint max_num_grids = 1;
3001 if (curve_input !=
nullptr)
3006 if (curve_input !=
nullptr && (
3016 bool single_cross_section =
true;
3018 bool cross_section_closed = (cross_section_shape == SurfaceShape::TUBE || cross_section_shape == SurfaceShape::SQUARE);
3019 bool cross_section_unrolled =
false;
3021 if (cross_section_input !=
nullptr)
3024 cross_section_range = cross_section_input->
getPrimitiveRange(cross_section_group);
3026 if (ncross_sections == 0)
3036 if (single_cross_section)
3042 single_cross_section_primoff = *it;
3043 bool nonempty =
getPolyProperties(cross_section_input, single_cross_section_primoff,
3044 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3051 if (!single_cross_section || curve_input ==
nullptr)
3052 cross_section_it =
GA_Iterator(cross_section_range);
3054 const bool is_primtype_auto = !output_points_only && (primitive_type ==
GA_PRIMNONE);
3061 closed_span_lengths.
append(0);
3065 bool hassharedpoints =
true;
3066 exint total_num_points = 0;
3067 exint total_num_verts = 0;
3068 exint total_num_prims = 0;
3069 if (curve_input ==
nullptr)
3072 UT_ASSERT(cross_section_input !=
nullptr);
3076 int local_primitive_type = primitive_type;
3077 unsigned char fallback_orderu = 0;
3078 unsigned char fallback_orderv;
3082 local_primitive_type,
3087 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[0];
3089 sop_SweepGrid grid_info;
3091 bool valid_grid = computeSingleGridSetup(
3092 cross_section_input,
3093 cross_section_group,
3097 0,
false,
false, CopyOrder::CYCLEVTX,
nullptr,
false,
nullptr,
3099 closed_if_no_curve_input,
3100 surface_type, output_points_only,
3101 unroll_closed_row_col,
3103 local_primitive_type,
3104 fallback_orderu, fallback_orderv,
3108 grid_info, num_points);
3114 total_num_points = num_points;
3116 exint num_grid_prims;
3117 exint num_grid_verts;
3118 appendSingleGridTopology(
3119 grid_info, surface_type, output_points_only, triangular_poles,
3120 grid_info.myHasPolygonCaps, swap_row_col,
3121 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3122 closed_span_lengths, num_grid_prims, num_grid_verts);
3125 total_num_verts = num_grid_verts;
3126 grid_info.myStartPrimOff =
GA_Offset(0);
3127 total_num_prims = num_grid_prims;
3128 grids.
append(std::move(grid_info));
3130 else if (!single_cross_section && copy_order == CopyOrder::EACH)
3134 for (; !cross_section_it.
atEnd(); ++cross_section_it)
3136 GA_Offset cross_section_primoff = *cross_section_it;
3139 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3147 if (interrupt.wasInterrupted())
3152 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3155 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3156 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3158 int local_primitive_type = primitive_type;
3159 unsigned char fallback_orderu = 0;
3160 unsigned char fallback_orderv;
3164 local_primitive_type,
3171 if (is_primtype_auto && cross_section_input !=
nullptr)
3172 updateAutoPrimType(cross_section_input, cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3174 sop_SweepGrid grid_info;
3176 bool valid_grid = computeSingleGridSetup(
3180 cross_section_primoff,
3181 cross_section_nedges,
3182 cross_section_closed,
3183 cross_section_unrolled,
3188 curve_input, curve_primoff,
3192 unroll_closed_row_col,
3194 local_primitive_type,
3195 fallback_orderu, fallback_orderv,
3205 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3206 total_num_points += num_points;
3208 exint num_grid_prims;
3209 exint num_grid_verts;
3210 appendSingleGridTopology(
3211 grid_info, surface_type, output_points_only, triangular_poles,
3212 grid_info.myHasPolygonCaps, swap_row_col,
3213 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3214 closed_span_lengths, num_grid_prims, num_grid_verts);
3216 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3217 total_num_verts += num_grid_verts;
3218 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3219 total_num_prims += num_grid_prims;
3220 grids.
append(std::move(grid_info));
3225 else if (!single_cross_section && (copy_order == CopyOrder::CYCLEPR ||
3236 cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data,
3242 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3251 if (interrupt.wasInterrupted())
3256 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3258 if (copy_order == CopyOrder::CYCLEPR)
3260 cross_section_primoff = *cross_section_it;
3262 if (cross_section_it.
atEnd())
3264 cross_section_it.
rewind();
3270 cross_section_primoff = lookupCrossSectionFromAttrib(copy_order_attrib_data,
3271 curve_primoff, cross_section_input, cross_section_group);
3280 cross_section_nedges, cross_section_closed, cross_section_unrolled);
3286 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3287 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3289 int local_primitive_type = primitive_type;
3290 unsigned char fallback_orderu = 0;
3291 unsigned char fallback_orderv;
3295 local_primitive_type,
3302 if (is_primtype_auto && cross_section_input !=
nullptr)
3303 updateAutoPrimType(cross_section_input, cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3305 sop_SweepGrid grid_info;
3307 bool valid_grid = computeSingleGridSetup(
3311 cross_section_primoff,
3312 cross_section_nedges,
3313 cross_section_closed,
3314 cross_section_unrolled,
3319 curve_input, curve_primoff,
3321 surface_type, output_points_only,
3322 unroll_closed_row_col,
3324 local_primitive_type,
3325 fallback_orderu, fallback_orderv,
3329 grid_info, num_points);
3334 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3335 total_num_points += num_points;
3337 exint num_grid_prims;
3338 exint num_grid_verts;
3339 appendSingleGridTopology(
3340 grid_info, surface_type, output_points_only, triangular_poles,
3341 grid_info.myHasPolygonCaps, swap_row_col,
3342 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3343 closed_span_lengths, num_grid_prims, num_grid_verts);
3345 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3346 total_num_verts += num_grid_verts;
3347 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3348 total_num_prims += num_grid_prims;
3349 grids.
append(std::move(grid_info));
3355 unsigned char fallback_orderu = 0;
3356 int cross_section_primitive_type = is_primtype_auto ?
GA_PRIMPOLY : primitive_type;
3357 bool varying_nedges_all_case =
false;
3359 const bool all_case = (!single_cross_section && copy_order ==
CopyOrder::ALL);
3360 const GA_Basis *all_case_grid_basisu =
nullptr;
3368 bool is_valid_grid = computeCombinedCrossSectionProperties(
3369 cross_section_input,
3370 cross_section_group,
3373 cross_section_nedges,
3374 cross_section_closed,
3375 cross_section_unrolled,
3376 varying_nedges_all_case,
3377 cross_section_primoffs_all_case,
3379 cross_section_primitive_type,
3381 &all_case_grid_basisu);
3392 if (interrupt.wasInterrupted())
3395 for (
GA_Offset curve_primoff = start; curve_primoff <
end; ++curve_primoff)
3398 const GA_Basis **pbasisu = grid_basisus.
isEmpty() ?
nullptr : &grid_basisus[gridi];
3399 const GA_Basis **pbasisv = grid_basisvs.
isEmpty() ?
nullptr : &grid_basisvs[gridi];
3401 int local_primitive_type = primitive_type;
3402 unsigned char fallback_orderv;
3406 local_primitive_type,
3413 if (single_cross_section && is_primtype_auto && cross_section_input !=
nullptr)
3414 updateAutoPrimType(cross_section_input, single_cross_section_primoff, local_primitive_type, fallback_orderu, pbasisu);
3418 local_primitive_type = cross_section_primitive_type;
3421 if (all_case && pbasisu !=
nullptr)
3425 *pbasisu = all_case_grid_basisu;
3428 sop_SweepGrid grid_info;
3430 bool valid_grid = computeSingleGridSetup(
3431 cross_section_input,
3432 cross_section_group,
3433 single_cross_section,
3435 single_cross_section_primoff,
3436 cross_section_nedges,
3437 cross_section_closed,
3438 cross_section_unrolled,
3440 copy_order_attrib_data,
3441 varying_nedges_all_case,
3442 (cross_section_primoffs_all_case.
size() == 0) ?
nullptr : &cross_section_primoffs_all_case,
3443 curve_input, curve_primoff,
3444 closed_if_no_curve_input,
3445 surface_type, output_points_only,
3446 unroll_closed_row_col,
3448 local_primitive_type,
3449 fallback_orderu, fallback_orderv,
3453 grid_info, num_points);
3458 grid_info.myStartPtOff =
GA_Offset(total_num_points);
3459 total_num_points += num_points;
3461 exint num_grid_prims;
3462 exint num_grid_verts;
3463 appendSingleGridTopology(
3464 grid_info, surface_type, output_points_only, triangular_poles,
3465 grid_info.myHasPolygonCaps, swap_row_col,
3466 prim_type_count_pairs, vertexlistsizelist, vertexpointnumbers,
3467 closed_span_lengths, num_grid_prims, num_grid_verts);
3469 grid_info.myStartVtxOff =
GA_Offset(total_num_verts);
3470 total_num_verts += num_grid_verts;
3471 grid_info.myStartPrimOff =
GA_Offset(total_num_prims);
3472 total_num_prims += num_grid_prims;
3473 grids.
append(std::move(grid_info));
3478 if (interrupt.wasInterrupted())
3485 if (output_points_only)
3491 prim_type_count_pairs.getArray(),
3492 start_ptoff, total_num_points,
3493 vertexlistsizelist, vertexpointnumbers.
getArray(),
3510 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3512 grids[gridi].myStartPtOff += start_ptoff;
3517 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3519 grids[gridi].myStartVtxOff += start_vtxoff;
3524 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3526 grids[gridi].myStartPrimOff += start_primoff;
3534 for (
exint gridi = 0, num_grids = grids.
size(); gridi < num_grids; ++gridi)
3536 const sop_SweepGrid &grid_info = grids[gridi];
3538 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3539 const GA_Basis *basisu = grid_basisus.
isEmpty() ?
nullptr : grid_basisus[gridi];
3540 const GA_Basis *basisv = grid_basisvs.
isEmpty() ?
nullptr : grid_basisvs[gridi];
3543 initNonPolyGridPrims(grid_info, grid, swap_row_col, basisu, basisv, output_geo);
3551 template<
typename FUNCTOR>
3553 copyVertexCrossSectionWrapper(
3555 const sop_SweepGrid &grid_info,
3556 const FUNCTOR &functor)
3560 exint cap_vertex_count = 0;
3561 if (grid_info.myHasPolygonCaps)
3568 for (
exint col = 0; col < cap_vertex_count; ++col)
3571 functor(grid_info.myStartVtxOff + col, 0, reverseVtx(col, cap_vertex_count,
true));
3579 for (
exint row = 0; row < cap_vertex_count; ++
row)
3582 functor(grid_info.myStartVtxOff + row, reverseVtx(row, cap_vertex_count,
true), 0);
3587 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
3588 auto &&functor_wrapper = [&functor,start_vtxoff](
exint vtxnum,
exint row,
exint col,
bool isrowend,
bool iscolend,
exint primnum,
exint primvtxnum)
3590 GA_Offset output_vtxoff = start_vtxoff + vtxnum;
3591 functor(output_vtxoff, row +
exint(isrowend), col +
exint(iscolend));
3594 if (grid_info.myHasPolygonCaps)
3601 for (
exint col = 0; col < cap_vertex_count; ++col)
3609 for (
exint row = 0; row < cap_vertex_count; ++
row)
3617 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>
3619 copyCrossSectionAttributeWrapper2(
3621 const OUTPUT_ATTRIB_T &outputh,
3622 const INPUT_ATTRIB_T &cross_sectionh,
3625 const sop_SweepGridTransformWrapper *transforms,
3626 const sop_SweepGrid &grid_info,
3627 const bool reverse_cross_sections,
3628 const bool swap_row_col,
3629 const GET_TRANSFORM_FUNCTOR &get_transform_functor,
3630 const TRANSFORM_FUNCTOR &transform_and_copy_functor,
3631 const INTERP_FUNCTOR &transform_and_interp_functor)
3634 UT_ASSERT(cross_section_owner == output_attrib_owner ||
3638 exint prev_curve_vtxi = -1;
3641 exint current_cross_section_nedges;
3642 bool current_cross_section_closed;
3643 bool current_cross_section_unrolled;
3645 auto &&functor = [&grid_info,&outputh,&cross_sectionh,
3646 cross_section_owner,
3647 &get_transform_functor,&transform_and_copy_functor,
3648 &transform_and_interp_functor,
3649 cross_section_input,
3651 reverse_cross_sections,
3654 &source_cross_section_primoff,
3655 &cross_section_vertices,
3656 ¤t_cross_section_nedges,
3657 ¤t_cross_section_closed,
3658 ¤t_cross_section_unrolled,
3661 exint num_curve_edges = grid_info.myCurveNEdges;
3662 bool is_curve_closed = grid_info.myCurveClosed;
3663 exint curve_vtxi = swap_row_col ? col :
row;
3664 exint num_cross_section_edges = grid_info.myCrossSectionNEdges;
3666 exint cross_section_vtxi = swap_row_col ? row : col;
3668 if (curve_vtxi != prev_curve_vtxi)
3673 if (output_attrib_owner ==
GA_ATTRIB_VERTEX && is_curve_closed && curve_vtxi == num_curve_edges)
3675 transform = get_transform_functor(transforms, curve_vtxi, grid_info);
3676 source_cross_section_primoff =
3677 grid_info.mySingleCrossSection ?
3678 GA_Offset(grid_info.myCrossSectionPrimOff) :
3683 cross_section_vertices = cross_section_input->getPrimitiveVertexList(source_cross_section_primoff);
3684 getPolyProperties(cross_section_input, cross_section_vertices, current_cross_section_nedges, current_cross_section_closed, current_cross_section_unrolled);
3686 prev_curve_vtxi = curve_vtxi;
3691 transform_and_copy_functor(cross_sectionh, source_cross_section_primoff, transform, outputh, output_offset);
3695 constexpr
bool is_vertex_attrib = (output_attrib_owner ==
GA_ATTRIB_VERTEX);
3697 if (current_cross_section_nedges == num_cross_section_edges)
3701 if (reverse_cross_sections)
3704 cross_section_vtxi = reverseVtx(cross_section_vtxi, current_cross_section_nedges +
exint(is_vertex_attrib || !current_cross_section_closed),
3705 !is_vertex_attrib && current_cross_section_closed);
3712 if (cross_section_vtxi == cross_section_vertices.size())
3714 if (wrap_to_invalid)
3721 vtxoff = cross_section_vertices[0];
3724 vtxoff = cross_section_vertices[cross_section_vtxi];
3726 transform_and_copy_functor(cross_sectionh, cross_section_offset, transform, outputh, output_offset);
3733 UT_ASSERT_P(num_cross_section_edges > current_cross_section_nedges);
3738 exint fine_fractions = cross_section_vtxi*current_cross_section_nedges;
3739 if (reverse_cross_sections)
3740 fine_fractions = num_cross_section_edges*current_cross_section_nedges - fine_fractions;
3741 exint current_cross_section_edge = fine_fractions / num_cross_section_edges;
3742 exint current_cross_section_fractions = fine_fractions % num_cross_section_edges;
3743 exint current_cross_section_pt = current_cross_section_fractions / current_cross_section_nedges;
3744 if (current_cross_section_pt == 0)
3748 if (current_cross_section_edge == cross_section_vertices.size())
3750 if (wrap_to_invalid)
3757 vtxoff = cross_section_vertices[0];
3760 vtxoff = cross_section_vertices[current_cross_section_edge];
3762 transform_and_copy_functor(cross_sectionh, cross_section_offset, transform, outputh, output_offset);
3770 exint current_cross_section_edge_start = (current_cross_section_edge*num_cross_section_edges + current_cross_section_nedges-1) / current_cross_section_nedges;
3771 exint current_cross_section_edge_end = ((current_cross_section_edge+1)*num_cross_section_edges + current_cross_section_nedges-1) / current_cross_section_nedges;
3772 exint current_cross_section_edge_npts = current_cross_section_edge_end - current_cross_section_edge_start;
3773 double u = double(current_cross_section_pt)/double(current_cross_section_edge_npts);
3777 UT_ASSERT_P(current_cross_section_edge != current_cross_section_nedges);
3778 exint vtxi0 = current_cross_section_edge;
3779 GA_Offset vtxoff0 = cross_section_vertices[vtxi0];
3782 if (current_cross_section_edge+1 == cross_section_vertices.size())
3784 if (wrap_to_invalid)
3791 vtxoff1 = cross_section_vertices[0];
3794 vtxoff1 = cross_section_vertices[current_cross_section_edge+1];
3800 cross_section_offset0 = vtxoff0;
3801 cross_section_offset1 = vtxoff1;
3805 cross_section_offset0 = cross_section_input->vertexPoint(vtxoff0);
3807 cross_section_offset1 = cross_section_input->vertexPoint(vtxoff1);
3809 cross_section_offset1 = vtxoff1;
3811 transform_and_interp_functor(cross_sectionh, cross_section_offset0, cross_section_offset1, u, transform, outputh, output_offset);
3820 copyVertexCrossSectionWrapper(grid, grid_info, functor);
3827 if (grid_info.myHasPolygonCaps)
3830 functor(grid_info.myStartPrimOff, 0, 0);
3833 const GA_Offset start_primoff = grid_info.myStartPrimOff +
exint(grid_info.myHasPolygonCaps);
3834 auto &&functor_wrapper = [&functor,start_primoff](
exint primnum,
exint row,
exint col,
exint primvtxcount,
bool closed)
3836 GA_Offset output_primoff = start_primoff + primnum;
3837 functor(output_primoff, row, col);
3840 if (grid_info.myHasPolygonCaps)
3857 template<
typename VALUE_T,
typename TRANSFORM_T,GA_AttributeOwner attrib_owner,
typename GET_TRANSFORM_FUNCTOR,
typename TRANSFORM_FUNCTOR,
typename INTERP_FUNCTOR>
3859 copyCrossSectionAttributeWrapper(
3864 const sop_SweepGridTransformWrapper *transforms,
3865 const sop_SweepGrid &grid_info,
3866 const bool reverse_cross_sections,
3867 const bool swap_row_col,
3868 const GET_TRANSFORM_FUNCTOR &get_transform_functor,
3869 const TRANSFORM_FUNCTOR &transform_and_copy_functor,
3870 const INTERP_FUNCTOR &transform_and_interp_functor)
3877 copyCrossSectionAttributeWrapper2<TRANSFORM_T,attrib_owner>(
3878 grid, outputh, cross_sectionh, attrib_owner,
3879 cross_section_input, transforms, grid_info,
3880 reverse_cross_sections,
3882 get_transform_functor,
3883 transform_and_copy_functor,
3884 transform_and_interp_functor);
3887 template<
typename T,GA_AttributeOwner attrib_owner>
3889 copyIntegerSingleGrid(
3893 const sop_SweepGridTransformWrapper *transforms,
3894 const sop_SweepGrid &grid_info,
3896 const bool output_points_only,
3897 const bool triangular_poles,
3898 const bool reverse_cross_sections,
3899 const bool swap_row_col)
3907 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
3912 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
3917 if (tuple_size == 1)
3920 auto &&transform_and_copy = [](
3925 T value = cross_sectionh.
get(cross_section_offset);
3926 outputh.set(output_offset, value);
3928 auto &&transform_and_interp = [](
3934 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
3935 T value = cross_sectionh.
get(cross_section_offset);
3936 outputh.set(output_offset, value);
3938 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
3939 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
3940 reverse_cross_sections, swap_row_col,
3941 get_transform, transform_and_copy, transform_and_interp);
3946 auto &&transform_and_copy = [tuple_size](
3951 for (
exint component = 0; component < tuple_size; ++component)
3953 T value = cross_sectionh.
get(cross_section_offset, component);
3954 outputh.set(output_offset, component, value);
3957 auto &&transform_and_interp = [tuple_size](
3963 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
3964 for (
exint component = 0; component < tuple_size; ++component)
3966 T value = cross_sectionh.
get(cross_section_offset, component);
3967 outputh.set(output_offset, component, value);
3970 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
3971 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
3972 reverse_cross_sections, swap_row_col,
3973 get_transform, transform_and_copy, transform_and_interp);
3976 template<
typename T,GA_TypeInfo transform_type,GA_AttributeOwner attrib_owner>
3978 copyFloatSingleGrid(
3982 const sop_SweepGridTransformWrapper *transforms,
3983 const sop_SweepGrid &grid_info,
3984 const exint cross_sections_per_vertex,
3985 const exint cap_divisions,
3987 const bool output_points_only,
3988 const bool triangular_poles,
3989 const bool reverse_cross_sections,
3990 const bool swap_row_col)
3998 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
4000 const exint cap_rows = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
4001 exint last_cap_start_row = -1;
4002 exint last_cap_start_transform = -1;
4003 if (cross_sections_per_vertex != 1 && cap_rows > 0)
4005 last_cap_start_row = grid_info.myCurveNEdges - cap_rows;
4006 last_cap_start_transform = (last_cap_start_row - cap_rows)/cross_sections_per_vertex + cap_rows;
4009 auto &&fix_transformi_for_all_case = [cap_rows,cross_sections_per_vertex,last_cap_start_row,last_cap_start_transform](
exint &transformi)
4015 transformi /= cross_sections_per_vertex;
4016 else if (transformi > cap_rows)
4018 if (transformi < last_cap_start_row)
4019 transformi = (transformi - cap_rows)/cross_sections_per_vertex + cap_rows;
4021 transformi = last_cap_start_transform + (transformi - last_cap_start_row);
4035 auto &&get_transform = [&
transform,cross_sections_per_vertex,&fix_transformi_for_all_case]
4036 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix4T<T>*
4039 if (cross_sections_per_vertex != 1)
4040 fix_transformi_for_all_case(transformi);
4042 transform.
setTranslates(transforms->getTranslates<T>()[transformi]);
4045 auto &&transform_and_copy = [](
4052 outputh.set(output_offset, value);
4054 auto &&transform_and_interp = [](
4064 outputh.set(output_offset, value);
4066 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix4T<T>, attrib_owner>(grid,
4067 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4068 reverse_cross_sections, swap_row_col,
4069 get_transform, transform_and_copy, transform_and_interp);
4076 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4077 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4080 if (cross_sections_per_vertex != 1)
4081 fix_transformi_for_all_case(transformi);
4082 return &transforms->getInverse3s<
T>()[transformi];
4084 auto &&transform_and_copy = [](
4091 outputh.set(output_offset, value);
4093 auto &&transform_and_interp = [](
4110 if (new_length2 != 0)
4111 value *= SYSsqrt(orig_length2/new_length2);
4112 outputh.set(output_offset, value);
4114 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4115 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4116 reverse_cross_sections, swap_row_col,
4117 get_transform, transform_and_copy, transform_and_interp);
4124 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4125 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4128 if (cross_sections_per_vertex != 1)
4129 fix_transformi_for_all_case(transformi);
4130 return &transforms->getMatrix3s<
T>()[transformi];
4132 auto &&transform_and_copy = [](
4139 outputh.set(output_offset, value);
4141 auto &&transform_and_interp = [](
4151 outputh.set(output_offset, value);
4153 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4154 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4155 reverse_cross_sections, swap_row_col,
4156 get_transform, transform_and_copy, transform_and_interp);
4163 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4164 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_QuaternionT<T>*
4167 if (cross_sections_per_vertex != 1)
4168 fix_transformi_for_all_case(transformi);
4169 return &transforms->getQuaternions<
T>()[transformi];
4171 auto &&transform_and_copy = [](
4178 outputh.set(output_offset, value);
4180 auto &&transform_and_interp = [](
4189 value = *transform *
value;
4190 outputh.set(output_offset, value);
4192 copyCrossSectionAttributeWrapper<UT_QuaternionT<T>,
UT_QuaternionT<T>, attrib_owner>(grid,
4193 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4194 reverse_cross_sections, swap_row_col,
4195 get_transform, transform_and_copy, transform_and_interp);
4200 if (tuple_size == 9)
4203 auto &&get_transform = [cross_sections_per_vertex,&fix_transformi_for_all_case]
4204 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix3T<T>*
4207 if (cross_sections_per_vertex != 1)
4208 fix_transformi_for_all_case(transformi);
4209 return &transforms->getMatrix3s<
T>()[transformi];
4211 auto &&transform_and_copy = [](
4218 outputh.set(output_offset, value);
4220 auto &&transform_and_interp = [](
4230 outputh.set(output_offset, value);
4232 copyCrossSectionAttributeWrapper<UT_Matrix3T<T>,
UT_Matrix3T<T>, attrib_owner>(grid,
4233 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4234 reverse_cross_sections, swap_row_col,
4235 get_transform, transform_and_copy, transform_and_interp);
4238 if (tuple_size == 16)
4243 auto &&get_transform = [&
transform,cross_sections_per_vertex,&fix_transformi_for_all_case]
4244 (
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const UT_Matrix4T<T>*
4247 if (cross_sections_per_vertex != 1)
4248 fix_transformi_for_all_case(transformi);
4250 transform.
setTranslates(transforms->getTranslates<T>()[transformi]);
4253 auto &&transform_and_copy = [](
4260 outputh.set(output_offset, value);
4262 auto &&transform_and_interp = [](
4272 outputh.set(output_offset, value);
4274 copyCrossSectionAttributeWrapper<UT_Matrix4T<T>,
UT_Matrix4T<T>, attrib_owner>(grid,
4275 output_attrib, cross_section_attrib, cross_section_input, transforms, grid_info,
4276 reverse_cross_sections, swap_row_col,
4277 get_transform, transform_and_copy, transform_and_interp);
4284 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
4290 if (tuple_size == 1)
4293 auto &&transform_and_copy = [](
4298 T value = cross_sectionh.
get(cross_section_offset);
4299 outputh.set(output_offset, value);
4301 if (is_integer_type)
4303 auto &&transform_and_interp = [](
4309 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4310 T value = cross_sectionh.
get(cross_section_offset);
4311 outputh.set(output_offset, value);
4313 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4314 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4315 reverse_cross_sections, swap_row_col,
4316 get_transform, transform_and_copy, transform_and_interp);
4320 auto &&transform_and_interp = [](
4326 const T value0 = cross_sectionh.
get(cross_section_offset0);
4327 const T value1 = cross_sectionh.
get(cross_section_offset1);
4328 T value =
SYSlerp(value0, value1, t);
4329 outputh.set(output_offset, value);
4331 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4332 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4333 reverse_cross_sections, swap_row_col,
4334 get_transform, transform_and_copy, transform_and_interp);
4338 if (tuple_size == 2 && !is_integer_type)
4341 auto &&transform_and_copy = [](
4347 outputh.set(output_offset, value);
4349 auto &&transform_and_interp = [](
4358 outputh.set(output_offset, value);
4360 copyCrossSectionAttributeWrapper<UT_Vector2T<T>,
void, attrib_owner>(grid,
4361 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4362 reverse_cross_sections, swap_row_col,
4363 get_transform, transform_and_copy, transform_and_interp);
4366 if (tuple_size == 3 && !is_integer_type)
4369 auto &&transform_and_copy = [](
4375 outputh.set(output_offset, value);
4377 auto &&transform_and_interp = [](
4386 outputh.set(output_offset, value);
4388 copyCrossSectionAttributeWrapper<UT_Vector3T<T>,
void, attrib_owner>(grid,
4389 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4390 reverse_cross_sections, swap_row_col,
4391 get_transform, transform_and_copy, transform_and_interp);
4396 auto &&transform_and_copy = [tuple_size](
4401 for (
exint component = 0; component < tuple_size; ++component)
4403 T value = cross_sectionh.
get(cross_section_offset, component);
4404 outputh.set(output_offset, component, value);
4407 if (is_integer_type)
4409 auto &&transform_and_interp = [tuple_size](
4415 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4416 for (
exint component = 0; component < tuple_size; ++component)
4418 T value = cross_sectionh.
get(cross_section_offset, component);
4419 outputh.set(output_offset, component, value);
4422 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4423 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4424 reverse_cross_sections, swap_row_col,
4425 get_transform, transform_and_copy, transform_and_interp);
4429 auto &&transform_and_interp = [tuple_size](
4435 for (
exint component = 0; component < tuple_size; ++component)
4437 const T value0 = cross_sectionh.
get(cross_section_offset0, component);
4438 const T value1 = cross_sectionh.
get(cross_section_offset1, component);
4439 T value =
SYSlerp(value0, value1, t);
4440 outputh.set(output_offset, component, value);
4443 copyCrossSectionAttributeWrapper<T, void, attrib_owner>(grid,
4444 output_attrib, cross_section_attrib, cross_section_input,
nullptr, grid_info,
4445 reverse_cross_sections, swap_row_col,
4446 get_transform, transform_and_copy, transform_and_interp);
4450 template<GA_AttributeOwner attrib_owner>
4452 copyAttribSingleGrid(
4456 const sop_SweepGrid &grid_info,
4458 const bool output_points_only,
4459 const bool triangular_poles,
4460 const bool reverse_cross_sections,
4461 const bool swap_row_col)
4466 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
4469 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
4474 auto &&transform_and_copy = [](
4479 output_attrib->copy(output_offset, *cross_section_attrib, cross_section_offset);
4481 auto &&transform_and_interp = [](
4487 GA_Offset cross_section_offset = (t < 0.5) ? cross_section_offset0 : cross_section_offset1;
4488 output_attrib->copy(output_offset, *cross_section_attrib, cross_section_offset);
4492 copyCrossSectionAttributeWrapper2<void, attrib_owner>(grid,
4493 output_attrib, cross_section_attrib, attrib_owner, cross_section_input,
nullptr, grid_info,
4494 reverse_cross_sections, swap_row_col,
4495 get_transform, transform_and_copy, transform_and_interp);
4498 static const sop_SweepGridTransformWrapper *
4499 gridOffsetTransforms(
4500 const SOP_SweepHDKCache *
const transform_cache,
4501 sop_SweepGridTransformWrapper &grid_transforms,
4504 if (transform_cache ==
nullptr)
4507 grid_transforms.
init(*transform_cache, gridi);
4509 return &grid_transforms;
4512 template<GA_AttributeOwner attrib_owner>
4514 copyCrossSectionAttrib2(
4518 const SOP_SweepHDKCache *transform_cache,
4519 const sop_SweepGrid *grids,
4521 const exint cross_sections_per_vertex,
4522 const exint cap_divisions,
4524 const bool output_points_only,
4525 const bool triangular_poles,
4526 const bool reverse_cross_sections,
4527 const bool swap_row_col)
4532 const exint PARALLEL_THRESHOLD = 2048;
4533 const bool parallel = (ngrids > 1 &&
4538 if (!output_numeric)
4545 copyAttribSingleGrid<attrib_owner>(
4546 output_attrib, cross_section_attrib, cross_section_input,
4548 surface_type, output_points_only, triangular_poles,
4549 reverse_cross_sections, swap_row_col);
4560 functor(grid_range);
4567 if (!cross_section_numeric)
4571 if (tuple_size != cross_section_numeric->
getTupleSize())
4586 sop_SweepGridTransformWrapper local_grid_transforms;
4587 if (tuple_size == 3)
4595 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4596 copyFloatSingleGrid<fpreal64,GA_TYPE_POINT,attrib_owner>(
4597 output_numeric, cross_section_numeric, cross_section_input,
4598 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4599 surface_type, output_points_only, triangular_poles,
4600 reverse_cross_sections, swap_row_col);
4607 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4608 copyFloatSingleGrid<fpreal32,GA_TYPE_POINT,attrib_owner>(
4609 output_numeric, cross_section_numeric, cross_section_input,
4610 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4611 surface_type, output_points_only, triangular_poles,
4612 reverse_cross_sections, swap_row_col);
4623 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4624 copyFloatSingleGrid<fpreal64,GA_TYPE_NORMAL,attrib_owner>(
4625 output_numeric, cross_section_numeric, cross_section_input,
4626 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4627 surface_type, output_points_only, triangular_poles,
4628 reverse_cross_sections, swap_row_col);
4635 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4636 copyFloatSingleGrid<fpreal32,GA_TYPE_NORMAL,attrib_owner>(
4637 output_numeric, cross_section_numeric, cross_section_input,
4638 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4639 surface_type, output_points_only, triangular_poles,
4640 reverse_cross_sections, swap_row_col);
4651 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4652 copyFloatSingleGrid<fpreal64,GA_TYPE_VECTOR,attrib_owner>(
4653 output_numeric, cross_section_numeric, cross_section_input,
4654 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4655 surface_type, output_points_only, triangular_poles,
4656 reverse_cross_sections, swap_row_col);
4663 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4664 copyFloatSingleGrid<fpreal32,GA_TYPE_VECTOR,attrib_owner>(
4665 output_numeric, cross_section_numeric, cross_section_input,
4666 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4667 surface_type, output_points_only, triangular_poles,
4668 reverse_cross_sections, swap_row_col);
4674 else if (tuple_size == 4)
4682 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4683 copyFloatSingleGrid<fpreal64,GA_TYPE_QUATERNION,attrib_owner>(
4684 output_numeric, cross_section_numeric, cross_section_input,
4685 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4686 surface_type, output_points_only, triangular_poles,
4687 reverse_cross_sections, swap_row_col);
4694 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4695 copyFloatSingleGrid<fpreal32,GA_TYPE_QUATERNION,attrib_owner>(
4696 output_numeric, cross_section_numeric, cross_section_input,
4697 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4698 surface_type, output_points_only, triangular_poles,
4699 reverse_cross_sections, swap_row_col);
4705 else if (tuple_size == 9 || tuple_size == 16)
4713 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4714 copyFloatSingleGrid<fpreal64,GA_TYPE_TRANSFORM,attrib_owner>(
4715 output_numeric, cross_section_numeric, cross_section_input,
4716 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4717 surface_type, output_points_only, triangular_poles,
4718 reverse_cross_sections, swap_row_col);
4725 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
4726 copyFloatSingleGrid<fpreal32,GA_TYPE_TRANSFORM,attrib_owner>(
4727 output_numeric, cross_section_numeric, cross_section_input,
4728 grid_transforms, grids[gridi], cross_sections_per_vertex, cap_divisions,
4729 surface_type, output_points_only, triangular_poles,
4730 reverse_cross_sections, swap_row_col);
4741 copyFloatSingleGrid<fpreal64,GA_TYPE_VOID,attrib_owner>(
4742 output_numeric, cross_section_numeric, cross_section_input,
4743 nullptr, grids[gridi], cross_sections_per_vertex, cap_divisions,
4744 surface_type, output_points_only, triangular_poles,
4745 reverse_cross_sections, swap_row_col);
4752 copyFloatSingleGrid<fpreal32,GA_TYPE_VOID,attrib_owner>(
4753 output_numeric, cross_section_numeric, cross_section_input,
4754 nullptr, grids[gridi], cross_sections_per_vertex, cap_divisions,
4755 surface_type, output_points_only, triangular_poles,
4756 reverse_cross_sections, swap_row_col);
4763 copyIntegerSingleGrid<int64,attrib_owner>(
4764 output_numeric, cross_section_numeric, cross_section_input,
4765 nullptr, grids[gridi],
4766 surface_type, output_points_only, triangular_poles,
4767 reverse_cross_sections, swap_row_col);
4774 copyIntegerSingleGrid<int32,attrib_owner>(
4775 output_numeric, cross_section_numeric, cross_section_input,
4776 nullptr, grids[gridi],
4777 surface_type, output_points_only, triangular_poles,
4778 reverse_cross_sections, swap_row_col);
4786 functor(grid_range);
4790 copyCrossSectionAttrib(
4794 const SOP_SweepHDKCache *transform_cache,
4795 const sop_SweepGrid *grids,
4797 const exint cross_sections_per_vertex,
4798 const exint cap_divisions,
4800 const bool output_points_only,
4801 const bool triangular_poles,
4802 const bool reverse_cross_sections,
4803 const bool swap_row_col)
4810 copyCrossSectionAttrib2<GA_ATTRIB_POINT>(
4811 output_attrib, cross_section_attrib, cross_section_input,
4812 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4813 surface_type, output_points_only, triangular_poles,
4814 reverse_cross_sections, swap_row_col);
4818 copyCrossSectionAttrib2<GA_ATTRIB_VERTEX>(
4819 output_attrib, cross_section_attrib, cross_section_input,
4820 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4821 surface_type, output_points_only, triangular_poles,
4822 reverse_cross_sections, swap_row_col);
4826 copyCrossSectionAttrib2<GA_ATTRIB_PRIMITIVE>(
4827 output_attrib, cross_section_attrib, cross_section_input,
4828 transform_cache, grids, ngrids, cross_sections_per_vertex, cap_divisions,
4829 surface_type, output_points_only, triangular_poles,
4830 reverse_cross_sections, swap_row_col);
4834 output_attrib->
replace(*cross_section_attrib);
4838 template<
bool wrap_to_inval
id,
typename FUNCTOR>
4840 copyVertexCurveAttribWrapper(
4841 const sop_SweepGrid &grid_info,
4844 exint cap_divisions,
4845 exint cross_sections_per_vertex,
4846 const bool swap_row_col,
4847 const FUNCTOR ©_functor)
4849 const exint curve_nedges = grid_info.myCurveNEdges;
4850 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
4852 const exint cap_divs = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
4853 exint prev_vtxi = -1;
4855 exint cap_vertex_count = 0;
4856 if (grid_info.myHasPolygonCaps)
4861 cap_vertex_count = cross_section_nedges;
4866 for (
exint col = 0; col < cap_vertex_count; ++col)
4868 copy_functor(grid_info.myStartVtxOff + col, 0);
4874 cap_vertex_count = curve_nedges;
4876 for (
exint row = 0; row < cap_vertex_count; ++
row)
4878 copy_functor(grid_info.myStartVtxOff + row, row);
4883 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
4884 const bool closed_curve = grid_info.myCurveClosed;
4886 start_vtxoff, cross_sections_per_vertex, swap_row_col, closed_curve, ©_functor]
4889 exint vtxi = swap_row_col ? col :
row;
4890 vtxi +=
exint(swap_row_col ? iscolend : isrowend);
4891 if (vtxi != prev_vtxi)
4893 curve_vtxi = vtxi - cap_divs;
4894 if (cross_sections_per_vertex != 1)
4895 curve_vtxi /= cross_sections_per_vertex;
4898 else if (curve_vtxi >= num_vertices)
4901 curve_vtxi = num_vertices-1;
4902 else if (wrap_to_invalid)
4909 copy_functor(start_vtxoff + vtxnum, curve_vtxi);
4911 if (grid_info.myHasPolygonCaps)
4918 curve_vtxi = num_vertices-1;
4920 for (
exint col = 0; col < cap_vertex_count; ++col)
4922 copy_functor(cap_start_vtxoff + col, curve_vtxi);
4928 for (
exint row = 0; row < cap_vertex_count; ++
row)
4930 copy_functor(cap_start_vtxoff + row, row);
4936 template<GA_AttributeOwner attrib_owner,
bool wrap_to_inval
id=false,
typename COPY_FUNCTOR>
4941 const sop_SweepGrid *grids,
4943 const exint cross_sections_per_vertex,
4945 const bool output_points_only,
4946 const bool triangular_poles,
4947 const exint cap_divisions,
4948 const bool swap_row_col,
4949 const COPY_FUNCTOR ©_functor)
4960 const sop_SweepGrid &grid_info = grids[gridi];
4962 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
4967 copyVertexCurveAttribWrapper<wrap_to_invalid>(grid_info, grid, vertices.
size(), cap_divisions, cross_sections_per_vertex, swap_row_col,
4968 [©_functor,&vertices](
GA_Offset output_vtxoff,
exint curve_vtxi)
4971 copy_functor(output_vtxoff, curve_vtxoff);
4977 const exint cap_divs = (grid_info.myVEndPoles && !grid_info.myHasPolygonCaps) ? cap_divisions : 0;
4978 exint prev_vtxi = -1;
4981 &curve_ptoff, curve_input, cross_sections_per_vertex, swap_row_col, ©_functor]
4984 exint vtxi = swap_row_col ? col :
row;
4985 if (vtxi != prev_vtxi)
4987 exint curve_vtxi = vtxi - cap_divs;
4988 if (cross_sections_per_vertex != 1)
4989 curve_vtxi /= cross_sections_per_vertex;
4992 else if (curve_vtxi >= vertices.
size())
4993 curve_vtxi = vertices.
size()-1;
4994 GA_Offset curve_vtxoff = vertices(curve_vtxi);
4995 curve_ptoff = curve_input->
vertexPoint(curve_vtxoff);
4998 copy_functor(output_ptoff, curve_ptoff);
5004 const exint PARALLEL_THRESHOLD = 2048;
5023 const sop_SweepGrid *grids,
5025 const exint cross_sections_per_vertex,
5027 const bool output_points_only,
5028 const bool triangular_poles,
5029 const exint cap_divisions,
5030 const bool swap_row_col)
5037 auto &©_functor = [output_attrib,curve_attrib](
GA_Offset output_off,
GA_Offset curve_off)
5039 output_attrib->
copy(output_off, *curve_attrib, curve_off);
5041 copyCurveAttrib2<GA_ATTRIB_POINT>(
5042 output_attrib, curve_input,
5043 grids, ngrids, cross_sections_per_vertex,
5044 surface_type, output_points_only, triangular_poles, cap_divisions,
5045 swap_row_col, copy_functor);
5049 if (!output_points_only)
5051 auto &©_functor = [output_attrib,curve_attrib](
GA_Offset output_off,
GA_Offset curve_off)
5053 output_attrib->
copy(output_off, *curve_attrib, curve_off);
5055 copyCurveAttrib2<GA_ATTRIB_VERTEX>(
5056 output_attrib, curve_input,
5057 grids, ngrids, cross_sections_per_vertex,
5058 surface_type, output_points_only, triangular_poles, cap_divisions,
5059 swap_row_col, copy_functor);
5064 if (!output_points_only)
5074 const sop_SweepGrid &grid_info = grids[gridi];
5076 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
5079 const GA_Offset startprimoff = grid_info.myStartPrimOff;
5081 output_attrib->
fill(
GA_Range(output_attrib->
getIndexMap(), startprimoff, endprimoff), *curve_attrib, grid_info.myCurvePrimOff);
5085 const exint PARALLEL_THRESHOLD = 2048;
5101 output_attrib->
replace(*curve_attrib);
5113 template<
typename T,GA_AttributeOwner output_owner>
5115 copyCrossSectionUVSingleGrid(
5120 const sop_SweepGrid &grid_info,
5122 const bool is_cross_section_uv_computed,
5123 const bool reverse_cross_sections,
5124 const bool swap_row_col,
5137 auto &&get_transform = [](
const sop_SweepGridTransformWrapper *transforms,
exint row,
const sop_SweepGrid &grid_info) ->
const void*
5147 if (tuple_size == 2)
5151 auto &©_functor = [missing_input_us,&outputh,flipu,swap_row_col,uscale](
5154 const exint cross_section_vtxi = swap_row_col ? row : col;
5155 T value = (cross_section_vtxi == missing_input_us->size()) ?
T(1.0) : (*missing_input_us)[cross_section_vtxi];
5159 output_value[theUComponent] = uscale*
value;
5160 outputh.set(output_offset, output_value);
5163 copyVertexCrossSectionWrapper(grid, grid_info, copy_functor);
5167 else if (tuple_size == 3)
5171 auto &©_functor = [missing_input_us,&outputh,flipu,swap_row_col,uscale](
5174 const exint cross_section_vtxi = swap_row_col ? row : col;
5175 T value = (cross_section_vtxi == missing_input_us->size()) ?
T(1.0) : (*missing_input_us)[cross_section_vtxi];
5179 output_value[theUComponent] = uscale*
value;
5180 outputh.set(output_offset, output_value);
5183 copyVertexCrossSectionWrapper(grid, grid_info, copy_functor);
5190 if (tuple_size == 2)
5193 auto &&transform_and_copy = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5200 value = reverse_cross_sections ?
T(0.0) : T(1.0);
5202 value = cross_sectionh.get(cross_section_offset);
5205 value = T(1.0)-
value;
5206 if (is_cross_section_uv_computed)
5209 output_value[theUComponent] =
value;
5210 outputh.set(output_offset, output_value);
5212 auto &&transform_and_interp = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5219 const T value0 = cross_sectionh.get(cross_section_offset0);
5224 value1 = reverse_cross_sections ? T(0.0) : T(1.0);
5226 value1 = cross_sectionh.get(cross_section_offset1);
5228 T value =
SYSlerp(value0, value1, t);
5230 value = T(1.0)-
value;
5231 if (is_cross_section_uv_computed)
5234 output_value[theUComponent] =
value;
5235 outputh.set(output_offset, output_value);
5242 copyCrossSectionAttributeWrapper2<void, output_owner, wrap_to_invalid>(grid,
5243 outputh, cross_sectionh, cross_section_owner, cross_section_input,
nullptr, grid_info,
5244 reverse_cross_sections, swap_row_col,
5245 get_transform, transform_and_copy, transform_and_interp);
5248 if (tuple_size == 3)
5251 auto &&transform_and_copy = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5258 value = reverse_cross_sections ? T(0.0) : T(1.0);
5260 value = cross_sectionh.get(cross_section_offset);
5263 value = T(1.0)-
value;
5264 if (is_cross_section_uv_computed)
5267 output_value[theUComponent] =
value;
5268 outputh.set(output_offset, output_value);
5270 auto &&transform_and_interp = [flipu,reverse_cross_sections,uscale,is_cross_section_uv_computed](
5277 const T value0 = cross_sectionh.get(cross_section_offset0);
5282 value1 = reverse_cross_sections ? T(0.0) : T(1.0);
5284 value1 = cross_sectionh.get(cross_section_offset1);
5286 T value =
SYSlerp(value0, value1, t);
5288 value = T(1.0)-
value;
5289 if (is_cross_section_uv_computed)
5292 output_value[theUComponent] =
value;
5293 outputh.set(output_offset, output_value);
5300 copyCrossSectionAttributeWrapper2<void, output_owner, wrap_to_invalid>(grid,
5301 outputh, cross_sectionh, cross_section_owner, cross_section_input,
nullptr, grid_info,
5302 reverse_cross_sections, swap_row_col,
5303 get_transform, transform_and_copy, transform_and_interp);
5308 template<
typename T>
5313 const exint cross_section_nedges,
5314 const exint curve_row)
5317 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_nedges; ++cross_section_vtxi)
5319 exint row = curve_row;;
5320 exint col = cross_section_vtxi;
5327 return sum / cross_section_nedges;
5336 template<
typename T>
5337 static double crossSectionLength(
5341 const exint cross_section_nedges,
5342 const exint curve_row,
5346 double cross_section_length = 0;
5347 exint row = curve_row;
5354 if (dir0 !=
nullptr)
5356 T d = prevpos.
dot(*dir0);
5357 prevpos0 = prevpos - d*(*dir0);
5358 if (dir1 !=
nullptr)
5360 d = prevpos.
dot(*dir1);
5361 prevpos1 = prevpos - d*(*dir1);
5364 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_nedges; ++cross_section_vtxi)
5366 exint row = curve_row;
5367 exint col = cross_section_vtxi+1;
5373 if (dir0 !=
nullptr)
5375 T d = nextpos.
dot(*dir0);
5376 nextpos0 = nextpos - d*(*dir0);
5377 T dist0 = prevpos0.
distance(nextpos0);
5378 if (dir1 !=
nullptr)
5380 d = nextpos.
dot(*dir1);
5381 nextpos1 = nextpos - d*(*dir1);
5383 cross_section_length += 0.5f*(dist0 + prevpos1.
distance(nextpos1));
5387 cross_section_length += dist0;
5392 cross_section_length += prevpos.
distance(nextpos);
5395 if (dir0 !=
nullptr)
5397 prevpos0 = nextpos0;
5398 if (dir1 !=
nullptr)
5399 prevpos1 = nextpos1;
5402 return cross_section_length;
5405 template<
typename T,
typename FUNCTOR>
5406 static void iterateCurveEdgeLengths(
5407 const exint curve_nedges,
5408 const bool use_mesh_edge_lengths,
5410 const exint cross_section_npts,
5411 const bool swap_row_col,
5415 const sop_SweepGrid &grid_info,
5416 const exint cap_divisions,
5423 for (
exint curve_vtxi = 0; curve_vtxi < curve_nedges; ++curve_vtxi)
5425 double length_sum = 0;
5426 exint length_sum_count;
5427 if (use_mesh_edge_lengths)
5429 length_sum_count = cross_section_npts;
5430 for (
exint cross_section_vtxi = 0; cross_section_vtxi < cross_section_npts; ++cross_section_vtxi)
5432 exint col0 = swap_row_col ? curve_vtxi : cross_section_vtxi;
5433 exint col1 = swap_row_col ? curve_vtxi+1 : cross_section_vtxi;
5434 exint row0 = swap_row_col ? cross_section_vtxi : curve_vtxi;
5435 exint row1 = swap_row_col ? cross_section_vtxi : curve_vtxi+1;
5443 length_sum_count = 1;
5444 exint orig_curve_vtxi = curve_vtxi;
5445 if (grid_info.myVEndPoles)
5448 orig_curve_vtxi -= cap_divisions;
5452 exint orig_curve_vtxi1 = (curve_vertices.
getExtraFlag() && curve_vtxi+1 == curve_nedges) ? 0 : curve_vtxi+1;
5453 if (grid_info.myVEndPoles)
5457 orig_curve_vtxi1 -= cap_divisions;
5464 functor(curve_vtxi, length_sum, length_sum_count);
5469 template<GA_AttributeOwner output_owner,
typename T>
5471 generateLengthWeightedV(
5472 const sop_SweepGrid &grid_info,
5474 const exint cross_sections_per_vertex,
5479 bool scalevasu_usingmax,
5483 bool use_mesh_edge_lengths,
5488 const exint curve_nedges = grid_info.myCurveNEdges;
5489 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
5494 exint cap_divisions = 0;
5495 if (curve_input !=
nullptr)
5498 if (grid_info.myVEndPoles)
5501 exint orig_curve_nedges = curve_vertices.
size() - 1;
5502 cap_divisions = (grid_info.myCurveNEdges - orig_curve_nedges)/2;
5505 curve_pos.
bind(curve_input->
getP());
5508 bool norm_u_unnorm_v = (ustyle == UVStyle::NORMALIZED && vstyle != UVStyle::NORMALIZED);
5509 bool special_case_u_division = (!scalevasu_usingmax && norm_u_unnorm_v);
5513 bool prevPosValid =
false;
5515 bool currPosValid =
false;
5523 double prev_cross_section_length = 0;
5524 if (special_case_u_division)
5526 if (curve_input !=
nullptr)
5530 if (curve_vertices.
size() >= 2)
5532 currPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[0]));
5533 nextPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[1]));
5534 currPosValid =
true;
5535 if (grid_info.myCurveClosed)
5539 exint last_vtxi = curve_vertices.
size() - (unrolled ? 2 : 1);
5540 prevPos = curve_pos.
get(curve_input->
vertexPoint(curve_vertices[last_vtxi]));
5541 prevPosValid =
true;
5545 else if (curve_nedges >= 1 + (grid_info.myVEndPoles ? 2*cap_divisions : 0))
5549 exint start = grid_info.myVEndPoles ? cap_divisions : 0;
5550 currPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start);
5551 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start+1);
5552 currPosValid =
true;
5553 if (grid_info.myCurveClosed)
5555 prevPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, curve_nedges-1);
5556 prevPosValid =
true;
5562 dir0 = (currPos - prevPos);
5563 dir1 = (nextPos - currPos);
5566 if (length0 != 0 && length1 != 0)
5571 else if (length0 != 0 || length1 != 0)
5572 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5574 else if (currPosValid)
5576 dir1 = (nextPos - currPos);
5582 prev_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, 0, pdir0, pdir1);
5591 double max_cross_section_length = 0;
5592 if (need_max_cross_section_length)
5594 for (
exint curve_vtxi = 0; curve_vtxi <= curve_nedges; ++curve_vtxi)
5596 double cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi, dir0, dir1);
5597 max_cross_section_length =
SYSmax(cross_section_length, max_cross_section_length);
5605 double total_length_sum = 0;
5606 exint curve_npts = curve_nedges + !grid_info.myCurveClosed;
5607 exint cross_section_npts = cross_section_nedges + !grid_info.myCrossSectionClosed;
5608 iterateCurveEdgeLengths(
5610 use_mesh_edge_lengths,
5620 [&](
exint curve_vtxi,
double length_sum,
exint length_sum_count)
5622 if (special_case_u_division)
5624 bool nextPosValid =
false;
5626 if (!grid_info.myVEndPoles || (curve_vtxi >= cap_divisions && curve_vtxi < curve_npts-cap_divisions))
5628 nextPosValid =
true;
5629 if (cross_section_nedges >= 1)
5631 exint nextPosVtxi = curve_vtxi+2;
5632 exint threshold = curve_npts;
5633 if (grid_info.myVEndPoles)
5635 nextPosVtxi -= cap_divisions;
5636 threshold -= 2*cap_divisions;
5638 if (nextPosVtxi >= threshold)
5640 if (grid_info.myCurveClosed)
5641 nextPosVtxi -= curve_npts;
5643 nextPosValid =
false;
5647 if (curve_input !=
nullptr)
5650 exint next_curve_vtxi = nextPosVtxi;
5651 if (cross_sections_per_vertex != 1)
5652 next_curve_vtxi /= cross_sections_per_vertex;
5653 if (next_curve_vtxi < 0)
5654 next_curve_vtxi = 0;
5655 else if (next_curve_vtxi >= curve_vertices.
size())
5656 next_curve_vtxi = curve_vertices.
size()-1;
5657 GA_Offset curve_vtxoff = curve_vertices[next_curve_vtxi];
5659 nextPos = curve_pos.
get(curve_ptoff);
5663 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, nextPosVtxi);
5671 dir1 = (nextPos - currPos);
5673 if (length0 != 0 && length1 != 0)
5678 else if (length0 != 0 || length1 != 0)
5679 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5681 else if (length0 != 0)
5686 double next_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi+1, pdir0, pdir1);
5694 double curr_cross_section_length_avg = 0.5*(prev_cross_section_length + next_cross_section_length);
5695 if (curr_cross_section_length_avg == 0)
5700 length_sum /= (length_sum_count*curr_cross_section_length_avg);
5703 prev_cross_section_length = next_cross_section_length;
5708 length_sum /= length_sum_count;
5711 total_length_sum += length_sum;
5712 length_sums[curve_vtxi+1] = vscale*total_length_sum;
5715 UT_ASSERT_MSG(total_length_sum != 0 || (vstyle != UVStyle::NORMALIZED),
"computeGridUVScales should have fallen back to v being uniform");
5717 if (vstyle == UVStyle::NORMALIZED)
5720 length_sums[curve_nedges] = orig_vscale;
5722 for (
exint curve_vtxi = curve_nedges-1; curve_vtxi >= 0 && length_sums[curve_vtxi] > orig_vscale; ++curve_vtxi)
5724 length_sums[curve_vtxi] = orig_vscale;
5727 else if (vstyle == UVStyle::ROUNDED)
5730 double &rounded = length_sums[curve_nedges];
5734 length_sums[curve_nedges] = rounded;
5736 for (
exint curve_vtxi = curve_nedges-1; curve_vtxi >= 0 && length_sums[curve_vtxi] > rounded; ++curve_vtxi)
5738 length_sums[curve_vtxi] = rounded;
5745 exint cap_vertex_count = 0;
5751 cap_vertex_count = cross_section_nedges;
5752 for (
exint col = 0; col < cap_vertex_count; ++col)
5754 outputh.
set(grid_info.myStartVtxOff + col, theVComponent, 0);
5760 cap_vertex_count = curve_nedges;
5764 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
5771 exint curve_vtxi = swap_row_col ? col :
row;
5772 curve_vtxi +=
exint(swap_row_col ? iscolend : isrowend);
5773 outputh.
set(start_vtxoff + vtxnum, theVComponent, length_sums[curve_vtxi]);
5779 const GA_Offset start_ptoff = grid_info.myStartPtOff;
5783 exint curve_vtxi = swap_row_col ? col :
row;
5784 outputh.
set(start_ptoff + ptnum, theVComponent, length_sums[curve_vtxi]);
5794 for (
exint col = 0; col < cap_vertex_count; ++col)
5796 outputh.
set(cap_start_vtxoff + col, theVComponent, length_sums[curve_nedges]);
5807 template<GA_AttributeOwner output_owner,
typename T>
5810 const sop_SweepGrid &grid_info,
5816 const exint curve_nedges = grid_info.myCurveNEdges;
5817 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
5820 exint cap_vertex_count = 0;
5826 cap_vertex_count = cross_section_nedges;
5827 for (
exint col = 0; col < cap_vertex_count; ++col)
5829 outputh.
set(grid_info.myStartVtxOff + col, theVComponent, 0);
5835 cap_vertex_count = curve_nedges;
5840 const GA_Offset start_vtxoff = grid_info.myStartVtxOff + cap_vertex_count;
5841 const T recip_curve_nedges = (curve_nedges == 0) ? T(0.0) : (vscale/curve_nedges);
5848 exint curve_vtxi = swap_row_col ? col :
row;
5849 curve_vtxi +=
exint(swap_row_col ? iscolend : isrowend);
5850 outputh.
set(start_vtxoff + vtxnum, theVComponent, T(curve_vtxi)*recip_curve_nedges);
5856 const GA_Offset start_ptoff = grid_info.myStartPtOff;
5860 exint curve_vtxi = swap_row_col ? col :
row;
5861 outputh.
set(start_ptoff + ptnum, theVComponent, T(curve_vtxi)*recip_curve_nedges);
5871 for (
exint col = 0; col < cap_vertex_count; ++col)
5873 outputh.
set(cap_start_vtxoff + col, theVComponent, vscale);
5888 const sop_SweepGrid &grid_info,
5890 const bool swap_row_col,
5891 const exint cross_sections_per_vertex,
5892 const exint cap_divisions,
5895 const bool use_mesh_edge_lengths,
5896 const bool scalevasu_usingmax,
5898 bool &fallback_to_uniform_v)
5900 fallback_to_uniform_v =
false;
5902 const exint curve_nedges = grid_info.myCurveNEdges;
5903 const exint curve_npts = curve_nedges + !grid_info.myCurveClosed;
5904 const exint cross_section_nedges = grid_info.myCrossSectionNEdges;
5905 exint cross_section_npts = cross_section_nedges + !grid_info.myCrossSectionClosed;
5913 bool prevPosValid =
false;
5915 bool currPosValid =
false;
5917 if (curve_input !=
nullptr)
5919 curve_pos.bind(curve_input->
getP());
5923 if (curve_vertices.size() >= 2)
5925 currPos = curve_pos.get(curve_input->
vertexPoint(curve_vertices[0]));
5926 nextPos = curve_pos.get(curve_input->
vertexPoint(curve_vertices[1]));
5927 currPosValid =
true;
5928 if (grid_info.myCurveClosed)
5931 bool unrolled = !curve_vertices.getExtraFlag();
5932 exint last_vtxi = curve_vertices.size() - (unrolled ? 2 : 1);
5933 prevPos = curve_pos.get(curve_input->
vertexPoint(curve_vertices[last_vtxi]));
5934 prevPosValid =
true;
5938 else if (curve_nedges >= 1 + (grid_info.myVEndPoles ? 2*cap_divisions : 0))
5942 exint start = grid_info.myVEndPoles ? cap_divisions : 0;
5943 currPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start);
5944 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, start+1);
5945 currPosValid =
true;
5946 if (grid_info.myCurveClosed)
5948 prevPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, curve_nedges-1);
5949 prevPosValid =
true;
5961 dir0 = (currPos - prevPos);
5962 dir1 = (nextPos - currPos);
5965 if (length0 != 0 && length1 != 0)
5970 else if (length0 != 0 || length1 != 0)
5971 pdir0 = (length0 != 0) ? &dir0 : &dir1;
5973 else if (currPosValid)
5975 dir1 = (nextPos - currPos);
5981 double prev_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, 0, pdir0, pdir1);
5988 double curve_length = 0;
5989 double curve_length_per_cross_section_length_sum = 0;
5990 double cross_section_length_sum = prev_cross_section_length;
5991 exint cross_section_length_count = 1;
5992 double cross_section_length_max = prev_cross_section_length;
5993 iterateCurveEdgeLengths(
5995 use_mesh_edge_lengths,
6005 [&](
exint curve_vtxi,
double length_sum,
exint length_sum_count)
6007 double curr_curve_length = (length_sum/length_sum_count);
6008 curve_length += curr_curve_length;
6010 bool nextPosValid =
false;
6012 if (!grid_info.myVEndPoles || (curve_vtxi >= cap_divisions && curve_vtxi < curve_npts-cap_divisions))
6014 nextPosValid =
true;
6015 if (cross_section_nedges >= 1)
6017 exint nextPosVtxi = curve_vtxi+2;
6018 exint threshold = curve_npts;
6019 if (grid_info.myVEndPoles)
6021 nextPosVtxi -= cap_divisions;
6022 threshold -= 2*cap_divisions;
6024 if (nextPosVtxi >= threshold)
6026 if (grid_info.myCurveClosed)
6027 nextPosVtxi -= curve_npts;
6029 nextPosValid =
false;
6033 if (curve_input !=
nullptr)
6036 exint next_curve_vtxi = nextPosVtxi;
6037 if (cross_sections_per_vertex != 1)
6038 next_curve_vtxi /= cross_sections_per_vertex;
6039 if (next_curve_vtxi < 0)
6040 next_curve_vtxi = 0;
6041 else if (next_curve_vtxi >= curve_vertices.size())
6042 next_curve_vtxi = curve_vertices.size()-1;
6043 GA_Offset curve_vtxoff = curve_vertices[next_curve_vtxi];
6045 nextPos = curve_pos.get(curve_ptoff);
6049 nextPos = crossSectionCenter(swap_row_col, pos, grid, cross_section_nedges, nextPosVtxi);
6057 dir1 = (nextPos - currPos);
6059 if (length0 != 0 && length1 != 0)
6064 else if (length0 != 0 || length1 != 0)
6065 pdir0 = (length0 != 0) ? &dir0 : &dir1;
6067 else if (length0 != 0)
6072 double next_cross_section_length = crossSectionLength(swap_row_col, pos, grid, cross_section_nedges, curve_vtxi+1, pdir0, pdir1);
6081 double curr_cross_section_length_avg = 0.5*(prev_cross_section_length + next_cross_section_length);
6082 if (curr_cross_section_length_avg != 0)
6087 curve_length_per_cross_section_length_sum += (curr_curve_length/curr_cross_section_length_avg);
6090 if (curve_vtxi+1 != curve_nedges || !grid_info.myCurveClosed)
6092 cross_section_length_max =
SYSmax(next_cross_section_length, cross_section_length_max);
6093 cross_section_length_sum += next_cross_section_length;
6094 ++cross_section_length_count;
6095 prev_cross_section_length = next_cross_section_length;
6098 double cross_section_length_avg = (cross_section_length_sum/cross_section_length_count);
6102 if (ustyle == UVStyle::NORMALIZED)
6106 if (vstyle == UVStyle::NORMALIZED)
6109 if (curve_length == 0)
6110 fallback_to_uniform_v =
true;
6112 uvscale[1] /= curve_length;
6118 if ((scalevasu_usingmax && cross_section_length_max == 0) || (!scalevasu_usingmax && curve_length_per_cross_section_length_sum == 0))
6121 fallback_to_uniform_v =
true;
6123 else if (vstyle == UVStyle::FULL)
6125 if (scalevasu_usingmax)
6126 uvscale[1] /= cross_section_length_max;
6136 if (scalevasu_usingmax)
6138 if (curve_length == 0)
6141 fallback_to_uniform_v =
true;
6145 double rounded =
SYSrint(uvscale[1]*curve_length/cross_section_length_max);
6148 uvscale[1] = rounded/curve_length;
6153 UT_ASSERT(curve_length_per_cross_section_length_sum != 0);
6154 double rounded =
SYSrint(uvscale[1]*curve_length_per_cross_section_length_sum);
6157 uvscale[1] = rounded/curve_length_per_cross_section_length_sum;
6162 else if (ustyle == UVStyle::FULL)
6166 uvscale[0] *= cross_section_length_avg;
6168 if (vstyle == UVStyle::NORMALIZED)
6171 if (curve_length == 0)
6173 fallback_to_uniform_v =
true;
6177 uvscale[0] /= curve_length;
6178 uvscale[1] /= curve_length;
6181 else if (vstyle == UVStyle::FULL)
6190 if (curve_length == 0)
6193 fallback_to_uniform_v =
true;
6197 double old_vscale = uvscale[1];
6198 double rounded =
SYSrint(old_vscale*curve_length);
6201 uvscale[1] = rounded/curve_length;
6202 uvscale[0] *= (uvscale[1]/old_vscale);
6215 if (vstyle == UVStyle::NORMALIZED)
6217 if (curve_length == 0)
6219 double rounded =
SYSrint(cross_section_length_avg*uvscale[0]);
6222 uvscale[0] = rounded;
6223 fallback_to_uniform_v =
true;
6227 double rounded =
SYSrint(cross_section_length_avg*uvscale[0]/curve_length);
6230 uvscale[0] = rounded;
6231 uvscale[1] /= curve_length;
6236 const double old_uscale = cross_section_length_avg*uvscale[0];
6237 uvscale[0] =
SYSrint(old_uscale);
6241 if (vstyle == UVStyle::FULL)
6243 if (old_uscale != 0)
6244 uvscale[1] *= (uvscale[0]/old_uscale);
6249 if (curve_length == 0)
6252 fallback_to_uniform_v =
true;
6256 double rounded =
SYSrint(curve_length*uvscale[1]);
6259 uvscale[1] = rounded/curve_length;
6268 template<GA_AttributeOwner output_owner>
6270 copyUVAttribPairPtOrVtx(
6276 const sop_SweepGrid *grids,
6278 const exint cross_sections_per_vertex,
6280 const bool output_points_only,
6281 const bool triangular_poles,
6282 const exint cap_divisions,
6283 const bool reverse_cross_sections,
6284 const bool swap_row_col,
6286 const bool length_weighted_uvs,
6289 const bool use_mesh_edge_lengths,
6290 const bool scalevasu_usingmax,
6294 const exint PARALLEL_THRESHOLD = 2048;
6295 const bool parallel = (ngrids > 1 &&
6305 const bool is_cross_section_uv_computed = cross_section_attrib ==
nullptr || cross_section_attrib->
isDetached();
6308 UT_ASSERT((cross_section_attrib !=
nullptr) != (missing_input_us !=
nullptr));
6316 const sop_SweepGrid &grid_info = grids[gridi];
6318 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
6320 bool fallback_to_uniform_v =
false;
6322 if (length_weighted_uvs && (is_cross_section_uv_computed || curve_attrib ==
nullptr))
6325 grid_uvscale = computeGridUVScales(
6327 cross_section_input,
6331 cross_sections_per_vertex,
6334 use_mesh_edge_lengths,
6337 fallback_to_uniform_v);
6340 UT_ASSERT((cross_section_attrib !=
nullptr) != (missing_input_us !=
nullptr));
6343 copyCrossSectionUVSingleGrid<fpreal64,output_owner>(
6344 output_attrib, cross_section_attrib, cross_section_owner, cross_section_input,
6345 grid_info, grid, is_cross_section_uv_computed,
6346 reverse_cross_sections, swap_row_col, flipu, grid_uvscale[0],
6351 copyCrossSectionUVSingleGrid<fpreal32,output_owner>(
6352 output_attrib, cross_section_attrib, cross_section_owner, cross_section_input,
6353 grid_info, grid, is_cross_section_uv_computed,
6354 reverse_cross_sections, swap_row_col, flipu, grid_uvscale[0],
6358 if (curve_attrib ==
nullptr)
6367 if (length_weighted_uvs && !fallback_to_uniform_v)
6368 generateLengthWeightedV<output_owner>(grid_info, grid, cross_sections_per_vertex, outputh, pos, ustyle, vstyle,
6369 scalevasu_usingmax, grid_uvscale[1], uvscale[1], swap_row_col, use_mesh_edge_lengths, curve_input);
6371 generateUniformV<output_owner>(grid_info, grid, outputh, swap_row_col, grid_uvscale[1]);
6377 if (length_weighted_uvs && !fallback_to_uniform_v)
6378 generateLengthWeightedV<output_owner>(grid_info, grid, cross_sections_per_vertex, outputh, pos, ustyle, vstyle,
6379 scalevasu_usingmax,
float(grid_uvscale[1]),
float(uvscale[1]), swap_row_col, use_mesh_edge_lengths, curve_input);
6381 generateUniformV<output_owner>(grid_info, grid, outputh, swap_row_col,
float(grid_uvscale[1]));
6391 functor(grid_range);
6401 outputh.
set(output_off, theVComponent,
GAisValid(curve_off) ? curveh.get(curve_off) : 1.0);
6403 copyCurveAttrib2<output_owner,true>(
6404 output_attrib, curve_input,
6405 grids, ngrids, cross_sections_per_vertex,
6406 surface_type, output_points_only, triangular_poles, cap_divisions,
6407 swap_row_col, copy_functor);
6415 outputh.
set(output_off, theVComponent,
GAisValid(curve_off) ? curveh.get(curve_off) : 1.0f);
6417 copyCurveAttrib2<output_owner,true>(
6418 output_attrib, curve_input,
6419 grids, ngrids, cross_sections_per_vertex,
6420 surface_type, output_points_only, triangular_poles, cap_divisions,
6421 swap_row_col, copy_functor);
6432 auto &©_functor = [&outputh,&curveh,curve_input](
GA_Offset output_off,
GA_Offset curve_vtxoff)
6438 value = curveh.get(curve_off);
6442 outputh.
set(output_off, theVComponent, value);
6444 copyCurveAttrib2<output_owner,true>(
6445 output_attrib, curve_input,
6446 grids, ngrids, cross_sections_per_vertex,
6447 surface_type, output_points_only, triangular_poles, cap_divisions,
6448 swap_row_col, copy_functor);
6454 auto &©_functor = [&outputh,&curveh,curve_input](
GA_Offset output_off,
GA_Offset curve_vtxoff)
6460 value = curveh.get(curve_off);
6464 outputh.
set(output_off, theVComponent, value);
6466 copyCurveAttrib2<output_owner,true>(
6467 output_attrib, curve_input,
6468 grids, ngrids, cross_sections_per_vertex,
6469 surface_type, output_points_only, triangular_poles, cap_divisions,
6470 swap_row_col, copy_functor);
6482 const sop_SweepGrid *grids,
6484 const exint cross_sections_per_vertex,
6486 const bool output_points_only,
6487 const bool triangular_poles,
6488 const exint cap_divisions,
6489 const bool reverse_cross_sections,
6490 const bool swap_row_col,
6492 const bool length_weighted_uvs,
6495 const bool use_mesh_edge_lengths,
6496 const bool scalevasu_usingmax,
6523 copyUVAttribPairPtOrVtx<GA_ATTRIB_POINT>(
6525 cross_section_attrib,
6526 cross_section_input,
6530 cross_sections_per_vertex,
6535 reverse_cross_sections,
6538 length_weighted_uvs,
6540 use_mesh_edge_lengths,
6547 if (output_points_only)
6554 copyUVAttribPairPtOrVtx<GA_ATTRIB_VERTEX>(
6556 cross_section_attrib,
6557 cross_section_input,
6561 cross_sections_per_vertex,
6566 reverse_cross_sections,
6569 length_weighted_uvs,
6571 use_mesh_edge_lengths,
6583 const exint PARALLEL_THRESHOLD = 2048;
6584 const bool parallel = (ngrids > 1 &&
6606 const sop_SweepGrid &grid_info = grids[gridi];
6608 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
6610 copyCrossSectionUVSingleGrid<fpreal64,GA_ATTRIB_PRIMITIVE>(
6612 grid_info, grid,
false,
6613 reverse_cross_sections, swap_row_col, flipu, uvscale[0]);
6615 if (curveh.isValid() && outputh.
isValid() && outputh.getTupleSize() >= 2)
6617 const double v = curveh.get(grid_info.myCurvePrimOff);
6622 outputh.
set(grid_info.myStartPrimOff + primnum, theVComponent, v);
6633 const sop_SweepGrid &grid_info = grids[gridi];
6635 initGUGrid(grid_info, surface_type, output_points_only, triangular_poles, swap_row_col, grid_info.myStartPtOff, grid);
6637 copyCrossSectionUVSingleGrid<fpreal32,GA_ATTRIB_PRIMITIVE>(
6639 grid_info, grid,
false,
6640 reverse_cross_sections, swap_row_col, flipu, uvscale[0]);
6642 if (curveh.isValid() && outputh.
isValid() && outputh.getTupleSize() >= 2)
6644 const float v = curveh.get(grid_info.myCurvePrimOff);
6649 outputh.
set(grid_info.myStartPrimOff + primnum, theVComponent, v);
6660 functor(grid_range);
6669 case SurfaceType::ROWS:
6671 case SurfaceType::COLS:
6673 case SurfaceType::ROWCOL:
6675 case SurfaceType::QUADS:
6677 case SurfaceType::TRIS:
6679 case SurfaceType::REVTRIS:
6681 case SurfaceType::ALTTRIS:
6684 case SurfaceType::POINTS:
6691 copySurfaceAttributes(
6696 const exint cross_sections_per_vertex,
6697 const UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &cross_section_attribs,
6698 const UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &curve_attribs,
6699 const UT_Array<std::pair<std::pair<const GA_ATINumeric*,const GA_ATINumeric*>,
GA_ATINumeric*>> &uv_attribs,
6700 const SOP_SweepHDKCache *
const transform_cache,
6702 const bool output_points_only,
6703 const bool triangular_poles,
6704 const exint cap_divisions,
6705 const bool reverse_cross_sections,
6706 const bool swap_row_col,
6707 const exint uv_attrib_index,
6709 const bool length_weighted_uvs,
6712 const bool use_mesh_edge_lengths,
6713 const bool scalevasu_usingmax,
6718 if (interrupt.wasInterrupted())
6722 for (
exint attribi = 0; attribi < cross_section_attribs.size(); ++attribi)
6724 if (interrupt.wasInterrupted())
6727 const GA_Attribute *cross_section_attrib = cross_section_attribs[attribi].first;
6728 GA_Attribute *output_attrib = cross_section_attribs[attribi].second;
6729 copyCrossSectionAttrib(
6731 cross_section_attrib,
6732 cross_section_input,
6735 cross_sections_per_vertex, cap_divisions,
6736 surface_type, output_points_only, triangular_poles,
6737 reverse_cross_sections, swap_row_col);
6741 for (
exint attribi = 0; attribi < curve_attribs.size(); ++attribi)
6743 if (interrupt.wasInterrupted())
6746 const GA_Attribute *curve_attrib = curve_attribs[attribi].first;
6747 GA_Attribute *output_attrib = curve_attribs[attribi].second;
6753 cross_sections_per_vertex,
6754 surface_type, output_points_only, triangular_poles,
6755 cap_divisions, swap_row_col);
6759 for (
exint attribi = 0; attribi < uv_attribs.size(); ++attribi)
6761 if (interrupt.wasInterrupted())
6764 const GA_ATINumeric *cross_section_attrib = uv_attribs[attribi].first.first;
6765 const GA_ATINumeric *curve_attrib = uv_attribs[attribi].first.second;
6769 cross_section_attrib,
6770 cross_section_input,
6774 cross_sections_per_vertex,
6775 surface_type, output_points_only, triangular_poles,
6777 reverse_cross_sections, swap_row_col,
6778 (uv_attrib_index == attribi) ? missing_input_us :
nullptr,
6779 length_weighted_uvs,
6781 use_mesh_edge_lengths,
6783 (uv_attrib_index == attribi) && flipu,
6790 static void setupCrossSectionAttribs(
6791 SOP_SweepHDKCache *sopcache,
6793 const SOP_SweepHDKParms &sopparms,
6794 bool &same_cross_section_data,
6800 UT_ASSERT_MSG(cross_section_input && curve_input,
"Copy order only makes sense if both inputs are present.");
6802 CrossSectionAttribMatchData ©_order_attrib_data = sopcache->myCrossSectionAttribMatchData;
6807 const UT_StringHolder &cross_section_attrib_name = sopparms.getCrossSectionAttrib();
6818 bool string_missing_error_case =
false;
6822 same_cross_section_data &= (sopcache->myPrevCrossSectCurveAttribDataId == new_curve_data_id);
6823 sopcache->myPrevCrossSectCurveAttribDataId = new_curve_data_id;
6825 copy_order_attrib_data.myCurveAttribOwner = curve_attrib->
getOwner();
6829 copy_order_attrib_data.myCurveIntAttrib.bind(curve_attrib);
6830 if (!copy_order_attrib_data.myCurveIntAttrib.isValid()) {
6831 copy_order_attrib_data.myCurveStrAttrib.bind(curve_attrib);
6832 if (!copy_order_attrib_data.myCurveStrAttrib.isValid()) {
6834 curve_attrib =
nullptr;
6838 if (!cross_section_name_attrib.isValid()) {
6840 curve_attrib =
nullptr;
6841 copy_order_attrib_data.myCurveStrAttrib.clear();
6842 string_missing_error_case =
true;
6846 const int64 new_cross_section_data_id = cross_section_name_attrib->getDataId();
6847 const bool same_map = (sopcache->myPrevCrossSectPrimAttribDataId == new_cross_section_data_id);
6848 same_cross_section_data &= same_map;
6849 sopcache->myPrevCrossSectPrimAttribDataId = new_cross_section_data_id;
6850 copy_order_attrib_data.myIsUsingMap =
true;
6855 copy_order_attrib_data.myIntToPrimOff.destroy();
6856 copy_order_attrib_data.myStrToPrimOff.destroy();
6862 for (
GA_Offset primoff = start; primoff <
end; ++primoff) {
6874 copy_order_attrib_data.myStrToPrimOff.insert(name, primoff);
6883 if (!cross_section_id_attrib.isValid()) {
6885 copy_order_attrib_data.myIsUsingMap =
false;
6886 same_cross_section_data &= (sopcache->myPrevCrossSectPrimAttribDataId == -1);
6887 sopcache->myPrevCrossSectPrimAttribDataId = -1;
6890 copy_order_attrib_data.myIntToPrimOff.destroy();
6891 copy_order_attrib_data.myStrToPrimOff.destroy();
6895 copy_order_attrib_data.myIsUsingMap =
true;
6896 const int64 new_cross_section_data_id = cross_section_id_attrib->getDataId();
6897 const bool same_map = (sopcache->myPrevCrossSectPrimAttribDataId == new_cross_section_data_id);
6898 same_cross_section_data &= same_map;
6899 sopcache->myPrevCrossSectPrimAttribDataId = new_cross_section_data_id;
6904 copy_order_attrib_data.myIntToPrimOff.destroy();
6905 copy_order_attrib_data.myStrToPrimOff.destroy();
6911 for (
GA_Offset primoff = start; primoff <
end; ++primoff) {
6912 exint id = cross_section_id_attrib.get(primoff);
6921 copy_order_attrib_data.myIntToPrimOff.insert(
id, primoff);
6928 if (!curve_attrib) {
6931 if (!string_missing_error_case)
6932 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());
6934 buf.
sprintf(
"Cross section doesn't have a primitive string attribute named \"%s\" for selecting cross section primitives,", cross_section_attrib_name.
c_str());
6938 copy_order = CopyOrder::CYCLEVTX;
6939 same_cross_section_data = (sopcache->myPrevCopyOrder == copy_order);
6940 sopcache->myPrevCrossSectCurveAttribDataId = -1;
6941 sopcache->myPrevCrossSectPrimAttribDataId = -1;
6942 copy_order_attrib_data.myIntToPrimOff.destroy();
6943 copy_order_attrib_data.myStrToPrimOff.destroy();
6948 static void removeUnnecessarySweepAttribs(
6959 attribs_to_delete.
append(attrib);
6961 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
6970 attribs_to_delete.
clear();
6974 attribs_to_delete.
append(attrib);
6976 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
6985 attribs_to_delete.
clear();
6988 attribs_to_delete.
append(attrib);
6990 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
6999 attribs_to_delete.
clear();
7002 attribs_to_delete.
append(attrib);
7004 for (
exint i = 0, n = attribs_to_delete.
size(); i <
n; ++i)
7011 edge_groups_to_delete.
append(it.group());
7013 for (
exint i = 0, n = edge_groups_to_delete.
size(); i <
n; ++i)
7019 static void setupSweepTransferAttribs(
7025 UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &cross_section_attribs,
7026 UT_Array<std::pair<const GA_Attribute*,GA_Attribute*>> &curve_attribs,
7027 UT_Array<std::pair<std::pair<const GA_ATINumeric*,const GA_ATINumeric*>,
GA_ATINumeric*>> &uv_attribs,
7028 exint &uv_attrib_index,
7029 const bool compute_uvs,
7030 const bool override_existing_uvs)
7037 UT_ASSERT(compute_uvs || !override_existing_uvs);
7038 uv_attrib_index = -1;
7044 if (cross_section_input)
7050 auto &&clone_attrib_functor = [&cross_section_attribs,&uv_attribs,&uv_attrib_index,&
filter,output_geo,
7051 curve_input,&curve_filter,override_existing_uvs,compute_uvs](
const GA_Attribute *attrib)
7053 if (!filter.match(attrib))
7060 const bool isuv = point_or_vertex &&
7063 if ((compute_uvs && override_existing_uvs) && isuv)
7079 GA_Attribute *new_attribute = output_geo->getAttributes().cloneAttribute(
7080 output_owner, attrib->
getName(),
7084 uv_attribs.append(std::make_pair(
7092 if (isuv && compute_uvs)
7096 GA_Attribute *new_attribute = output_geo->getAttributes().cloneAttribute(
7101 uv_attrib_index = uv_attribs.size();
7102 uv_attribs.append(std::make_pair(
7114 new_attribute = output_geo->getAttributes().cloneAttribute(
7122 output_geo->getElementGroupTable(owner).newGroup(attrib->
getName()));
7126 cross_section_attribs.append(std::make_pair(attrib, new_attribute));
7142 auto &&clone_attrib_functor = [&curve_attribs,&uv_attribs,&uv_attrib_index,&curve_filter,output_geo,
7143 cross_section_input,override_existing_uvs,compute_uvs](
const GA_Attribute *attrib)
7145 if (!curve_filter.match(attrib))
7154 if (cross_section_input)
7157 output_geo->findAttribute(owner, attrib->
getScope(), attrib->
getName());
7168 old_attrib = output_geo->findAttribute(
7177 const bool isuv = point_or_vertex &&
7180 if ((compute_uvs && override_existing_uvs) && isuv)
7188 if (isuv && compute_uvs)
7192 GA_Attribute *new_attribute = output_geo->getAttributes().cloneAttribute(
7197 uv_attrib_index = uv_attribs.size();
7198 uv_attribs.append(std::make_pair(
7209 new_attribute = output_geo->getAttributes().cloneAttribute(
7217 output_geo->getElementGroupTable(owner).newGroup(attrib->
getName()));
7221 curve_attribs.append(std::make_pair(attrib, new_attribute));
7231 .forEachAttribute(clone_attrib_functor);
7261 centre = 0.5*(p0+p1);
7270 UT_Vector3D new_normal = *out_normal -
dot(*out_normal, diff)*diff;
7273 *out_normal = new_normal;
7282 for (
exint i = 2; i <
n; ++i)
7291 covariance_matrix.
zero();
7294 pdiff = p1 - pos_avg;
7296 for (
exint i = 2; i <
n; ++i)
7299 pdiff = p - pos_avg;
7302 const double row_length2s[] = {
7303 covariance_matrix[0].length2(),
7304 covariance_matrix[1].length2(),
7305 covariance_matrix[2].length2()
7307 const int maxrow = SYSargmax(
7311 if (row_length2s[maxrow] == 0)
7319 UT_Vector3D maxrow_vec = covariance_matrix[maxrow];
7324 double maxrow_vec_eigen2 = (maxrow_vec*covariance_matrix).length2();
7325 double other_dir0_eigen2 = (other_dir0*covariance_matrix).length2();
7326 double other_dir1_eigen2 = (other_dir1*covariance_matrix).length2();
7329 if (other_dir0_eigen2+other_dir1_eigen2 < 1e-8*maxrow_vec_eigen2)
7331 pdiff = p0 - pos_avg;
7332 double min_from_avg = pdiff.
dot(maxrow_vec);
7333 double max_from_avg = min_from_avg;
7334 pdiff = p1 - pos_avg;
7335 double d = pdiff.
dot(maxrow_vec);
7336 min_from_avg =
SYSmin(min_from_avg, d);
7337 max_from_avg =
SYSmax(max_from_avg, d);
7338 for (
exint i = 2; i <
n; ++i)
7341 pdiff = p - pos_avg;
7342 d = pdiff.
dot(maxrow_vec);
7343 min_from_avg =
SYSmin(min_from_avg, d);
7344 max_from_avg =
SYSmax(max_from_avg, d);
7347 radius = 0.5*(max_from_avg - min_from_avg);
7348 centre = pos_avg + 0.5*(min_from_avg + max_from_avg);
7351 UT_Vector3D new_normal = *out_normal -
dot(*out_normal, maxrow_vec)*maxrow_vec;
7354 *out_normal = new_normal;
7362 for (
exint i = 2; i <
n; ++i)
7365 normal +=
cross(pprev-p0, pnext-p0);
7370 if (normal.length2() == 0)
7375 double max_distance2 =
distance2(centre, p0);
7376 for (
exint i = 1; i <
n; ++i)
7381 radius = SYSsqrt(max_distance2);
7386 double min_normal_dot = 0;
7387 double max_normal_dot = 0;
7388 for (
exint i = 1; i <
n; ++i)
7391 double dot = (p-p0).
dot(normal);
7392 min_normal_dot =
SYSmin(dot, min_normal_dot);
7393 max_normal_dot =
SYSmax(dot, max_normal_dot);
7397 double mid_normal_dot = 0.5*(min_normal_dot+max_normal_dot);
7403 tangent1 =
cross(normal, tangent0);
7409 for (
exint i = 1; i <
n; ++i)
7417 radius = SYSsqrt(radius2);
7421 centre = p0 + (normal*mid_normal_dot + tangent0*centre2d[0] + tangent1*centre2d[1]);
7427 if (out_normal->
dot(normal) < 0)
7428 *out_normal = -normal;
7430 *out_normal = normal;
7435 sopPrescaleTranslate(
7447 pret[0]*transform0[0][0] + pret[1]*transform0[1][0] + pret[2]*transform0[2][0] + transform0[3][0],
7448 pret[0]*transform0[0][1] + pret[1]*transform0[1][1] + pret[2]*transform0[2][1] + transform0[3][1],
7449 pret[0]*transform0[0][2] + pret[1]*transform0[1][2] + pret[2]*transform0[2][2] + transform0[3][2]
7453 scale*transform0[0][0], scale*transform0[0][1], scale*transform0[0][2], scale*transform0[0][3],
7454 scale*transform0[1][0], scale*transform0[1][1], scale*transform0[1][2], scale*transform0[1][3],
7455 scale*transform0[2][0], scale*transform0[2][1], scale*transform0[2][2], scale*transform0[2][3],
7456 t[0], t[1], t[2], 1.0
7463 const exint cap_divisions,
7471 scaled_z_dir = -scaled_z_dir;
7481 ztranslate = scaled_z_dir;
7485 const double scale_portion = double(capi)/double(cap_divisions);
7486 const double ztranslate_portion = 1.0 - scale_portion;
7492 const double theta =
M_PI_2*ztranslate_portion;
7493 const double scale_round = SYScos(theta);
7494 const double ztranslate_round = SYSsin(theta);
7501 const double scale_pointed = scale_portion;
7502 const double ztranslate_pointed = ztranslate_portion;
7505 double ztranslate_scalar;
7508 scale =
SYSlerp(scale_pointed, scale_round, roundness);
7509 ztranslate_scalar =
SYSlerp(ztranslate_pointed, ztranslate_round, roundness);
7511 else if (roundness == 0)
7513 scale = scale_pointed;
7514 ztranslate_scalar = ztranslate_pointed;
7524 scale =
SYSlerp(scale_pointed, 1.0-ztranslate_round, -roundness);
7525 ztranslate_scalar =
SYSlerp(ztranslate_pointed, 1.0-scale_round, -roundness);
7527 ztranslate = ztranslate_scalar*scaled_z_dir;
7529 return sopPrescaleTranslate(scale, centre, ztranslate, transform0);
7533 sopAllEndCapTransforms(
7534 const sop_SweepGrid &grid,
7535 const SOP_SweepHDKParms &sopparms,
7539 const exint num_vertices,
7542 bool use_cross_section_normal_for_z)
7544 const exint cap_divisions = sopparms.getCapDivs();
7555 if (grid.mySingleCrossSection && !
GAisValid(grid.myCrossSectionPrimOff))
7563 else if (grid.mySingleCrossSection)
7570 sopBoundingTube(cross_section_input, primoff, radius, centre,
7571 use_cross_section_normal_for_z ? &normal :
nullptr);
7574 centres[0] = centre;
7575 centres[1] = centre;
7576 if (use_cross_section_normal_for_z)
7578 normals[0] = normal;
7579 normals[1] = normal;
7584 GA_Offset primoff0 = (*grid.myCrossSectionPrimOffs)[0];
7585 GA_Offset primoff1 = grid.myCrossSectionPrimOffs->last();
7587 if (use_cross_section_normal_for_z && grid.myCrossSectionPrimOffs->size() >= 2*cap_divisions+1)
7592 sopBoundingTube(cross_section_input, primoff0, radius, centreA,
nullptr);
7593 sopBoundingTube(cross_section_input, (*grid.myCrossSectionPrimOffs)[cap_divisions+1], radius, centreB,
nullptr);
7594 normals[0] = centreA-centreB;
7596 sopBoundingTube(cross_section_input, primoff1, radius, centreA,
nullptr);
7597 sopBoundingTube(cross_section_input, (*grid.myCrossSectionPrimOffs)[grid.myCrossSectionPrimOffs->size()-2-cap_divisions], radius, centreB,
nullptr);
7598 normals[1] = centreB-centreA;
7601 sopBoundingTube(cross_section_input, primoff0, radii[0], centres[0],
7602 use_cross_section_normal_for_z ? &normals[0] :
nullptr);
7603 sopBoundingTube(cross_section_input, primoff1, radii[1], centres[1],
7604 use_cross_section_normal_for_z ? &normals[1] :
nullptr);
7606 if (use_cross_section_normal_for_z)
7616 const double cap_scale = sopparms.getCapScale();
7617 const double cap_roundness = sopparms.getCapRoundness();
7620 for (
exint i = 0; i < cap_divisions; ++i)
7622 const exint row = i;
7625 centres[0], (cap_scale*radii[0])*normals[0],
7626 cap_roundness, transform0);
7633 for (
exint i = 0; i < cap_divisions; ++i)
7637 const exint row = cap_divisions+num_vertices+i;
7639 cap_divisions-1-i, cap_divisions,
7640 centres[1], (-cap_scale*radii[1])*normals[1],
7641 cap_roundness, transform1);
7649 void SOP_SweepHDKVerb::cook(
const CookParms &cookparms)
const
7668 using namespace GU_Copy;
7677 auto &&sopparms = cookparms.
parms<SOP_SweepHDKParms>();
7684 const GU_Detail *
const cross_section_input =
7685 (sopparms.getSurfaceShape() == SurfaceShape::INPUT)
7686 ? cookparms.
inputGeo(theCrossSectionInput)
7691 if (!cookparms.
inputGeo(theCrossSectionInput) && !curve_input)
7694 output_geo->clearAndDestroy();
7698 if (!cross_section_input && (sopparms.getSurfaceShape() == SurfaceShape::INPUT))
7701 output_geo->clearAndDestroy();
7704 if (!curve_input && (sopparms.getSurfaceShape() != SurfaceShape::INPUT))
7707 output_geo->clearAndDestroy();
7718 if (sopparms.getCurveGroup().isstring())
7720 curve_group = group_manager.parsePrimitiveGroups(
7721 sopparms.getCurveGroup(),
7724 if (curve_group ==
nullptr)
7726 curve_group_list = curve_input->getPrimitiveMap().getOffsetFromIndexList();
7734 curve_group_list.setTrivialRange(curve_group_list.size(), start, end-start);
7740 if (cross_section_input)
7742 if (sopparms.getCrossSectionGroup().isstring())
7744 cross_section_group = group_manager.parsePrimitiveGroups(
7745 sopparms.getCrossSectionGroup(),
7748 if (cross_section_group ==
nullptr)
7758 cross_section_group_list.setTrivialRange(cross_section_group_list.size(), start, end-start);
7771 CopyOrder copy_order = (cross_section_input && curve_input) ? sopparms.getCopyOrder() : CopyOrder::CYCLEVTX;
7772 bool same_cross_section_data = (sopcache->myPrevCopyOrder == copy_order);
7776 setupCrossSectionAttribs(
7777 sopcache, cookparms, sopparms,
7778 same_cross_section_data, copy_order,
7779 cross_section_input, curve_input,
7780 cross_section_group);
7786 removeUnnecessarySweepAttribs(output_geo);
7793 bool need_to_build_surface =
true;
7795 const bool same_output_geo_as_last_cook =
7796 (output_geo->getUniqueId() == sopcache->myPrevOutputDetailID);
7797 int64 new_curve_prim_list_data_id = (curve_input ? curve_input->getPrimitiveList().getDataId() : -1);
7798 int64 new_curve_topology_data_id = (curve_input ? curve_input->getTopology().getDataId() : -1);
7799 if (same_output_geo_as_last_cook)
7801 const bool same_input_curves =
7802 (new_curve_prim_list_data_id == sopcache->myPrevCurvePrimListDataID) &&
7803 (new_curve_topology_data_id == sopcache->myPrevCurveTopologyDataID) &&
7804 (curve_group_list.size() == sopcache->myPrevCurveGroup.size()) &&
7805 (curve_group_list.isEqual(sopcache->myPrevCurveGroup, 0, curve_group_list.size()));
7807 bool same_surface_parms =
7808 (sopparms.getSurfaceType() == sopcache->myPrevSurfaceType) &&
7809 (sopparms.getUnrollClosedRowCol() == sopcache->myPrevUnrollClosedRowCol) &&
7810 (sopparms.getPrimType() == sopcache->myPrevPrimType) &&
7811 (sopparms.getEndCapType() == sopcache->myPrevEndCapType) &&
7812 (sopparms.getCapDivs() == sopcache->myPrevEndCapDivs) &&
7813 (sopparms.getTriangularPoles() == sopcache->myPrevTriangularPoles) &&
7814 (sopparms.getSwapRowCol() == sopcache->myPrevSwapRowCol);
7815 if (same_surface_parms)
7817 if (cross_section_input && sopcache->myPrevSurfaceShape == SurfaceShape::INPUT)
7819 same_surface_parms =
7820 (sopcache->myPrevSurfaceShape == SurfaceShape::INPUT) &&
7821 (sopcache->myPrevCloseIfNoCurveInput == sopparms.getCloseIfNoCurveInput()) &&
7822 same_cross_section_data &&
7824 (cross_section_input->
getTopology().
getDataId() == sopcache->myPrevCrossSectionTopologyDataID) &&
7825 (cross_section_group_list.size() == sopcache->myPrevCrossSectionGroup.size()) &&
7826 (cross_section_group_list.isEqual(sopcache->myPrevCrossSectionGroup, 0, cross_section_group_list.size()));
7830 same_surface_parms =
7831 (sopparms.getSurfaceShape() == sopcache->myPrevSurfaceShape) &&
7832 (sopparms.getCols() == sopcache->myPrevCols);
7839 if (same_input_curves && same_surface_parms)
7840 need_to_build_surface =
false;
7843 sopcache->myPrevOutputDetailID = output_geo->getUniqueId();
7844 sopcache->myPrevCurvePrimListDataID = new_curve_prim_list_data_id;
7845 sopcache->myPrevCurveTopologyDataID = new_curve_topology_data_id;
7846 sopcache->myPrevCurveGroup = std::move(curve_group_list);
7847 sopcache->myPrevSurfaceType = sopparms.getSurfaceType();
7848 sopcache->myPrevUnrollClosedRowCol = sopparms.getUnrollClosedRowCol();
7849 sopcache->myPrevPrimType = sopparms.getPrimType();
7850 sopcache->myPrevCloseIfNoCurveInput = sopparms.getCloseIfNoCurveInput();
7851 sopcache->myPrevSurfaceShape = sopparms.getSurfaceShape();
7852 sopcache->myPrevCols = (cross_section_input && sopcache->myPrevSurfaceShape == SurfaceShape::INPUT) ? -1 : sopparms.getCols();
7853 sopcache->myPrevEndCapType = sopparms.getEndCapType();
7854 sopcache->myPrevEndCapDivs = sopparms.getCapDivs();
7855 sopcache->myPrevTriangularPoles = sopparms.getTriangularPoles();
7856 sopcache->myPrevSwapRowCol = sopparms.getSwapRowCol();
7857 sopcache->myPrevCrossSectionPrimListDataID = cross_section_input ? cross_section_input->
getPrimitiveList().
getDataId() : -1;
7858 sopcache->myPrevCrossSectionTopologyDataID = cross_section_input ? cross_section_input->
getTopology().
getDataId() : -1;
7859 sopcache->myPrevCrossSectionGroup = std::move(cross_section_group_list);
7860 sopcache->myPrevCopyOrder = copy_order;
7863 const CrossSectionAttribMatchData *copy_order_attrib_data = (copy_order ==
CopyOrder::ATTRIB) ? &sopcache->myCrossSectionAttribMatchData :
nullptr;
7865 GEO_SurfaceType surface_type = sweepSurfaceToGeoSurface(sopparms.getSurfaceType());
7866 bool output_points_only = (sopparms.getSurfaceType() == SurfaceType::POINTS);
7867 exint cap_divisions =
7868 (sopparms.getEndCapType() ==
EndCapType::NONE || sopparms.getEndCapType() == EndCapType::SINGLE || sopparms.getEndCapType() == EndCapType::SIDESINGLE) ? 0 : sopparms.getCapDivs();
7870 if (need_to_build_surface)
7872 bool finished = createGrids(
7873 cross_section_input, cross_section_group,
7874 sopparms.getSurfaceShape(),
7875 sopparms.getCols() * ((sopparms.getSurfaceShape() == SurfaceShape::SQUARE) ? 4 : 1),
7876 copy_order, copy_order_attrib_data,
7877 curve_input, curve_group,
7878 sopparms.getCloseIfNoCurveInput(),
7879 surface_type, output_points_only, sopparms.getUnrollClosedRowCol(),
7880 sopParmToPrimType(sopparms.getPrimType()),
7881 sopparms.getEndCapType(), cap_divisions,
7882 sopparms.getTriangularPoles(),
7883 sopparms.getSwapRowCol(),
7898 exint uv_attrib_index = -1;
7900 setupSweepTransferAttribs(output_geo,
7901 cross_section_input, sopparms.getAttribsFromCrossSection(),
7902 curve_input, sopparms.getAttribsFromBackbone(),
7903 cross_section_attribs,
7907 sopparms.getComputeUVs(),
7908 sopparms.getComputeUVs() && sopparms.getOverrideExistingUVs());
7920 if (sopparms.getComputeUVs())
7922 if (cross_section_input)
7925 if (!sopparms.getOverrideExistingUVs())
7928 if (!input_uv_attrib.
isValid())
7933 if (!input_uv_attrib.
isValid() || sopparms.getOverrideExistingUVs())
7937 detached_cross_section_uv =
7940 rw_uv_attrib.
bind(detached_cross_section_uv.get());
7946 computeCurveUVs(cross_section_input, cross_section_group, rw_uv_attrib, sopparms.getLengthWeightedUVs(), sopparms.getReverseCrossSections());
7948 if (uv_attrib_index >= 0)
7951 uv_attribs[uv_attrib_index].first.first = rw_uv_attrib.
getAttribute();
7958 uv_attrib_index = uv_attribs.size();
7959 uv_attribs.append(std::make_pair(std::make_pair(rw_uv_attrib.
getAttribute(), (
const GA_ATINumeric*)
nullptr), output_attrib));
7966 exint nedgecols = sopparms.getCols();
7967 if (sopparms.getSurfaceShape() == SurfaceShape::SQUARE)
7969 bool closed = (sopparms.getSurfaceShape() == SurfaceShape::TUBE || sopparms.getSurfaceShape() == SurfaceShape::SQUARE);
7970 exint nvertices = nedgecols + !closed;
7972 for (
exint i = 0; i < nvertices; ++i)
7974 missing_input_us[i] = double(i)/double(nedgecols);
7977 if (uv_attrib_index < 0)
7984 uv_attrib_index = uv_attribs.size();
7985 uv_attribs.append(std::make_pair(std::make_pair((
const GA_ATINumeric*)
nullptr, (
const GA_ATINumeric*)
nullptr), output_attrib));
7995 if (!sopparms.getOverrideExistingUVs())
7998 if (!input_uv_attrib.
isValid())
8003 if (!input_uv_attrib.
isValid() || sopparms.getOverrideExistingUVs())
8008 curve_uv_deleter.reset(detached_uv_attrib);
8009 rw_uv_attrib.
bind(detached_uv_attrib);
8015 computeCurveUVs(curve_input, curve_group, rw_uv_attrib, sopparms.getLengthWeightedUVs());
8017 if (uv_attrib_index >= 0)
8020 uv_attribs[uv_attrib_index].first.second = rw_uv_attrib.
getAttribute();
8026 uv_attrib_index = uv_attribs.size();
8027 uv_attribs.append(std::make_pair(std::make_pair((
const GA_ATINumeric*)
nullptr, rw_uv_attrib.
getAttribute()), output_attrib));
8035 bool closed = sopparms.getCloseIfNoCurveInput();
8036 exint nedgecols = num_cross_sections - !closed;
8038 bool length_weighted_uvs = sopparms.getLengthWeightedUVs();
8039 if (length_weighted_uvs)
8047 exint cross_section_i = 0;
8048 double total_distance = 0;
8049 for (; !cross_section_it.
atEnd(); ++cross_section_it)
8055 for (
exint i = 0; i <
n; ++i)
8058 centroid += pos_attrib.get(ptoff);
8063 if (cross_section_i == 0)
8065 first_centroid = centroid;
8072 missing_input_us[cross_section_i] = total_distance;
8075 prev_centroid = centroid;
8080 double distance = first_centroid.distance(prev_centroid);
8084 if (total_distance == 0)
8087 length_weighted_uvs =
false;
8091 for (
exint i = 0, n = missing_input_us.
size(); i <
n; ++i)
8093 missing_input_us[i] /= total_distance;
8099 if (!length_weighted_uvs)
8102 for (
exint i = 0; i < num_cross_sections; ++i)
8104 missing_input_us[i] = double(i)/double(nedgecols);
8111 const bool computing_uvs = (uv_attrib_index >= 0);
8119 exint total_transforms = 0;
8120 if (curve_input !=
nullptr)
8128 curve_input->createDetachedTupleAttribute(
8130 GA_RWHandleM4D transform_attrib(detached_transform_attrib.get());
8135 parms.myExtrapolateEndTangents = sopparms.getExtrapolateEndTangents();
8136 parms.myTransformByInstanceAttribs = sopparms.getTransformByAttribs();
8140 const bool applypitch = sopparms.getApplyPitch();
8141 const bool applyyaw = sopparms.getApplyYaw();
8142 const bool applyroll = sopparms.getApplyRoll();
8144 applypitch ? SYSdegToRad(sopparms.getPitch()) : 0.0,
8145 applyyaw ? SYSdegToRad(sopparms.getYaw()) : 0.0,
8146 applyroll ? SYSdegToRad(sopparms.getRoll()) : 0.0);
8147 parms.myAngles = angles;
8149 applypitch ? SYSdegToRad(sopparms.getIncPitch()) : 0.0,
8150 applyyaw ? SYSdegToRad(sopparms.getIncYaw()) : 0.0,
8151 applyroll ? SYSdegToRad(sopparms.getIncRoll() + 360.0*sopparms.getFullTwists()) : 0.0);
8152 parms.myIncAngles = incangles;
8164 parms.myRotAttribs[0].bind(curve_input->findAttribute(sopparms.getPitchAttrib(), search_order, 4));
8166 parms.myRotAttribs[1].bind(curve_input->findAttribute(sopparms.getYawAttrib(), search_order, 4));
8168 parms.myRotAttribs[2].bind(curve_input->findAttribute(sopparms.getRollAttrib(), search_order, 4));
8172 switch (sopparms.getUpVectorType())
8180 parms.myTargetUpVectorAttrib.bind(curve_input, GA_ATTRIB_PRIMITIVE, sopparms.getUpVectorAttrib());
8181 if (!parms.myTargetUpVectorAttrib.isValid())
8183 parms.myTargetUpVectorAttrib.bind(curve_input,
GA_ATTRIB_DETAIL, sopparms.getUpVectorAttrib());
8185 if (parms.myTargetUpVectorAttrib.isValid() && parms.myTargetUpVectorAttrib->getOwner() ==
GA_ATTRIB_DETAIL)
8188 parms.myTargetUpVector = parms.myTargetUpVectorAttrib.get(
GA_DETAIL_OFFSET);
8189 parms.myTargetUpVectorAttrib.clear();
8193 if (!parms.myTargetUpVectorAttrib.isValid())
8201 case UpVectorType::CUSTOM: parms.myTargetUpVector = sopparms.getUpVector();
break;
8203 parms.myUseCurveNormalAsTargetUp = (sopparms.getUpVectorType() == UpVectorType::NORMAL);
8204 parms.myTargetUpVectorAtStart = sopparms.getUpVectorAtStart();
8205 parms.myContinuousClosedCurves = sopparms.getContinuousClosed();
8207 if (parms.myTargetUpVectorAtStart && sopparms.getUseEndUpVector())
8209 parms.myUseEndTargetUpVector =
true;
8212 parms.myEndTargetUpVectorAttrib.bind(curve_input, GA_ATTRIB_PRIMITIVE, sopparms.getEndUpVectorAttrib());
8213 if (!parms.myEndTargetUpVectorAttrib.isValid())
8215 parms.myEndTargetUpVectorAttrib.bind(curve_input,
GA_ATTRIB_DETAIL, sopparms.getEndUpVectorAttrib());
8217 if (parms.myEndTargetUpVectorAttrib.isValid() && parms.myEndTargetUpVectorAttrib->getOwner() ==
GA_ATTRIB_DETAIL)
8220 parms.myEndTargetUpVector = parms.myEndTargetUpVectorAttrib.get(
GA_DETAIL_OFFSET);
8221 parms.myEndTargetUpVectorAttrib.clear();
8225 if (!parms.myEndTargetUpVectorAttrib.isValid())
8227 cookparms.
sopAddWarning(
SOP_MESSAGE,
"End target up vector attribute not found; defaulting to no end target up vector.");
8228 parms.myUseEndTargetUpVector =
false;
8233 else if (sopparms.getUpVectorType() == UpVectorType::CUSTOM)
8235 parms.myEndTargetUpVector = sopparms.getEndUpVector();
8239 parms.myEndTargetUpVector = parms.myTargetUpVector;
8243 parms.myNormalizeScales =
false;
8245 if (sopparms.getSurfaceShape() == SurfaceShape::INPUT)
8246 parms.myUniformScale = sopparms.getScale();
8247 else if (sopparms.getSurfaceShape() == SurfaceShape::TUBE)
8248 parms.myUniformScale = sopparms.getRadius();
8250 parms.myUniformScale = 0.5*sopparms.getWidth();
8252 if(sopparms.getApplyScale())
8253 parms.myScaleRamp = sopparms.getScaleRamp().get();
8255 parms.myStretchAroundTurns = sopparms.getStretchAroundTurns();
8256 parms.myMaxStretchScale = sopparms.getMaxStretchAroundTurns();
8261 total_transforms = 0;
8262 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8264 const sop_SweepGrid &grid = grids[gridi];
8265 total_transforms += grid.myCurveNEdges + !grid.myCurveClosed;
8267 sopcache->myGridTransformStarts.reset(
new exint[grids.
size()]);
8268 sopcache->clearTransformArrays();
8269 sopcache->myTransformMatrices3D.reset(
new UT_Matrix3D[total_transforms]);
8270 sopcache->myTransformTranslates3D.reset(
new UT_Vector3D[total_transforms]);
8271 sopcache->myTransformCacheSize = total_transforms;
8272 exint *grid_transform_starts = sopcache->myGridTransformStarts.get();
8273 UT_Matrix3D *transform_matrix3ds = sopcache->myTransformMatrices3D.get();
8274 UT_Vector3D *transform_translate3ds = sopcache->myTransformTranslates3D.get();
8275 exint current_transform_start = 0;
8276 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8278 const sop_SweepGrid &grid = grids[gridi];
8279 grid_transform_starts[gridi] = current_transform_start;
8280 current_transform_start += grid.myCurveNEdges + !grid.myCurveClosed;
8283 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8285 const sop_SweepGrid &grid = grids[gridi];
8287 const GA_Offset curve_primoff = grid.myCurvePrimOff;
8288 const GA_OffsetListRef vertices = curve_input->getPrimitiveVertexList(curve_primoff);
8293 (curve_input->vertexPoint(vertices(0)) == curve_input->vertexPoint(vertices.
last()));
8295 if (vertices.
size() == 1)
8299 curve_unrolled =
false;
8305 const exint grid_transform_start = grid_transform_starts[gridi];
8306 UT_Matrix3D *grid_matrix3ds = transform_matrix3ds + grid_transform_start;
8307 UT_Vector3D *grid_translate3ds = transform_translate3ds + grid_transform_start;
8310 const exint row_start = grid.myVEndPoles ? cap_divisions : 0;
8311 for (
exint i = 0; i < num_vertices; ++i)
8313 const UT_Matrix4D transform = transform_attrib.get(vertices(i));
8314 UT_ASSERT(grid_transform_start+row_start+i < total_transforms);
8315 grid_matrix3ds[row_start+i] =
UT_Matrix3D(transform);
8319 if (grid.myVEndPoles)
8323 const UT_Matrix4D transform0 = transform_attrib.get(vtxoff0);
8324 const UT_Matrix4D transform1 = transform_attrib.get(vtxoff1);
8326 sopAllEndCapTransforms(
8327 grid, sopparms, cross_section_input,
8328 transform0, transform1, num_vertices,
8329 grid_matrix3ds, grid_translate3ds,
8334 else if (grids.
size() == 1 && grids[0].myVEndPoles)
8338 const sop_SweepGrid &grid = grids[0];
8341 total_transforms = grid.myCurveNEdges + !grid.myCurveClosed;
8342 exint num_vertices = total_transforms - 2*cap_divisions;
8344 sopcache->myGridTransformStarts.reset(
new exint[1]);
8345 sopcache->clearTransformArrays();
8346 sopcache->myTransformMatrices3D.reset(
new UT_Matrix3D[total_transforms]);
8347 sopcache->myTransformTranslates3D.reset(
new UT_Vector3D[total_transforms]);
8348 sopcache->myTransformCacheSize = total_transforms;
8349 exint *grid_transform_starts = sopcache->myGridTransformStarts.get();
8350 UT_Matrix3D *grid_matrix3ds = sopcache->myTransformMatrices3D.get();
8351 UT_Vector3D *grid_translate3ds = sopcache->myTransformTranslates3D.get();
8352 grid_transform_starts[0] = 0;
8355 for (
exint i = 0; i < num_vertices; ++i)
8357 UT_ASSERT(cap_divisions+i < total_transforms);
8358 grid_matrix3ds[cap_divisions+i].
identity();
8359 grid_translate3ds[cap_divisions+i] =
UT_Vector3D(0,0,0);
8363 sopAllEndCapTransforms(
8364 grid, sopparms, cross_section_input,
8365 identity, identity, num_vertices,
8366 grid_matrix3ds, grid_translate3ds,
8371 sopcache->clearTransformArrays();
8378 needed_transforms[i] =
false;
8380 for (
exint attribi = 0, nattribs = cross_section_attribs.size(); attribi < nattribs; ++attribi)
8382 GA_Attribute *output_attrib = cross_section_attribs[attribi].second;
8384 if (output_numeric ==
nullptr)
8391 using namespace NeededTransforms;
8396 needed_transforms[
matrix3f] |= !double_precision;
8397 needed_transforms[
translate3f] |= !double_precision;
8401 needed_transforms[
matrix3f] |= !double_precision;
8405 needed_transforms[
inverse3d] |= double_precision;
8406 needed_transforms[
inverse3f] |= !double_precision;
8410 needed_transforms[
quaterniond] |= double_precision;
8411 needed_transforms[
quaternionf] |= !double_precision;
8415 needed_transforms[
matrix3f] |= !double_precision;
8426 const SOP_SweepHDKCache *transform_cache = (sopcache->myTransformCacheSize != 0) ? sopcache :
nullptr;
8437 if (!cross_section_input)
8441 output_geo->getP()->bumpDataId();
8446 const exint cross_section_nedges = sopparms.getCols();
8447 if (sopparms.getSurfaceShape() == SurfaceShape::TUBE)
8449 cross_section_positions.
setSize(cross_section_nedges);
8450 if (cross_section_nedges == 1)
8452 cross_section_positions[0].assign(1,0,0);
8456 cross_section_positions[0].assign(1,0,0);
8457 for (
exint cross_sectioni = 1; cross_sectioni < cross_section_nedges; ++cross_sectioni)
8459 exint tcross_sectioni = cross_sectioni;
8460 if (sopparms.getReverseCrossSections())
8461 tcross_sectioni = reverseVtx(cross_sectioni, cross_section_nedges,
true);
8462 double t = double(tcross_sectioni)/double(cross_section_nedges);
8472 double theta = (2.0*
M_PI)*t;
8473 double c = SYScos(theta);
8474 double s = SYSsin(theta);
8480 cross_section_positions[cross_sectioni] =
v;
8484 else if (sopparms.getSurfaceShape() == SurfaceShape::RIBBON)
8486 cross_section_positions.setSize(cross_section_nedges+1);
8489 double x0 = (sopparms.getReverseCrossSections() ? 1 : -1);
8491 cross_section_positions[0].assign(x0, 0, 0);
8492 for (
exint cross_sectioni = 1; cross_sectioni < cross_section_nedges; ++cross_sectioni)
8494 double t = double(cross_sectioni)/double(cross_section_nedges);
8496 cross_section_positions[cross_sectioni] =
UT_Vector3D(x,0,0);
8498 cross_section_positions.last().assign(x1,0,0);
8502 UT_ASSERT(sopparms.getSurfaceShape() == SurfaceShape::SQUARE);
8504 cross_section_positions.setSize(4*cross_section_nedges);
8513 if (!sopparms.getReverseCrossSections())
8514 UTswap(corners[1], corners[3]);
8517 for (
exint big_edgei = 0; big_edgei < 4; ++big_edgei)
8520 cross_section_positions[arrayi].assign(corners[big_edgei][0], corners[big_edgei][1], 0);
8524 UT_Vector2D next = corners[(big_edgei==3) ? 0 : (big_edgei+1)];
8525 for (
exint small_edgei = 1; small_edgei < cross_section_nedges; ++small_edgei, ++arrayi)
8527 double t = double(small_edgei)/double(cross_section_nedges);
8529 cross_section_positions[arrayi].assign(pos2d[0], pos2d[1], 0);
8544 auto grid_transforms = gridOffsetTransforms(transform_cache, local_grid_transforms, gridi);
8545 const sop_SweepGrid &grid_info = grids[gridi];
8547 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8549 const bool swap_row_col = sopparms.getSwapRowCol();
8550 exint prev_vtxi = -1;
8551 auto&& functor = [&prev_vtxi,&cross_section_positions,swap_row_col,grid_transforms,&
transform,&outputP]
8554 const exint curve_vtxi = swap_row_col ? col :
row;
8555 if (curve_vtxi != prev_vtxi)
8557 transform =
UT_Matrix4D(grid_transforms->getMatrix3s<
double>()[curve_vtxi]);
8558 transform.setTranslates(grid_transforms->getTranslates<
double>()[curve_vtxi]);
8559 prev_vtxi = curve_vtxi;
8564 const exint cross_section_vtxi = swap_row_col ? row : col;
8565 const UT_Vector3D &cross_section_pos = cross_section_positions[cross_section_vtxi];
8566 outputP.set(output_offset, (cross_section_pos * transform));
8573 const exint PARALLEL_THRESHOLD = 2048;
8574 if (ngrids > 1 && output_geo->getNumPoints() >= PARALLEL_THRESHOLD)
8577 outputP->hardenAllPages();
8587 exint num_cross_sections;
8588 if (cross_section_group !=
nullptr)
8590 num_cross_sections = cross_section_group->
entries();
8592 else if (cross_section_input !=
nullptr)
8598 num_cross_sections = 1;
8601 const UVStyle ustyle = (!computing_uvs || !sopparms.getLengthWeightedUVs() || sopparms.getNormalizeU()) ?
8602 UVStyle::NORMALIZED :
8603 (sopparms.getWrapU() ? UVStyle::ROUNDED : UVStyle::FULL);
8604 const UVStyle vstyle = (!computing_uvs || !sopparms.getLengthWeightedUVs() || sopparms.getNormalizeV()) ?
8605 UVStyle::NORMALIZED :
8606 (sopparms.getWrapV() ? UVStyle::ROUNDED : UVStyle::FULL);
8608 bool finished = copySurfaceAttributes(
8609 output_geo, curve_input, cross_section_input,
8611 cross_section_attribs,
8612 curve_attribs, uv_attribs,
8614 surface_type, output_points_only, sopparms.getTriangularPoles(), cap_divisions,
8615 sopparms.getReverseCrossSections(), sopparms.getSwapRowCol(),
8617 (!missing_input_us.
isEmpty()) ? &missing_input_us :
nullptr,
8618 sopparms.getLengthWeightedUVs(),
8620 (curve_input ==
nullptr) || sopparms.getUseMeshEdgeLengths(),
8621 sopparms.getPropScalePerCurve(),
8622 computing_uvs && sopparms.getFlipU(),
8623 sopparms.getUVScale());
8635 if (sopparms.getAddPointRow() && sopparms.getPtRowAttrib().isstring())
8640 if (attrib.isValid())
8642 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8644 const sop_SweepGrid &grid_info = grids[gridi];
8646 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8650 attrib.set(output_ptoff, ptrow);
8655 if (sopparms.getAddPointCol() && sopparms.getPtColAttrib().isstring())
8660 if (attrib.isValid())
8662 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8664 const sop_SweepGrid &grid_info = grids[gridi];
8666 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8670 attrib.set(output_ptoff, ptcol);
8675 if (sopparms.getAddPrimRow() && sopparms.getPrimRowAttrib().isstring())
8680 if (attrib.isValid())
8682 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8684 const sop_SweepGrid &grid_info = grids[gridi];
8686 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8688 GA_Offset grid_start_primoff = grid_info.myStartPrimOff;
8689 if (grid_info.myHasPolygonCaps)
8692 attrib.set(grid_start_primoff, 0);
8693 ++grid_start_primoff;
8699 attrib.set(grid_start_primoff + primnum, primrow);
8702 if (grid_info.myHasPolygonCaps)
8705 attrib.set(grid_start_primoff + grid.
myNumPrimitives, grid_info.myCurveNEdges);
8710 if (sopparms.getAddPrimCol() && sopparms.getPrimColAttrib().isstring())
8715 if (attrib.isValid())
8717 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8719 const sop_SweepGrid &grid_info = grids[gridi];
8721 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8723 GA_Offset grid_start_primoff = grid_info.myStartPrimOff;
8724 if (grid_info.myHasPolygonCaps)
8727 attrib.set(grid_start_primoff, 0);
8728 ++grid_start_primoff;
8734 attrib.set(grid_start_primoff + primnum, primcol);
8737 if (grid_info.myHasPolygonCaps)
8745 if (sopparms.getAddCurveNum() && sopparms.getCurveNumAttrib().isstring())
8750 if (attrib.isValid())
8752 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8754 const sop_SweepGrid &grid_info = grids[gridi];
8756 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8759 exint curve_number = (curve_input !=
nullptr) ?
exint(curve_input->primitiveIndex(grid_info.myCurvePrimOff)) : 0;
8763 attrib.set(output_ptoff, curve_number);
8768 if (sopparms.getAddCrossSectionNum() && sopparms.getCrossSectionNumAttrib().isstring())
8771 const UT_StringHolder &attribname = sopparms.getCrossSectionNumAttrib();
8773 if (attrib.isValid())
8775 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8777 const sop_SweepGrid &grid_info = grids[gridi];
8779 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8781 if (cross_section_input !=
nullptr)
8785 GA_Offset source_cross_section_primoff =
8786 grid_info.mySingleCrossSection ?
8787 GA_Offset(grid_info.myCrossSectionPrimOff) :
8788 (*grid_info.myCrossSectionPrimOffs)[ptrow];
8790 exint cross_section_number = cross_section_input->
primitiveIndex(source_cross_section_primoff);
8792 attrib.set(output_ptoff, cross_section_number);
8800 attrib.set(output_ptoff, 0);
8806 if (sopparms.getAddEndCapsGroup() && sopparms.getEndCapsGroup().isstring())
8813 for (
exint gridi = 0, ngrids = grids.
size(); gridi < ngrids; ++gridi)
8815 const sop_SweepGrid &grid_info = grids[gridi];
8817 initGUGrid(grid_info, surface_type, output_points_only, sopparms.getTriangularPoles(), sopparms.getSwapRowCol(), grid_info.myStartPtOff, grid);
8819 GA_Offset grid_start_primoff = grid_info.myStartPrimOff;
8820 if (grid_info.myHasPolygonCaps)
8826 else if (grid_info.myVEndPoles)
8829 exint last_cap_start_vtxi = grid_info.myCurveNEdges - cap_divisions;
8830 const bool swap_row_col = sopparms.getSwapRowCol();
8834 exint curve_vtxi = swap_row_col ? primcol : primrow;
8835 if (curve_vtxi < cap_divisions || curve_vtxi >= last_cap_start_vtxi)
8837 group->
addOffset(grid_start_primoff + primnum);
8850 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
PUGI__FN 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
#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.
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
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".
GA_API const UT_StringHolder parms
IMATH_NAMESPACE::V2f IMATH_NAMESPACE::Box2i std::string this attribute is obsolete as of OpenEXR v3 float
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_NO_DISCARD_RESULT 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 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)
const char * inputLabel(OP_InputIdx idx) const override
These are the labels that appear when hovering over the inputs.
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.
int isRefInput(OP_InputIdx i) const override
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
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