HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_GridImpl.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GU_GridImpl.h (GU Library, C++)
7  *
8  * COMMENTS: Definitions of GU_Grid-related functions
9  */
10 
11 #pragma once
12 
13 #include "GU_Grid.h"
14 #include <GEO/GEO_SurfaceType.h>
15 #include <UT/UT_Assert.h>
16 #include <SYS/SYS_Types.h>
17 
18 /// This calls functor for each point in grid, as:
19 /// functor(point, row, col)
20 ///
21 /// Consecutive repeated points in a row are skipped,
22 /// as well as points at the beginning and end of a wrap.
23 ///
24 /// Unlike the primitive and vertex iteration functions,
25 /// the points passed to the functor are not in ascending order,
26 /// they are the points in the grid.
27 template<typename INT_TYPE,typename FUNCTOR>
28 void GUiterateGridPoints(const GU_GridT<INT_TYPE> &grid, FUNCTOR &&functor)
29 {
30  const exint nedgerows = grid.myNumEdgeRows;
31  const exint nedgecols = grid.myNumEdgeCols;
32 
33  if (nedgerows < 0 || nedgecols < 0)
34  return;
35 
36  // NOTE: This -1 will never be used, but is here just in case.
37  INT_TYPE prev_pt = INT_TYPE(-1);
38 
39  for (exint row = 0; row < nedgerows; ++row)
40  {
41  for (exint col = 0; col < nedgecols; ++col)
42  {
43  INT_TYPE point = grid.getPoint(row, col);
44  if (col == 0 || point != prev_pt)
45  {
46  functor(point, row, col);
47  prev_pt = point;
48  }
49  }
50  INT_TYPE point = grid.getPoint(row, nedgecols);
51  if (nedgecols == 0 || (!grid.doesRowWrap(row) && point != prev_pt))
52  {
53  functor(point, row, nedgecols);
54  prev_pt = point;
55  }
56  }
57  for (exint col = 0; col < nedgecols; ++col)
58  {
59  INT_TYPE point = grid.getPoint(nedgerows, col);
60  if (nedgerows == 0 || (!grid.doesColWrap(col) && (col == 0 || point != prev_pt)))
61  {
62  functor(point, nedgerows, col);
63  prev_pt = point;
64  }
65  }
66  INT_TYPE point = grid.getPoint(nedgerows, nedgecols);
67  if ((nedgecols == 0 || !grid.doesRowWrap(nedgerows)) && (nedgerows == 0 || !grid.doesColWrap(nedgecols)) && point != prev_pt)
68  {
69  functor(point, nedgerows, nedgecols);
70  prev_pt = point;
71  }
72 }
73 
74 /// This calls functor for each primitive in grid, as:
75 /// functor(primnum, row, col, primvtxcount, closed)
76 template<typename INT_TYPE,typename FUNCTOR>
77 void GUiterateGridPrimitives(const GU_GridT<INT_TYPE> &grid, FUNCTOR &&functor)
78 {
79  using PrimitiveType = typename GU_GridT<INT_TYPE>::PrimitiveType;
80  if (grid.myPrimitiveType == PrimitiveType::POINTS)
81  return;
82 
83  const GEO_SurfaceType surface_type = grid.mySurfaceType;
84  const bool rows_and_cols = (surface_type == GEO_PATCH_ROWCOL);
85  const exint nedgerows = grid.myNumEdgeRows;
86  const exint nedgecols = grid.myNumEdgeCols;
87 
88  if (nedgerows < 0 || nedgecols < 0)
89  return;
90 
91  exint primnum = 0;
92 
93  if (grid.isInvalidTPSurf())
94  return;
95 
96  if (grid.myPrimitiveType != PrimitiveType::POLYGON)
97  {
98  // Only one primitive
99  // FIXME: Support myCurvesIfBasisRowCol!
100  functor(primnum, 0, 0, grid.myNumVertices, false);
101  return;
102  }
103 
104  // Get the special cases out of the way so that it's easier later
105  if (nedgerows == 0)
106  {
107  // Single row
108  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
109  {
110  exint nvertices = 1; // 1 vertex if both zero, regardless of wrap or unroll.
111  bool closed = false;
112  if (nedgecols > 0)
113  {
114  closed = (grid.doesRowWrap(0) && !grid.myUnrollCurves);
115  nvertices = nedgecols + exint(!closed);
116  }
117  functor(primnum, 0, 0, nvertices, closed);
118  ++primnum;
119 
120  if (!rows_and_cols)
121  return;
122  }
123  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
124  {
125  exint npoints = 1; // 1 point if both zero, regardless of wrap.
126  if (nedgecols > 0)
127  {
128  bool closed_curve = grid.doesRowWrap(0);
129  npoints = nedgecols + exint(!closed_curve);
130  }
131  for (exint col = 0; col < npoints; ++col)
132  {
133  functor(primnum, 0, col, 1, false);
134  ++primnum;
135  }
136  }
137  // Only rows, cols, and rowcol have vertices when a single row.
138  return;
139  }
140  if (nedgecols == 0)
141  {
142  // Single column (and multiple rows, since nedgerows==0 has already returned)
143  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
144  {
145  bool closed_curve = grid.doesColWrap(0);
146  exint npoints = nedgerows + exint(!closed_curve);
147 
148  for (exint row = 0; row < npoints; ++row)
149  {
150  functor(primnum, row, 0, 1, false);
151  ++primnum;
152  }
153 
154  if (!rows_and_cols)
155  return;
156  }
157  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
158  {
159  bool closed = (grid.doesColWrap(0) && !grid.myUnrollCurves);
160  exint nvertices = nedgerows + exint(!closed);
161  functor(primnum, 0, 0, nvertices, closed);
162  ++primnum;
163  }
164  // Only rows, cols, and rowcol have vertices when a single row.
165  return;
166  }
167 
168  // Main cases; note that nedgerows and nedgecols are both at least 1.
169 
170  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
171  {
172  bool closed = (grid.myAllWrapU && !grid.myUnrollCurves);
173  exint nvertices = nedgecols + exint(!closed);
174  bool different_nvertices = (!grid.myAllWrapU && !grid.myNoWrapU && !grid.myUnrollCurves);
175 
176  exint first_row = (grid.myNoWrapV && !grid.myFirstRowIfNotWrapped);
177  for (exint row = first_row; row < nedgerows; ++row, ++primnum)
178  {
179  if (different_nvertices)
180  {
181  closed = grid.doesRowWrap(row);
182  nvertices = nedgecols + exint(!closed);
183  }
184  functor(primnum, row, 0, nvertices, closed);
185  }
186 
187  if (!grid.myAllWrapV && grid.myLastRowIfNotWrapped)
188  {
189  if (grid.myNoWrapV)
190  {
191  if (different_nvertices)
192  {
193  closed = grid.doesRowWrap(nedgerows);
194  nvertices = nedgecols + exint(!closed);
195  }
196  functor(primnum, nedgerows, 0, nvertices, closed);
197  ++primnum;
198  }
199  else
200  {
201  exint primvtx = 0;
202  bool col_wraps = grid.doesColWrap(0);
203  bool next_col_wraps;
204  exint primstartcol;
205  for (exint col = 0; col < nedgecols; ++col, col_wraps = next_col_wraps)
206  {
207  next_col_wraps = grid.doesColWrap(col+1);
208  bool currently_in_a_curve = (primvtx != 0);
209  if (!currently_in_a_curve)
210  {
211  if (col_wraps && next_col_wraps)
212  {
213  // If current point and next point are wrapping v,
214  // and we're not currently in a curve, skip.
215  // O=======(O)=======O
216  continue;
217  }
218 
219  // (O)------O //
220  // (O)------O //
221  // or //
222  // (O)-----\ //
223  // (O)------O //
224  // or //
225  // /------O //
226  // O=======(O)-------O //
227  primstartcol = col;
228  primvtx = 1;
229  }
230  else if (col_wraps && next_col_wraps)
231  {
232  // O------\ //
233  // O-------(O)=======O //
234  // Done a curve, so call the functor.
235  functor(primnum, nedgerows, primstartcol, col+1-primstartcol, false);
236  ++primnum;
237  primvtx = 0;
238  }
239  else
240  {
241  // O------\ /------O //
242  // O-------(O)-------O //
243  // or //
244  // O-------(O)-------O //
245  // O--------O--------O //
246  // or //
247  // O-------(O)------\ //
248  // O--------O--------O //
249  // Already in a curve, so no need to call the functor.
250  ++primvtx;
251  }
252  }
253  if ((!grid.doesRowWrap(nedgerows) || grid.myUnrollCurves) && (primvtx != 0))
254  {
255  // O-------(O) //
256  // O-------(O) //
257  // or //
258  // O------\ //
259  // O-------(O) //
260  // or //
261  // /------(O) //
262  // O-------(O) //
263  // Done a curve, so call the functor.
264  functor(primnum, nedgerows, primstartcol, nedgecols+1-primstartcol, false);
265  ++primnum;
266  primvtx = 0;
267  }
268  }
269  }
270 
271  if (!rows_and_cols)
272  return;
273  }
274  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
275  {
276  // Just like the rows case, but with rows and cols (mostly) swapped
277  bool closed = (grid.myAllWrapV && !grid.myUnrollCurves);
278  exint nvertices = nedgerows + exint(!closed);
279  bool different_nvertices = (!grid.myAllWrapV && !grid.myNoWrapV && !grid.myUnrollCurves);
280 
281  exint first_col = (grid.myNoWrapU && !grid.myFirstColIfNotWrapped);
282  for (exint col = first_col; col < nedgecols; ++col, ++primnum)
283  {
284  if (different_nvertices)
285  {
286  closed = grid.doesColWrap(col);
287  nvertices = nedgerows + exint(!closed);
288  }
289  functor(primnum, 0, col, nvertices, closed);
290  }
291 
292  if (!grid.myAllWrapU && grid.myLastColIfNotWrapped)
293  {
294  if (grid.myNoWrapU)
295  {
296  if (different_nvertices)
297  {
298  closed = grid.doesColWrap(nedgecols);
299  nvertices = nedgerows + exint(!closed);
300  }
301  functor(primnum, 0, nedgecols, nvertices, closed);
302  ++primnum;
303  }
304  else
305  {
306  exint primvtx = 0;
307  bool row_wraps = grid.doesRowWrap(0);
308  bool next_row_wraps;
309  exint primstartrow;
310  for (exint row = 0; row < nedgerows; ++row, row_wraps = next_row_wraps)
311  {
312  next_row_wraps = grid.doesRowWrap(row+1);
313  bool currently_in_a_curve = (primvtx != 0);
314  if (!currently_in_a_curve)
315  {
316  if (row_wraps && next_row_wraps)
317  {
318  // If current point and next point are wrapping u,
319  // and we're not currently in a curve, skip.
320  // O=======(O)=======O
321  continue;
322  }
323 
324  // (O)------O //
325  // (O)------O //
326  // or //
327  // (O)-----\ //
328  // (O)------O //
329  // or //
330  // /------O //
331  // O=======(O)-------O //
332  primstartrow = row;
333  primvtx = 1;
334  }
335  else if (row_wraps && next_row_wraps)
336  {
337  // O------\ //
338  // O-------(O)=======O //
339  // Done a curve, so call the functor.
340  functor(primnum, primstartrow, nedgecols, row+1-primstartrow, false);
341  ++primnum;
342  primvtx = 0;
343  }
344  else
345  {
346  // O------\ /------O //
347  // O-------(O)-------O //
348  // or //
349  // O-------(O)-------O //
350  // O--------O--------O //
351  // or //
352  // O-------(O)------\ //
353  // O--------O--------O //
354  // Already in a curve, so no need to call the functor.
355  ++primvtx;
356  }
357  }
358  if ((!grid.doesColWrap(nedgecols) || grid.myUnrollCurves) && (primvtx != 0))
359  {
360  // O-------(O) //
361  // O-------(O) //
362  // or //
363  // O------\ //
364  // O-------(O) //
365  // or //
366  // /------(O) //
367  // O-------(O) //
368  // Done a curve, so call the functor.
369  functor(primnum, primstartrow, nedgecols, nedgerows+1-primstartrow, false);
370  ++primnum;
371  primvtx = 0;
372  }
373  }
374  }
375  return;
376  }
377 
378  UT_ASSERT_MSG(nedgerows >= 1 && nedgecols >= 1, "Caller should have switched quads to rows or cols");
379 
380  if (!grid.myTriangularPoles)
381  {
382  if (surface_type == GEO_PATCH_QUADS)
383  {
384  // All quads: simple.
385  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
386  {
387  for (exint col = 0; col < nedgecols; ++col, ++primnum)
388  {
389  functor(primnum, row, col, 4, true);
390  }
391  }
392  return;
393  }
394 
395  // All tris in the form of quads: simple.
396  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
397  {
398  for (exint col = 0; col < nedgecols; ++col, primnum+=2)
399  {
400  functor(primnum, row, col, 3, true);
401  functor(primnum+1, row, col, 3, true);
402  }
403  }
404  return;
405  }
406 
407  // grid.myTriangularPoles is true, which means that any
408  // adjacent duplicate points on the boundary will result in triangles,
409  // instead of quads. The big caveat is that if there's only one edge row
410  // or only one edge column, things get messy. The smaller caveat is that if
411  // the 3 points of a corner are all the same point, there'd be a degenerate
412  // triangle that should probably be removed, so we will. To deal with
413  // both at the same time, we just deal with all boundary quads the same way.
414 
415  auto &&boundary_quad = [&grid,surface_type,&functor](exint row, exint col, exint &primnum)
416  {
417  // Single "quad", but removing degeneracies.
418 
419  INT_TYPE points[4];
420  points[0] = grid.getPoint(row, col );
421  points[1] = grid.getPoint(row, col+1);
422  points[2] = grid.getPoint(row+1, col );
423  points[3] = grid.getPoint(row+1, col+1);
424 
425  // If the diagonally opposite points are the same, degenerate.
426  if (points[0] == points[2] || points[1] == points[3])
427  return;
428 
429  const bool row0_equal = (points[0] == points[1]);
430  const bool row1_equal = (points[2] == points[3]);
431  const bool col0_equal = (points[0] == points[2]);
432  const bool col1_equal = (points[1] == points[3]);
433  // Both ends equal, so degenerate.
434  if ((row0_equal && row1_equal) || (col0_equal && col1_equal))
435  return;
436 
437  if (!row0_equal && !row1_equal && !col0_equal && !col1_equal)
438  {
439  // Just a quad
440  if (surface_type == GEO_PATCH_QUADS)
441  {
442  functor(primnum, row, col, 4, true);
443  ++primnum;
444  }
445  else
446  {
447  functor(primnum, row, col, 3, true);
448  functor(primnum+1, row, col, 3, true);
449  primnum += 2;
450  }
451  return;
452  }
453 
454  // Exactly one adjacent equal pair, so a triangle
455  functor(primnum, row, col, 3, true);
456  ++primnum;
457  };
458 
459  exint row = 0;
460  for (exint col = 0; col < nedgecols; ++col)
461  {
462  boundary_quad(row, col, primnum);
463  }
464  for (row = 1; row < nedgerows-1; ++row)
465  {
466  exint col = 0;
467  boundary_quad(row, col, primnum);
468 
469  // Interior quads (tris) as normal, ignoring any potential degeneracy.
470  if (surface_type == GEO_PATCH_QUADS)
471  {
472  for (col = 1; col < nedgecols-1; ++col, ++primnum)
473  {
474  functor(primnum, row, col, 4, true);
475  }
476  }
477  else
478  {
479  for (col = 1; col < nedgecols-1; ++col, primnum+=2)
480  {
481  functor(primnum, row, col, 3, true);
482  functor(primnum+1, row, col, 3, true);
483  }
484  }
485 
486  boundary_quad(row, col, primnum);
487  }
488  for (exint col = 0; col < nedgecols; ++col)
489  {
490  boundary_quad(row, col, primnum);
491  }
492 }
493 
494 /// This calls functor for each vertex in grid, as:
495 /// functor(vtxnum, row, col, isrowend, iscolend, primnum, primvtxnum)
496 template<typename INT_TYPE,typename FUNCTOR>
497 void GUiterateGridVertices(const GU_GridT<INT_TYPE> &grid, FUNCTOR &&functor)
498 {
499  using PrimitiveType = typename GU_GridT<INT_TYPE>::PrimitiveType;
500  if (grid.myPrimitiveType == PrimitiveType::POINTS)
501  return;
502 
503  const GEO_SurfaceType surface_type = grid.mySurfaceType;
504  const bool rows_and_cols = (surface_type == GEO_PATCH_ROWCOL);
505  const exint nedgerows = grid.myNumEdgeRows;
506  const exint nedgecols = grid.myNumEdgeCols;
507 
508  if (nedgerows < 0 || nedgecols < 0)
509  return;
510 
511  exint primnum = 0;
512  exint vtxnum = 0;
513 
514  if (grid.isInvalidTPSurf())
515  return;
516 
517  if (grid.myPrimitiveType != PrimitiveType::POLYGON)
518  {
519  // Single primitive
520  // FIXME: Support myCurvesIfBasisRowCol!
521  // "Unroll" in this case allows for UV seams.
522  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
523  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
524  // if surface_type is rows or cols or rowcol?
525  const bool has_endrow = grid.myNoWrapV || grid.myUnrollCurves;
526  const bool has_endcol = grid.myNoWrapU || grid.myUnrollCurves;
527  for (exint row = 0; row < nedgerows; ++row)
528  {
529  for (exint col = 0; col < nedgecols; ++col)
530  {
531  functor(vtxnum, row, col, false, false, primnum, vtxnum);
532  ++vtxnum;
533  }
534 
535  if (has_endcol)
536  {
537  functor(vtxnum, row, nedgecols-1, false, true, primnum, vtxnum);
538  ++vtxnum;
539  }
540  }
541 
542  if (has_endrow)
543  {
544  for (exint col = 0; col < nedgecols; ++col)
545  {
546  functor(vtxnum, nedgerows-1, col, true, false, primnum, vtxnum);
547  ++vtxnum;
548  }
549 
550  if (has_endcol)
551  {
552  functor(vtxnum, nedgerows-1, nedgecols-1, true, true, primnum, vtxnum);
553  ++vtxnum;
554  }
555  }
556 
557  return;
558  }
559 
560  // Get the special cases out of the way so that it's easier later
561  if (nedgerows == 0)
562  {
563  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
564  {
565  if (nedgecols == 0)
566  {
567  // Single vertex
568  functor(vtxnum, 0, 0, false, false, primnum, 0);
569  ++vtxnum;
570  ++primnum;
571  }
572  else
573  {
574  // Single row
575  for (exint col = 0; col < nedgecols; ++col, ++vtxnum)
576  functor(vtxnum, 0, col, false, false, primnum, col);
577 
578  if (!grid.doesRowWrap(0) || grid.myUnrollCurves)
579  {
580  // Last vertex of the curve is treated as end of last edge col.
581  functor(vtxnum, 0, nedgecols-1, false, true, primnum, nedgecols);
582  ++vtxnum;
583  }
584  ++primnum;
585  }
586  if (!rows_and_cols)
587  return;
588  }
589  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
590  {
591  if (nedgecols == 0)
592  {
593  // Single vertex
594  functor(vtxnum, 0, 0, false, false, primnum, 0);
595  ++vtxnum;
596  ++primnum;
597  }
598  else
599  {
600  // Single row
601  for (exint col = 0; col < nedgecols; ++col, ++vtxnum, ++primnum)
602  functor(vtxnum, 0, col, false, false, primnum, 0);
603 
604  if (!grid.doesRowWrap(0))
605  {
606  // Last vertex of the curve is treated as end of last edge col.
607  functor(vtxnum, 0, nedgecols-1, false, true, primnum, 0);
608  ++vtxnum;
609  ++primnum;
610  }
611  }
612  }
613  // Only rows, cols, and rowcol have vertices when a single row.
614  return;
615  }
616 
617  if (nedgecols == 0)
618  {
619  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
620  {
621  // Single col
622  for (exint row = 0; row < nedgerows; ++row, ++vtxnum, ++primnum)
623  functor(vtxnum, row, 0, false, false, primnum, 0);
624 
625  if (!grid.doesColWrap(0))
626  {
627  // Last vertex of the curve is treated as end of last edge row.
628  functor(vtxnum, nedgerows-1, 0, true, false, primnum, 0);
629  ++vtxnum;
630  ++primnum;
631  }
632  if (!rows_and_cols)
633  return;
634  }
635  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
636  {
637  // Single col
638  for (exint row = 0; row < nedgerows; ++row, ++vtxnum)
639  functor(vtxnum, row, 0, false, false, primnum, row);
640 
641  if (!grid.doesColWrap(0) || grid.myUnrollCurves)
642  {
643  // Last vertex of the curve is treated as end of last edge row.
644  functor(vtxnum, nedgerows-1, 0, true, false, primnum, nedgerows);
645  ++vtxnum;
646  }
647  }
648  // Only rows, cols, and rowcol have vertices when a single col.
649  return;
650  }
651 
652  // Main cases; note that nedgerows and nedgecols are both at least 1.
653 
654  if (surface_type == GEO_PATCH_ROWS || rows_and_cols)
655  {
656  exint first_row = (grid.myNoWrapV && !grid.myFirstRowIfNotWrapped);
657  for (exint row = first_row; row < nedgerows; ++row, ++primnum)
658  {
659  for (exint col = 0; col < nedgecols; ++col, ++vtxnum)
660  functor(vtxnum, row, col, false, false, primnum, col);
661 
662  if (!grid.doesRowWrap(row) || grid.myUnrollCurves)
663  {
664  // Last vertex of the curve is treated as end of last edge col.
665  functor(vtxnum, row, nedgecols-1, false, true, primnum, nedgecols);
666  ++vtxnum;
667  }
668  }
669 
670  if (!grid.myAllWrapV && grid.myLastRowIfNotWrapped)
671  {
672  exint primvtx = 0;
673  bool col_wraps = grid.doesColWrap(0);
674  bool next_col_wraps;
675  for (exint col = 0; col < nedgecols; ++col, col_wraps = next_col_wraps)
676  {
677  next_col_wraps = grid.doesColWrap(col+1);
678  bool currently_in_a_curve = (primvtx != 0);
679  if (!currently_in_a_curve)
680  {
681  if (col_wraps && next_col_wraps)
682  {
683  // If current point and next point are wrapping v,
684  // and we're not currently in a curve, skip.
685  // O=======(O)=======O
686  continue;
687  }
688 
689  // (O)------O //
690  // (O)------O //
691  // or //
692  // (O)-----\ //
693  // (O)------O //
694  // or //
695  // /------O //
696  // O=======(O)-------O //
697  functor(vtxnum, nedgerows-1, col, true, false, primnum, 0);
698  ++vtxnum;
699  primvtx = 1;
700  }
701  else if (col_wraps && next_col_wraps)
702  {
703  // O------\ //
704  // O-------(O)=======O //
705  functor(vtxnum, nedgerows-1, col, true, false, primnum, primvtx);
706  ++vtxnum;
707  ++primnum;
708  primvtx = 0;
709  }
710  else
711  {
712  // O------\ /------O //
713  // O-------(O)-------O //
714  // or //
715  // O-------(O)-------O //
716  // O--------O--------O //
717  // or //
718  // O-------(O)------\ //
719  // O--------O--------O //
720  functor(vtxnum, nedgerows-1, col, true, false, primnum, primvtx);
721  ++vtxnum;
722  ++primvtx;
723  }
724  }
725  if ((!grid.doesRowWrap(nedgerows) || grid.myUnrollCurves) && (primvtx != 0))
726  {
727  // O-------(O) //
728  // O-------(O) //
729  // or //
730  // O------\ //
731  // O-------(O) //
732  // or //
733  // /------(O) //
734  // O-------(O) //
735  functor(vtxnum, nedgerows-1, nedgecols-1, true, true, primnum, primvtx);
736  ++vtxnum;
737  ++primnum;
738  primvtx = 0;
739  }
740  }
741 
742  if (!rows_and_cols)
743  return;
744  }
745  if (surface_type == GEO_PATCH_COLS || rows_and_cols)
746  {
747  // Just like the rows case, but with rows and cols (mostly) swapped
748  exint first_col = (grid.myNoWrapU && !grid.myFirstColIfNotWrapped);
749  for (exint col = first_col; col < nedgecols; ++col, ++primnum)
750  {
751  for (exint row = 0; row < nedgerows; ++row, ++vtxnum)
752  functor(vtxnum, row, col, false, false, primnum, row);
753 
754  if (!grid.doesColWrap(col) || grid.myUnrollCurves)
755  {
756  // Last vertex of the curve is treated as end of last edge row.
757  functor(vtxnum, nedgerows-1, col, true, false, primnum, nedgerows);
758  ++vtxnum;
759  }
760  }
761 
762  if (!grid.myAllWrapU && grid.myLastColIfNotWrapped)
763  {
764  exint primvtx = 0;
765  bool row_wraps = grid.doesRowWrap(0);
766  bool next_row_wraps;
767  for (exint row = 0; row < nedgerows; ++row, row_wraps = next_row_wraps)
768  {
769  next_row_wraps = grid.doesRowWrap(row+1);
770  bool currently_in_a_curve = (primvtx != 0);
771  if (!currently_in_a_curve)
772  {
773  if (row_wraps && next_row_wraps)
774  {
775  // If current point and next point are wrapping u,
776  // and we're not currently in a curve, skip.
777  // O=======(O)=======O
778  continue;
779  }
780 
781  // (O)------O //
782  // (O)------O //
783  // or //
784  // (O)-----\ //
785  // (O)------O //
786  // or //
787  // /------O //
788  // O=======(O)-------O //
789  functor(vtxnum, row, nedgecols-1, false, true, primnum, 0);
790  ++vtxnum;
791  primvtx = 1;
792  }
793  else if (row_wraps && next_row_wraps)
794  {
795  // O------\ //
796  // O-------(O)=======O //
797  functor(vtxnum, row, nedgecols-1, false, true, primnum, primvtx);
798  ++vtxnum;
799  ++primnum;
800  primvtx = 0;
801  }
802  else
803  {
804  // O------\ /------O //
805  // O-------(O)-------O //
806  // or //
807  // O-------(O)-------O //
808  // O--------O--------O //
809  // or //
810  // O-------(O)------\ //
811  // O--------O--------O //
812  functor(vtxnum, row, nedgecols-1, false, true, primnum, primvtx);
813  ++vtxnum;
814  ++primvtx;
815  }
816  }
817  if ((!grid.doesColWrap(nedgecols) || grid.myUnrollCurves) && (primvtx != 0))
818  {
819  // O-------(O) //
820  // O-------(O) //
821  // or //
822  // O------\ //
823  // O-------(O) //
824  // or //
825  // /------(O) //
826  // O-------(O) //
827  functor(vtxnum, nedgerows-1, nedgecols-1, true, true, primnum, primvtx);
828  ++vtxnum;
829  ++primnum;
830  primvtx = 0;
831  }
832  }
833  return;
834  }
835 
836  const bool alt = (surface_type == GEO_PATCH_ALTTRIANGLE);
837  const bool rev = (surface_type == GEO_PATCH_REVTRIANGLE);
838 
839  UT_ASSERT_MSG(nedgerows >= 1 && nedgecols >= 1, "Caller should have switched quads to rows or cols");
840  if (!grid.myTriangularPoles)
841  {
842  if (surface_type == GEO_PATCH_QUADS)
843  {
844  // All quads: simple.
845  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
846  {
847  for (exint col = 0; col < nedgecols; ++col, ++primnum, vtxnum+=4)
848  {
849  functor(vtxnum , row, col, false, false, primnum, 0);
850  functor(vtxnum+1, row, col, false, true, primnum, 1);
851  functor(vtxnum+2, row, col, true, true, primnum, 2);
852  functor(vtxnum+3, row, col, true, false, primnum, 3);
853  }
854  }
855  return;
856  }
857 
858  // All tris in the form of quads: simple.
859  for (exint row = 0, primnum = 0; row < nedgerows; ++row)
860  {
861  for (exint col = 0; col < nedgecols; ++col, primnum+=2, vtxnum+=6)
862  {
863  // Switch diagonal with checkerboard pattern
864  const bool switched = (rev || (alt && ((row^col)&1)));
865 
866  functor(vtxnum , row, col, false, false, primnum , 0);
867  functor(vtxnum+1, row, col, false, true, primnum , 1);
868  functor(vtxnum+2, row, col, true, !switched, primnum , 2);
869 
870  functor(vtxnum+3, row, col, false, switched, primnum+1, 0);
871  functor(vtxnum+4, row, col, true, true, primnum+1, 1);
872  functor(vtxnum+5, row, col, true, false, primnum+1, 2);
873  }
874  }
875  return;
876  }
877 
878  // grid.myTriangularPoles is true, which means that any
879  // adjacent duplicate points on the boundary will result in triangles,
880  // instead of quads. The big caveat is that if there's only one edge row
881  // or only one edge column, things get messy. The smaller caveat is that if
882  // the 3 points of a corner are all the same point, there'd be a degenerate
883  // triangle that should probably be removed, so we will. To deal with
884  // both at the same time, we just deal with all boundary quads the same way.
885 
886  auto &&boundary_quad = [&grid,surface_type,&functor,rev,alt](exint &vtxnum, exint row, exint col, exint &primnum)
887  {
888  // Single "quad", but removing degeneracies.
889 
890  INT_TYPE points[4];
891  points[0] = grid.getPoint(row, col );
892  points[1] = grid.getPoint(row, col+1);
893  points[2] = grid.getPoint(row+1, col );
894  points[3] = grid.getPoint(row+1, col+1);
895 
896  // If the diagonally opposite points are the same, degenerate.
897  if (points[0] == points[2] || points[1] == points[3])
898  return;
899 
900  const bool row0_equal = (points[0] == points[1]);
901  const bool row1_equal = (points[2] == points[3]);
902  const bool col0_equal = (points[0] == points[2]);
903  const bool col1_equal = (points[1] == points[3]);
904  // Both ends equal, so degenerate.
905  if ((row0_equal && row1_equal) || (col0_equal && col1_equal))
906  return;
907 
908  if (!row0_equal && !row1_equal && !col0_equal && !col1_equal)
909  {
910  // Just a quad
911  if (surface_type == GEO_PATCH_QUADS)
912  {
913  functor(vtxnum , row, col, false, false, primnum, 0);
914  functor(vtxnum+1, row, col, false, true, primnum, 1);
915  functor(vtxnum+2, row, col, true, true, primnum, 2);
916  functor(vtxnum+3, row, col, true, false, primnum, 3);
917  ++primnum;
918  vtxnum += 4;
919  }
920  else
921  {
922  // Switch diagonal with checkerboard pattern
923  const bool switched = (rev || (alt && ((row^col)&1)));
924 
925  functor(vtxnum , row, col, false, false, primnum , 0);
926  functor(vtxnum+1, row, col, false, true, primnum , 1);
927  functor(vtxnum+2, row, col, true, !switched, primnum , 2);
928 
929  functor(vtxnum+3, row, col, false, switched, primnum+1, 0);
930  functor(vtxnum+4, row, col, true, true, primnum+1, 1);
931  functor(vtxnum+5, row, col, true, false, primnum+1, 2);
932  primnum += 2;
933  vtxnum += 6;
934  }
935  return;
936  }
937 
938  // Exactly one adjacent equal pair, so a triangle
939  functor(vtxnum, row, col, false, false, primnum, vtxnum);
940  ++vtxnum;
941  if (!row0_equal)
942  {
943  functor(vtxnum, row, col, false, true, primnum, vtxnum);
944  ++vtxnum;
945  }
946  if (!row1_equal && !col1_equal)
947  {
948  functor(vtxnum, row, col, true, true, primnum, vtxnum);
949  ++vtxnum;
950  }
951  if (!col0_equal)
952  {
953  functor(vtxnum, row, col, true, false, primnum, vtxnum);
954  ++vtxnum;
955  }
956  ++primnum;
957  };
958 
959  exint row = 0;
960  for (exint col = 0; col < nedgecols; ++col)
961  {
962  boundary_quad(vtxnum, row, col, primnum);
963  }
964  for (row = 1; row < nedgerows-1; ++row)
965  {
966  exint col = 0;
967  boundary_quad(vtxnum, row, col, primnum);
968 
969  // Interior quads (tris) as normal, ignoring any potential degeneracy.
970  if (surface_type == GEO_PATCH_QUADS)
971  {
972  for (col = 1; col < nedgecols-1; ++col, ++primnum, vtxnum+=4)
973  {
974  functor(vtxnum , row, col, false, false, primnum, 0);
975  functor(vtxnum+1, row, col, false, true, primnum, 1);
976  functor(vtxnum+2, row, col, true, true, primnum, 2);
977  functor(vtxnum+3, row, col, true, false, primnum, 3);
978  }
979  }
980  else
981  {
982  for (col = 1; col < nedgecols-1; ++col, primnum+=2, vtxnum+=6)
983  {
984  // Switch diagonal with checkerboard pattern
985  const bool switched = (rev || (alt && ((row^col)&1)));
986 
987  functor(vtxnum , row, col, false, false, primnum , 0);
988  functor(vtxnum+1, row, col, false, true, primnum , 1);
989  functor(vtxnum+2, row, col, true, !switched, primnum , 2);
990 
991  functor(vtxnum+3, row, col, false, switched, primnum+1, 0);
992  functor(vtxnum+4, row, col, true, true, primnum+1, 1);
993  functor(vtxnum+5, row, col, true, false, primnum+1, 2);
994  }
995  }
996 
997  boundary_quad(vtxnum, row, col, primnum);
998  }
999  for (exint col = 0; col < nedgecols; ++col)
1000  {
1001  boundary_quad(vtxnum, row, col, primnum);
1002  }
1003 }
1004 
1005 template<typename INT_TYPE>
1007 {
1008  const exint nedgerows = myNumEdgeRows;
1009  const exint nedgecols = myNumEdgeCols;
1010  if (nedgerows < 0 || nedgecols < 0 || (nedgerows == 0 && nedgecols == 0))
1011  {
1012  myNoWrapU = true;
1013  myNoWrapV = true;
1014  myAllWrapU = false;
1015  myAllWrapV = false;
1016  return;
1017  }
1018  if (nedgerows == 0)
1019  {
1020  const bool wrapu = (myCorners[0] == myCorners[1]);
1021  myNoWrapU = !wrapu;
1022  myNoWrapV = true;
1023  myAllWrapU = wrapu;
1024  myAllWrapV = false;
1025  return;
1026  }
1027  if (nedgecols == 0)
1028  {
1029  const bool wrapv = (myCorners[0] == myCorners[2]);
1030  myNoWrapU = true;
1031  myNoWrapV = !wrapv;
1032  myAllWrapU = false;
1033  myAllWrapV = wrapv;
1034  return;
1035  }
1036 
1037  bool wrapu0 = (myCorners[0] == myCorners[1]);
1038  bool wrapu1 = (myCorners[2] == myCorners[3]);
1039  bool has_wrapu = wrapu0 || wrapu1;
1040  bool has_notwrapu = !wrapu0 || !wrapu1;
1041 
1042  bool wrapv0 = (myCorners[0] == myCorners[2]);
1043  bool wrapv1 = (myCorners[1] == myCorners[3]);
1044  bool has_wrapv = wrapv0 || wrapv1;
1045  bool has_notwrapv = !wrapv0 || !wrapv1;
1046 
1047  if ((myCol0Start < INT_TYPE(0)) || (myCol1Start < INT_TYPE(0)) || (myCol0Step != myCol1Step))
1048  {
1049  // Uncommon case: iterate to check.
1050  for (exint rowm1 = 0; rowm1 < nedgerows-1; ++rowm1)
1051  {
1052  INT_TYPE pt0 = (myCol0Start < INT_TYPE(0)) ? myCol0Array[rowm1] : (myCol0Start + myCol0Step*rowm1);
1053  INT_TYPE pt1 = (myCol1Start < INT_TYPE(0)) ? myCol1Array[rowm1] : (myCol1Start + myCol1Step*rowm1);
1054  bool wrapu = (pt0 == pt1);
1055  has_wrapu |= wrapu;
1056  has_notwrapu |= !wrapu;
1057  }
1058  }
1059  else
1060  {
1061  // Common case: uniform step.
1062  bool wrapu = (myCol0Start == myCol1Start);
1063  has_wrapu |= wrapu;
1064  has_notwrapu |= !wrapu;
1065  }
1066 
1067  if ((myRow0Start < INT_TYPE(0)) || (myRow1Start < INT_TYPE(0)) || (myRow0Step != myRow1Step))
1068  {
1069  // Uncommon case: iterate to check.
1070  for (exint colm1 = 0; colm1 < nedgecols-1; ++colm1)
1071  {
1072  INT_TYPE pt0 = (myRow0Start < INT_TYPE(0)) ? myRow0Array[colm1] : (myRow0Start + myRow0Step*colm1);
1073  INT_TYPE pt1 = (myRow1Start < INT_TYPE(0)) ? myRow1Array[colm1] : (myRow1Start + myRow1Step*colm1);
1074  bool wrapv = (pt0 == pt1);
1075  has_wrapv |= wrapv;
1076  has_notwrapv |= !wrapv;
1077  }
1078  }
1079  else
1080  {
1081  // Common case: uniform step.
1082  bool wrapv = (myRow0Start == myRow1Start);
1083  has_wrapv |= wrapv;
1084  has_notwrapv |= !wrapv;
1085  }
1086 
1087  myAllWrapU = !has_notwrapu;
1088  myAllWrapV = !has_notwrapv;
1089  myNoWrapU = !has_wrapu;
1090  myNoWrapV = !has_wrapv;
1091 }
1092 
1093 template<typename INT_TYPE>
1095  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1096 {
1097  clear();
1098 
1099  myNumEdgeRows = nedgerows;
1100  myNumEdgeCols = nedgecols;
1101 
1102  myAllWrapU = false;
1103  myAllWrapV = false;
1104  myNoWrapU = true;
1105  myNoWrapV = true;
1106 
1107  fixTPSurf();
1108 
1109  myCorners[0] = start_pt;
1110  myCorners[1] = start_pt + nedgecols;
1111  myCorners[2] = start_pt + nedgerows*(nedgecols+1);
1112  myCorners[3] = start_pt + nedgerows*(nedgecols+1) + nedgecols;
1113 
1114  myRow0Step = INT_TYPE(1);
1115  myRow0Start = myCorners[0]+myRow0Step;
1116  myRow1Step = INT_TYPE(1);
1117  myRow1Start = myCorners[2]+myRow1Step;
1118 
1119  myCol0Step = INT_TYPE(nedgecols+1);
1120  myCol0Start = myCorners[0]+myCol0Step;
1121  myCol1Step = INT_TYPE(nedgecols+1);
1122  myCol1Start = myCorners[1]+myCol1Step;
1123 
1124  myMiddleStart = myCol0Start+1;
1125  myMiddleColStep = myRow0Step;
1126  myMiddleRowStep = myCol0Step;
1127 
1128  if (myPrimitiveType == PrimitiveType::POINTS)
1129  {
1130  myNumPrimitives = 0;
1131  myNumVertices = 0;
1132  return;
1133  }
1134 
1135  if (myPrimitiveType != PrimitiveType::POLYGON)
1136  {
1137  // Single primitive
1138  myNumPrimitives = 1;
1139 
1140  // FIXME: Support myCurvesIfBasisRowCol!
1141 
1142  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1143  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1144  // if surface_type is rows or cols or rowcol?
1145  const bool has_endrow = myNoWrapV || myUnrollCurves;
1146  const bool has_endcol = myNoWrapU || myUnrollCurves;
1147  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1148  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1149  myNumVertices = nvtxrows*nvtxcols;
1150  return;
1151  }
1152 
1153  if (mySurfaceType == GEO_PATCH_QUADS)
1154  {
1155  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1156  myNumVertices = 4*myNumPrimitives;
1157  return;
1158  }
1159 
1160  // Initialize to zero, so that cols and rowcol case can use +=
1161  myNumPrimitives = 0;
1162  myNumVertices = 0;
1163  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1164  {
1165  myNumPrimitives = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1166  myNumVertices = myNumPrimitives*(myNumEdgeCols+1);
1167  if (mySurfaceType != GEO_PATCH_ROWCOL)
1168  return;
1169  }
1170  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1171  {
1172  exint col_polys = myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1173  myNumPrimitives += col_polys;
1174  myNumVertices += col_polys*(myNumEdgeRows+1);
1175  return;
1176  }
1177 
1178  // Triangles
1179  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1180  myNumVertices = 3*myNumPrimitives;
1181 }
1182 
1183 template<typename INT_TYPE>
1185  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1186 {
1187  clear();
1188 
1189  myNumEdgeRows = nedgerows;
1190  myNumEdgeCols = nedgecols;
1191 
1192  myAllWrapU = true;
1193  myAllWrapV = false;
1194  myNoWrapU = false;
1195  myNoWrapV = true;
1196 
1197  fixTPSurf();
1198 
1199  myCorners[0] = start_pt;
1200  myCorners[1] = myCorners[0];
1201  myCorners[2] = start_pt + nedgerows*nedgecols;
1202  myCorners[3] = myCorners[2];
1203 
1204  myRow0Step = INT_TYPE(1);
1205  myRow0Start = myCorners[0]+myRow0Step;
1206  myRow1Step = INT_TYPE(1);
1207  myRow1Start = myCorners[2]+myRow1Step;
1208 
1209  myCol0Step = INT_TYPE(nedgecols);
1210  myCol0Start = myCorners[0]+myCol0Step;
1211  myCol1Step = INT_TYPE(nedgecols);
1212  myCol1Start = myCorners[1]+myCol1Step;
1213 
1214  myMiddleStart = myCol0Start+1;
1215  myMiddleColStep = myRow0Step;
1216  myMiddleRowStep = myCol0Step;
1217 
1218  if (myPrimitiveType == PrimitiveType::POINTS)
1219  {
1220  myNumPrimitives = 0;
1221  myNumVertices = 0;
1222  return;
1223  }
1224 
1225  if (myPrimitiveType != PrimitiveType::POLYGON)
1226  {
1227  // Single primitive
1228  myNumPrimitives = 1;
1229 
1230  // FIXME: Support myCurvesIfBasisRowCol!
1231 
1232  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1233  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1234  // if surface_type is rows or cols or rowcol?
1235  const bool has_endrow = myNoWrapV || myUnrollCurves;
1236  const bool has_endcol = myNoWrapU || myUnrollCurves;
1237  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1238  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1239  myNumVertices = nvtxrows*nvtxcols;
1240  return;
1241  }
1242 
1243  if (mySurfaceType == GEO_PATCH_QUADS)
1244  {
1245  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1246  myNumVertices = 4*myNumPrimitives;
1247  return;
1248  }
1249 
1250  // Initialize to zero, so that cols and rowcol case can use +=
1251  myNumPrimitives = 0;
1252  myNumVertices = 0;
1253  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1254  {
1255  myNumPrimitives = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1256  myNumVertices = myNumPrimitives*(myNumEdgeCols+myUnrollCurves);
1257  if (mySurfaceType != GEO_PATCH_ROWCOL)
1258  return;
1259  }
1260  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1261  {
1262  myNumPrimitives += myNumEdgeCols;
1263  myNumVertices += myNumEdgeCols*(myNumEdgeRows+1);
1264  return;
1265  }
1266 
1267  // Triangles
1268  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1269  myNumVertices = 3*myNumPrimitives;
1270 }
1271 
1272 template<typename INT_TYPE>
1274  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1275 {
1276  clear();
1277 
1278  myNumEdgeRows = nedgerows;
1279  myNumEdgeCols = nedgecols;
1280 
1281  myAllWrapU = false;
1282  myAllWrapV = true;
1283  myNoWrapU = true;
1284  myNoWrapV = false;
1285 
1286  fixTPSurf();
1287 
1288  myCorners[0] = start_pt;
1289  myCorners[1] = start_pt + nedgecols;
1290  myCorners[2] = myCorners[0];
1291  myCorners[3] = myCorners[1];
1292 
1293  myRow0Step = INT_TYPE(1);
1294  myRow0Start = myCorners[0]+myRow0Step;
1295  myRow1Step = INT_TYPE(1);
1296  myRow1Start = myCorners[2]+myRow1Step;
1297 
1298  myCol0Step = INT_TYPE(nedgecols+1);
1299  myCol0Start = myCorners[0]+myCol0Step;
1300  myCol1Step = INT_TYPE(nedgecols+1);
1301  myCol1Start = myCorners[1]+myCol1Step;
1302 
1303  myMiddleStart = myCol0Start+1;
1304  myMiddleColStep = myRow0Step;
1305  myMiddleRowStep = myCol0Step;
1306 
1307  if (myPrimitiveType == PrimitiveType::POINTS)
1308  {
1309  myNumPrimitives = 0;
1310  myNumVertices = 0;
1311  return;
1312  }
1313 
1314  if (myPrimitiveType != PrimitiveType::POLYGON)
1315  {
1316  // Single primitive
1317  myNumPrimitives = 1;
1318 
1319  // FIXME: Support myCurvesIfBasisRowCol!
1320 
1321  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1322  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1323  // if surface_type is rows or cols or rowcol?
1324  const bool has_endrow = myNoWrapV || myUnrollCurves;
1325  const bool has_endcol = myNoWrapU || myUnrollCurves;
1326  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1327  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1328  myNumVertices = nvtxrows*nvtxcols;
1329  return;
1330  }
1331 
1332  if (mySurfaceType == GEO_PATCH_QUADS)
1333  {
1334  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1335  myNumVertices = 4*myNumPrimitives;
1336  return;
1337  }
1338 
1339  // Initialize to zero, so that cols and rowcol case can use +=
1340  myNumPrimitives = 0;
1341  myNumVertices = 0;
1342  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1343  {
1344  myNumPrimitives = myNumEdgeRows;
1345  myNumVertices = myNumPrimitives*(myNumEdgeCols+1);
1346  if (mySurfaceType != GEO_PATCH_ROWCOL)
1347  return;
1348  }
1349  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1350  {
1351  exint col_polys = myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1352  myNumPrimitives += col_polys;
1353  myNumVertices += col_polys*(myNumEdgeRows+myUnrollCurves);
1354  return;
1355  }
1356 
1357  // Triangles
1358  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1359  myNumVertices = 3*myNumPrimitives;
1360 }
1361 
1362 template<typename INT_TYPE>
1364  exint nedgerows, exint nedgecols,
1365  INT_TYPE start_pt, INT_TYPE end_pt, INT_TYPE start_mid_pt)
1366 {
1367  clear();
1368 
1369  myNumEdgeRows = nedgerows;
1370  myNumEdgeCols = nedgecols;
1371 
1372  myAllWrapU = true;
1373  myAllWrapV = false;
1374  myNoWrapU = false;
1375  myNoWrapV = true;
1376 
1377  fixTPSurf();
1378 
1379  myCorners[0] = start_pt;
1380  myCorners[1] = myCorners[0];
1381  myCorners[2] = end_pt;
1382  myCorners[3] = myCorners[2];
1383 
1384  myRow0Step = INT_TYPE(0);
1385  myRow0Start = start_pt;
1386  myRow1Step = INT_TYPE(0);
1387  myRow1Start = end_pt;
1388 
1389  myCol0Step = INT_TYPE(nedgecols);
1390  myCol0Start = start_mid_pt;
1391  myCol1Step = INT_TYPE(nedgecols);
1392  myCol1Start = start_mid_pt;
1393 
1394  myMiddleStart = myCol0Start+1;
1395  myMiddleColStep = INT_TYPE(1);
1396  myMiddleRowStep = INT_TYPE(nedgecols);
1397 
1398  if (myPrimitiveType == PrimitiveType::POINTS)
1399  {
1400  myNumPrimitives = 0;
1401  myNumVertices = 0;
1402  return;
1403  }
1404 
1405  if (myPrimitiveType != PrimitiveType::POLYGON)
1406  {
1407  // Single primitive
1408  myNumPrimitives = 1;
1409 
1410  // FIXME: Support myCurvesIfBasisRowCol!
1411 
1412  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1413  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1414  // if surface_type is rows or cols or rowcol?
1415  const bool has_endrow = myNoWrapV || myUnrollCurves;
1416  const bool has_endcol = myNoWrapU || myUnrollCurves;
1417  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1418  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1419  myNumVertices = nvtxrows*nvtxcols;
1420  return;
1421  }
1422 
1423  if (mySurfaceType == GEO_PATCH_QUADS)
1424  {
1425  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1426  myNumVertices = 4*myNumPrimitives - (myTriangularPoles ? 2*myNumEdgeCols : 0);
1427  return;
1428  }
1429 
1430  // Initialize to zero, so that cols and rowcol case can use +=
1431  myNumPrimitives = 0;
1432  myNumVertices = 0;
1433  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1434  {
1435  const exint rowprims = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1436  myNumPrimitives = rowprims;
1437  myNumVertices = rowprims*(myNumEdgeCols+myUnrollCurves);
1438  if (mySurfaceType != GEO_PATCH_ROWCOL)
1439  return;
1440  }
1441  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1442  {
1443  myNumPrimitives += myNumEdgeCols;
1444  myNumVertices += myNumEdgeCols*(myNumEdgeRows+1);
1445  return;
1446  }
1447 
1448  // Triangles
1449  myNumPrimitives = (myNumEdgeRows - exint(myTriangularPoles))*2*myNumEdgeCols;
1450  myNumVertices = 3*myNumPrimitives;
1451 }
1452 
1453 template<typename INT_TYPE>
1455  exint nedgerows, exint nedgecols,
1456  INT_TYPE start_pt, INT_TYPE end_pt, INT_TYPE start_mid_pt)
1457 {
1458  clear();
1459 
1460  myNumEdgeRows = nedgerows;
1461  myNumEdgeCols = nedgecols;
1462 
1463  myAllWrapU = false;
1464  myAllWrapV = true;
1465  myNoWrapU = true;
1466  myNoWrapV = false;
1467 
1468  fixTPSurf();
1469 
1470  myCorners[0] = start_pt;
1471  myCorners[1] = end_pt;
1472  myCorners[2] = start_pt;
1473  myCorners[3] = end_pt;
1474 
1475  myRow0Step = INT_TYPE(1);
1476  myRow0Start = start_mid_pt;
1477  myRow1Step = INT_TYPE(1);
1478  myRow1Start = start_mid_pt;
1479 
1480  myCol0Step = INT_TYPE(0);
1481  myCol0Start = start_pt;
1482  myCol1Step = INT_TYPE(0);
1483  myCol1Start = end_pt;
1484 
1485  myMiddleStart = myRow0Start+nedgecols-1;
1486  myMiddleColStep = INT_TYPE(1);
1487  myMiddleRowStep = INT_TYPE(nedgecols-1);
1488 
1489  if (myPrimitiveType == PrimitiveType::POINTS)
1490  {
1491  myNumPrimitives = 0;
1492  myNumVertices = 0;
1493  return;
1494  }
1495 
1496  if (myPrimitiveType != PrimitiveType::POLYGON)
1497  {
1498  // Single primitive
1499  myNumPrimitives = 1;
1500 
1501  // FIXME: Support myCurvesIfBasisRowCol!
1502 
1503  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1504  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1505  // if surface_type is rows or cols or rowcol?
1506  const bool has_endrow = myNoWrapV || myUnrollCurves;
1507  const bool has_endcol = myNoWrapU || myUnrollCurves;
1508  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1509  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1510  myNumVertices = nvtxrows*nvtxcols;
1511  return;
1512  }
1513 
1514  if (mySurfaceType == GEO_PATCH_QUADS)
1515  {
1516  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1517  myNumVertices = 4*myNumPrimitives - (myTriangularPoles ? 2*myNumEdgeRows : 0);
1518  return;
1519  }
1520 
1521  // Initialize to zero, so that cols and rowcol case can use +=
1522  myNumPrimitives = 0;
1523  myNumVertices = 0;
1524  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1525  {
1526  myNumPrimitives = myNumEdgeRows;
1527  myNumVertices = myNumEdgeRows*(myNumEdgeCols+1);
1528  if (mySurfaceType != GEO_PATCH_ROWCOL)
1529  return;
1530  }
1531  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1532  {
1533  const exint colprims = myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1534  myNumPrimitives += colprims;
1535  myNumVertices += colprims*(myNumEdgeRows+myUnrollCurves);
1536  return;
1537  }
1538 
1539  // Triangles
1540  myNumPrimitives = myNumEdgeRows*2*(myNumEdgeCols - exint(myTriangularPoles));
1541  myNumVertices = 3*myNumPrimitives;
1542 }
1543 
1544 template<typename INT_TYPE>
1546  exint nedgerows, exint nedgecols,
1547  INT_TYPE start_pt, INT_TYPE end_pt, INT_TYPE start_mid_pt)
1548 {
1549  clear();
1550 
1551  myNumEdgeRows = nedgerows;
1552  myNumEdgeCols = nedgecols;
1553 
1554  // Same wrapping settings as initSplitColSphere
1555  myAllWrapU = false;
1556  myAllWrapV = false;
1557  myNoWrapU = true;
1558  myNoWrapV = true;
1559 
1560  fixTPSurf();
1561 
1562  // Same corner orientation as initRowSphere
1563  myCorners[0] = start_pt;
1564  myCorners[1] = end_pt;
1565  myCorners[2] = start_pt;
1566  myCorners[3] = end_pt;
1567 
1568  // Used when stepping along the open seams of the sphere.
1569  // The steps in this direction should be continuous since
1570  // the rows and columns are swapped. This is the open
1571  // version of initRowSphere.
1572  myRow0Step = INT_TYPE(1);
1573  myRow0Start = start_mid_pt;
1574  myRow1Step = INT_TYPE(1);
1575  myRow1Start = end_pt - nedgecols + 1;
1576 
1577  // Used when stepping along the pole of the sphere;
1578  // hence, the zero step which gives one point for each
1579  // of these rows. It is the transposed version of
1580  // initSplitColSphere.
1581  myCol0Step = INT_TYPE(0);
1582  myCol0Start = start_pt;
1583  myCol1Step = INT_TYPE(0);
1584  myCol1Start = end_pt;
1585 
1586  // This gives the proper transposition of points when
1587  // stepping along the interior of the grid with
1588  // swapped rows and columns. This is the open
1589  // version of initRowSphere.
1590  myMiddleStart = INT_TYPE(start_mid_pt + nedgecols - 1);
1591  myMiddleColStep = INT_TYPE(1);
1592  myMiddleRowStep = INT_TYPE(nedgecols - 1);
1593 
1594  if (myPrimitiveType == PrimitiveType::POINTS)
1595  {
1596  myNumPrimitives = 0;
1597  myNumVertices = 0;
1598  return;
1599  }
1600 
1601  // Similar code used in companion functions
1602  if (myPrimitiveType != PrimitiveType::POLYGON)
1603  {
1604  // Single primitive
1605  myNumPrimitives = 1;
1606 
1607  // FIXME: Support myCurvesIfBasisRowCol!
1608  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1609  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1610  // if surface_type is rows or cols or rowcol?
1611  const bool has_endrow = myNoWrapV || myUnrollCurves;
1612  const bool has_endcol = myNoWrapU || myUnrollCurves;
1613  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1614  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1615  myNumVertices = nvtxrows * nvtxcols;
1616  return;
1617  }
1618 
1619  if (mySurfaceType == GEO_PATCH_QUADS)
1620  {
1621  myNumPrimitives = myNumEdgeRows * myNumEdgeCols;
1622  myNumVertices = 4 * myNumPrimitives - (myTriangularPoles ? 2 * myNumEdgeRows : 0);
1623  return;
1624  }
1625 
1626  // Initialize to zero, so that cols and rowcol case can use +=
1627  myNumPrimitives = 0;
1628  myNumVertices = 0;
1629  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1630  {
1631  // Transpose of initSplitColSphere
1632  myNumPrimitives = myNumEdgeRows - 1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1633  myNumVertices = (myNumEdgeCols + 1) * (myNumEdgeRows + 1);
1634  if (mySurfaceType != GEO_PATCH_ROWCOL)
1635  return;
1636  }
1637 
1638  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1639  {
1640  // Transpose of initSplitColSphere
1641  const exint colprims = myNumEdgeCols - 1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1642  myNumPrimitives += colprims;
1643  myNumVertices += colprims * (myNumEdgeRows + 1);
1644  return;
1645  }
1646 
1647  // Triangles
1648  myNumPrimitives = myNumEdgeRows * 2 * (myNumEdgeCols - exint(myTriangularPoles));
1649  myNumVertices = 3 * myNumPrimitives;
1650 }
1651 
1652 template<typename INT_TYPE>
1654  exint nedgerows, exint nedgecols,
1655  INT_TYPE start_pt, INT_TYPE end_pt, INT_TYPE start_mid_pt)
1656 {
1657  clear();
1658 
1659  myNumEdgeRows = nedgerows;
1660  myNumEdgeCols = nedgecols;
1661 
1662  myAllWrapU = false;
1663  myAllWrapV = false;
1664  myNoWrapU = true;
1665  myNoWrapV = true;
1666 
1667  fixTPSurf();
1668 
1669  myCorners[0] = start_pt;
1670  myCorners[1] = myCorners[0];
1671  myCorners[2] = end_pt;
1672  myCorners[3] = myCorners[2];
1673 
1674  myRow0Step = INT_TYPE(0);
1675  myRow0Start = start_pt;
1676  myRow1Step = INT_TYPE(0);
1677  myRow1Start = end_pt;
1678 
1679  myCol0Step = INT_TYPE(nedgecols+1);
1680  myCol0Start = start_mid_pt;
1681  myCol1Step = INT_TYPE(nedgecols+1);
1682  myCol1Start = start_mid_pt+nedgecols;
1683 
1684  myMiddleStart = myCol0Start+1;
1685  myMiddleColStep = INT_TYPE(1);
1686  myMiddleRowStep = INT_TYPE(nedgecols+1);
1687 
1688  if (myPrimitiveType == PrimitiveType::POINTS)
1689  {
1690  myNumPrimitives = 0;
1691  myNumVertices = 0;
1692  return;
1693  }
1694 
1695  if (myPrimitiveType != PrimitiveType::POLYGON)
1696  {
1697  // Single primitive
1698  myNumPrimitives = 1;
1699 
1700  // FIXME: Support myCurvesIfBasisRowCol!
1701 
1702  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1703  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1704  // if surface_type is rows or cols or rowcol?
1705  const bool has_endrow = myNoWrapV || myUnrollCurves;
1706  const bool has_endcol = myNoWrapU || myUnrollCurves;
1707  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1708  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1709  myNumVertices = nvtxrows*nvtxcols;
1710  return;
1711  }
1712 
1713  if (mySurfaceType == GEO_PATCH_QUADS)
1714  {
1715  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1716  myNumVertices = 4*myNumPrimitives - (myTriangularPoles ? 2*myNumEdgeCols : 0);
1717  return;
1718  }
1719 
1720  // Initialize to zero, so that cols and rowcol case can use +=
1721  myNumPrimitives = 0;
1722  myNumVertices = 0;
1723  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1724  {
1725  const exint rowprims = myNumEdgeRows-1 + exint(myFirstRowIfNotWrapped) + exint(myLastRowIfNotWrapped);
1726  myNumPrimitives = rowprims;
1727  myNumVertices = rowprims*(myNumEdgeCols+1);
1728  if (mySurfaceType != GEO_PATCH_ROWCOL)
1729  return;
1730  }
1731  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1732  {
1733  myNumPrimitives += myNumEdgeCols-1 + exint(myFirstColIfNotWrapped) + exint(myLastColIfNotWrapped);
1734  myNumVertices += (myNumEdgeCols+1)*(myNumEdgeRows+1);
1735  return;
1736  }
1737 
1738  // Triangles
1739  myNumPrimitives = (myNumEdgeRows - exint(myTriangularPoles))*2*myNumEdgeCols;
1740  myNumVertices = 3*myNumPrimitives;
1741 }
1742 
1743 template<typename INT_TYPE>
1745  exint nedgerows, exint nedgecols, INT_TYPE start_pt)
1746 {
1747  clear();
1748 
1749  myNumEdgeRows = nedgerows;
1750  myNumEdgeCols = nedgecols;
1751 
1752  myAllWrapU = true;
1753  myAllWrapV = true;
1754  myNoWrapU = false;
1755  myNoWrapV = false;
1756 
1757  fixTPSurf();
1758 
1759  myCorners[0] = start_pt;
1760  myCorners[1] = start_pt;
1761  myCorners[2] = start_pt;
1762  myCorners[3] = start_pt;
1763 
1764  myRow0Step = INT_TYPE(1);
1765  myRow0Start = myCorners[0]+myRow0Step;
1766  myRow1Step = INT_TYPE(1);
1767  myRow1Start = myCorners[2]+myRow1Step;
1768 
1769  myCol0Step = INT_TYPE(nedgecols);
1770  myCol0Start = myCorners[0]+myCol0Step;
1771  myCol1Step = INT_TYPE(nedgecols);
1772  myCol1Start = myCorners[1]+myCol1Step;
1773 
1774  myMiddleStart = myCol0Start+1;
1775  myMiddleColStep = myRow0Step;
1776  myMiddleRowStep = myCol0Step;
1777 
1778  if (myPrimitiveType == PrimitiveType::POINTS)
1779  {
1780  myNumPrimitives = 0;
1781  myNumVertices = 0;
1782  return;
1783  }
1784 
1785  if (myPrimitiveType != PrimitiveType::POLYGON)
1786  {
1787  // Single primitive
1788  myNumPrimitives = 1;
1789 
1790  // FIXME: Support myCurvesIfBasisRowCol!
1791 
1792  // FIXME: Does this need to take into account myFirstRowIfNotWrapped,
1793  // myLastRowIfNotWrapped, myFirstColIfNotWrapped, myLastColIfNotWrapped
1794  // if surface_type is rows or cols or rowcol?
1795  const bool has_endrow = myNoWrapV || myUnrollCurves;
1796  const bool has_endcol = myNoWrapU || myUnrollCurves;
1797  const exint nvtxrows = myNumEdgeRows + exint(has_endrow);
1798  const exint nvtxcols = myNumEdgeCols + exint(has_endcol);
1799  myNumVertices = nvtxrows*nvtxcols;
1800  return;
1801  }
1802 
1803  if (mySurfaceType == GEO_PATCH_QUADS)
1804  {
1805  myNumPrimitives = myNumEdgeRows*myNumEdgeCols;
1806  myNumVertices = 4*myNumPrimitives;
1807  return;
1808  }
1809 
1810  // Initialize to zero, so that cols and rowcol case can use +=
1811  myNumPrimitives = 0;
1812  myNumVertices = 0;
1813  if (mySurfaceType == GEO_PATCH_ROWS || mySurfaceType == GEO_PATCH_ROWCOL)
1814  {
1815  myNumPrimitives = myNumEdgeRows;
1816  myNumVertices = myNumPrimitives*(myNumEdgeCols+myUnrollCurves);
1817  if (mySurfaceType != GEO_PATCH_ROWCOL)
1818  return;
1819  }
1820  if (mySurfaceType == GEO_PATCH_COLS || mySurfaceType == GEO_PATCH_ROWCOL)
1821  {
1822  myNumPrimitives += myNumEdgeCols;
1823  myNumVertices += myNumEdgeCols*(myNumEdgeRows+myUnrollCurves);
1824  return;
1825  }
1826 
1827  // Triangles
1828  myNumPrimitives = 2*myNumEdgeRows*myNumEdgeCols;
1829  myNumVertices = 3*myNumPrimitives;
1830 }
void initColTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1184
GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glad.h:2676
bool myNoWrapU
Definition: GU_Grid.h:143
bool myFirstRowIfNotWrapped
Definition: GU_Grid.h:105
int64 exint
Definition: SYS_Types.h:125
bool myFirstColIfNotWrapped
Definition: GU_Grid.h:115
exint myNumEdgeCols
Definition: GU_Grid.h:46
#define UT_ASSERT_MSG(ZZ,...)
Definition: UT_Assert.h:159
bool myTriangularPoles
Definition: GU_Grid.h:127
void GUiterateGridPrimitives(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
Definition: GU_GridImpl.h:77
bool myAllWrapU
Definition: GU_Grid.h:141
void GUiterateGridVertices(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
Definition: GU_GridImpl.h:497
bool myUnrollCurves
Definition: GU_Grid.h:100
bool isInvalidTPSurf() const
Definition: GU_Grid.h:375
void precompute()
Definition: GU_GridImpl.h:1006
void GUiterateGridPoints(const GU_GridT< INT_TYPE > &grid, FUNCTOR &&functor)
Definition: GU_GridImpl.h:28
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))
Definition: GU_GridImpl.h:1363
GEO_SurfaceType mySurfaceType
Definition: GU_Grid.h:77
bool myLastRowIfNotWrapped
Definition: GU_Grid.h:110
exint myNumVertices
Definition: GU_Grid.h:146
INT_TYPE getPoint(exint row, exint col) const
Definition: GU_Grid.h:282
bool myLastColIfNotWrapped
Definition: GU_Grid.h:120
PrimitiveType myPrimitiveType
Definition: SOP_SweepHDK.C:298
void initSplitRowSphere(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))
Definition: GU_GridImpl.h:1545
bool myNoWrapV
Definition: GU_Grid.h:144
exint myNumEdgeRows
Definition: GU_Grid.h:45
bool doesRowWrap(exint row) const
Definition: GU_Grid.h:313
GEO_SurfaceType
GLenum GLenum GLsizei void * row
Definition: glad.h:5135
bool myAllWrapV
Definition: GU_Grid.h:142
bool doesColWrap(exint col) const
Definition: GU_Grid.h:325
PrimitiveType
Definition: GU_Grid.h:79
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))
Definition: GU_GridImpl.h:1454
PrimitiveType myPrimitiveType
Definition: GU_Grid.h:88
void initRowTube(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1273
void initTorus(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1744
void initSingleGrid(exint nedgerows, exint nedgecols, INT_TYPE start_pt=INT_TYPE(0))
Definition: GU_GridImpl.h:1094
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))
Definition: GU_GridImpl.h:1653