opennurbs_subd.h
1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2014 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 
18 #if 0
19 #define ON_SUBD_CENSUS
20 //////////////////////////////////////////////////////////////////////////
21 //
22 // ON_CensusCounter
23 //
24 // This tool is used to study memory leaks and other shared ptr issues.
25 // The classes have no size but effect performance. Use only in
26 // debugging situations. Never ship a release with ON_SUBD_CENSUS defined.
27 //
28 class ON_SUBD_CLASS ON_CensusCounter
29 {
30 public:
31  enum class Class : unsigned int
32  {
33  unset = 0,
34  subd = 1,
35  subd_impl = 2,
36  subd_limit_mesh = 3,
37  subd_limit_mesh_impl = 4,
38  subd_ref = 5,
39 
40  count
41  };
42 
43  static void RegisterBirth(ON_CensusCounter::Class,ON__UINT_PTR);
44 
45  static void RegisterDeath(ON_CensusCounter::Class,ON__UINT_PTR);
46 
47  static void CensusReport(
48  class ON_TextLog&
49  );
50 
51  static void Clear();
52 };
53 
54 class ON_SUBD_CLASS ON_SubDCensusCounter
55 {
56 public:
57  ON_SubDCensusCounter() ON_NOEXCEPT;
58  ~ON_SubDCensusCounter() ON_NOEXCEPT;
59  ON_SubDCensusCounter(const ON_SubDCensusCounter&) ON_NOEXCEPT;
60  ON_SubDCensusCounter& operator=(const ON_SubDCensusCounter&) = default;
61  //ON_SubDCensusCounter( ON_SubDCensusCounter&& ) ON_NOEXCEPT;
62  //ON_SubDCensusCounter& operator=( ON_SubDCensusCounter&& ) ON_NOEXCEPT;
63 };
64 
65 class ON_SUBD_CLASS ON_SubDRefCensusCounter
66 {
67 public:
68  ON_SubDRefCensusCounter() ON_NOEXCEPT;
69  ~ON_SubDRefCensusCounter() ON_NOEXCEPT;
70  ON_SubDRefCensusCounter(const ON_SubDRefCensusCounter&) ON_NOEXCEPT;
71  ON_SubDRefCensusCounter& operator=(const ON_SubDRefCensusCounter&) = default;
72  //ON_SubDRefCensusCounter( ON_SubDRefCensusCounter&& ) ON_NOEXCEPT;
73  //ON_SubDRefCensusCounter& operator=( ON_SubDRefCensusCounter&& ) ON_NOEXCEPT;
74 };
75 
76 
77 class ON_SUBD_CLASS ON_SubDImpleCensusCounter
78 {
79 public:
80  ON_SubDImpleCensusCounter() ON_NOEXCEPT;
81  ~ON_SubDImpleCensusCounter() ON_NOEXCEPT;
82  ON_SubDImpleCensusCounter(const ON_SubDImpleCensusCounter&) ON_NOEXCEPT;
83  ON_SubDImpleCensusCounter& operator=(const ON_SubDImpleCensusCounter&) = default;
84  //ON_SubDImplCensusCounter( ON_SubDImplCensusCounter&& ) ON_NOEXCEPT;
85  //ON_SubDImplCensusCounter& operator=( ON_SubDImplCensusCounter&& ) ON_NOEXCEPT;
86 };
87 
88 class ON_SUBD_CLASS ON_SubDLimitMeshCensusCounter
89 {
90 public:
91  ON_SubDLimitMeshCensusCounter() ON_NOEXCEPT;
92  ~ON_SubDLimitMeshCensusCounter() ON_NOEXCEPT;
93  ON_SubDLimitMeshCensusCounter(const ON_SubDLimitMeshCensusCounter&) ON_NOEXCEPT;
94  ON_SubDLimitMeshCensusCounter& operator=(const ON_SubDLimitMeshCensusCounter&) = default;
95  //ON_SubDLimitMeshCensusCounter( ON_SubDLimitMeshCensusCounter&& ) ON_NOEXCEPT;
96  //ON_SubDLimitMeshCensusCounter& operator=( ON_SubDLimitMeshCensusCounter&& ) ON_NOEXCEPT;
97 };
98 
99 
100 class ON_SUBD_CLASS ON_SubDLimitMeshImplCensusCounter
101 {
102 public:
103  ON_SubDLimitMeshImplCensusCounter() ON_NOEXCEPT;
104  ~ON_SubDLimitMeshImplCensusCounter() ON_NOEXCEPT;
105  ON_SubDLimitMeshImplCensusCounter(const ON_SubDLimitMeshImplCensusCounter&) ON_NOEXCEPT;
106  ON_SubDLimitMeshImplCensusCounter& operator=(const ON_SubDLimitMeshImplCensusCounter&) ON_NOEXCEPT;
107  ON_SubDLimitMeshImplCensusCounter( ON_SubDLimitMeshImplCensusCounter&& ) ON_NOEXCEPT;
108  ON_SubDLimitMeshImplCensusCounter& operator=( ON_SubDLimitMeshImplCensusCounter&& ) ON_NOEXCEPT;
109 };
110 
111 #endif
112 
113 
114 ////////////////////////////////////////////////////////////////
115 //
116 // Definition of subdivision surface
117 //
118 ////////////////////////////////////////////////////////////////
119 
120 #if !defined(OPENNURBS_SUBD_INC_)
121 #define OPENNURBS_SUBD_INC_
122 
123 #if defined(OPENNURBS_SUBD_WIP)
124 
125 #if 1
126 // SuD is exported from opennurbs DLL
127 #define ON_SUBD_CLASS ON_CLASS
128 #else
129 // SuD is not exported from opennurbs DLL
130 #define ON_SUBD_CLASS
131 #endif
132 
133 class ON_SUBD_CLASS ON_SubDVertexPtr
134 {
135 public:
136  // For performance reasons, m_ptr is not initialized and no constructors are declared
137  // or implemented. If you require initialization, then use x = ON_SubDVertexPtr::Null
138  // or x = ON_SubDVertexPtr::Create(...).
139  ON__UINT_PTR m_ptr;
140 
141  static const ON_SubDVertexPtr Null;
142 
143  bool IsNull() const;
144 
145  class ON_SubDVertex* Vertex() const;
146 
147  ON__UINT_PTR VertexPtrMark() const;
148 
149  ON_ComponentStatus Status() const;
150 
151  static
152  class ON_SubDVertexPtr Create(
153  const class ON_SubDVertex* vertex
154  );
155 
156  /*
157  Parameters:
158  vertex - [in]
159  mark - [in]
160  zero or one
161  */
162  static
163  class ON_SubDVertexPtr Create(
164  const class ON_SubDVertex* vertex,
165  ON__UINT_PTR vertex_mark
166  );
167 
168  static
169  class ON_SubDVertexPtr Create(
170  const class ON_SubDComponentPtr& vertex_component
171  );
172 };
173 
174 class ON_SUBD_CLASS ON_SubDEdgePtr
175 {
176 public:
177  // For performance reasons, m_ptr is not initialized and no constructors are declared
178  // or implemented. If you require initialization, then use x = ON_SubDEdgePtr::Null
179  // or x = ON_SubDEdgePtr::Create(...).
180  ON__UINT_PTR m_ptr;
181 
182  static const ON_SubDEdgePtr Null;
183 
184  bool IsNull() const;
185 
186  class ON_SubDEdge* Edge() const;
187 
188  ON__UINT_PTR EdgeDirection() const;
189 
190  ON_ComponentStatus Status() const;
191 
192  /*
193  Returns:
194  A pointer to the same edge with the direction flipped
195  */
196  ON_SubDEdgePtr Reversed() const;
197 
198  static ON_SubDEdgePtr Create(
199  const class ON_SubDEdge* edge,
200  ON__UINT_PTR direction
201  );
202 
203  static ON_SubDEdgePtr Create(
204  const class ON_SubDComponentPtr& edge_component
205  );
206 };
207 
208 class ON_SUBD_CLASS ON_SubDFacePtr
209 {
210 public:
211  // For performance reasons, m_ptr is not initialized and no constructors are declared
212  // or implemented. If you require initialization, then use x = ON_SubDFacePtr::Null
213  // or x = ON_SubDFacePtr::Create(...).
214  ON__UINT_PTR m_ptr;
215 
216  static const ON_SubDFacePtr Null;
217 
218  bool IsNull() const;
219 
220  class ON_SubDFace* Face() const;
221 
222  ON__UINT_PTR FaceDirection() const;
223 
224  ON_ComponentStatus Status() const;
225 
226  static
227  class ON_SubDFacePtr Create(
228  const class ON_SubDFace* face,
229  ON__UINT_PTR direction
230  );
231 
232  static ON_SubDFacePtr Create(
233  const class ON_SubDComponentPtr& face_component
234  );
235 };
236 
237 class ON_SUBD_CLASS ON_SubDComponentPtr
238 {
239 public:
240  // For performance reasons, m_ptr is not initialized and no constructors are declared
241  // or implemented. If you require initialization, then use x = ON_SubDComponentPtr::Null
242  // or x = ON_SubDComponentPtr::Create(...).
243  ON__UINT_PTR m_ptr;
244 
245  static const ON_SubDComponentPtr Null;
246 
247  enum class ComponentPtrType : unsigned char
248  {
249  unset = 0,
250  vertex = 1,
251  edge = 2,
252  face = 3
253  };
254 
255  static ON_SubDComponentPtr::ComponentPtrType ComponentPtrTypeFromUnsigned(
256  unsigned int component_pointer_type_as_unsigned
257  );
258 
259  /*
260  Description:
261  ON_SubDComponentPtr::ComponentPtrType::vertex
262  < ON_SubDComponentPtr::ComponentPtrType::edge
263  < ON_SubDComponentPtr::ComponentPtrType::face
264  < ON_SubDComponentPtr::ComponentPtrType::unset
265  < invalid
266  */
267  static int CompareComponentPtrType(
268  ON_SubDComponentPtr::ComponentPtrType a,
269  ON_SubDComponentPtr::ComponentPtrType b
270  );
271 
272  static int CompareType(
273  const ON_SubDComponentPtr* a,
274  const ON_SubDComponentPtr* b
275  );
276 
277  static int Compare(
278  const ON_SubDComponentPtr* a,
279  const ON_SubDComponentPtr* b
280  );
281 
282 
283  bool IsNull() const;
284  bool IsNotNull() const;
285 
286  ON_SubDComponentPtr::ComponentPtrType ComponentType() const;
287 
288  class ON_SubDComponentBase* ComponentBase() const;
289  class ON_SubDVertex* Vertex() const;
290  class ON_SubDEdge* Edge() const;
291  class ON_SubDFace* Face() const;
292 
293  ON_SubDVertexPtr VertexPtr() const;
294  ON_SubDEdgePtr EdgePtr() const;
295  ON_SubDFacePtr FacePtr() const;
296 
297  ON_COMPONENT_INDEX ComponentIndex() const;
298 
299  /*
300  Returns:
301  0 or 1.
302  The interpretation of the mark varies depending on the context.
303  For vertices, this is the vertex mark.
304  For edges, this is generally an index into ON_SubDEdge.m_vertex[]
305  or a direction flag with 1 indicating a reversed direction.
306  For face, this is generally an orientation flag with 1 indicating
307  a reversed (clockwise) orientation.
308  */
309  ON__UINT_PTR ComponentMark() const;
310 
311  ON_ComponentStatus Status() const;
312 
313  /*
314  Returns:
315  1: status changed.
316  0: status not changed.
317  */
318  unsigned int SetStates(
319  ON_ComponentStatus states_to_set
320  );
321 
322  /*
323  Returns:
324  1: status changed.
325  0: status not changed.
326  */
327  unsigned int ClearStates(
328  ON_ComponentStatus states_to_clear
329  );
330 
331  /*
332  Description:
333  Makes "this" an exact copy of status.
334  Parameters:
335  status - [in]
336  Returns:
337  1: status changed.
338  0: status not changed.
339  */
340  unsigned int SetStatus(
341  ON_ComponentStatus status
342  );
343 
344  static ON_SubDComponentPtr ClearMark(
345  ON_SubDComponentPtr component_ptr
346  );
347 
348  static
349  class ON_SubDComponentPtr Create(
350  const class ON_SubDVertex* vertex
351  );
352 
353  static
354  class ON_SubDComponentPtr Create(
355  const class ON_SubDEdge* edge
356  );
357 
358  static
359  class ON_SubDComponentPtr Create(
360  const class ON_SubDFace* face
361  );
362 
363  static
364  class ON_SubDComponentPtr Create(
365  const class ON_SubDVertex* vertex,
366  ON__UINT_PTR vertex_mark
367  );
368 
369  static
370  class ON_SubDComponentPtr Create(
371  const class ON_SubDEdge* edge,
372  ON__UINT_PTR edge_mark
373  );
374 
375  static
376  class ON_SubDComponentPtr Create(
377  const class ON_SubDFace* face,
378  ON__UINT_PTR face_mark
379  );
380 
381  static
382  class ON_SubDComponentPtr Create(
383  ON_SubDVertexPtr vertexptr
384  );
385 
386  static
387  class ON_SubDComponentPtr Create(
388  ON_SubDEdgePtr edgeptr
389  );
390 
391  static
392  class ON_SubDComponentPtr Create(
393  ON_SubDFacePtr faceptr
394  );
395 };
396 
397 /*
398 Description:
399  The ON_SubDComponentLocation enum is used when an ON_SubD component
400  is referenced and it is important to distinguish between the
401  component's location in the SubD control net and its location
402  in the SubD limit surface.
403 */
404 enum class ON_SubDComponentLocation : unsigned char
405 {
406  Unset = 0,
407  ControlNet = 1,
408  LimitSurface = 2
409 };
410 
411 //////////////////////////////////////////////////////////////////////////
412 //
413 // ON_SubD
414 //
415 class ON_SUBD_CLASS ON_SubD : public ON_Geometry
416 {
417  ON_OBJECT_DECLARE(ON_SubD);
418 
419 #if defined(ON_SUBD_CENSUS)
420 private:
421  ON_SubDCensusCounter m_census_counter;
422 #endif
423 
424 public:
425  static const ON_SubD Empty;
426 
427  enum : unsigned int
428  {
429  maximum_subd_level = 128 // uses as a sanity check on input parameters
430  };
431 
432 #pragma region RH_C_SHARED_ENUM [ON_SubD::VertexTag] [Rhino.Geometry.SubD.SubDVertexTag] [nested:byte]
433  /// <summary>
434  /// SubD::VertexTag identifies the type of subdivision vertex. Different tags use
435  /// different subdivision algorithms to determine where the subdivision point and
436  /// limit point are located. There are toplological constraints that restrict which
437  /// tags can be assigned.
438  /// </summary>
439  enum class VertexTag : unsigned char
440  {
441  ///<summary>
442  /// Not a valid vertex tag and the default value for ON_SubDVertex::m_vertex_tag.
443  /// This encourages developers to thoughtfully initialize ON_SubDVertex::m_vertex_tag.
444  ///</summary>
445  Unset = 0,
446 
447  ///<summary>
448  /// Must be an interior vertex.
449  /// All edges ending at a smooth vertex must be tagged as ON_SubD::EdgeTag::Smooth.
450  ///</summary>
451  Smooth = 1,
452 
453  ///<summary>
454  /// Can be an iterior or a boundary vertex.
455  /// Exactly two edges ending at a crease vertex must be tagged as ON_SubD::EdgeTag::Crease.
456  /// All other edges ending at a crease must be tagged as tagON_SubD::EdgeTag::smooth.
457  ///</summary>
458  Crease = 2,
459 
460  ///<summary>
461  /// Can be an iterior, boundary or isolated vertex.
462  /// The location of a corner vertex is fixed.
463  /// The all subdivision points and the limit point are at the initial vertex location.
464  /// The edges ending at a corner vertex can be smooth or crease edges.
465  ///</summary>
466  Corner = 3,
467 
468  ///<summary>
469  /// Must be an interior vertex.
470  /// Exactly one edge ending at a dart vertex must be tagged as ON_SubD::EdgeTag::Smooth.
471  /// All other edges ending at a dart vertex must be tagged as tagON_SubD::EdgeTag::smooth.
472  ///</summary>
473  Dart = 4
474  };
475 #pragma endregion
476 
477  static ON_SubD::VertexTag VertexTagFromUnsigned(
478  unsigned int vertex_tag_as_unsigned
479  );
480 
481  /*
482  Parameters:
483  vertex_tag - [in]
484  Returns:
485  True if vertex_tag is Smooth, Crease, Corner, or Dart.
486  False otherwise.
487  */
488  static bool VertexTagIsSet(
489  ON_SubD::VertexTag vertex_tag
490  );
491 
492 #pragma region RH_C_SHARED_ENUM [ON_SubD::EdgeTag] [Rhino.Geometry.SubD.SubDEdgeTag] [nested:byte]
493  /// <summary>
494  /// SubD::EdgeTag identifies the type of subdivision edge. Different tags use
495  /// different subdivision algorithms to determine where the subdivision point is located.
496  /// </summary>
497  enum class EdgeTag : unsigned char
498  {
499  ///<summary>
500  /// Not a valid edge tag and the default value for ON_SubDEdge::m_edge_tag.
501  /// This encourages developers to thoughtfully initialize ON_SubDEdge::m_edge_tag.
502  ///</summary>
503  Unset = 0,
504 
505  ///<summary>
506  /// One or two of the edge's vertices must be tagged as ON_SubD::VertexTag::Smooth.
507  /// The edge must have exactly two faces.
508  ///</summary>
509  Smooth = 1,
510 
511  ///<summary>
512  /// Both of the edge's vertices must be tagged as not ON_SubD::VertexTag::Smooth.
513  /// The edge can have any number of faces.
514  ///</summary>
515  Crease = 2,
516 
517  ///<summary>
518  /// Reserved for version 2 of the ON_SubD project.
519  /// Currently this tag is not used and is invalid.
520  ///
521  /// FUTURE: The edge is a "soft crease" or "semi-sharp".
522  /// At lease one end vertex must be tagged as ON_SubD::VertexTag::Smooth
523  /// The edge must have exactly two faces.
524  /// The value of ON_SubDEdge::m_sharpness controls how
525  /// soft/hard the edge appears.
526  /// ON_SubDEdge::m_sharpness = 0 is identical to ON_SubD::EdgeTag::Smooth.
527  /// ON_SubDEdge::m_sharpness = 1 is identical to ON_SubD::EdgeTag::Crease.
528  ///</summary>
529  Sharp = 3,
530 
531  ///<summary>
532  /// This tag appears only on edges that have exactly two neighboring faces
533  /// and neither end vertex is tagged as ON_SubD::VertexTag::Smooth.
534  /// The level 1 subdivision point for a level 0 edge tagged as ON_SubD::EdgeTag::X
535  /// is the standard smooth edge subdivision point.
536  /// When subdivided, the new subdivision vertex will be tagged
537  /// as ON_SubD::VertexTag::Smooth and the subdivided edges will
538  /// be tagged as ON_SubD::EdgeTag::Smooth. Thus, the tag ON_SubD::EdgeTag::X
539  /// should only appear at level 0.
540  /// This tag exists because the ON_SubD subdivision
541  /// algorithm requires any edge with both end vertices
542  /// tagged as not smooth must be subdivided at its midpoint.
543  /// Sector iterators treat "X" edges as smooth.
544  /// Both edge end weights must be set so the smooth
545  /// subdivided edges will be valid.
546  ///</summary>
547  X = 4
548  };
549 #pragma endregion
550 
551  static ON_SubD::EdgeTag EdgeTagFromUnsigned(
552  unsigned int edge_tag_as_unsigned
553  );
554 
555 
556  /*
557  Parameters:
558  edge_tag - [in]
559  Returns:
560  True if edge_tag is Smooth, Crease, Sharp, or X.
561  False otherwise.
562  */
563  static bool EdgeTagIsSet(
564  ON_SubD::EdgeTag edge_tag
565  );
566 
567 
568 #pragma region RH_C_SHARED_ENUM [ON_SubD::FacetType] [Rhino.Geometry.SubD.SubDFacetType] [nested:byte]
569  /// <summary>
570  /// SubD::FacetType reports the default facet type for subdivision algorithms.
571  /// </summary>
572  enum class FacetType : unsigned char
573  {
574  ///<summary> Not a valid facet type. </summary>
575  Unset = 0,
576 
577  ///<summary> Triangle </summary>
578  Tri = 3,
579 
580  ///<summary> Quadrangle </summary>
581  Quad = 4
582  };
583 #pragma endregion
584 
585  static ON_SubD::FacetType FacetTypeFromUnsigned(
586  unsigned int facet_type_as_unsigned
587  );
588 
589  //enum class VertexEdgeOrder : unsigned char
590  //{
591  // unset = 0,
592  // radial, // The ON_SubDVertex edge and face information satisfies:
593  // // 1) m_face_count = m_edge_count or m_face_count+1 == m_edge_count
594  // // 2) m_faces[i] is between m_edges[i] and m_edges[(i+1)%m_edge_count]
595  // // 3) When 0 < i < m_edge_count-1, m_edges[i].m_edge_count = 2
596  // // and m_edges[i].m_face2[] references m_faces[i-1] and m_faces[i]
597  // // in an unspecified order.
598  // notradial // one of the conditions conditions for radial is not satisfied.
599  //};
600 
601  //static ON_SubD::VertexEdgeOrder VertexEdgeOrderFromUnsigned(
602  // unsigned int vertex_edge_order_as_unsigned
603  // );
604 
605 #pragma region RH_C_SHARED_ENUM [ON_SubD::VertexFacetType] [Rhino.Geometry.SubD.VertexFacetType] [nested:byte]
606 
607  ///<summary>Summarizes the number of edges in faces in the whole object.</summary>
608  enum class VertexFacetType : unsigned char
609  {
610  ///<summary>Not a valid vertex face type.</summary>
611  Unset = 0,
612 
613  ///<summary>All faces are triangular.</summary>
614  Tri = 3,
615 
616  ///<summary>All faces are quads.</summary>
617  Quad = 4,
618 
619  ///<summary>Edge count of faces is constant and &gt; 4.</summary>
620  Ngon = 5,
621 
622  ///<summary>Edge count of faces is not constant.</summary>
623  Mixed = 0xFF
624  };
625 #pragma endregion
626 
627  static ON_SubD::VertexFacetType VertexFacetTypeFromUnsigned(
628  unsigned int vertex_facet_type_as_unsigned
629  );
630 
631 #pragma region RH_C_SHARED_ENUM [ON_SubD::SubDType] [Rhino.Geometry.SubD.SubDType] [nested:byte]
632  /// <summary>
633  /// Subdivision algorithm.
634  /// </summary>
635  enum class SubDType : unsigned char
636  {
637  ///<summary>
638  /// Not a valid subdivision type.
639  ///</summary>
640  Unset = 0,
641 
642  ///<summary>
643  /// Built-in Loop-Warren triangle with Bernstein-Levin-Zorin creases and darts.
644  ///</summary>
645  TriLoopWarren = 3,
646 
647  ///<summary>
648  /// Built-in Catmull-Clark quad with Bernstein-Levin-Zorin creases and darts.
649  ///</summary>
650  QuadCatmullClark = 4,
651 
652  ///<summary>
653  /// Custom triangle face algorithm. (Not built-in. Provided for use by 3rd party developers.)
654  ///</summary>
655  CustomTri = 5,
656 
657  ///<summary>
658  /// Custom quad facet algorithm. (Not built-in. Provided for use by 3rd party developers.)
659  ///</summary>
660  CustomQuad = 6,
661 
662  ///<summary>
663  /// Custom algorithm. (Not built-in. Provided for use by 3rd party developers.)
664  ///</summary>
665  Custom = 7
666 
667  // All values must be <= 31; i.e., (((unsigned char)0xE0U) & subd_type)) must be zero.
668  };
669 #pragma endregion
670 
671  static ON_SubD::SubDType SubDTypeFromUnsigned(
672  unsigned int subd_type_as_unsigned
673  );
674 
675  static ON_SubD::SubDType DefaultSubDType();
676 
677  static unsigned int FacetEdgeCount(
678  ON_SubD::FacetType facet_type
679  );
680 
681  static unsigned int FacetEdgeCount(
682  ON_SubD::SubDType subd_type
683  );
684 
685  /*
686  Parameters:
687  sit - [in]
688  vertex sector iterator
689  component_ring_capacity - [in]
690  capacity of component_ring[] array
691  1 + center_vertex.m_edge_count + center_vertex.m_face_count
692  will be large enough.
693  component_ring - [out]
694  A sorted list of ON_SubDComponentPtr values are returned in component_ring[]
695  component_ring[0] is the central vertex.
696  component_ring[1] and subsequent components with odd indices are sector edges.
697  component_ring[2] and subsequent components with even indices are sector faces.
698  For edge components (i is odd), component_ring[i].ComponentMark() is the index of
699  the center vertex in ON_SubDEge.m_vertex[].
700  Returns:
701  Number of components set in component_ring[].
702 
703  0: failure
704 
705  >= 4 and even:
706  component_ring[0] = center vertex
707  component_ring[1] = starting crease edge
708  component_ring[2] = starting face
709  ... zero or more interior smooth edge, face pairs ...
710  component_ring[component_count-1] = ending crease edge
711 
712  >= 5 and odd:
713  component_ring[0] = vit.CenterVertex()
714  component_ring[1] = first edge (smooth)
715  component_ring[2] = first face
716  ... zero or more smooth edge, face, pairs ...
717  component_ring[component_count-2] = last edge (smooth)
718  component_ring[component_count-1] = last face
719 
720  Example:
721  unsinged int component_ring_count = GetVertexComponentRing(vit,component_ring);
722  unsinged int N = component_ring_count/2; // number of edges in ring
723  const bool bSectorHasCreaseBoundary = (0 == (component_ring_count % 2));
724  */
725  static unsigned int GetSectorComponentRing(
726  const class ON_SubDSectorIterator& sit,
727  size_t component_ring_capacity,
728  ON_SubDComponentPtr* component_ring
729  );
730 
731  /*
732  Parameters:
733  sit - [in]
734  vertex sector iterator
735  component_ring - [out]
736  A sorted listof ON_SubDComponentPtr values are returned in component_ring[]
737 
738 
739 
740  Returns:
741  Number of components set in component_ring[].
742 
743  0: failure
744 
745  >= 4 and even:
746  component_ring[0] = vit.CenterVertex()
747  component_ring[1] = starting crease edge
748  component_ring[2] = starting face
749  ... zero or more interior smooth edge, face pairs ...
750  component_ring[component_count-1] = ending crease edge
751 
752  >= 5 and odd:
753  component_ring[0] = center vertex
754  component_ring[1] = first edge (smooth)
755  component_ring[2] = first face
756  ... zero or more smooth edge, face, pairs ...
757  component_ring[component_count-2] = last edge (smooth)
758  component_ring[component_count-1] = last face
759 
760  Example:
761  unsinged int component_ring_count = GetVertexComponentRing(vit,component_ring);
762  unsinged int N = component_ring_count/2; // number of edges in ring
763  const bool bSectorHasCreaseBoundary = (0 == (component_ring_count % 2));
764  */
765  static unsigned int GetSectorComponentRing(
766  const class ON_SubDSectorIterator& sit,
768  );
769 
770  /*
771  Returns:
772  Number of edges in an component ring returned by ON_SubD::GetVertexComponentRing();
773  */
774  static unsigned int ComponentRingEdgeCount(
775  size_t component_ring_count
776  );
777 
778  /*
779  Returns:
780  Number of faces in an component ring returned by ON_SubD::GetVertexComponentRing();
781  */
782  static unsigned int ComponentRingFaceCount(
783  size_t component_ring_count
784  );
785 
786  static bool ComponentRingIsValid(
787  size_t component_ring_count,
788  const ON_SubDComponentPtr* component_ring
789  );
790 
791  /*
792  Returns:
793  Number of points in the subdivision ring or 0 if the call fails.
794  */
795  static unsigned int GetSectorSubdivsionPointRing(
796  ON_SubD::SubDType subd_type,
797  size_t component_ring_count,
798  const ON_SubDComponentPtr* component_ring,
799  size_t point_ring_capacity,
800  size_t point_ring_stride,
801  double* point_ring
802  );
803 
804  static unsigned int GetSectorSubdivisionPointRing(
805  ON_SubD::SubDType subd_type,
806  size_t component_ring_count,
807  const ON_SubDComponentPtr* component_ring,
808  ON_SimpleArray<ON_3dPoint>& subd_point_ring
809  );
810 
811  static unsigned int GetSectorPointRing(
812  ON_SubD::SubDType subd_type,
813  bool bSubdivideIfNeeded,
814  size_t component_ring_count,
815  const ON_SubDComponentPtr* component_ring,
816  size_t subd_point_ring_capacity,
817  size_t subd_point_ring_stride,
818  double* subd_point_ring
819  );
820 
821  static unsigned int GetSectorPointRing(
822  ON_SubD::SubDType subd_type,
823  bool bSubdivideIfNeeded,
824  size_t component_ring_count,
825  const ON_SubDComponentPtr* component_ring,
826  ON_SimpleArray<ON_3dPoint>& point_ring
827  );
828 
829  static unsigned int GetSectorPointRing(
830  ON_SubD::SubDType subd_type,
831  bool bSubdivideIfNeeded,
832  const class ON_SubDSectorIterator& sit,
833  size_t point_ring_capacity,
834  size_t point_ring_stride,
835  double* point_ring
836  );
837 
838  static unsigned int GetSectorPointRing(
839  ON_SubD::SubDType subd_type,
840  bool bSubdivideIfNeeded,
841  const class ON_SubDSectorIterator& sit,
842  ON_SimpleArray<ON_3dPoint>& point_ring
843  );
844 
845  /*
846  Parameters:
847  subd_type - [in]
848  A quad based subdivision algorithm.
849  bFirstPass - [in]
850  If bFirstPass is true and the components are in standard form for the vertex
851  and subdivision type, then locations of the component vertices opposite the
852  center vertex are returned in the point ring.
853  bSecondPass - [in]
854  If bSecondtPass is true and the first pass is disable or does not succeed,
855  then the component subdivision locations are returned in the point ring.
856  vertex0 - [in]
857  If not null, then vertex0->m_edges and vertex0->m_faces must
858  be radially sorted and span a single sector and component_ring[]
859  is ignored.
860  component_ring_count - [in]
861  If vertex0 is null, then component_ring_count specifies the number
862  of components in the component_ring[] array.
863  component_ring[] - [in]
864  If vertex0 is null, then component_ring[0] is the central vertex,
865  component_ring[1] and subsequent components with odd indices are
866  sector edges, component_ring[2] and subsequent components with even
867  indices are sector faces, all sorted radially.
868  point_ring_stride - [in]
869  point_ring - [out]
870  point locations are returned here.
871  Returns:
872  Number of points in the subdivision ring or 0 if the call fails.
873  The number of points is
874  1 + ON_SubD::ComponentRingEdgeCount(component_ring_count) + ON_SubD::ComponentRingFaceCount(component_ring_count).
875  Remarks:
876  No validation checking is performed. This function will crash
877  if the input is not valid. Call GetSubdivisionPointRing() if
878  you want a crash proof call.
879  */
880  static unsigned int GetQuadSectorPointRing(
881  ON_SubD::SubDType subd_type,
882  bool bFirstPass,
883  bool bSecondPass,
884  const class ON_SubDVertex* vertex0,
885  size_t component_ring_count,
886  const class ON_SubDComponentPtr* component_ring,
887  size_t point_ring_stride,
888  double* point_ring
889  );
890 
891  /*
892  Parameters:
893  subd_type - [in]
894  A tri based subdivision algorithm.
895  bFirstPass - [in]
896  If bFirstPass is true and the components are in standard form for the vertex
897  and subdivision type, then locations of the component vertices opposite the
898  center vertex are returned in the point ring.
899  bSecondPass - [in]
900  If bSecondPass is true and the first pass is disable or does not succeed,
901  then the component subdivision locations are returned in the point ring.
902  vertex0 - [in]
903  If not null, then vertex0->m_edges and vertex0->m_faces must
904  be radially sorted and span a single sector and component_ring[]
905  is ignored.
906  component_ring_count - [in]
907  If vertex0 is null, then component_ring_count specifies the number
908  of components in the component_ring[] array.
909  component_ring[] - [in]
910  If vertex0 is null, then component_ring[0] is the central vertex,
911  component_ring[1] and subsequent components with odd indices are
912  sector edges, component_ring[2] and subsequent components with even
913  indices are sector faces, all sorted radially.
914  point_ring_stride - [in]
915  point_ring - [out]
916  point locations are returned here.
917  Returns:
918  Number of points in the subdivision ring or 0 if the call fails.
919  The number of points is 1 + ON_SubD::ComponentRingEdgeCount(component_ring_count).
920  Remarks:
921  No validation checking is performed. This function will crash
922  if the input is not valid. Call GetSubdivisionPointRing() if
923  you want a crash proof call.
924  */
925  static unsigned int GetTriSectorPointRing(
926  ON_SubD::SubDType subd_type,
927  bool bFirstPass,
928  bool bSecondPass,
929  const class ON_SubDVertex* vertex0,
930  size_t component_ring_count,
931  const class ON_SubDComponentPtr* component_ring,
932  size_t point_ring_stride,
933  double* point_ring
934  );
935 
936  static const class ON_SubDVertex* SubdivideSector(
937  ON_SubD::SubDType subd_type,
938  const class ON_SubDVertex* center_vertex,
939  size_t component_ring_count,
940  const class ON_SubDComponentPtr* component_ring,
941  class ON_SubD_FixedSizeHeap& fsh
942  );
943 
944  /*
945  Returns:
946  true if sector_edge_count is valid for the vertex type
947  */
948  static bool IsValidSectorEdgeCount(
949  ON_SubD::VertexTag vertex_tag,
950  unsigned int sector_edge_count
951  );
952 
953  static bool IsValidSectorFaceCount(
954  ON_SubD::VertexTag vertex_tag,
955  unsigned int sector_face_count
956  );
957 
958  /*
959  Returns:
960  Type of facets the basic subdivision algorithm requires.
961  ON_SubD::FacetType::Quad if subd_type is ON_SubD::SubDType::TriLoopWarren.
962  ON_SubD::FacetType::Tri if subd_type is ON_SubD::SubDType::QuadCatmullClark.
963  ON_SubD::FacetType::Unset otherwise.
964  Remark:
965  All built in subdivision algorithm will handle faces with 3 or more edges.
966  */
967  static ON_SubD::FacetType FacetTypeFromSubDType(
968  ON_SubD::SubDType subd_type
969  );
970 
971  static ON_SubD::SubDType SubDTypeFromFacetType(
972  ON_SubD::FacetType facet_type
973  );
974 
975  static bool PointRingHasFacePoints(
976  ON_SubD::SubDType subd_type
977  );
978 
979  /*
980  Returns:
981  true if facet_type is ON_SubD::FacetType::Tri or ON_SubD::FacetType::Quad.
982  */
983  static bool IsQuadOrTriFacetType(
984  ON_SubD::FacetType facet_type
985  );
986 
987  /*
988  Returns:
989  true if subd_type is ON_SubD::SubDType::TriLoopWarren or ON_SubD::SubDType::QuadCatmullClark.
990  */
991  static bool IsQuadOrTriSubDType(
992  ON_SubD::SubDType subd_type
993  );
994 
995  ON_SubD() ON_NOEXCEPT;
996  virtual ~ON_SubD();
997 
998  /*
999  Description:
1000  Creates an independent copy of src.
1001  */
1002  ON_SubD( const ON_SubD& src );
1003 
1004  /*
1005  Description:
1006  Creates an independent copy of src.
1007  */
1008  ON_SubD& operator=(const ON_SubD& src);
1009 
1010 #if defined(ON_HAS_RVALUEREF)
1011  // rvalue copy constructor
1012  ON_SubD( ON_SubD&& ) ON_NOEXCEPT;
1013 
1014  // The rvalue assignment operator calls ON_Object::operator=(ON_Object&&)
1015  // which could throw exceptions. See the implementation of
1016  // ON_Object::operator=(ON_Object&&) for details.
1017  ON_SubD& operator=( ON_SubD&& );
1018 #endif
1019 
1020  /*
1021  Description:
1022  The subdivision information referenced by src_subd will be shared with this
1023  Remarks:
1024  ON_Geometry base class information, like ON_UserData, is not copied or shared.
1025  */
1026  void ShareContentsFrom(
1027  ON_SubD& subd
1028  );
1029 
1030  static void SwapContents(
1031  ON_SubD& a,
1032  ON_SubD& b
1033  );
1034 
1035  //virtual
1036  void MemoryRelocate() override;
1037 
1038  //virtual
1039  bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
1040 
1041  //virtual
1042  void Dump(
1043  ON_TextLog&
1044  ) const override;
1045 
1046  //virtual
1047  unsigned int SizeOf() const override;
1048 
1049  //virtual
1050  ON__UINT32 DataCRC(
1051  ON__UINT32 current_remainder
1052  ) const override;
1053 
1054  //virtual
1055  bool Write(
1056  ON_BinaryArchive& archive
1057  ) const override;
1058 
1059  //virtual
1060  bool Read(
1061  ON_BinaryArchive& archive
1062  ) override;
1063 
1064  //virtual
1065  ON::object_type ObjectType() const override;
1066 
1067 
1068  //virtual
1069  unsigned int ClearComponentStates(
1070  ON_ComponentStatus states_to_clear
1071  ) const override;
1072 
1073  //virtual
1074  unsigned int GetComponentsWithSetStates(
1075  ON_ComponentStatus states_filter,
1076  bool bAllEqualStates,
1078  ) const override;
1079 
1080  //virtual
1081  unsigned int SetComponentStates(
1082  ON_COMPONENT_INDEX component_index,
1083  ON_ComponentStatus states_to_set
1084  ) const override;
1085 
1086  //virtual
1087  unsigned int ClearComponentStates(
1088  ON_COMPONENT_INDEX component_index,
1089  ON_ComponentStatus states_to_clear
1090  ) const override;
1091 
1092  //virtual
1093  unsigned int SetComponentStatus(
1094  ON_COMPONENT_INDEX component_index,
1095  ON_ComponentStatus status_to_copy
1096  ) const override;
1097 
1098  //virtual
1099  ON_AggregateComponentStatus AggregateComponentStatus() const override;
1100 
1101  //virtual
1102  void MarkAggregateComponentStatusAsNotCurrent() const override;
1103 
1104  //virtual
1105  bool DeleteComponents(
1106  const ON_COMPONENT_INDEX* ci_list,
1107  size_t ci_count
1108  ) override;
1109 
1110  /*
1111  Remarks:
1112  For ON_SubD objects, ClearBoundingBox() and DestroyRuntimeCache()
1113  are identical.
1114  */
1115  //virtual
1116  void DestroyRuntimeCache(
1117  bool bDelete = true
1118  ) override;
1119 
1120  //virtual
1121  int Dimension() const override;
1122 
1123  // virtual ON_Geometry GetBBox override
1124  bool GetBBox( double* boxmin, double* boxmax, bool bGrowBox = false ) const override;
1125 
1126  // virtual ON_Geometry GetTightBoundingBox override
1127  bool GetTightBoundingBox( class ON_BoundingBox& tight_bbox, bool bGrowBox = false, const class ON_Xform* xform = nullptr ) const override;
1128 
1129  /*
1130  Description:
1131  Clears all saved information that depends on vertex locations,
1132  subdivision algorithms, vertex or edge tags, or control net topology.
1133  If you modify any of the above, then call ClearBoundingBox().
1134  Remarks:
1135  For ON_SubD objects, ClearBoundingBox() and DestroyRuntimeCache()
1136  are identical.
1137  */
1138  //virtual
1139  void ClearBoundingBox() override;
1140 
1141  //virtual
1142  bool Transform(
1143  const ON_Xform& xform
1144  ) override;
1145 
1146  //virtual
1147  bool IsDeformable() const override;
1148 
1149  //virtual
1150  bool MakeDeformable() override;
1151 
1152  //virtual
1153  bool SwapCoordinates(
1154  int i,
1155  int j
1156  ) override;
1157 
1158 
1159 
1160  //virtual
1161  bool HasBrepForm() const override;
1162 
1163  //virtual
1164  ON_Brep* BrepForm(
1165  ON_Brep* brep = nullptr
1166  ) const override;
1167 
1168  //virtual
1169  ON_COMPONENT_INDEX ComponentIndex() const override;
1170 
1171  //virtual
1172  bool EvaluatePoint(
1173  const class ON_ObjRef& objref,
1174  ON_3dPoint& P
1175  ) const override;
1176 
1177  /*
1178  Description:
1179  Uses the input mesh to define the level zero control polygon.
1180  Parameters:
1181  level_zero_mesh - [in]
1182  from_mesh_parameters - [in]
1183  To get the smoothest possible result, pass nullptr
1184  or ON_SubDFromMeshOptions::Smooth. To get a sub-D with interior
1185  creases use other static ON_SubDFromMeshOptions values or
1186  create one with custom settings.
1187  */
1188  static ON_SubD* CreateFromMesh(
1189  const class ON_Mesh* level_zero_mesh,
1190  const class ON_SubDFromMeshOptions* from_mesh_parameters,
1191  ON_SubD* subd
1192  );
1193 
1194  unsigned int DumpTopology(
1195  ON_TextLog&
1196  ) const;
1197 
1198  unsigned int DumpTopology(
1199  ON_2udex vertex_id_range,
1200  ON_2udex edge_id_range,
1201  ON_2udex face_id_range,
1202  ON_TextLog&
1203  ) const;
1204 
1205  /*
1206  Description:
1207  Discard all contents of this ON_SubD.
1208  Remarks:
1209  More efficient than Destroy() if this ON_SubD will be reused soon.
1210  */
1211  void Clear();
1212 
1213  /*
1214  Description:
1215  Delete all contents release all memory used by this ON_SubD.
1216  */
1217  void Destroy();
1218 
1219  ON_SubD::SubDType ActiveLevelSubDType() const;
1220 
1221  /*
1222  Returns:
1223  The number of explicitly computed levels that are currently available.
1224  A value of 0 indicates this SubD is empty.
1225  */
1226  unsigned int LevelCount() const;
1227 
1228  /*
1229  Returns:
1230  If the SubD is not empty, then the index of the active level is returned. This value will be < LevelCount().
1231  If the SubD is empty, then ON_UNSET_UINT_INDEX is returned.
1232  */
1233  unsigned int ActiveLevelIndex() const;
1234 
1235  /*
1236  Description:
1237  Remove subdivision levels
1238  Paramters:
1239  max_level_count - [in]
1240  Maximum number of levels to keep.
1241  */
1242  void ClearSubdivisionLevels(
1243  unsigned int max_level_index
1244  );
1245 
1246  bool IsEmpty() const;
1247 
1248 
1249  /*
1250  Description:
1251  Get aggregate edge demographics for the subd.
1252  Returns:
1253  Bitwise or of ON_ComponentAttributes::EdgeFlags values for every edge in the subd.
1254  */
1255  unsigned int EdgeFlags() const;
1256 
1257  /////////////////////////////////////////////////////////
1258  //
1259  // Component (Vertex, Edge, Face) access
1260  //
1261  ON_SubDComponentPtr ComponentPtrFromComponentIndex(
1262  ON_COMPONENT_INDEX component_index
1263  ) const;
1264 
1265  unsigned int ComponentPtrFromComponentIndex(
1266  const ON_COMPONENT_INDEX* ci_list,
1267  size_t ci_count,
1269  ) const;
1270 
1271  unsigned int ComponentPtrFromComponentIndex(
1272  const ON_COMPONENT_INDEX* ci_list,
1273  size_t ci_count,
1274  bool bIncludeVertices,
1275  bool bIncludeEdges,
1276  bool bIncludeFaces,
1278  ) const;
1279 
1280  /////////////////////////////////////////////////////////
1281  //
1282  // Vertex access
1283  //
1284 
1285  unsigned int VertexCount() const;
1286 
1287  const class ON_SubDVertex* FirstVertex() const;
1288 
1289  class ON_SubDVertexIterator VertexIterator() const;
1290 
1291  class ON_SubDVertexArray VertexArray() const;
1292 
1293  /*
1294  Parameters:
1295  vertex_id - [in]
1296  Returns:
1297  If vertex_id identifies a valid vertex in this ON_SubD, then
1298  a pointer to that vertex is returned.
1299  Otherwise, nullptr is returned.
1300  */
1301  const class ON_SubDVertex* VertexFromId(
1302  unsigned int vertex_id
1303  ) const;
1304 
1305  /////////////////////////////////////////////////////////
1306  //
1307  // Edge access
1308  //
1309 
1310  unsigned int EdgeCount() const;
1311 
1312  const class ON_SubDEdge* FirstEdge() const;
1313 
1314  class ON_SubDEdgeIterator EdgeIterator() const;
1315 
1316  class ON_SubDEdgeArray EdgeArray() const;
1317 
1318  /*
1319  Parameters:
1320  edge_id - [in]
1321  Returns:
1322  If edge_id identifies a valid edge in this ON_SubD, then
1323  a pointer to that edge is returned.
1324  Otherwise, nullptr is returned.
1325  */
1326  const class ON_SubDEdge* EdgeFromId(
1327  unsigned int edge_id
1328  ) const;
1329 
1330  /////////////////////////////////////////////////////////
1331  //
1332  // Face access
1333  //
1334 
1335  unsigned int FaceCount() const;
1336 
1337  const class ON_SubDFace* FirstFace() const;
1338 
1339  class ON_SubDFaceIterator FaceIterator() const;
1340 
1341  class ON_SubDFaceArray FaceArray() const;
1342 
1343  /*
1344  Parameters:
1345  face_id - [in]
1346  Returns:
1347  If face_id identifies a valid face in this ON_SubD, then
1348  a pointer to that face is returned.
1349  Otherwise, nullptr is returned.
1350  */
1351  const class ON_SubDFace* FaceFromId(
1352  unsigned int face_id
1353  ) const;
1354 
1355  /////////////////////////////////////////////////////////
1356  //
1357  // Component (vertex, edge, face) state ( selected, highlighted, ... ) tools
1358  // NOTE:
1359  // All component status settings are mutable
1360  // All are copied.
1361  // None are saved.
1362  //
1363 
1364  /*
1365  Parameters:
1366  states_filter - [in]
1367  bAllEqualStates - [in]
1368  If a state is set in states_filter, all active level components
1369  with the same state set will be included in the
1370  components_with_set_states[] array.
1371  If bAllEqualStates is true, then ON_ComponentStatus::AllEqualStates()
1372  is used to test for inclusion.
1373  If bAllEqualStates is false, then ON_ComponentStatus::SomeEqualStates()
1374  is used to test for inclusion.
1375  components_with_set_states - [out]
1376  Returns:
1377  Number of returned components.
1378  */
1379  unsigned int GetComponentsWithSetStates(
1380  ON_ComponentStatus states_filter,
1381  bool bAllEqualStates,
1382  ON_SimpleArray< ON_SubDComponentPtr >& components_with_set_states
1383  ) const;
1384 
1385 
1386  /*
1387  Description:
1388  Set states on an individual component.
1389  Parameters:
1390  component_ptr - [in]
1391  The states will be set on this component.
1392  states_to_set - [in]
1393  If a state is set in the states_to_set parameter, the same
1394  state will be set on the component.
1395  Returns:
1396  0: no state settings changed on the component.
1397  1: some state setting changed on the component.
1398  */
1399  unsigned int SetComponentStates(
1400  ON_SubDComponentPtr component_ptr,
1401  ON_ComponentStatus states_to_set
1402  ) const;
1403 
1404  /*
1405  Description:
1406  Clear states on an individual component.
1407  Parameters:
1408  component_ptr - [in]
1409  The states will be cleared on this component.
1410  states_to_clear - [in]
1411  If a state is set in the states_to_clear parameter, the same
1412  state will be cleared on the component.
1413  Returns:
1414  0: no state settings changed on the component.
1415  1: some state setting changed on the component.
1416  */
1417  unsigned int ClearComponentStates(
1418  ON_SubDComponentPtr component_ptr,
1419  ON_ComponentStatus states_to_clear
1420  ) const;
1421 
1422  /*
1423  Description:
1424  Copy status settings to an individual component.
1425  Parameters:
1426  component_ptr - [in]
1427  The states will be copied to this component.
1428  status_to_copy - [in]
1429  Returns:
1430  1: some state settings changed on the component.
1431  1: some state setting changed on the component.
1432  */
1433  unsigned int SetComponentStatus(
1434  ON_SubDComponentPtr component_ptr,
1435  ON_ComponentStatus status_to_copy
1436  ) const;
1437 
1438  bool DeleteComponents(
1439  const ON_SubDComponentPtr* cptr_list,
1440  size_t cptr_count
1441  );
1442 
1443 
1444  /////////////////////////////////////////////////////////
1445  //
1446  // Editing tools
1447  //
1448 
1449  unsigned int MergeColinearEdges(
1450  double distance_tolerance,
1451  double maximum_aspect,
1452  double sin_angle_tolerance
1453  );
1454 
1455  ON_SubDEdgePtr MergeEdges(
1456  ON_SubDEdgePtr eptr0,
1457  ON_SubDEdgePtr eptr1
1458  );
1459 
1460  static bool EdgesCanBeMerged(
1461  ON_SubDEdgePtr eptr0,
1462  ON_SubDEdgePtr eptr1
1463  );
1464 
1465  // returns true if all facets are consistently oriented
1466  bool IsOriented(
1467  unsigned int level_index
1468  ) const;
1469 
1470  // reverses the orientation of all facets
1471  bool ReverseOrientation(
1472  unsigned int level_index
1473  ) const;
1474 
1475  // Attempts to orient all facet to match the first facet.
1476  bool Orient(
1477  unsigned int level_index
1478  ) const;
1479 
1480  /*
1481  Description:
1482  Interior vertices (smooth and dart) must have at least three faces.
1483  Concave corner vertices must have at least two faces.
1484  */
1485  bool RepairInvalidSectors(
1486  unsigned int level_index
1487  );
1488 
1489  /*
1490  Description:
1491  Split and edge.
1492  The input edge is modifed to terminate at the input vertex.
1493  The new edge begins at the input vertex and ends at the final vertex
1494  of the original input edge.
1495  edge - [in]
1496  edge to split.
1497  vertex_location - [in]
1498  location of inserted vertex.
1499  If vertex_location == ON_ON_3dPoint::UnsetPoint,
1500  then the edge's midpoint is used.
1501  Returns:
1502  A pointer to the new edge or nullptr if the input is not valid.
1503  */
1504  const class ON_SubDEdge* SplitEdge(
1505  class ON_SubDEdge* edge,
1506  ON_3dPoint vertex_location
1507  );
1508 
1509  /*
1510  Description:
1511  Split a face into two faces by inserting and edge connecting the
1512  specified vertices.
1513  Parameters:
1514  face - [in]
1515  A face with at least four edges.
1516  fvi0 - [in]
1517  fvi1 - [in]
1518  Indices of the inserted edge ends.
1519  Returns:
1520  A pointer to the inserted edge.
1521  The inserted edge runs from face->Vertex(fvi0) to face->Vertex(fvi1).
1522  ON_SubDEdge.Face(0) is the original face and ON_SubDEdge::Face(1) is
1523  the added face.
1524  The first edge of the input face remains the first edge of face.
1525  The inserted edge is the first edge of the added face.
1526  */
1527  const class ON_SubDEdge* SplitFace(
1528  class ON_SubDFace* face,
1529  unsigned int fvi0,
1530  unsigned int fvi1
1531  );
1532 
1533  const class ON_SubDVertex* TriangulateFace(
1534  class ON_SubDFace* face
1535  );
1536 
1537  const class ON_SubDFace* MergeFaces(
1538  class ON_SubDEdge* edge
1539  );
1540 
1541  /*
1542  Description:
1543  Updates vertex tag, edge tag, and edge coefficient values
1544  on the active level.
1545 
1546  After completing custom editing operations that modify the
1547  topology of the SubD control net or changing values of
1548  vertex or edge tags, the tag and sector coefficients
1549  information on nearby components in the edited areas
1550  need to be updated.
1551 
1552  Parameters:
1553  bUnsetValuesOnly - [in]
1554  If true, the update is restricted to vertices tagged as
1555  ON_SubD::VertexTag::Unset and edges tagged as ON_SubD::EdgeTag::Unset.
1556 
1557  Returns:
1558  Number of vertices and edges that were changed during the update.
1559  */
1560  unsigned int UpdateAllTagsAndSectorCoefficients(
1561  bool bUnsetValuesOnly
1562  );
1563 
1564  /*
1565  Description:
1566  This tool if for expert users writing advanced editing tools.
1567  After completing custom editing operations that modify the
1568  topology of the SubD control net or changing values of
1569  vertex or edge tags, the tag and sector coefficients
1570  information on nearby components in the edited areas
1571  need to be updated.
1572  Parameters:
1573  bUnsetTagsOnly - [in]
1574  If bUnsetTagsOnly is true, then only unset tags and
1575  ill be updated.
1576  If bUnsetTagsOnly is false, then all tags and
1577  will be checked and updated as needed.
1578  Returns:
1579  Number of vertices that changed during the update.
1580  Remarks:
1581  It is easiest to call UpdateTagsAndSectorCoefficients().
1582  */
1583  unsigned int UpdateVertexTags(
1584  bool bUnsetVertexTagsOnly
1585  );
1586 
1587  /*
1588  Description:
1589  This tool if for expert users writing advanced editing tools.
1590  After completing custom editing operations that modify the
1591  topology of the SubD control net or changing values of
1592  vertex or edge tags, the tag and sector coefficients
1593  information on nearby components in the edited areas
1594  need to be updated.
1595  Parameters:
1596  bUnsetValuesOnly - [in]
1597  If bUnsetValuesOnly is true, then only unset tags and
1598  sector weights will be updated.
1599  If bUnsetValuesOnly is false, then all tags and
1600  sector weights will be checked and updated as needed.
1601  Returns:
1602  Number of edges that had a tag value changed or sector
1603  coefficient set to ON_SubDSectorType::UnsetSectorWeight.
1604  Remarks:
1605  It is easiest to call UpdateTagsAndSectorCoefficients().
1606  */
1607  unsigned int UpdateEdgeTags(
1608  bool bUnsetEdgeTagsOnly
1609  );
1610 
1611  /*
1612  Description:
1613  This tool if for expert users writing advanced editing tools.
1614  After completing custom editing operations that modify the
1615  topology of the SubD control net or changing values of
1616  vertex or edge tags, the tag and sector coefficients
1617  information on nearby components in the edited areas
1618  need to be updated.
1619  Parameters:
1620  bUnsetValuesOnly - [in]
1621  If bUnsetValuesOnly is true, then only unset tags and
1622  sector weights will be updated.
1623  If bUnsetValuesOnly is false, then all tags and
1624  sector weights will be checked and updated as needed.
1625  Returns:
1626  Number of edges that had a tag value changed or sector
1627  coefficient set to ON_SubDSectorType::UnsetSectorWeight.
1628  Remarks:
1629  It is easiest to call UpdateTagsAndSectorCoefficients().
1630  */
1631  unsigned int UpdateEdgeSectorCoefficients(
1632  bool bUnsetSectorCoefficientsOnly
1633  );
1634 
1635  /*
1636  Descripiton:
1637  Clears the ON_ComponentState
1638  */
1639  unsigned int ClearComponentMarks(
1640  bool bClearVertexMarks,
1641  bool bClearEdgeMarks,
1642  bool bClearFaceMarks,
1644  ) const;
1645 
1646  unsigned int SetComponentMarks(
1647  bool bClearBeforeSet,
1648  const ON_SimpleArray< const class ON_SubDComponentBase* >& marked_component_list
1649  ) const;
1650 
1651  unsigned int GetMarkedComponents(
1652  bool bIncludeVertices,
1653  bool bIncludeEdges,
1654  bool bIncludeFaces,
1656  ) const;
1657 
1658 
1659  /*
1660  Description:
1661  Transforms the SubD components in ci_list[].
1662  Parameters:
1663  xform - [in]
1664  ci_list - [in]
1665  ci_count - [in]
1666  Returns:
1667  Number of vertex locations that changed.
1668  */
1669  unsigned int TransformComponents(
1670  const ON_Xform& xform,
1671  const ON_COMPONENT_INDEX* ci_list,
1672  size_t ci_count
1673  );
1674 
1675  unsigned int TransformComponents(
1676  const ON_Xform& xform,
1677  const ON_SubDComponentPtr* cptr_list,
1678  size_t cptr_count
1679  );
1680 
1681  unsigned int ExtrudeComponents(
1682  const ON_Xform& xform,
1683  const ON_COMPONENT_INDEX* ci_list,
1684  size_t ci_count,
1685  bool bPermitNonManifoldEdgeCreation,
1686  ON_SubD::EdgeTag original_edge_tag,
1687  ON_SubD::EdgeTag moved_edge_tag
1688  );
1689 
1690  unsigned int ExtrudeComponents(
1691  const ON_Xform& xform,
1692  const ON_SubDComponentPtr* cptr_list,
1693  size_t cptr_count,
1694  bool bPermitNonManifoldEdgeCreation,
1695  ON_SubD::EdgeTag original_edge_tag,
1696  ON_SubD::EdgeTag moved_edge_tag
1697  );
1698 
1699  /////*
1700  ////Description:
1701  //// Apply the built-in triangle subdivision subdivision algorithm globally.
1702  ////Returns:
1703  //// New level.
1704  ////*/
1705  ////unsigned int TriSubdivision();
1706 
1707  ////unsigned int GetSector(
1708  //// const class ON_SubDFace* face,
1709  //// ON__UINT_PTR face_vertex_index,
1710  //// class ON_SubDVertex& sector
1711  //// ) const;
1712 
1713  ////unsigned int GetSector(
1714  //// const class ON_SubDVertex* vertex,
1715  //// const ON_SubDFace* face,
1716  //// class ON_SubDVertex& sector
1717  //// ) const;
1718 
1719  ////unsigned int GetSector(
1720  //// const ON_SubDVertex* vertex,
1721  //// ON_SubDFacePtr face_ptr,
1722  //// class ON_SubDVertex& sector
1723  //// ) const;
1724 
1725  ////unsigned int GetSector(
1726  //// const class ON_SubDVertex* vertex,
1727  //// const class ON_SubDEdge* smooth_edge,
1728  //// ON_SubDVertex& sector
1729  //// ) const;
1730 
1731  ////unsigned int GetSector(
1732  //// const ON_SubDEdge* smooth_edge,
1733  //// ON__UINT_PTR smooth_edge_end_index,
1734  //// ON_SubDVertex& sector
1735  //// ) const;
1736 
1737  ////unsigned int GetSector(
1738  //// ON_SubDEdgePtr smooth_edge_ptr,
1739  //// class ON_SubDVertex& sector
1740  //// ) const;
1741 
1742  /*
1743  Description:
1744  Apply the built-in subdivision algorithm and save the results
1745  in this ON_SubD.
1746  Parameters:
1747  subd_type - [in]
1748  unset will use the current subdivision type.
1749  level_index - [in]
1750  Level where subdivision starts
1751  count - [in] > 0
1752  Number of times to subdivide.
1753  Returns:
1754  Number of subdivision steps that succeeded.
1755  (= count when everything works, < count when input is not valid)
1756  */
1757  bool Subdivide(
1758  ON_SubD::SubDType subd_type,
1759  unsigned int level_index,
1760  unsigned int count
1761  );
1762 
1763  /*
1764  Returns:
1765  Active level subdivison type.
1766  */
1767  bool SetSubDType(
1768  ON_SubD::SubDType subd_type
1769  );
1770 
1771  class ON_SubDVertex* AddVertex(
1772  ON_SubD::VertexTag vertex_tag,
1773  const double* P
1774  );
1775 
1776  /*
1777  Parameters:
1778  edge_face_count - [in]
1779  Number of faces the edge will eventually have.
1780  Pass 0 if the value is not known.
1781  v0 - [in]
1782  starting vertex
1783  v1 - [in]
1784  ending vertex
1785  Returns:
1786  If edge_face_count > 0x7FFFU, then ON_SubD::EdgeTag::Unset is returned.
1787 
1788  If edge_face_count is 1 or >= 3, then ON_SubD::EdgeTag::Crease is returned.
1789 
1790  If both vertex tags are ON_SubD::VertexTag::Smooth, then ON_SubD::EdgeTag::Smooth is returned.
1791 
1792  If edge_face_count is 1 and both vertex tags are ON_SubD::VertexTag::Crease or ON_SubD::VertexTag::Corner,
1793  then ON_SubD::EdgeTag::Crease is returned.
1794 
1795  If edge_face_count is 2 and both vertex tags are set and both are not ON_SubD::VertexTag::Smooth,
1796  then ON_SubD::EdgeTag::X is returned.
1797 
1798  Otherwise, ON_SubD::EdgeTag::Unset is returned.
1799  */
1800  static ON_SubD::EdgeTag EdgeTagFromContext(
1801  unsigned int edge_face_count,
1802  const ON_SubD::VertexTag v0_tag,
1803  const ON_SubD::VertexTag v1_tag
1804  );
1805 
1806  static ON_SubD::EdgeTag EdgeTagFromContext(
1807  unsigned int edge_face_count,
1808  const ON_SubDVertex* v0,
1809  const ON_SubDVertex* v1
1810  );
1811 
1812  /*
1813  Description:
1814  Add an edge to the subd.
1815  Parameters:
1816  edge_tag - [in]
1817  ON_SubD::EdgeTag::Unset
1818  Edge tag is not known at this time.
1819  ON_SubD::EdgeTag::Smooth
1820  Smooth edge. If both vertices are tagged as not smooth, the
1821  tag on the returned edge will be ON_SubD::EdgeTag::X. This
1822  tag is changed to ON_SubD::EdgeTag::Smooth on the first
1823  subdivision step.
1824  ON_SubD::EdgeTag::Crease.
1825  Crease edge. Both vertices must be tagged as not smooth.
1826  v0 - [in]
1827  v1 - [in]
1828  The edge begins at v0 and ends at v1.
1829  The edge will be on the same level as the vertices.
1830  Returns:
1831  Pointer to the allocated edge.
1832  Remarks:
1833  ON_SubD::EdgeTagFromContext() can be used to determine edge
1834  tag values in simple situations.
1835  */
1836  class ON_SubDEdge* AddEdge(
1837  ON_SubD::EdgeTag edge_tag,
1838  class ON_SubDVertex* v0,
1839  class ON_SubDVertex* v1
1840  );
1841 
1842  /*
1843  Description:
1844  Expert use tool to add an edge with precomputed sector coefficients.
1845  Parameters:
1846  edge_tag - [in]
1847  This expert user function does not automatically set the edge tag.
1848  v0 - [in]
1849  v0_sector_coefficient - [in]
1850  v1 - [in]
1851  v1_sector_coefficient - [in]
1852  The edge begins at v0 and ends at v1.
1853  The edge will be on the same level as the vertices.
1854  The edges sector weights are set
1855  */
1856  class ON_SubDEdge* AddEdgeWithSectorCoefficients(
1857  ON_SubD::EdgeTag edge_tag,
1858  class ON_SubDVertex* v0,
1859  double v0_sector_coefficient,
1860  class ON_SubDVertex* v1,
1861  double v1_sector_coefficient
1862  );
1863 
1864  class ON_SubDFace* AddFace(
1865  unsigned int edge_count,
1866  const class ON_SubDEdgePtr* edge
1867  );
1868 
1869  /*
1870  Description:
1871  Expert user tool to insert an edge in the face's edge array.
1872  Parameters:
1873  face - [in]
1874  edge - [in]
1875  edge_direction -[in]
1876  i - [in]
1877  index where the edge should be inserted.
1878  Returns:
1879  true if successful.
1880  Remarks:
1881  This tool is used during construction or editing of a SubD and the
1882  connection is added even if the result is an invalid face or edge.
1883  It is up to the expert user to make enough changes to create a valid SubD.
1884  */
1885  bool AddFaceEdgeConnection(
1886  ON_SubDFace* face,
1887  unsigned int i,
1888  ON_SubDEdge* edge,
1889  ON__UINT_PTR edge_direction
1890  );
1891 
1892  /*
1893  Description:
1894  Expert user tool to insert an edge in the face's edge array.
1895  Parameters:
1896  face - [in]
1897  eptr - [in]
1898  direction must be set correctly
1899  i - [in]
1900  index where the edge should be inserted.
1901  Returns:
1902  true if successful.
1903  Remarks:
1904  This tool is used during construction or editing of a SubD and the
1905  connection is added even if the result is an invalid face or edge.
1906  It is up to the expert user to make enough changes to create a valid SubD.
1907  */
1908  bool AddFaceEdgeConnection(
1909  ON_SubDFace* face,
1910  unsigned int i,
1911  ON_SubDEdgePtr eptr
1912  );
1913 
1914  /*
1915  Description:
1916  Expert user tool to insert an edge in the face's edge array.
1917  Parameters:
1918  face - [in]
1919  edge - [in]
1920  edge to remove
1921  Returns:
1922  true if successful.
1923  Remarks:
1924  This tool is used during construction or editing of a SubD and the
1925  connection is removed even if the result is an invalid face or edge.
1926  It is up to the expert user to make enough changes to create a valid SubD.
1927  */
1928  bool RemoveFaceEdgeConnection(
1929  ON_SubDFace* face,
1930  ON_SubDEdge* edge
1931  );
1932 
1933  /*
1934  Description:
1935  Expert user tool to insert an edge in the face's edge array.
1936  Parameters:
1937  face - [in]
1938  i - [in]
1939  index where the edge should be removed.
1940  removed_edge - [out]
1941  removed edge
1942  Remarks:
1943  This tool is used during construction or editing of a SubD and the
1944  connection is removed even if the result is an invalid face or edge.
1945  It is up to the expert user to make enough changes to create a valid SubD.
1946  */
1947  bool RemoveFaceEdgeConnection(
1948  ON_SubDFace* face,
1949  unsigned int i
1950  );
1951 
1952  /*
1953  Description:
1954  Expert user tool to insert an edge in the face's edge array.
1955  Parameters:
1956  face - [in]
1957  i - [in]
1958  index where the edge should be removed.
1959  removed_edge - [out]
1960  removed edge
1961  Remarks:
1962  This tool is used during construction or editing of a SubD and the
1963  connection is removed even if the result is an invalid face or edge.
1964  It is up to the expert user to make enough changes to create a valid SubD.
1965  */
1966  bool RemoveFaceEdgeConnection(
1967  ON_SubDFace* face,
1968  unsigned int i,
1969  ON_SubDEdgePtr& removed_edge
1970  );
1971 
1972  bool GrowVertexEdgeArray(
1973  ON_SubDVertex* v,
1974  size_t capacity
1975  );
1976  bool GrowVertexFaceArray(
1977  ON_SubDVertex* v,
1978  size_t capacity
1979  );
1980  bool GrowEdgeFaceArray(
1981  ON_SubDEdge* e,
1982  size_t capacity
1983  );
1984  bool GrowFaceEdgeArray(
1985  ON_SubDFace* f,
1986  size_t capacity
1987  );
1988 
1989  /*
1990  Description:
1991  Get the limit surface mesh for this subD.
1992  Parameters:
1993  minimum_display_density - [in]
1994  Returns:
1995  A mesh of the subdivision limit surface.
1996  Remarks:
1997  The mesh is a reference counted mesh managed by this ON_SubD.
1998  */
1999  class ON_SubDLimitMesh LimitSurfaceMesh() const;
2000 
2001  ON_SubDLimitMesh UpdateLimitSurfaceMesh(
2002  unsigned int minimum_display_density
2003  ) const;
2004 
2005  void ClearLimitSurfaceMesh() const;
2006 
2007  void ClearEvaluationCache() const;
2008 
2009  /*
2010  Description:
2011  Get an ON_Mesh of the subdivision limit surface
2012  Parameters:
2013  display_parameters - [in]
2014  mesh - [in]
2015  If not null, the returned mesh will be stored on
2016  the input class.
2017  Returns:
2018  A mesh of the subdivision limit surface.
2019  */
2020  class ON_Mesh* GetLimitSurfaceMesh(
2021  const class ON_SubDDisplayParameters& display_parameters,
2022  class ON_Mesh* mesh
2023  ) const;
2024 
2025 
2026  /*
2027  Description:
2028  Get a mesh of the subdivision control net.
2029  Parameters:
2030  level_index - [in] (>=0)
2031  mesh - [in]
2032  If not null, the returned mesh will be stored on
2033  the input class.
2034  Returns:
2035  The subdivision level as a mesh.
2036  */
2037  class ON_Mesh* GetControlNetMesh(
2038  class ON_Mesh* mesh
2039  ) const;
2040 
2041 
2042  /*
2043  Description:
2044  Get the limit surface mesh as a set of fragments.
2045  Parameters:
2046  display_parameters - [in]
2047 
2048  fragment_callback_context - [in]
2049  first parameter for the FragmentCallback function
2050 
2051  fragment_callback_function - [in]
2052  A function pointer with prototype:
2053 
2054  bool fragment_callback_function(
2055  void *fragment_callback_context,
2056  const class ON_SubDLimitMeshFragment* fragment
2057  );
2058 
2059  For each fragment that is produced, fragment_callback_function() is called.
2060  You must copy the retuned fragment if you want to keep it for future use.
2061  If fragment_callback_function returns false, the calculation is canceled.
2062  Returns:
2063  Number of fragments produced.
2064  */
2065  unsigned int GetLimitSurfaceMeshInFragments(
2066  const class ON_SubDDisplayParameters& display_parameters,
2067  ON__UINT_PTR fragment_callback_context,
2068  bool(*fragment_callback_function)(ON__UINT_PTR , const class ON_SubDLimitMeshFragment*)
2069  ) const;
2070 
2071  /*
2072  Returns:
2073  The number of limit surface mesh fragments (ON_SubDLimitMeshFragment) that
2074  GetLimitSurfaceMeshFragments() will produce.
2075  */
2076  unsigned int LimitSurfaceMeshFragmentCount() const;
2077 
2078 
2079  /*
2080  Description:
2081  Get the limit surface as a set of bicubic patch fragments.
2082  Parameters:
2083  display_parameters - [in]
2084 
2085  fragment_callback_context - [in]
2086  first parameter for the FragmentCallback function
2087 
2088  fragment_callback_function - [in]
2089  A function pointer with prototype:
2090 
2091  bool fragment_callback_function(
2092  void *fragment_callback_context,
2093  const class ON_SubDLimitPatchFragment* fragment
2094  );
2095 
2096  For each fragment that is produced, fragment_callback_function() is called.
2097  You must copy the retuned fragment if you want to keep it for future use.
2098  If fragment_callback_function returns false, the calculation is canceled.
2099  Returns:
2100  Number of fragments produced.
2101  */
2102  unsigned int GetLimitSurfaceInPatches(
2103  const class ON_SubDDisplayParameters& display_parameters,
2104  ON__UINT_PTR fragment_callback_context,
2105  bool(*fragment_callback_function)(ON__UINT_PTR , const class ON_SubDLimitPatchFragment*)
2106  ) const;
2107 
2108  /*
2109  Description:
2110  Get the SubD limit surface as a list of bicubic NURBS patches.
2111  Parameters:
2112  display_parameters - [in]
2113  bClampPatchKnots - [in]
2114  true to clamp knots
2115  sUserStringPatchKey - [in]
2116  If non empty, a user string with this key will be added that
2117  contains a description of which portion of which SubD face generated
2118  the patch.
2119  patches - [out]
2120  The bicubic NURBS patches are appended to this array.
2121  Returns:
2122  Number of patches appended to patches[]
2123  */
2124  unsigned int GetLimitSurfacePatches(
2125  const class ON_SubDDisplayParameters& display_parameters,
2126  bool bClampPatchKnots,
2127  const wchar_t* sUserStringPatchKey,
2129  ) const;
2130 
2131 public:
2132  /*
2133  Description:
2134  Pretend this function and ON_SubDimple do not exist.
2135  Returns:
2136  Something that you are pretending does not exist.
2137  Remarks:
2138  It is intentional that the definition of ON_SubDimple class is not
2139  available in the opennurbs library interface (not in a header file).
2140  The size and design of ON_SubDimple will change constantly.
2141  If you choose to hack and whack so you can dereference an
2142  ON_SubDimple* pointer, then your code will crash unpredictably.
2143  */
2144  const class ON_SubDimple* SubDimple() const;
2145  const class ON_SubDLevel& ActiveLevel() const;
2146  unsigned int SubDimpleUseCount() const;
2147 
2148  void ShareDimple(const ON_SubD&);
2149  void SwapDimple(ON_SubD&);
2150 
2151  void ShareDimple(const class ON_SubDLimitMeshImpl&);
2152  void SwapDimple(class ON_SubDLimitMeshImpl& );
2153 
2154 private:
2155  class ON_SubDimple* SubDimple(bool bCreateIfNeeded);
2156  class ON_SubDLevel const * ActiveLevelConstPointer() const;
2157  class ON_SubDLevel* ActiveLevelPointer();
2158 
2159  void CopyHelper(const ON_SubD&);
2160 
2161 private:
2162  friend class ON_SubDRef;
2163 #pragma ON_PRAGMA_WARNING_PUSH
2164 #pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
2165  // C4251: ... needs to have dll-interface to be used by clients of class ...
2166  // m_subdimple_sp is private and all code that manages m_subdimple_sp is explicitly implemented in the DLL.
2167 private:
2168  std::shared_ptr<class ON_SubDimple> m_subdimple_sp;
2169 #pragma ON_PRAGMA_WARNING_POP
2170 
2171 public:
2172  // The ON_SubD code increments ON_SubD::ErrorCount everytime something
2173  // unexpected happens. This is useful for debugging.
2174  static unsigned int ErrorCount;
2175 };
2176 
2177 
2178 //////////////////////////////////////////////////////////////////////////
2179 //
2180 // ON_SubDRef
2181 //
2182 class ON_SUBD_CLASS ON_SubDRef
2183 {
2184 #if defined(ON_SUBD_CENSUS)
2185 private:
2186  ON_SubDRefCensusCounter m_census_counter;
2187 #endif
2188 
2189 public:
2190  static const ON_SubDRef Empty;
2191 
2192  ON_SubDRef() ON_NOEXCEPT;
2193  ~ON_SubDRef();
2194  ON_SubDRef(const ON_SubDRef& src) ON_NOEXCEPT;
2195  ON_SubDRef& operator=(const ON_SubDRef& src);
2196 
2197 #if defined(ON_HAS_RVALUEREF)
2198  // rvalue copy constructor
2199  ON_SubDRef( ON_SubDRef&& ) ON_NOEXCEPT;
2200  // rvalue assignment operator
2201  ON_SubDRef& operator=( ON_SubDRef&& );
2202 #endif
2203 
2204  const class ON_SubD& SubD() const;
2205 
2206  /*
2207  Returns:
2208  Number of references to the ON_SubD, including the one by this ON_SubDRef.
2209  */
2210  unsigned int ReferenceCount() const;
2211 
2212  /*
2213  Description:
2214  Allocates a new ON_SubD and has this ON_SubDRef reference it.
2215  */
2216  class ON_SubD& NewSubD();
2217 
2218 
2219  /*
2220  Description:
2221  Allocates a new ON_SubD and has this ON_SubDRef reference it.
2222  */
2223  class ON_SubD& CopySubD(
2224  const ON_SubDRef& src
2225  );
2226  class ON_SubD& CopySubD(
2227  const ON_SubD& src
2228  );
2229 
2230  class ON_SubD& UniqueSubD();
2231 
2232  /*
2233  Description:
2234  Remove this reference to the managed ON_SubD.
2235  If this is the last reference, then the managed ON_SubD is deleted.
2236  */
2237  void Clear();
2238 
2239 public:
2240  class ON_SubDVertexIterator VertexIterator() const;
2241  class ON_SubDEdgeIterator EdgeIterator() const;
2242  class ON_SubDFaceIterator FaceIterator() const;
2243 
2244  /*
2245  Description:
2246  Expert user function to have this ON_SubDRef manage the lifetime of subd.
2247  Parameters:
2248  subd - [in/out]
2249  subd must point to an ON_SubD that was constructed on the heap using
2250  an operator new call with a public ON_SubD constructor.
2251  Returns:
2252  a pointer to the managed subd or nullptr subd in not valid.
2253  Example:
2254  ON_SubD* subd = new ON_SubD(...);
2255  ON_SubDRef subr;
2256  ON_SubD* managed_subd = subdr.SetSubD(subd);
2257  // subd = nullptr
2258  // managed_subd = pointer you can use
2259  */
2260  class ON_SubD* SetSubDForExperts(
2261  class ON_SubD*& subd
2262  );
2263 
2264  /*
2265  Description:
2266  Expert user function to have this ON_SubDRef reference the
2267  contents of an existing ON_SubD.
2268  Do not use if user data on the referenced subd needs to be accessed.
2269  Parameters:
2270  subd - [in]
2271  Any subd on the heap or the stack.
2272  Returns:
2273  true if successful.
2274  */
2275  static ON_SubDRef CreateReferenceForExperts(
2276  const ON_SubD& subd
2277  );
2278 
2279 private:
2280  /*
2281  Description:
2282  Expert user function to have this ON_SubDRef reference the
2283  contents of an existing ON_SubD.
2284  Do not use if user data on the referenced subd needs to be accessed.
2285  Parameters:
2286  subd - [in]
2287  Any subd on the heap or the stack.
2288  */
2289  ON_SubDRef(
2290  const class ON_SubD& subd
2291  );
2292 
2293 private:
2294 #pragma ON_PRAGMA_WARNING_PUSH
2295 #pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
2296  // C4251: ... needs to have dll-interface to be used by clients of class ...
2297  // m_subd_sp is private and all code that manages m_subd_sp is explicitly implemented in the DLL.
2298 private:
2299  std::shared_ptr<class ON_SubD> m_subd_sp;
2300 #pragma ON_PRAGMA_WARNING_POP
2301 };
2302 
2303 
2304 //////////////////////////////////////////////////////////////////////////
2305 //
2306 // ON_SubDSectorType
2307 //
2308 class ON_SUBD_CLASS ON_SubDSectorType
2309 {
2310 public:
2311  ON_SubDSectorType() = default;
2312  ON_SubDSectorType(const ON_SubDSectorType&) = default;
2313  ON_SubDSectorType& operator=(const ON_SubDSectorType&) = default;
2314 
2315  static const ON_SubDSectorType Empty;
2316 
2317  bool IsValid() const;
2318 
2319  unsigned int SectorTypeHash() const;
2320 
2321  static int Compare(const ON_SubDSectorType*, const ON_SubDSectorType*);
2322 
2323 
2324  /////////////////////////////////////////////////////////////////////////////////////
2325  //
2326  // Sector Weights
2327  //
2328  /////////////////////////////////////////////////////////////////////////////////////
2329  //
2330  // In the comment below,
2331  // F = number of faces in the sector,
2332  // E = number of edges in the sector.
2333  //
2334  // There are five valid sector configurations of edges and faces. In all
2335  // configurations, the edges have one end at the center vertex and the
2336  // faces have one corner at the center vertex.
2337  //
2338  // SMOOTH
2339  // 1) The center vertex is smooth.
2340  // 2) F >= 2
2341  // 3) E = F
2342  // 4) Every edge is smooth.
2343  // 5) Every edge is an edge of two different faces in the sector.
2344  //
2345  // DART
2346  // 1) The center vertex is a dart.
2347  // 2) F >= 2
2348  // 3) E = F
2349  // 4) One edge is a crease.
2350  // 5) The crease edge is an edge of two geometrically adjacent sector faces.
2351  //
2352  // DART* (The same as "DART", but the crease edge has been duplicated.)
2353  // 1) The center vertex is a dart.
2354  // 2) F >= 2
2355  // 3) E = F+1
2356  // 4) Two edges are creases that have the same end locations.
2357  // 5) Each crease edge is an edge of a single face in the sector,
2358  // these faces are different and are geometrically adjacent.
2359  //
2360  // BOUNDED
2361  // 1) The center vertex is a crease or corner vertex.
2362  // 2) F >= 2
2363  // 3) E = F+1
2364  // 4) Two edges are crease edges that have different vertices at their ends.
2365  // 5) Each crease edge is an edge of a single face in the sector,
2366  // these faces are different and not geometrically adjacent.
2367  //
2368  // BOUNDED*
2369  // 1) The center vertex is a crease or corner vertex.
2370  // 2) F = 1
2371  // 3) E = 2
2372  // 4) The edges are crease edges that have different vertices at their ends.
2373  // 5) The edges a edges of the face.
2374  //
2375  /////////////////////////////////////////////////////////////////////////////////////
2376  //
2377  // The sector weight is used when subdividing smooth edges in sectors
2378  // with a DART, DART* or BOUNDED configuration. In these cases the
2379  // sector weight is a value strictly between 0.0 and 1.0 that depends on
2380  // 1) the center vertex tag (crease, corner or dart),
2381  // 2) the value of F,
2382  // 3) and when the center vertex is a corner, the angle between
2383  // the boundary edges.
2384  //
2385  // The sector weight is ignored when dividing smooth edges in SMOOTH sectors.
2386  // The sector weight is ignored when subdividing crease edges.
2387  //
2388  // For a smooth edge in a sector with a DART, DART* or BOUNDED configuration,
2389  // with w = sector weight, C = location of the center vertex
2390  // and P = location of the smooth vertex at the other end
2391  // of the smooth edge, the point
2392  //
2393  // Q = 3/4 * (w*C + (1-w)*P)
2394  //
2395  // is the contribution of C and P to the edge's subdivision point.
2396  //
2397  // When a smooth edge has smooth vertices at both ends located
2398  // at A and B, the contribution of A and B to the edge's subdivision
2399  // point is
2400  //
2401  // Q = 3/8 * (A + B) = 3/4 * (1/2*A + 1/2*B)
2402  //
2403  // A crease edge's subdivision point is alwasy the edge's midpoint.
2404  /*
2405  Description:
2406  Calculates sector weight value for the sector type
2407  identified by this ON_SubDSectorType.
2408  Returns:
2409  w: 0.0 <= w < 1.0
2410  w = sector theta value.
2411  ON_SubDSectorType::ErrorSectorWeight
2412  This ON_SubDSectorType is not valid and the calculation failed.
2413  */
2414  double SectorWeight() const;
2415 
2416 
2417  ON_SubD::SubDType SubDType() const;
2418 
2419  ON_SubD::FacetType FacetType() const;
2420 
2421  unsigned int FacetEdgeCount() const;
2422 
2423  ON_SubD::VertexTag VertexTag() const;
2424 
2425 
2426  unsigned int EdgeCount() const;
2427 
2428  unsigned int FaceCount() const;
2429 
2430  /*
2431  Returns:
2432  Number of points in the point ring.
2433  For quad subds, this is 1 + FaceCount() + EdgeCount().
2434  For tri subds, this is 1 + EdgeCount().
2435  */
2436  unsigned int PointRingCount() const;
2437 
2438  /*
2439  Returns:
2440  1 + FaceCount() + EdgeCount()
2441  */
2442  unsigned int ComponentRingCount() const;
2443 
2444  /*
2445  Returns:
2446  If the sector vertex tag is ON_SubD::VertexTag::Corner,
2447  the angle between the corner crease boundary edges is
2448  returned.
2449  Otherwise, ON_SubDSectorType::ErrorCornerSectorAngle is returned.
2450  */
2451  double CornerSectorAngleRadians() const;
2452 
2453  /*
2454  Returns:
2455  a value >= 0 and <= ON_SubDSectorType::MaximumAngleIndex
2456  */
2457  unsigned int CornerSectorAngleIndex() const;
2458 
2459  /*
2460  Description:
2461  An angle index value of ON_SubDSectorType::MaximumAngleIndex indicates
2462  the angle is 2pi radians.
2463  */
2464  static const unsigned int MaximumAngleIndex; // = 72
2465 
2466  /*
2467  Parameters:
2468  angle_radians - [in] (0.0 <= angle_radians <= 2*ON_PI
2469  The angle between the bounding crease edges
2470  Returns:
2471  angle_index: >= 0 and <= ON_SubDSectorType::MaximumCornerSectorIndex
2472  | angle_radians - angle_index/M * 2pi | <= 1/2 * 1/M * 2pi,
2473  where M = ON_SubDSectorType::MaximumAngleIndex
2474  ON_UNSET_UINT_INDEX
2475  angle_radians is not valid and the calculation failed.
2476  */
2477  static unsigned int AngleIndexFromAngleRadians(
2478  double angle_radians
2479  );
2480 
2481  /*
2482  Convert and angle index into radians
2483  Parameters:
2484  angle_index - [in]
2485  0 to ON_SubDSectorType::MaximumAngleIndex.
2486  Returns:
2487  If angle_index is valid, the corresponding angle in radians is returned.
2488  = angle_index / ON_SubDSectorType::MaximumAngleIndex * 2 * ON_PI
2489  (double division performed)
2490  Otherwise ON_UNSET_VALUE is returned.
2491  */
2492  static double AngleRadiansFromAngleIndex(
2493  unsigned int angle_index
2494  );
2495 
2496  /*
2497  Returns:
2498  True if this is a smooth interior vertex sector
2499  */
2500  bool IsSmoothSector() const;
2501 
2502 
2503  /*
2504  Returns:
2505  True if this is a dart interior vertex sector
2506  */
2507  bool IsDartSector() const;
2508 
2509 
2510  /*
2511  Returns:
2512  True if this is a crease vertex sector
2513  */
2514  bool IsCreaseSector() const;
2515 
2516  /*
2517  Returns:
2518  True if this is a corner vertex sector
2519  */
2520  bool IsCornerSector() const;
2521 
2522  /*
2523  Returns:
2524  True if this is a convex corner vertex sector (sector angle <= pi)
2525  */
2526  bool IsConvexCornerSector() const;
2527 
2528  /*
2529  Returns:
2530  True if this is a concave corner vertex sector (sector angle > pi)
2531  */
2532  bool IsConcaveCornerSector() const;
2533 
2534  /*
2535  Parameters:
2536  sector_boundary_edge0_ptr - [in]
2537  sector_boundary_edge1_ptr - [in]
2538  Crease edges that bound the sector containing the smooth edge.
2539  The edge direction must identify the corner vertex.
2540  Returns:
2541  tagged end angle for a smooth edge that
2542  1) ends at a vertex tagged on ON_SubD::VertexTag::Corner
2543  2) has two adjacent faces.
2544  3) lies in a sector bounded by 2 distinct crease edges.
2545  */
2546  static double CornerSectorAngleRadiansFromEdges(
2547  ON_SubDEdgePtr sector_boundary_edge0_ptr,
2548  ON_SubDEdgePtr sector_boundary_edge1_ptr
2549  );
2550 
2551  static bool IsValidCornerSectorAngleRadians(
2552  double corner_sector_angle_radians
2553  );
2554 
2555  static double ClampCornerSectorAngleRadians(
2556  double corner_sector_angle_radians
2557  );
2558 
2559  /*
2560  Returns:
2561  Number of subdivision points in a sector ring
2562  facet_type vertex_tag ring count
2563  tri smooth N+1
2564  tri crease N+2
2565  quad smooth 2N+1
2566  quad crease 2N+2
2567  (2 * valence + 1) for quad subds
2568  (valence + 1) for tri subds
2569  */
2570  static unsigned int SectorPointRingCountFromEdgeCount(
2571  ON_SubD::SubDType subd_type,
2572  ON_SubD::VertexTag vertex_tag,
2573  unsigned int sector_edge_count
2574  );
2575 
2576  static unsigned int SectorPointRingCountFromFaceCount(
2577  ON_SubD::SubDType subd_type,
2578  ON_SubD::VertexTag vertex_tag,
2579  unsigned int sector_face_count
2580  );
2581 
2582  static unsigned int SectorFaceCountFromEdgeCount(
2583  ON_SubD::VertexTag vertex_tag,
2584  unsigned int sector_edge_count
2585  );
2586 
2587  static unsigned int SectorEdgeCountFromFaceCount(
2588  ON_SubD::VertexTag vertex_tag,
2589  unsigned int sector_face_count
2590  );
2591 
2592  static unsigned int MinimumSectorEdgeCount(
2593  ON_SubD::VertexTag vertex_tag
2594  );
2595 
2596  static unsigned int MinimumSectorFaceCount(
2597  ON_SubD::VertexTag vertex_tag
2598  );
2599 
2600 public:
2601  /*
2602  Returns:
2603  ON_SubDSectorType::IgnoredSectorWeight
2604  */
2605  static double SmoothSectorWeight();
2606 
2607  /*
2608  Parameters:
2609  face_type - [in]
2610  sector_face_count - [in]
2611  number of faces in the smooth sector.
2612  Returns:
2613  0:
2614  failed to caclulate weight
2615  ON_SubDSectorType::UnsetSectorWeight:
2616  subd_type was set ON_SubD::SubDType::Unset
2617  and was required to calculate the weight.
2618  This typically happens when a SubD control net is being
2619  created and a facet type is not specified.
2620  The weights will be calculated at the first subdivision.
2621  0 < w < 1:
2622  1/2 + 1/3*cos(tagged end angle) for quadrangle facets
2623  1/3 + 1/3*cos(tagged end angle) for triangle facets
2624  Remarks:
2625  This is a useful tool when calling AddEdge while a subdivision
2626  level is being constructed.
2627  */
2628  static double CreaseSectorWeight(
2629  ON_SubD::SubDType subd_type,
2630  unsigned int sector_face_count
2631  );
2632 
2633  static double DartSectorWeight(
2634  ON_SubD::SubDType subd_type,
2635  unsigned int sector_face_count
2636  );
2637 
2638  static double CornerSectorWeight(
2639  ON_SubD::SubDType subd_type,
2640  unsigned int sector_face_count,
2641  double corner_sector_angle_radians
2642  );
2643 
2644  // This value is is used to set sector angles when the
2645  // actual value is not needed. This occurs at both ends
2646  // of a creased edge and when the end of a smooth edge
2647  // is a smooth vertex.
2648  static const double IgnoredCornerSectorAngle; // = 0.0;
2649 
2650  // This value is used to set sector weights that could not be
2651  // correctly set because something in the calculation failed.
2652  // It is typically used when an invalid component in SubD object
2653  // was needed to calculate the weight.
2654  static const double UnsetCornerSectorAngle; // = -8881.0;
2655 
2656  // This value is indicate a corner sector angle calculation failed.
2657  static const double ErrorCornerSectorAngle; // = -9991.0;
2658 
2659 
2660  // This value is used for smooth sector thetas
2661  static const double SmoothSectorTheta; // = 0.5*ON_PI
2662 
2663  // This value is used to indicate a sector theta needs to be set
2664  static const double UnsetSectorTheta; // = -8882.0;
2665 
2666  // This value is used to indicate a sector theta calculation failed.
2667  static const double ErrorSectorTheta; // = -9992.0;
2668 
2669 
2670  // This value is is used to set sector weights when the
2671  // actual value is not needed. This occurs at both ends
2672  // of a creased edge and when the end of a smooth edge
2673  // is a smooth vertex.
2674  static const double IgnoredSectorWeight; // = 0.0;
2675 
2676  // This value is used to mark sector weights that need to be
2677  // set in the future when more information is available.
2678  // It is typically used when creating a subD control net
2679  // and the facet type is not known. Any value < 0.0 and not
2680  // equal to ON_UNSET_VALUE would work. The fact that the actual
2681  // value is -999.0 has no other significance.
2682  static const double UnsetSectorWeight; // = -8883.0;
2683 
2684  // This value is indicate a sector weight calculation failed.
2685  static const double ErrorSectorWeight; // = -9993.0;
2686 
2687  static bool IsValidSectorWeightValue(
2688  double weight_value,
2689  bool bAllowUnsetTaggedEndWeight
2690  );
2691 
2692  /*
2693  Returns:
2694  ON_SubDSectorType::ErrorSectorWeight and calls debug breakpoint
2695  */
2696  static double SectorWeightCalculationError();
2697 
2698 
2699  /*
2700  Description:
2701  Create a ON_SubDSectorType from a ON_SubDSectorIterator.
2702  Parameters:
2703  subd_type - [in]
2704  vertex_tag - [in]
2705  sector_face_count - [in]
2706  Number of faces in the sector.
2707  corner_sector_angle_radians - [in]
2708  If vertex_tag is ON_SubD::VertexTag::Corner, this
2709  parameter is the angle between the crease edges
2710  that bound the corner.
2711  If vertex_tag is not ON_SubD::VertexTag::Corner,
2712  this parameter is ignored.
2713  Returns:
2714  An ON_SubDSectorType for the case the input parameters
2715  identify.
2716  */
2717  static ON_SubDSectorType Create(
2718  ON_SubD::SubDType subd_type,
2719  ON_SubD::VertexTag vertex_tag,
2720  unsigned int sector_face_count,
2721  double corner_sector_angle_radians
2722  );
2723 
2724 
2725  /*
2726  Description:
2727  Create a ON_SubDSectorType from a ON_SubDSectorIterator.
2728  Parameters:
2729  subd_type - [in]
2730  sit - [in]
2731  Returns:
2732  An ON_SubDSectorType for the sector identified by sit.
2733  */
2734  static ON_SubDSectorType Create(
2735  ON_SubD::SubDType subd_type,
2736  const ON_SubDSectorIterator& sit
2737  );
2738 
2739  /*
2740  Description:
2741  Create a ON_SubDSectorType for the sector containing the face.
2742  Parameters:
2743  subd_type - [in]
2744  face - [in]
2745  face_vertex_index - [in]
2746  face->Vertex(face_vertex_index) will be the sector's
2747  center vertex.
2748  Returns:
2749  An ON_SubDSectorType for the sector containing the face.
2750  */
2751  static ON_SubDSectorType Create(
2752  ON_SubD::SubDType subd_type,
2753  const class ON_SubDFace* face,
2754  unsigned int face_vertex_index
2755  );
2756 
2757  static ON_SubDSectorType Create(
2758  ON_SubD::SubDType subd_type,
2759  const class ON_SubDFace* face,
2760  const class ON_SubDVertex* vertex
2761  );
2762 
2763  /*
2764  Description:
2765  Create a ON_SubDSectorType for the sector containing the edge.
2766  Parameters:
2767  subd_type - [in]
2768  edge - [in]
2769  edge_vertex_index - [in]
2770  edge->Vertex(edge_vertex_index) will be the sector's
2771  center vertex.
2772  Returns:
2773  An ON_SubDSectorType for the sector containing the edge.
2774  */
2775  static ON_SubDSectorType Create(
2776  ON_SubD::SubDType subd_type,
2777  const class ON_SubDEdge* edge,
2778  unsigned int edge_vertex_index
2779  );
2780 
2781  /*
2782  Description:
2783  Create a smooth ON_SubDSectorType.
2784  Parameters:
2785  subd_type - [in]
2786  sector_face_count - [in]
2787  Number of faces in the sector.
2788  Returns:
2789  An ON_SubDSectorType for the smooth sector case specified
2790  by the input parameters.
2791  */
2792  static ON_SubDSectorType CreateSmoothSectorType(
2793  ON_SubD::SubDType subd_type,
2794  unsigned int sector_face_count
2795  );
2796 
2797  /*
2798  Description:
2799  Create a crease ON_SubDSectorType.
2800  Parameters:
2801  subd_type - [in]
2802  sector_face_count - [in]
2803  Number of faces in the sector.
2804  Returns:
2805  An ON_SubDSectorType for the crease sector case specified
2806  by the input parameters.
2807  */
2808  static ON_SubDSectorType CreateCreaseSectorType(
2809  ON_SubD::SubDType subd_type,
2810  unsigned int sector_face_count
2811  );
2812 
2813  /*
2814  Description:
2815  Create a dart ON_SubDSectorType.
2816  Parameters:
2817  subd_type - [in]
2818  sector_face_count - [in]
2819  Number of faces in the sector.
2820  Returns:
2821  An ON_SubDSectorType for the dart sector case specified
2822  by the input parameters.
2823  */
2824  static ON_SubDSectorType CreateDartSectorType(
2825  ON_SubD::SubDType subd_type,
2826  unsigned int sector_face_count
2827  );
2828 
2829  /*
2830  Description:
2831  Create a corner ON_SubDSectorType.
2832  Parameters:
2833  subd_type - [in]
2834  sector_face_count - [in]
2835  Number of faces in the sector.
2836  corner_sector_angle_radians - [in]
2837  The angle between the crease edges that bound the corner.
2838  Returns:
2839  An ON_SubDSectorType for the corner sector case specified
2840  by the input parameters.
2841  */
2842  static ON_SubDSectorType CreateCornerSectorType(
2843  ON_SubD::SubDType subd_type,
2844  unsigned int sector_face_count,
2845  double sector_corner_angle_radians
2846  );
2847 
2848  static int Compare(
2849  const ON_SubDSectorType& a,
2850  const ON_SubDSectorType& b
2851  );
2852 
2853 
2854  /*
2855  Description:
2856  Get the subdivision matrix for the default subdivison algorithms
2857  used by ON_SubD.
2858 
2859  The matrix coefficents are ordered so that the matrix acts on
2860  the left of the points returned by ON_SubDSectorIterator::GetVertexRing().
2861 
2862  For an interior vertex (smooth or dart), the coefficents are ordered
2863  so that one iteration of subdivision is given by:
2864  ON_SubD::SubDType::TriLoopWarren case:
2865  S*Transpose(V, E[0], E[1], ..., E[N-1])
2866  ON_SubD::SubDType::QuadCatmullClark case:
2867  S*Transpose(V, E[0], F[0], E[1], F[1], ..., E[N-1], F[N-1]).
2868  For a dart vertex, E[0] is the point at the end of the creased edge.
2869 
2870 
2871  For a boundary vertex (crease or corner), the coefficents are ordered
2872  so that one iteration of subdivision is given by:
2873  ON_SubD::SubDType::TriLoopWarren case:
2874  S*Transpose(V, E[0], E[1], ..., E[N-1]).
2875  ON_SubD::SubDType::QuadCatmullClark case:
2876  S*Transpose(V, E[0], F[0], E[1], F[1], ..., F[N-2], E[N-1]).
2877 
2878  N = edge valence = number of edges in the sector.
2879  E[i] = end of i-th edge radiating from V.
2880  In the ON_SubD::SubDType::QuadCatmullClark case, F[i] = point on the quad
2881  that is opposite V.
2882  The edges and faces are ordered radially so that the face for F[i]
2883  lies between the edges for E[i] and E[(i+1)%N].
2884 
2885  Parameters:
2886  matrix_capacity - [in]
2887  S[] can store any RxR matrix with R <= matrix_capacity.
2888  S - [out]
2889  subdivision matrix
2890  Matrix coefficent (i,j) = S[i][j]
2891  0 <= i < R, 0 <= j < R, R = ON_SubDSectorType.PointRingCount()
2892 
2893  Returns:
2894  R > 0:
2895  R = PointRingCount() and S is the RxR subdivision matrix for the sector type.
2896  0: Invalid input
2897  */
2898  unsigned int GetSubdivisionMatrix(
2899  size_t matrix_capacity,
2900  double** S
2901  ) const;
2902 
2903  /*
2904  Parameters:
2905  S_capacity - [in]
2906  Number of elements in S[] array
2907  S - [out]
2908  subdivision matrix.
2909  Matrix coefficent (i,j) = S[i*R + j],
2910  0 <= i < R, 0 <= j < R, R = ON_SubDSectorType.PointRingCount()
2911  Returns:
2912  0: Invalid input.
2913  >0: Number of rows and columns in S.
2914  This number is always ON_SubDSectorType.PointRingCount().
2915  */
2916  unsigned int GetSubdivisionMatrix(
2917  size_t S_capacity,
2918  double* S
2919  ) const;
2920 
2921  /*
2922  Description:
2923  All the subdivision matrices for the ON_SubD built-in
2924  subdivision algorithms have eigenvalues (1, lambda1, lambda2, e4, ..., eR),
2925  where 1 > lambda1 >= lambda2 > |e4| >= ... >= |eR| > 0.
2926 
2927  The subdominant eigenvalue is lambda1 and,
2928  with one exception, lambda1 = lambda2.
2929  The exception is described in the description of
2930  ON_SubDSectorType::SubdominantEigenvalueMulitiplicity().
2931 
2932  Returns:
2933  > 0.0:
2934  The subdominant eigenvalue for the subdivision matrix.
2935 
2936  ON_UNSET_VALUE:
2937  This ON_SubDSectorType is not valid.
2938  */
2939  double SubdominantEigenvalue() const;
2940 
2941  /*
2942  Returns:
2943  0:
2944  The sector type is not set.
2945 
2946  2:
2947  The subdominant eigenvalue has algebraic and geometric multiplicty = 2.
2948  This is the most common case.
2949 
2950  1:
2951  The subdominant eigenvalue has algebraic and geometric multiplicty = 1.
2952  This occures in Catmull-Clark subdivision at a crease vertex with
2953  two crease edges and a single face. The subdivision matrix for this
2954  case is
2955  S is a 4 x 4 matrix with rows =
2956  (3/4, 1/8, 0, 1/8),
2957  (1/2, 1/2, 0, 0),
2958  (1/4, 1/4, 1/4, 1/4),
2959  (1/2, 0, 0, 1/2).
2960  S has 4 real eigenvalues = (1, 1/2, 1/4, 1/4), all wtih
2961  geometric multiplicity = 1.
2962  The three eigenvectors are
2963  (1, 1, 1, 1), (0, -1, 0, 1), (0, 0, 1, 0).
2964  */
2965  unsigned int SubdominantEigenvalueMulitiplicity() const;
2966 
2967  /*
2968  Description:
2969  With one exception, which is described below,
2970  all the subdivision matrices for the ON_SubD built-in
2971  subdivision algorithms have eigenvalues (1, lambda, lambda, e4, ..., eR),
2972  where lambda is real, 1 > lambda > |e4| >= ... >= |eR| > 0, and the
2973  geometric dimension of the lambda eigenspace is 2 (there are two
2974  linearly independent lambda eigenvectors).
2975 
2976  The subdominant eigenvalue is lamda. This function returns an
2977  orthogonal basis, (E1, E2), for the subdominant eigenspace.
2978 
2979  An eigenvector for the dominant eigen value 1 has is (1,1,...,1).
2980  The domainant eignevector is orthogonal to the subdominant eigenspace.
2981 
2982  Put another way,
2983  0 = E1[0] + ... + E1[R-1]
2984  0 = E2[0] + ... + E2[R-1]
2985  0 = E1[0]*E2[0] + ... + E1[R-1]*E2[R-1]
2986 
2987  Exceptional case:
2988  The Catmull-Clark subdivision matrix for a crease vertex with
2989  two crease edges and a single face is a special case.
2990  In this exceptional, this function returns
2991  lambda = 1/2, E1 = {0,-1,0,-1} and E2 = {1, -2, -5, -2}.
2992  For more information about the exceptional case, see the description of
2993  ON_SubDSectorType::SubdominantEigenvalueMulitiplicity().
2994 
2995  Parameters:
2996  E1_capacity - [in]
2997  Capacity of the E1[] array.
2998  E1 - [out]
2999  E2_capacity - [in]
3000  Capacity of the E2[] array.
3001  E2 - [out]
3002  When E1_capacity > 0 and E2_capacity > 0, two orthoganal eigenvectors
3003  spanning the subdivision matrix subdominant eigenspace are returned
3004  in E1[] and E2[].
3005  If one of E1_capacity or E2_capacity is > 0, then both must be > 0.
3006 
3007  Returns:
3008  ON_UNSET_VALUE: Invalid input.
3009  e > 0.0 and e < 1.0:
3010  subdominant eigenvalue.
3011  */
3012  double GetSubdominantEigenvectors(
3013  size_t E1_capacity,
3014  double* E1,
3015  size_t E2_capacity,
3016  double* E2
3017  ) const;
3018 
3019  /*
3020  Parameters:
3021  LPev_capacity - [in]
3022  Capacity of the LPev[] array.
3023  LPev - [out]
3024  When LPev_capacity > 0, then the limit surface point evaluation coefficients are
3025  returned in LPev[]. Otherwise LPev is ignored.
3026  LT0ev_capacity - [in]
3027  Capacity of the LPev[] array.
3028  LT0ev - [out]
3029  LT1ev_capacity - [in]
3030  Capacity of the LPev[] array.
3031  LT1ev - [out]
3032  When LT0ev_capacity > 0 and LT1ev_capacity > 0, then the limit surface
3033  tangent coefficients are returned in LT0ev[] and LT1ev[]. Otherwise,
3034  LT0ev[] and LT1ev[] are ignored.
3035  If one of LT0ev_capacity or LT1ev_capacity is > 0, then both must be > 0.
3036  Returns:
3037  0: Invalid input.
3038  >0: Number of evaluation coefficients in the L*ev[] arrays.
3039  This number is always ON_SubDSectorType.PointRingCount().
3040  */
3041  unsigned int GetLimitSurfaceEvaluationCoefficients(
3042  size_t LPev_capacity,
3043  double* LPev,
3044  size_t LT0ev_capacity,
3045  double* LT0ev,
3046  size_t LT1ev_capacity,
3047  double* LT1ev
3048  ) const;
3049 
3050  // LimitSurfaceNormalSign() is a debugging tool - slow and not useful in general
3051  double LimitSurfaceNormalSign() const;
3052 
3053  bool LimitEvaluationCoefficientsAvailable() const;
3054 
3055  /*
3056  Parameters:
3057  eigenvalues_capacity - [in]
3058  Capacity of the eigenvalues[] array.
3059  Must be 0 or >= PointRingCount()
3060  eigenvalues - [out]
3061  If 0 = eigenvalues_capacity, eigenvalues must be nullptr.
3062  If eigenvalues_capacity > 0, is specifies the capactiy
3063  of the eigenvalues[] array.
3064  Returns:
3065  R > 0:
3066  A complete set of eigenvalues is available for this sector type.
3067  The eigenvalues are (1, lambda, lambda, e3, ..., eR), where
3068  1 > lambda > e3 >= ... >= eR > 0.
3069  0:
3070  Invalid input or the eigenvalues for this sector typoe are not available.
3071  */
3072  unsigned int GetAllEigenvalues(
3073  size_t eigenvalues_capacity,
3074  double* eigenvalues
3075  );
3076 
3077  /*
3078  Description:
3079  The subdivision matrix for all cases is known.
3080  A complete set of eigenvalues are available for some cases.
3081  Parameters:
3082  facet_type - [in]
3083  vertex_tag - [in]
3084  sector_edge_count - [in]
3085  The input parameters identify the subdivision case.
3086  Returns:
3087  R > 0: Eigenvalues are known. There subdivison matrix is R x R.
3088  0: Eigenvalues for this case are not known.
3089  */
3090  static unsigned int AllEigenvaluesAvailableKnown(
3091  ON_SubD::SubDType subd_type,
3092  ON_SubD::VertexTag vertex_tag,
3093  unsigned int sector_edge_count
3094  );
3095 
3096  /*
3097  Description:
3098  Create a partial subdivison sector around vertex.
3099  The resulting ON_SubD has an outer ring with smooth edges and vertices,
3100  which is not valid as a stand-alone subd. This is typically used for
3101  testing.
3102  Parameters:
3103  radius - [in]
3104  The center vertex is located at (0,0,0),
3105  If radius > 0.0, then the end of the first edge is at (radius,0,0),
3106  subsequent edges are in a radial array and quad face points, if any,
3107  are 2*radius from the origin.
3108  sector_angle_radians - [in]
3109  If radius > 0,
3110  this->VertexTag() is ON_SubD::VertexTag::Crease,
3111  crease_sector_angle_radians > 0.0 and
3112  crease_sector_angle_radians < 2.0*ON_PI,
3113  then this will be the angle between the crease boundary edges.
3114  In all other cases, crease_sector_angle_radians is ignored.
3115  subd - [in]
3116  If subd is not null, the vertex ring is put in this
3117  subd.
3118  Returns:
3119  a pointer to the vertex ring
3120  nullptr is returned if the input is not valid.
3121  */
3122  ON_SubD* SectorRingSubD(
3123  double radius,
3124  double sector_angle_radians,
3125  ON_SubD* subd
3126  ) const;
3127 
3128 private:
3129  ON_SubD::SubDType m_subd_type = ON_SubD::SubDType::Unset;
3130  ON_SubD::FacetType m_facet_type = ON_SubD::FacetType::Unset;
3131  ON_SubD::VertexTag m_vertex_tag = ON_SubD::VertexTag::Unset;
3132  unsigned char m_reserved1 = 0;
3133  unsigned int m_hash = 0; // SetHash() sets this field, SectorTypeHash() returns its value.
3134  unsigned int m_corner_sector_angle_index = 0; // >= 0 and <= ON_SubDSectorType::MaximumAngleIndex
3135  unsigned int m_sector_face_count = 0;
3136  double m_sector_weight = 0.0;
3137  double m_sector_theta = 0.0;
3138  double m_corner_sector_angle_radians = 0.0;
3139 
3140 private:
3141  void SetHash();
3142 
3143  /*
3144  Description:
3145  Calculates sector theta value for the sector type
3146  identified by this ON_SubDSectorType.
3147  Returns:
3148  theta: 0.0 <= theta <= ON_PI
3149  The sector theta value.
3150  ON_SubDSectorType::ErrorSectorTheta
3151  This ON_SubDSectorType is not valid and the calculation failed.
3152  */
3153  double SectorTheta() const;
3154 
3155  /*
3156  Parameters:
3157  sector_face_count - [in] >= 1
3158  Number of faces in the crease sector.
3159  Returns:
3160  theta: 0.0 < theta <= ON_PI
3161  sector theta value for a crease sector with sector_face_count faces.
3162  ON_SubDSectorType::ErrorSectorTheta
3163  sector_face_count is not valid and the calculation failed.
3164  */
3165  static double CreaseSectorTheta(
3166  unsigned int sector_face_count
3167  );
3168 
3169  /*
3170  Parameters:
3171  sector_face_count - [in] >= 2
3172  Number of faces in the dart sector.
3173  Returns:
3174  theta: 0.0 < theta <= ON_PI
3175  sector theta value for a dart sector with sector_face_count faces.
3176  ON_SubDSectorType::ErrorSectorTheta
3177  sector_face_count is not valid and the calculation failed.
3178  */
3179  static double DartSectorTheta(
3180  unsigned int sector_face_count
3181  );
3182 
3183  /*
3184  Parameters:
3185  sector_face_count - [in] >= 2
3186  Number of faces in the dart sector.
3187  corner_sector_angle_radians - [in] (0.0 <= corner_sector_angle_radians <= 2*ON_PI
3188  The angle between the bounding crease edges
3189  Returns:
3190  theta: 0.0 < theta <= ON_PI/2
3191  sector theta value for the corner sector.
3192  ON_SubDSectorType::ErrorSectorTheta
3193  sector_face_count or corner_sector_angle_radians were not valid
3194  and the calculation failed.
3195  */
3196  static double CornerSectorThetaFromCornerAngle(
3197  unsigned int sector_face_count,
3198  double corner_sector_angle_radians
3199  );
3200 
3201  /*
3202  Parameters:
3203  subd_type - [in]
3204  sector_theta - [in]
3205  value from one of the sector theta functions.
3206  ON_SubDEdge::SectorTheta()
3207  ON_SubDEdge::SmoothSectorTheta()
3208  ON_SubDEdge::CreaseSectorTheta()
3209  ON_SubDEdge::CornerSectorTheta()
3210  ON_SubDEdge::DartSectorTheta()
3211  Returns:
3212  0:
3213  failed to caclulate weight
3214  ON_UNSET_VALUE:
3215  subd_type was set ON_SubD::SubDType::Unset
3216  and the tagged end weight cannot be calculated until
3217  the facet type is known. This typically happens
3218  when a SubD control net is being created and
3219  a facet type is not specified. The weights will
3220  be calculated at the first subdivision.
3221  0 < w < 1:
3222  If ON_SubD::SubDType::QuadCatmullClark == subd_type,
3223  then the returned value is
3224  1/2 + 1/3*cos(sector_angle_radians). (1/6 <= w <= 5/6)
3225  If ON_SubD::SubDType::TriLoopWarren == subd_type,
3226  then the returned value is
3227  1/3 + 1/3*cos(sector_angle_radians). (0 < w <= 2/3)
3228  Remarks:
3229  This is a useful tool when calling AddEdge while a subdivision
3230  level is being constructed.
3231  */
3232  static double SectorWeightFromTheta(
3233  ON_SubD::SubDType subd_type,
3234  double sector_theta
3235  );
3236 };
3237 
3238 //////////////////////////////////////////////////////////////////////////
3239 //
3240 // ON_SubDLimitMeshFragment
3241 //
3242 // Meshes of ON_SubD limit surface are calculated in fragments.
3243 //
3244 class ON_SUBD_CLASS ON_SubDLimitMeshFragmentGrid
3245 {
3246 public:
3247  // No construction for performance reasons.
3248  // If you require initialization, use = ON_SubDLimitMeshFragmentGrid::Empty
3249  //
3250  //ON_SubDLimitMeshFragmentGrid() = default;
3251  //~ON_SubDLimitMeshFragmentGrid() = default;
3252  //ON_SubDLimitMeshFragmentGrid(const ON_SubDLimitMeshFragmentGrid&) = default;
3253  //ON_SubDLimitMeshFragmentGrid& operator=(const ON_SubDLimitMeshFragmentGrid&) = default;
3254  static const ON_SubDLimitMeshFragmentGrid Empty;
3255 
3256  /*
3257  Description:
3258  Get mesh facet quads that index into a grid of points.
3259  Parameters:
3260  side_segment_count - [in]
3261  number quads in each row and column of the quad grid.
3262  side_segment_count >= 1
3263  side_segment_count <= ON_SubDLimitMesh::MaximumSideSegmentCount
3264  side_segment_count must be a power of 2
3265 
3266  level_of_detail - [in]
3267  0: quad count = maximum quad count = (side_count x side_count)
3268  1: quad count = 1/4 maximum quad count
3269  1: quad count = 1/16 maximum quad count
3270  ...
3271  If 4^level_of_detail > maximum quad count, then a single quad is returned.
3272  */
3273  static ON_SubDLimitMeshFragmentGrid Quads(
3274  unsigned int side_segment_count,
3275  unsigned int level_of_detail
3276  );
3277 
3278  static ON_SubDLimitMeshFragmentGrid Tris(
3279  unsigned int side_segment_count,
3280  unsigned int level_of_detail
3281  );
3282 
3283  static ON_SubDLimitMeshFragmentGrid Facets(
3284  ON_SubD::FacetType facet_type,
3285  unsigned int side_segment_count,
3286  unsigned int level_of_detail
3287  );
3288 
3289  /*
3290  Description:
3291  Get mesh facet quads that index into a grid of points.
3292  Parameters:
3293  side_segment_count - [in]
3294  number quads in each row and column of the quad grid
3295  with the highest level of detail (level_of_detail = 0)
3296  side_count must be a power of 2
3297  level_of_detail - [in]
3298  Desired level of detail of the returned grid
3299  0: highest (side_count x side_count) quads
3300  1: 1/4 density (side_count x side_count)/4 quads
3301  2: 1/16 density (side_count x side_count)/16 quads
3302  ...
3303  side_count-2: 4 quads
3304  side_count-1: 1 quad
3305  >= side_count: 1 quad
3306  Returns:
3307  Number of quads in the grid.
3308  */
3309  static unsigned int SetQuads(
3310  unsigned int side_segment_count,
3311  unsigned int level_of_detail,
3312  size_t quad_capacity,
3313  size_t quad_stride,
3314  unsigned int* quads,
3315  size_t side_capacity,
3316  size_t side_stride,
3317  unsigned int* sides
3318  );
3319 
3320 
3321  unsigned int SideSegmentCount() const;
3322 
3323  /*
3324  Description:
3325  The GridId() is persistent and unique based on the contents of the
3326  grid. It is intended to be used in render applications that store
3327  copies of ON_SubDLimitMeshFragmentGrid settings in things like
3328  vertex object buffers and want a reliable way to index into them.
3329  The Empty grid has id = 0;
3330  Returns:
3331  0:
3332  when the grid is empty
3333  32*n + 2*lod + t:
3334  t = 0 for quads and 1 for tris,
3335  (0 <= n <= 8) m_F_count = 2^(2n),
3336  (0 <= lod <= 8) m_F_level_of_detail = lod
3337  Remarks:
3338  m_F_count is always
3339  */
3340  unsigned int GridId() const;
3341 
3342  /*
3343  Returns:
3344  3 for tris, 4 for quads, 0 for unset.
3345  */
3346  unsigned int GridFacetSideCount() const;
3347 
3348  bool GetGridParameters(
3349  unsigned int grid_point_index,
3350  double grid_parameters[2]
3351  ) const;
3352 
3353 
3354 private:
3355  unsigned char m_reserved;
3356 
3357 public:
3358 
3359  ON_SubD::FacetType m_F_type;
3360  unsigned char m_side_segment_count; // = 2^n for non-empty grids (0 <= n <= 8)
3361  unsigned short m_F_count; // = m_side_count*m_side_count
3362  unsigned short m_F_level_of_detail; // 0 = highest, > 0 = reduced
3363  unsigned short m_F_stride;
3364  const unsigned int* m_F;
3365  const unsigned int* m_S; // [4*m_side_segment_count + 1] indices that form the polyline boundary.
3366  const ON_SubDLimitMeshFragmentGrid* m_prev_level_of_detail; // nullptr or the previous level with more facets.
3367  const ON_SubDLimitMeshFragmentGrid* m_next_level_of_detail; // nullptr or the next level with fewer facets.
3368 };
3369 
3370 class ON_SUBD_CLASS ON_SubDLimitMeshFragment
3371 {
3372 public:
3373  // No construction for performance reasons.
3374  // If you require initialization, use = ON_SubDLimitMeshFragment::Empty
3375  //
3376  //ON_SubDLimitMeshFragment() = default;
3377  //~ON_SubDLimitMeshFragment() = default;
3378  //ON_SubDLimitMeshFragment(const ON_SubDLimitMeshFragment&) = default;
3379  //ON_SubDLimitMeshFragment& operator=(const ON_SubDLimitMeshFragment&) = default;
3380 
3381  // Every field of ON_SubDLimitMeshFragment::Empty is zero.
3382  static const ON_SubDLimitMeshFragment Empty;
3383 
3384  static const unsigned int MaximumSideSegmentCount;
3385 
3386  /*
3387  Returns:
3388  side_segment_count = 2^display_density
3389  */
3390  static unsigned int SideSegmentCountFromDisplayDensity(
3391  unsigned int display_density
3392  );
3393 
3394  /*
3395  Returns:
3396  base 2 log of side_segment_count.
3397  Remarks:
3398  side_segment_count = 2^display_density
3399  */
3400  static unsigned int DisplayDensityFromSideSegmentCount(
3401  unsigned int side_segment_count
3402  );
3403 
3404  /*
3405  Parameters:
3406  facet_type - [in]
3407  ON_SubD::FacetType::Quad or ON_SubD::FacetType::Tri
3408 
3409  display_density - [in]
3410  >= 0
3411  Returns:
3412  total number of points in the limit mesh fragment.
3413  Remarks:
3414  The number of points is the same for quad or tri subdivision limit
3415  mesh fragments, even though one is a rectanglular collection of
3416  quads and the other is a trianglular collection of triangles.
3417  */
3418  static unsigned int PointCountFromDisplayDensity(
3419  ON_SubD::FacetType facet_type,
3420  unsigned int display_density
3421  );
3422 
3423  /*
3424  Parameters:
3425  display_density - [in]
3426  >= 0
3427  Returns:
3428  total number of faces in the limit mesh fragment.
3429  */
3430  static unsigned int FaceCountFromDisplayDensity(
3431  unsigned int display_density
3432  );
3433 
3434  /*
3435  Returns:
3436  true if side_segment_count is valid.
3437  Otherwise 0 is returned.
3438  */
3439  static bool SideSegmentCountIsValid(
3440  unsigned int side_segment_count
3441  );
3442 
3443  /*
3444  Returns:
3445  If side_segment_count is valide, then (side_segment_count+1) is returned.
3446  Otherwise 0 is returned.
3447  */
3448  static unsigned int SidePointCountFromSideCount(
3449  unsigned int side_segment_count
3450  );
3451 
3452  /*
3453  Returns:
3454  If side_segment_count is valide, then (side_segment_count+1)^2 is returned.
3455  Otherwise 0 is returned.
3456  */
3457  static unsigned int QuadGridPointCountFromSideCount(
3458  unsigned int side_segment_count
3459  );
3460 
3461  /*
3462  Returns:
3463  If side_segment_count is valide, then side_segment_count^2 is returned.
3464  Otherwise 0 is returned.
3465  */
3466  static unsigned int QuadGridQuadCountFromSideCount(
3467  unsigned int side_segment_count
3468  );
3469 
3470 public:
3471  const class ON_SubDFace* m_face;
3472 
3473  // m_face_vertex_index[] stores the information needed for the Vertex()
3474  // and Edge() functions to work.
3475  //
3476  // If m_face is nullptr, then m_face_vertex_index[] has no meaning.
3477  // If m_face is not nullptr and a corner of the grid is on a face
3478  // vertex, then the corresponding m_face_vertex_index[] value
3479  // will be <= ON_SubDFace::MaximumEdgeCount and m_face->Vertex(m_face_vertex_index[])
3480  // is the vertex. Otherwise, the corresponding m_face_vertex_index[] value
3481  // will be > ON_SubDFace::MaximumEdgeCount. For partial fragments,
3482  // only some m_face_vertex_index[] identify vertices and the grid extends
3483  // halfway along the neighboring face edges are
3484  unsigned short m_face_vertex_index[4];
3485 
3486  /*
3487  Parameters:
3488  grid_side_index - [in]
3489  0 to 3 for quad grids.
3490  0 to 2 for tri grids
3491  Returns:
3492  The subd edge that is on the identified side of the grid.
3493  */
3494  const class ON_SubDEdgePtr EdgePtr(
3495  unsigned int grid_side_index
3496  ) const;
3497  const class ON_SubDEdge* Edge(
3498  unsigned int grid_side_index
3499  ) const;
3500 
3501  const class ON_SubDVertexPtr VertexPtr(
3502  unsigned int grid_corner_index
3503  ) const;
3504  const class ON_SubDVertex* Vertex(
3505  unsigned int grid_corner_index
3506  ) const;
3507 
3508  ON_3dPoint CornerPoint(
3509  unsigned int grid_corner_index
3510  ) const;
3511 
3512  /*
3513  Returns:
3514  Status of the face.
3515  */
3516  ON_ComponentStatus Status() const;
3517 
3518  /*
3519  Returns:
3520  True if this fragment covers a subset of a face.
3521  */
3522  bool IsSubFragment() const;
3523 
3524  /*
3525  Returns:
3526  True if this fragment covers an entier subd face.
3527  */
3528  bool IsCompleteFragment() const;
3529 
3530  bool Transform(
3531  const ON_Xform& xform
3532  );
3533 
3534  unsigned short m_face_fragment_count; // Number of fragments that will be delivered for this face.
3535  unsigned short m_face_fragment_index; // First fragment has index = 0. Last fragment has index = m_face_fragment_count-1.
3536 
3537  // For quad based subdivision algorithms, the mesh fragment
3538  // is a tesselation of a rectangular shaped surface,
3539  // there are m_side_count quad edges along each side of the tesselation,
3540  // there are a total of m_side_count X m_side_count quads, and
3541  // m_P_count = (m_side_count+1)*(m_side_count+1).
3542  //
3543  // For trangle based subdivision algorithms, the mesh fragment
3544  // is a tesselation of a triangular shaped surface,
3545  // there are m_side_count triangle edges along each side of the tesselation,
3546  // there are a total of m_side_count X m_side_count triangles, and
3547  // m_P_count = (m_side_count+1)*(m_side_count+2)/2.
3548  //
3549 
3550  // Number of points
3551  unsigned short m_P_count;
3552  unsigned short m_P_capacity;
3553 
3554  // points
3555  size_t m_P_stride;
3556  // The memory m_P references is managed by some other class or function.
3557  // Never modify the values in m_P.
3558  double* m_P;
3559 
3560  // surface normals parallel to m_P[] array
3561  size_t m_N_stride;
3562  // If m_N is not nullptr, then it can accomodate up to m_P_capacity normals.
3563  // The memory m_N references is managed by some other class or function.
3564  // Never modify the values in m_N.
3565  double* m_N;
3566 
3567  // quads or tris
3568  ON_SubDLimitMeshFragmentGrid m_grid; //
3569 
3570  ON_BoundingBox m_bbox;
3571 
3572  ON_SubDLimitMeshFragment* m_next_fragment;
3573  ON_SubDLimitMeshFragment* m_prev_fragment;
3574 };
3575 
3576 class ON_SUBD_CLASS ON_SubDManagedLimitMeshFragment : public ON_SubDLimitMeshFragment
3577 {
3578 public:
3579  ON_SubDManagedLimitMeshFragment() ON_NOEXCEPT;
3580  ~ON_SubDManagedLimitMeshFragment() ON_NOEXCEPT;
3581  ON_SubDManagedLimitMeshFragment(const ON_SubDManagedLimitMeshFragment&) ON_NOEXCEPT;
3582  ON_SubDManagedLimitMeshFragment& operator=(const ON_SubDManagedLimitMeshFragment&) ON_NOEXCEPT;
3583 
3584  static ON_SubDManagedLimitMeshFragment Create(const ON_SubDLimitMeshFragment& src) ON_NOEXCEPT;
3585 
3586 #if defined(ON_HAS_RVALUEREF)
3587  // rvalue copy constructor
3588  ON_SubDManagedLimitMeshFragment( ON_SubDManagedLimitMeshFragment&& ) ON_NOEXCEPT;
3589 
3590  // rvalue assignment operator
3591  ON_SubDManagedLimitMeshFragment& operator=( ON_SubDManagedLimitMeshFragment&& ) ON_NOEXCEPT;
3592 #endif
3593 
3594  void Clear() ON_NOEXCEPT;
3595 
3596  void Destroy() ON_NOEXCEPT;
3597 
3598  bool ReserveCapacity(
3599  ON_SubD::FacetType facet_type,
3600  unsigned int mesh_density
3601  ) ON_NOEXCEPT;
3602 
3603 private:
3604  void CopyHelper(const ON_SubDLimitMeshFragment& src);
3605  size_t m_storage_capacity = 0;
3606  double* m_storage = nullptr;
3607 };
3608 
3609 //////////////////////////////////////////////////////////////////////////
3610 //
3611 // ON_SubDDisplayParameters
3612 //
3613 // A collection of parameters that are passed to functions that
3614 // calculate a various representations of the limit surface.
3615 //
3616 class ON_SUBD_CLASS ON_SubDDisplayParameters
3617 {
3618 public:
3619  static const ON_SubDDisplayParameters Empty;
3620 
3621  // Parameters for the default limit surface display mesh.
3622  static const ON_SubDDisplayParameters DefaultDisplayMeshParameters;
3623 
3624  /*
3625  Description:
3626  In most applications, the caller sets the mesh_density
3627  and leaves the other parameters set to the default
3628  values.
3629  */
3630  static ON_SubDDisplayParameters CreateFromDisplayDensity(
3631  unsigned int display_density
3632  );
3633 
3634  ON_SubDDisplayParameters() = default;
3635  ~ON_SubDDisplayParameters() = default;
3636  ON_SubDDisplayParameters(const ON_SubDDisplayParameters&) = default;
3637  ON_SubDDisplayParameters& operator=(const ON_SubDDisplayParameters&) = default;
3638 
3639  unsigned int m_display_density = 0;
3640 
3641  bool m_bUseMultipleThreads = false;
3642  ON_Terminator* m_terminator = nullptr;
3643  // optional progress reporting
3644  ON_ProgressReporter* m_progress_reporter = nullptr;
3645  ON_Interval m_progress_reporter_interval = ON_Interval::ZeroToOne;
3646 };
3647 
3648 //////////////////////////////////////////////////////////////////////////
3649 //
3650 // ON_SubDLimitMesh
3651 //
3652 class ON_SUBD_CLASS ON_SubDLimitMesh
3653 {
3654 #if defined(ON_SUBD_CENSUS)
3655 private:
3656  ON_SubDLimitMeshCensusCounter m_census_counter;
3657 #endif
3658 
3659 public:
3660  static const ON_SubDLimitMesh Empty;
3661 
3662  /*
3663  Returns:
3664  A runtime number that changes if the limit mesh content changes.
3665  0: Empty limit mesh
3666  Remarks:
3667  This is a runtime number. It is not saved in archives and begins
3668  at 1 with each new runtime instance of the opennurbs library.
3669  */
3670  unsigned int ContentSerialNumber() const;
3671 
3672  enum : unsigned int
3673  {
3674  DefaultDisplayDensity = 4, // default limit mesh density 16x16 quads per SubD quad 16 = 2^4
3675  MaximumDisplayDensity = 8 // 8 (256x256 quads per SubD quad 256 = 2^8)
3676  //MaximumLevelOfDetail = 0, // 0 = most facets per fragment
3677  //MinimumLevelOfDetail = 8 // 8 = fewest facets per fragment
3678  };
3679 
3680  static ON_SubDLimitMesh* Create(
3681  const ON_SubD& subd,
3682  const class ON_SubDDisplayParameters& limit_mesh_parameters,
3683  ON_SubDLimitMesh* destination_mesh
3684  );
3685 
3686  /*
3687  Description:
3688  This version is for expert users who want to take
3689  responsibility for managing the subd and limit mesh
3690  */
3691  static ON_SubDLimitMesh* Create(
3692  ON_SubDFaceIterator fit,
3693  const class ON_SubDDisplayParameters& limit_mesh_parameters,
3694  ON_SubDLimitMesh* destination_mesh
3695  );
3696 
3697  ON_SubDLimitMesh() = default;
3698  ~ON_SubDLimitMesh() = default;
3699  ON_SubDLimitMesh(const ON_SubDLimitMesh&) = default;
3700  ON_SubDLimitMesh& operator=(const ON_SubDLimitMesh&) = default;
3701 
3702 
3703 #if defined(ON_HAS_RVALUEREF)
3704  // rvalue copy constructor
3705  ON_SubDLimitMesh( ON_SubDLimitMesh&& ) ON_NOEXCEPT;
3706  // rvalue assignment operator
3707  ON_SubDLimitMesh& operator=( ON_SubDLimitMesh&& );
3708 #endif
3709 
3710  ON_SubDLimitMesh Copy() const;
3711 
3712  ON_SubDLimitMesh& CopyFrom(
3713  const ON_SubDLimitMesh& src
3714  );
3715 
3716  static void Swap(
3717  ON_SubDLimitMesh& a,
3718  ON_SubDLimitMesh& b
3719  );
3720 
3721  bool Transform(
3722  const ON_Xform& xform
3723  );
3724 
3725  unsigned int DisplayDensity() const;
3726  ON_SubDDisplayParameters DisplayParameters() const;
3727  unsigned int FragmentCount() const;
3728  const ON_SubDLimitMeshFragment* FirstFragment() const; // linked list of mesh fragments
3729 
3730  /*
3731  Description:
3732  If the subd referenced by m_subd_ref changes, then call
3733  Update to update the limit mesh.
3734  */
3735  bool Update(
3736  bool bShareUpdate
3737  );
3738 
3739  /*
3740  Description:
3741  The ON__INT_PTRs in the tree are const ON_SubDLimitMeshFragment* pointers.
3742  */
3743  const ON_RTree& FragmentTree() const;
3744 
3745  /*
3746  Description:
3747  Clears everything.
3748  */
3749  void Clear();
3750 
3751  /*
3752  Description:
3753  If the tree is not needed and memory resources are tight, then call ClearTree()
3754  to remove the RTree.
3755  */
3756  void ClearTree();
3757 
3758  bool IsEmpty() const;
3759 
3760  ON_SubD::FacetType GridType() const;
3761 
3762  ON_BoundingBox BoundingBox() const;
3763 
3764  bool GetTightBoundingBox(
3765  ON_BoundingBox& bbox,
3766  bool bGrowBox,
3767  const ON_Xform* xform
3768  ) const;
3769 
3770  ON_SubDRef SubDRef() const;
3771  ON_SubD SubD() const;
3772 
3773 public:
3774  /*
3775  Description:
3776  Pretend this function and ON_SubDLimitMeshImpl do not exist.
3777  Returns:
3778  Something that you are pretending does not exist.
3779  Remarks:
3780  It is intentional that the definition of ON_SubDLimitMeshImpl class is not
3781  available in the opennurbs library interface (not in a header file).
3782  The size and design of ON_SubDLimitMeshImpl will change constantly.
3783  If you choose to hack and whack so you can dereference an
3784  ON_SubDLimitMeshImpl* pointer, then your code will crash unpredictably.
3785  */
3786  class ON_SubDLimitMeshImpl* SubLimple() const;
3787  unsigned int SubLimpleUseCount() const;
3788 
3789 private:
3790 #pragma ON_PRAGMA_WARNING_PUSH
3791 #pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
3792  friend class ON_SubDLimitMeshImpl;
3793  // C4251: ... needs to have dll-interface to be used by clients of class ...
3794  // m_impl_sp is private and all code that manages m_impl_sp is explicitly implemented in the DLL.
3795 private:
3796  std::shared_ptr< class ON_SubDLimitMeshImpl > m_impl_sp;
3797 #pragma ON_PRAGMA_WARNING_POP
3798 
3799 };
3800 
3801 
3802 
3803 class ON_SUBD_CLASS ON_SubDLimitPatchFragment
3804 {
3805 public:
3806  // No construction for performance reasons.
3807  // If you require initialization, use = ON_SubDLimitMeshFragment::Empty
3808  //
3809  //ON_SubDLimitMeshFragment() = default;
3810  //~ON_SubDLimitMeshFragment() = default;
3811  //ON_SubDLimitMeshFragment(const ON_SubDLimitMeshFragment&) = default;
3812  //ON_SubDLimitMeshFragment& operator=(const ON_SubDLimitMeshFragment&) = default;
3813 
3814  // Every field of ON_SubDLimitPatchFragment::Empty is zero.
3815  static const ON_SubDLimitPatchFragment Empty;
3816 
3817  // Every m_patch_cv[][][] value is ON_UNSET_VALUE.
3818  // Every other field of ON_SubDLimitPatchFragment::Unset is zero.
3819  static const ON_SubDLimitPatchFragment Unset;
3820 
3821  // Every m_patch_cv[][][] value is ON_DBL_QNAN.
3822  // Every other field of ON_SubDLimitPatchFragment::Unset is zero.
3823  static const ON_SubDLimitPatchFragment Nan;
3824 
3825 #pragma region RH_C_SHARED_ENUM [SubD::PatchType] [Rhino.Geometry.SubD.PatchType] [internal:nested:byte]
3826  enum class PatchType : unsigned char
3827  {
3828  ///<summary>Not a valid patch type.</summary>
3829  Unset = 0,
3830 
3831  ///<summary>Entire subdivision face is an exact bicubic patch.</summary>
3832  Bicubic = 1,
3833 
3834  ///<summary>A quadrant of the subdivision face is an exact bicubic patch.</summary>
3835  BicubicQuadrant = 2,
3836 
3837  ///<summary>Entire subdivision face is approximately a bicubic patch.</summary>
3838  ApproximateBicubic = 3,
3839 
3840  ///<summary>A quadrant of the subdivision face is approximately a bicubic patch.</summary>
3841  ApproximateBicubicQuadrant = 4,
3842 
3843  ///<summary>A patch cannot be calculated at the current subdivision level.</summary>
3844  None = 5
3845  };
3846 #pragma endregion
3847 
3848 public:
3849  double m_patch_cv[5][5][3];
3850  const double* m_patch_knots[2]; // nullptr or 7 uniform cubic knots. Never modify these values.
3851 
3852  const class ON_SubDFace* m_level0_face;
3853 
3854 
3855  // m_patch_state[] reports what information is returned in m_patch_cv[] and m_patch_knots[].
3856  // m_patch_state[0] report the state for the cubic patch:
3857  // CV[0][0] = m_patch_cv[0][0], knot[0] = m_patch_knots[0], knot[1] = m_patch_knots[1]
3858  // m_patch_state[1] report the state for the cubic patch:
3859  // CV[0][0] = m_patch_cv[1][0], knot[0] = m_patch_knots[0]+1, knot[1] = m_patch_knots[1]
3860  // m_patch_state[2] report the state for the cubic patch:
3861  // CV[0][0] = m_patch_cv[1][1], knot[0] = m_patch_knots[0]+1, knot[1] = m_patch_knots[1]+1
3862  // m_patch_state[3] report the state for the cubic patch:
3863  // CV[0][0] = m_patch_cv[0][1], knot[0] = m_patch_knots[0], knot[1] = m_patch_knots[1]+1
3864  ON_SubDLimitPatchFragment::PatchType m_patch_type[4];
3865 
3866  unsigned short m_patch_level;
3867 
3868  // When the subdivision method is quad based and m_face is a quad, there is one region.
3869  // When the subdivision method is quad based and m_face is not a quad, there are m_face->m_edge_count regions.
3870  unsigned short m_level0_face_region_count; // Number of regions in m_face.
3871  unsigned short m_level0_face_region_index; // First region has index = 0. Last region has index = m_face_region_count-1.
3872 
3873  unsigned short m_face_subdivision_count;
3874  unsigned short m_face_region_index[10]; // vertex index for subdivision
3875 
3876 public:
3877  ON_SubDLimitPatchFragment* m_next_fragment;
3878  ON_SubDLimitPatchFragment* m_prev_fragment;
3879 };
3880 
3881 
3882 class ON_SUBD_CLASS ON_SubDSectorLimitPoint
3883 {
3884 public:
3885  // For performance reasons, the default the data members are
3886  // not initialized by the default constructor
3887  // Use = ON_SubDSectorLimitPoint::Unset when initialization is required
3888  static const ON_SubDSectorLimitPoint Unset; // all doubles are ON_UNSET_VALUE, all pointer are nullptr
3889  static const ON_SubDSectorLimitPoint Nan; // all doubles are ON_DBL_QNAN, all pointer are nullptr
3890  static const ON_SubDSectorLimitPoint Zero; // all doubles are 0.0, all pointer are nullptr
3891 
3892  /*
3893  Returns:
3894  true if m_limitP[0] is a nan (like ON_DBL_QNAN).
3895  false otherwise.
3896  */
3897  bool IsUnset() const;
3898 
3899  /*
3900  Returns:
3901  true if m_limitP[0] is ON_UNSET_VALUE.
3902  false otherwise.
3903  */
3904  bool IsNan() const;
3905 
3906  /*
3907  Returns:
3908  true if all coordinates are zero.
3909  false otherwise.
3910  */
3911  bool IsZero() const;
3912 
3913  /*
3914  Returns:
3915  true if all coordinates are valid doubles and the tangents and normal have at least
3916  one nonzero coordinate.
3917  false otherwise.
3918  */
3919  bool IsSet() const;
3920 
3921  bool Transform(
3922  const ON_Xform& xform
3923  );
3924 
3925  // limit surface point, tangents and normal
3926  double m_limitP[3]; // point
3927  double m_limitT1[3]; // first unit tangent
3928  double m_limitT2[3]; // second unit tangent
3929  double m_limitN[3]; // unit normal (same direction as m_limitT1 x m_limitT2)
3930 
3931  // When an ON_SubDVertex has a single sector, these pointers are both null.
3932  // When an ON_SubDVertex has a multiple sectors,
3933  // m_sector_face is the "first" face in the sector and
3934  // m_next_sector_limit_point is used to create a linked list.
3935  // (The "first" face in a sector is the one ON_SubDSectorIterator.IncrementToCrease(-1) returns.)
3936  const class ON_SubDSectorLimitPoint* m_next_sector_limit_point; // nullptr for vertices with one sector
3937  const class ON_SubDFace* m_sector_face; // nullptr for vertices with one sector
3938 };
3939 
3940 
3941 
3942 ////////////////////////////////////////////////////////////////////////////
3943 //
3944 // ON_SubDComponentBase
3945 //
3946 class ON_SUBD_CLASS ON_SubDComponentBase
3947 {
3948 public:
3949  static const ON_SubDComponentBase Unset;
3950 
3951  ///*
3952  //Returns:
3953  // True if component is not nullptr, component->m_id > 0 and component->m_archive_id != ON_UNSET_UINT_INDEX.
3954  //*/
3955  //static bool IsActive(
3956  // const ON_SubDComponentBase* component
3957  // );
3958 
3959 public:
3960  ON_SubDComponentBase() = default;
3961  ~ON_SubDComponentBase() = default;
3962  ON_SubDComponentBase(const ON_SubDComponentBase&) = default;
3963  ON_SubDComponentBase& operator=(const ON_SubDComponentBase&) = default;
3964 
3965 public:
3966  // The audience for this comment is anybody who wants to change the data
3967  // fields in ON_SubDComponentBase. Everyone else should ignore this comment.
3968  // ON_SubD components come from ON_FixedSizePool and ON_SubD code
3969  // uses ON_FixedSizePool.ReturnElement. The first sizeof(void*) bytes
3970  // must be a data field that is not referenced in returned elements.
3971  // Since a returned element cannot have a "next level vertex",
3972  // m_subd_point1 is a good data member to put first.
3973 
3974  // m_subd_point1 points to the next level's vertex when this component
3975  // has been subdivided using an algorithm like Catmull-Clark or Loop-Warren.
3976  const class ON_SubDVertex* m_subd_point1 = nullptr;
3977 
3978 public:
3979  // The audience for this comment is anybody who wants to change the data
3980  // fields in ON_SubDComponentBase. Everyone else should ignore this comment.
3981  // It is critical that the offset of m_id in ON_SubDComponentBase be >= sizeof(void*).
3982  // ON_SubD components come from ON_FixedSizePool and ON_SubD code
3983  // use ON_FixedSizePool.ElementFromId and ON_FixedSizePool.ReturnElement.
3984  // Once assigned, m_id is never changed and that allows ON_SubD component
3985  // indices to work.
3986 
3987  // Id assigned to this component. Never modify this value. It is assigned
3988  // by allocators and used to find the component from an ON_COMPONENT_INDEX.
3989  unsigned int m_id = 0;
3990 
3991 private:
3992  // The m_archive_id must be immediately after the m_id field.
3993  mutable unsigned int m_archive_id = 0;
3994 
3995 public:
3996  unsigned short m_level = 0;
3997 
3998 public:
4000 
4001 public:
4002 
4003  //////////////////////////////////////////////////////////////
4004  //
4005  // Saved subdivision point
4006  //
4007  /*
4008  Description:
4009  Set the saved subdivision point.
4010  Parameters:
4011  subdivision_point_type - [in]
4012  Specifies subdivision algorithm.
4013  Use ON_SubD::SubDType::Unset to clear the cache.
4014  subdivision_point - [in]
4015  includes displacement if it exists
4016  Returns:
4017  true if successful
4018  */
4019  bool SetSavedSubdivisionPoint(
4020  ON_SubD::SubDType subd_type,
4021  const double subdivision_point[3]
4022  ) const;
4023 
4024  bool GetSavedSubdivisionPoint(
4025  ON_SubD::SubDType subd_type,
4026  double subdivision_point[3]
4027  ) const;
4028 
4029  ON_SubD::SubDType SavedSubdivisionPointType() const;
4030 
4031  /*
4032  Description:
4033  Clears saved subdivision information for this component.
4034  */
4035  void ClearSavedSubdivisionPoint() const;
4036 
4037  //////////////////////////////////////////////////////////////
4038  //
4039  // displacement applied to subdivision point
4040  //
4041  bool SetDisplacement(
4042  ON_SubD::SubDType subd_type,
4043  const double displacement[3]
4044  );
4045 
4046  bool GetDisplacement(
4047  ON_SubD::SubDType subd_type,
4048  double displacement[3]
4049  ) const;
4050 
4051  ON_SubD::SubDType DisplacementType() const;
4052 
4053  void ClearDisplacement() const;
4054 
4055 protected:
4056  // GetSubdivisionPoint( bUseSavedSubdivisionPoint=true ) can change the value of m_saved_points_flags
4057  // m_saved_points_flags & 0x1F = ON_SubD::SubDType value
4058  // m_saved_points_flags & 0x40 != 0 if m_cache_subd_P is set.
4059  // m_saved_points_flags & 0x80 != 0 if m_displacementV is set.
4060  // GetLimitPoint( bUseSavedLimitPoint=true ) can change the value of m_saved_points_flags
4061  // m_saved_points_flags & 0x20 != 0 if ON_subDVertex.m_limit* values are set.
4062  mutable unsigned char m_saved_points_flags = 0U;
4063 
4064 public:
4065 
4066  // All the faces with the same nonzero value of m_group_id are in the same "group".
4067  // SDK interface on ON_SubD will be added after we get a better idea of how this
4068  // feature will be used.
4069  unsigned int m_group_id = 0U;
4070 
4071 protected:
4072  // GetSubdivisionPoint( bUseSavedSubdivisionPoint=true ) can change the value of m_cache_subd_P
4073  mutable double m_saved_subd_point1[3]; // saved subdivision point
4074 
4075 protected:
4076  // optional displacement applied to standard subdivision point.
4077  double m_displacement_V[3];
4078 
4079 public:
4080  /*
4081  Description:
4082  Pretend ArchiveId() and SetArchiveId() do not exist.
4083  Returns:
4084  The ArchiveId is a value set and used by ON_BinaryArchive Read() and Write()
4085  functions and copy constructors and operator=().
4086  A public interface is supplied because it is not practical to use friends.
4087  Remarks:
4088  A value of ON_UNSET_UINT_INDEX indicates the component is not in use.
4089  */
4090  unsigned int ArchiveId() const
4091  {
4092  return m_archive_id;
4093  }
4094 
4095  void SetArchiveId(
4096  unsigned int archive_id
4097  ) const
4098  {
4099  // m_archive_id is mutable
4100  if ( ON_UNSET_UINT_INDEX != archive_id )
4101  m_archive_id = archive_id;
4102  }
4103 
4104 protected:
4105  void CopyBaseFrom(
4106  const ON_SubDComponentBase* src
4107  );
4108 };
4109 
4110 ////////////////////////////////////////////////////////////////////////////
4111 //
4112 // ON_SubDVertex
4113 //
4114 class ON_SUBD_CLASS ON_SubDVertex : public ON_SubDComponentBase
4115 {
4116 public:
4117  static const ON_SubDVertex Empty;
4118 
4119  bool Write (
4120  class ON_BinaryArchive& archive
4121  ) const;
4122 
4123  static bool Read (
4124  class ON_BinaryArchive& archive,
4125  class ON_SubD& subd,
4126  class ON_SubDVertex*& vertex
4127  );
4128 
4129  /*
4130  Description:
4131  Apply a tranxfomration matrix to vertex geometry information.
4132  Parameters:
4133  bTransformationSavedSubdivisionPoint - [in]
4134  If the transformation is being applied to every vertex, edge and
4135  face in every level of a subdivision object, and the transformation
4136  is an isometry (rotation, translation, ...), a uniform scale, or a
4137  composition of these types, then set
4138  bTransformationSavedSubdivisionPoint = true to apply the
4139  transformation to saved subdivision and saved limit point information.
4140  In all other cases, set bTransformationSavedSubdivisionPoint = false
4141  and any saved subdivision points or saved limit points will be
4142  deleted. When in doubt, pass false.
4143 
4144  xform - [in]
4145  */
4146  bool Transform(
4147  bool bTransformationSavedSubdivisionPoint,
4148  const class ON_Xform& xform
4149  );
4150 
4151  bool SetLocation(
4152  ON_3dPoint location,
4153  bool bClearNeighborhoodCache
4154  );
4155 
4156 
4157  ON_BoundingBox ControlNetBoundingBox() const;
4158  ON_BoundingBox LimitSurfaceBoundingBox(
4159  const ON_SubD& subd
4160  ) const;
4161 
4162 public:
4163  ON_COMPONENT_INDEX ComponentIndex() const;
4164  ON_SubDComponentPtr ComponentPtr() const;
4165 
4166 public:
4167  const class ON_SubDVertex* m_prev_vertex = nullptr; // linked list of vertices on this level
4168  const class ON_SubDVertex* m_next_vertex = nullptr; // linked list of vertices on this level
4169 
4170 public:
4171  ON_SubD::VertexTag m_vertex_tag = ON_SubD::VertexTag::Unset;
4172 
4173 
4174 private:
4175  //ON_SubD::VertexEdgeOrder m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
4176  unsigned char m_reserved1 = 0;
4177  unsigned short m_reserved2 = 0;
4178  unsigned int m_reserved3 = 0;
4179 
4180 public:
4181  unsigned short m_edge_count = 0;
4182  unsigned short m_face_count = 0;
4183 
4184  unsigned short m_edge_capacity = 0;
4185  unsigned short m_face_capacity = 0;
4186 
4187 public:
4188  // Array of m_edge_count edges.
4189  // m_edge[i].EdgeDirection() indicates which edge end is located at this vertex
4190  // If m_edge_capacity > 0, m_edge_capacity is the number of elements that
4191  // may be used in m_edges[].
4192  class ON_SubDEdgePtr* m_edges = nullptr;
4193 
4194  // Array of m_face_count faces.
4195  // If m_face_capacity > 0, m_face_capacity is the number of elements that
4196  // may be used in m_faces[].
4197  const class ON_SubDFace** m_faces = nullptr;
4198 
4199 public:
4200  double m_P[3]; // vertex location
4201 
4202 private:
4203  // Cached limit point and limit normal
4204  // GetLimitPoint( bUseSavedLimitPoint=true ) can change the value of m_limitP_type
4205  // If the limit point is set and vertex has a single sector, then
4206  // m_limit_point.m_sector_face = nullptr and m_limit_point.m_next_sector_limit_point = nullptr.
4207  // If the limit point is set and vertex has a multiple sectors, then
4208  // m_limit_point.m_sector_face = first face in the sector.
4209  // If multiple limit points are set, then are in a linked list
4210  // traversed using the ON_SubDSectorLimitPointm_next_sector_limit_point.
4211  // The second and any additional limit points are managed by a fixed size pool.
4212  // Calling ClearLimitPoint() will return these to the pool.
4213  mutable ON_SubDSectorLimitPoint m_limit_point = ON_SubDSectorLimitPoint::Unset;
4214 
4215 public:
4216  static const unsigned int MaximumEdgeCount;
4217  static const unsigned int MaximumFaceCount;
4218 
4219  static int CompareUnorderedEdges(
4220  const ON_SubDVertex* a,
4221  const ON_SubDVertex* b
4222  );
4223 
4224  static int CompareUnorderedFaces(
4225  const ON_SubDVertex* a,
4226  const ON_SubDVertex* b
4227  );
4228 
4229  static int CompareUnorderedEdgesAndFaces(
4230  const ON_SubDVertex* a,
4231  const ON_SubDVertex* b
4232  );
4233 
4234  ///*
4235  //Description:
4236  // Sort the m_edges[] and m_faces[] arrays so radial groups are together.
4237  // After the sorting is completed, m_vertex_edge_order is set to recored
4238  // the current sorting state and its value is returned.
4239  // The sorting is done unconditionally.
4240  //*/
4241  //ON_SubD::VertexEdgeOrder SortEdges();
4242 
4243  unsigned int EdgeCount(
4244  ON_SubD::EdgeTag edge_tag
4245  ) const;
4246 
4247  unsigned int EdgeCount() const;
4248 
4249  const class ON_SubDEdge* Edge(
4250  unsigned int i
4251  ) const;
4252 
4253  const ON_SubDEdgePtr EdgePtr(
4254  unsigned int i
4255  ) const;
4256 
4257  ON__UINT_PTR EdgeDirection(
4258  unsigned int i
4259  ) const;
4260 
4261  unsigned int EdgeArrayIndex(
4262  const ON_SubDEdge* edge
4263  ) const;
4264 
4265  unsigned int FaceCount() const;
4266 
4267  const class ON_SubDFace* Face(
4268  unsigned int i
4269  ) const;
4270 
4271  unsigned int FaceArrayIndex(
4272  const ON_SubDFace* face
4273  ) const;
4274 
4275  ON_SubD::FacetType FirstFaceFacetType() const;
4276 
4277  /*
4278  Returns
4279  true if m_vertex_tag is ON_SubD::VertexTag::Crease, ON_SubD::VertexTag::Corner or ON_SubD::VertexTag::Dart.
4280  */
4281  bool IsTagged() const;
4282 
4283  ///*
4284  //Parameters:
4285  // subd_type - [in]
4286  // Specifies subdivision algorithm
4287  // vertex_tag_filter - [in]
4288  // If vertex_tag is not ON_SubD::VertexTag::Unset and vertex_tag != m_vertex_tag,
4289  // then false is returned. This parameter can be used when a smooth or crease
4290  // vertex is explicity required.
4291  // bTestFaces - [in]
4292  // If true, and the edge and face count tests succeed, then the faces in the
4293  // vertex m_faces[] array are tested to insure they are
4294  // quads (ccquad subdivisiontype) or tris (lwtri subdivisiontype).
4295  //Returns:
4296  // If m_vertex_tag is ON_SubD::Vertex::Tag::smooth,
4297  // and the number of edges = number of faces,
4298  // and there are 4 (ccquad subdivisiontype) or 6 (lwtri subdivisiontype) edges,
4299  // and bTestFaces is false or the faces pass the face test,
4300  // then true is returned.
4301  //
4302  // If m_vertex_tag is ON_SubD::Vertex::Tag::crease,
4303  // and the number of edges = 1 + number of faces,
4304  // and there are 3 (ccquad subdivisiontype) or 4 (lwtri subdivisiontype) edges,
4305  // and bTestFaces is false or the faces pass the face test,
4306  // then true is returned.
4307 
4308  // In all other cases, false is returned.
4309  //*/
4310  //bool IsOrdinary(
4311  // ON_SubD::SubDType subd_type,
4312  // ON_SubD::VertexTag vertex_tag_filter,
4313  // bool bTestFaces
4314  // ) const;
4315 
4316 
4317  /*
4318  Returns:
4319  True if m_vertex_tag is ON_SubD::VertexTag::Smooth.
4320  */
4321  bool IsSmooth() const;
4322 
4323  /*
4324  Returns:
4325  True if m_vertex_tag is ON_SubD::VertexTag::Crease.
4326  */
4327  bool IsCrease() const;
4328 
4329  /*
4330  Returns:
4331  True if m_vertex_tag is ON_SubD::VertexTag::Corner.
4332  */
4333  bool IsCorner() const;
4334 
4335  /*
4336  Returns:
4337  True if m_vertex_tag is ON_SubD::VertexTag::Dart.
4338  */
4339  bool IsDart() const;
4340 
4341  /*
4342  Returns:
4343  True if m_vertex_tag is ON_SubD::VertexTag::Smooth or ON_SubD::VertexTag::Crease.
4344  */
4345  bool IsSmoothOrCrease() const;
4346 
4347  /*
4348  Returns:
4349  True if m_vertex_tag is ON_SubD::VertexTag::Crease or ON_SubD::VertexTag::Corner.
4350  */
4351  bool IsCreaseOrCorner() const;
4352 
4353  /*
4354  Returns:
4355  True if m_vertex_tag is ON_SubD::VertexTag::Crease or ON_SubD::VertexTag::Corner or ON_SubD::VertexTag::Dart.
4356  */
4357  bool IsCreaseOrCornerOrDart() const;
4358 
4359  /*
4360  Returns:
4361  True if m_vertex_tag is ON_SubD::VertexTag::Smooth or ON_SubD::VertexTag::Dart.
4362  */
4363  bool IsSmoothOrDart() const;
4364 
4365  /*
4366  Description:
4367  A "standard" vertex is one where the standard subdivsion matrix for that vertex
4368  can be used to calculate the subdivision point.
4369  This function is desinged to be useful for testing and debugging code when
4370  a certain situation is expected to exist. It is not used for evaluation
4371  because it is too slow.
4372 
4373  Returns:
4374  True if the subdivison point of the vertex can be calulated using the standard
4375  subdivion matrix for the vertex type and face count.
4376 
4377  Remarks:
4378  If the vertex is tagged and has multiple sectors, like an interior
4379  crease or corner vertex, then this function will return false.
4380  In this situation, it is possible that the vertex, as the center of a
4381  sector, is standard.
4382  */
4383  bool IsStandard(
4384  ON_SubD::SubDType subd_type
4385  ) const;
4386 
4387  /*
4388  Parameters:
4389  subdivision_point_type - [in]
4390  Selects subdivision algorithm. Must be either
4391  ON_SubD::SubDType::TriLoopWarren or ON_SubD::SubDType::QuadCatmullClark.
4392  bUseSavedSubdivisionPoint - [in]
4393  If there is a saved subdivision point and bUseSavedSubdivisionPoint
4394  is true, then the saved value is returned.
4395  subdivision_point - [out]
4396  Returns:
4397  true if successful
4398  */
4399  bool GetSubdivisionPoint(
4400  ON_SubD::SubDType subdivision_point_type,
4401  bool bUseSavedSubdivisionPoint,
4402  double subdivision_point[3]
4403  ) const;
4404 
4405  /*
4406  Parameters:
4407  facet_type - [in]
4408  Selects subdivision algorithm.
4409  bUseSavedLimitPoint - [in]
4410  If there is a saved limit point and normal and bUseSavedLimitPoint
4411  is true, then the saved value is used.
4412  limit_point - [out]
4413  Returns:
4414  true if successful
4415  */
4416  bool GetLimitPoint(
4417  ON_SubD::SubDType subd_type,
4418  const ON_SubDFace* sector_face,
4419  bool bUseSavedLimitPoint,
4420  class ON_SubDSectorLimitPoint& limit_point
4421  ) const;
4422 
4423  /*
4424  Description:
4425  Save limit point and limit normal for future use.
4426  Parameters:
4427  subd_type - [in]
4428  limit_point - [in]
4429  limit_normal - [in]
4430  Returns:
4431  true if successful
4432  */
4433  bool SetSavedLimitPoint(
4434  ON_SubD::SubDType subd_type,
4435  const ON_SubDSectorLimitPoint limit_point
4436  ) const;
4437 
4438  void ClearSavedLimitPoints() const;
4439 
4440  /*
4441  Returns:
4442  ON_SubD::SubDType::TriLoopWarren
4443  The vertex limit point and normal are saved for Loop trianglular subdivision.
4444  ON_SubD::SubDType::QuadCatmullClark
4445  The vertex limit point and normal are saved for Catmull-Clark quad subdivision.
4446  ON_SubD::SubDType::Unset
4447  The vertex limit point and normal are not saved.
4448  */
4449  ON_SubD::SubDType SavedLimitPointType() const;
4450 
4451  /*
4452  Description:
4453  Report what type of facet or facets use this vertex.
4454  */
4455  ON_SubD::VertexFacetType VertexFacetTypes() const;
4456 
4457 
4458  /*
4459  Description:
4460  Call this function if the vertex is modified and it will clear any
4461  cached subdivision information that needs to be recalculated.
4462  */
4463  void VertexModifiedNofification() const;
4464 
4465 private:
4466  static bool GetQuadPoint(
4467  const class ON_SubDVertex* vertex, // smooth or dart
4468  bool bUseSavedSubdivisionPoint,
4469  double vertex_point[3]
4470  );
4471 
4472  static bool GetTriPoint(
4473  const class ON_SubDVertex* vertex, // smooth or dart
4474  bool bUseSavedSubdivisionPoint,
4475  double vertex_point[3]
4476  );
4477 
4478  static unsigned int GetFacePointSum(
4479  const ON_SubDFace* face,
4480  const ON_SubDVertex* vertex,
4481  double* facePsum // sum of points that are not immediately adjacent to vertex
4482  );
4483 
4484 
4485  /*
4486  Description:
4487  Used for smooth and dart vertices when there are faces
4488  that use the vertex have different numbers of sides.
4489  This typically happen when a quad subd control net is
4490  being subdivided for the first time.
4491  Parameters:
4492  vertex - [in]
4493  vertex_point - [out]
4494  Returns:
4495  true if successful
4496  */
4497  static bool GetGeneralQuadSubdivisionPoint(
4498  const class ON_SubDVertex* vertex,
4499  bool bUseSavedSubdivisionPoint,
4500  double vertex_point[3]
4501  );
4502 
4503 private:
4504  friend class ON_SubDArchiveIdMap;
4505  void CopyFrom(
4506  const ON_SubDVertex* src,
4507  bool bCopyEdgeArray,
4508  bool bCopyFaceArray,
4509  bool bCopyLimitPointList
4510  );
4511 };
4512 
4513 //////////////////////////////////////////////////////////////////////////
4514 //
4515 // ON_SubDEdge
4516 //
4517 class ON_SUBD_CLASS ON_SubDEdge : public ON_SubDComponentBase
4518 {
4519 public:
4520  static const ON_SubDEdge Empty;
4521 
4522  bool Write (
4523  class ON_BinaryArchive& archive
4524  ) const;
4525 
4526  static bool Read (
4527  class ON_BinaryArchive& archive,
4528  class ON_SubD& subd,
4529  class ON_SubDEdge*& edge
4530  );
4531 
4532  /*
4533  Description:
4534  Apply a tranxfomration matrix to vertex geometry information.
4535 
4536  Parameters:
4537  bTransformationSavedSubdivisionPoint - [in]
4538  If the transformation is being applied to every vertex, edge and
4539  face in every level of a subdivision object, and the transformation
4540  is an isometry (rotation, translation, ...), a uniform scale, or a
4541  composition of these types, then set
4542  bTransformationSavedSubdivisionPoint = true to apply the
4543  transformation to saved subdivision and saved limit point information.
4544  In all other cases, set bTransformationSavedSubdivisionPoint = false
4545  and any saved subdivision points or saved limit points will be
4546  deleted. When in doubt, pass false.
4547 
4548  xform - [in]
4549  */
4550  bool Transform(
4551  bool bTransformationSavedSubdivisionPoint,
4552  const class ON_Xform& xform
4553  );
4554 
4555  ON_BoundingBox ControlNetBoundingBox() const;
4556  ON_BoundingBox LimitSurfaceBoundingBox(
4557  const ON_SubD& subd
4558  ) const;
4559 
4560 
4561  /*
4562  Description:
4563  Call this function if the edge is modified and it will clear any
4564  cached subdivision information that needs to be recalculated.
4565  */
4566  void EdgeModifiedNofification() const;
4567 
4568 
4569 public:
4570  ON_COMPONENT_INDEX ComponentIndex() const;
4571  ON_SubDComponentPtr ComponentPtr() const;
4572 
4573 public:
4574  const class ON_SubDEdge* m_prev_edge = nullptr; // linked list of edges on this level
4575  const class ON_SubDEdge* m_next_edge = nullptr; // linked list of edges on this level
4576 
4577 public:
4578  // When checking the edge tag, it is important to consider what
4579  // should happen in the ON_SubD::EdgeTag::X case. It is strongly
4580  // suggested that you use the member functions ON_SubDEdge::IsSmooth()
4581  // and ON_SubDEdge::IsCrease() instead of comparing m_edge_tag to
4582  // ON_SubD::EdgeTag values.
4583  ON_SubD::EdgeTag m_edge_tag = ON_SubD::EdgeTag::Unset;
4584 
4585 private:
4586  unsigned char m_reserved1 = 0;
4587  unsigned short m_reserved2 = 0;
4588 
4589 public:
4590  // Array of m_face_count faces.
4591  //
4592  // The first two are in m_face2[0] and m_face2[1].
4593  // When m_face_count > 3, the third and additional faces
4594  // are in m_facex[0], ..., m_facex[m_face_count-3];
4595  //
4596  // The value of ON_SubDFacePtr.FaceDirection() is 0 if the
4597  // edge's natural orientation from m_vertex[0] to m_vertex[1]
4598  // agrees with the face's boundary orientation.
4599  //
4600  // The value of ON_SubDFacePtr.FaceDirection() is 1 if the
4601  // edge's natural orientation from m_vertex[0] to m_vertex[1]
4602  // is opposited the face's boundary orientation.
4603  static const unsigned int MaximumFaceCount;
4604  unsigned short m_face_count = 0;
4605  unsigned short m_facex_capacity = 0;
4606  ON_SubDFacePtr m_face2[2];
4607  ON_SubDFacePtr* m_facex = nullptr;
4608 
4609  // m_vertex[0] = vertex at the start of the edge.
4610  // m_vertex[1] = vertex at the end of the edge.
4611  const class ON_SubDVertex* m_vertex[2];
4612 
4613  // If the value of vertex->m_vertex_tag is not ON_SubD::VertexTag::Smooth,
4614  // then that vertex is "tagged".
4615  //
4616  // If the value of m_edge_tag is ON_SubD::EdgeTag::Crease,
4617  // then m_sector_coefficient[] should be {0,0}.
4618  // In any case m_sector_coefficient[] values are ignored and the
4619  // midpoint of the edge is the location of the edge.s subdivision point.
4620  // The edge's subdivision vertex will be tagged as ON_SubD::VertexTag::Crease
4621  // and both subdivision edges will be tagged as ON_SubD::EdgeTag::Crease.
4622  //
4623  // If the value of m_edge_tag is ON_SubD::EdgeTag::Smooth
4624  // and neither end vertex is tagged, then m_sector_coefficient[] should be {0,0}.
4625  // In any case m_sector_coefficient[] values are ignored on smooth edges
4626  // with smooth vertices at both ends.
4627  // The edge's subdivision vertex will be tagged as ON_SubD::VertexTag::Smooth
4628  // and both subdivision edges will be tagged as ON_SubD::EdgeTag::Smooth.
4629  //
4630  // If the value of m_edge_tag is ON_SubD::EdgeTag::Smooth and
4631  // exactly one end vertex is tagged, then the m_sector_coefficient[]
4632  // value for the tagged end is calculated by ON_SubDSectorType::SectorWeight().
4633  // tagged_weight*tagged_vertex + (1.0 - tagged_weight)*untagged_vertex
4634  // is used when combining the edge ends.
4635  // The edge's subdivision vertex will be tagged as ON_SubD::VertexTag::Smooth
4636  // and both subdivision edges will be tagged as ON_SubD::EdgeTag::Smooth.
4637  //
4638  // If the value of m_edge_tag is ON_SubD::EdgeTag::X, then the edge
4639  // must have exactly two neighboring faces,
4640  // both vertices must be tagged and the m_sector_coefficient[]
4641  // values are calculated by ON_SubDSectorType::SectorWeight().
4642  // When the edge is subdivided, the midpoint of the edge is the
4643  // location of the edge.s subdivision point.
4644  // The edge's subdivision vertex will be tagged as ON_SubD::VertexTag::Smooth
4645  // and both subdivision edges will be tagged as ON_SubD::EdgeTag::Smooth.
4646  //
4647  // If the value of m_edge_tag is ON_SubD::EdgeTag::Smooth
4648  // and both end vertices are tagged, that is a severe error
4649  // condition and the edge is subdivided at its midpoint.
4650  //
4651  // If the value of m_edge_tag is ON_SubD::EdgeTag::X
4652  // and both end vertices are not tagged, that is a severe error
4653  // condition and the edge is subdivided at its midpoint.
4654  double m_sector_coefficient[2];
4655 
4656  // If m_edge_tag is not ON_SubD::EdgeTag::Sharp, then m_sharpness is ignored.
4657  // If m_edge_tag is ON_SubD::EdgeTag::Sharp, then m_sharpness controls how hard/soft
4658  // the edge appears.
4659  // The behavior of a "sharp" edge with m_sharpness = 1 is identical to a crease edge.
4660  // A "sharp" edge with m_sharpness = 0 is identical to a smooth edge.
4661  // For this reason, m_sharpness must be > 0 and < 1.
4662  double m_sharpness = 0.0;
4663 
4664 public:
4665  unsigned int FaceCount() const;
4666 
4667  ON_SubDFacePtr FacePtr(
4668  unsigned int i
4669  ) const;
4670 
4671  ON_SubDFacePtr FacePtr(
4672  const class ON_SubDFace* f
4673  ) const;
4674 
4675  const class ON_SubDFace* Face(
4676  unsigned int i
4677  ) const;
4678 
4679  ON__UINT_PTR FaceDirection(
4680  unsigned int i
4681  ) const;
4682 
4683  unsigned int FaceArrayIndex(
4684  const class ON_SubDFace* f
4685  ) const;
4686 
4687  /*
4688  Description:
4689  Expert user tool to remove a face from the edges's face array.
4690  Remarks:
4691  Does not modify the face. If the edge is referenced in the face's edge array,
4692  then the edge must be removed from the face's edge array.
4693  */
4694  bool RemoveFaceFromArray(
4695  const ON_SubDFace* f
4696  );
4697 
4698  /*
4699  Description:
4700  Expert user tool to remove a face from the edges's face array.
4701  Remarks:
4702  Does not modify the face. If the edge is referenced in the face's edge array,
4703  then the edge must be removed from the face's edge array.
4704  */
4705  bool RemoveFaceFromArray(
4706  unsigned int i,
4707  ON_SubDFacePtr& removed_face
4708  );
4709 
4710  /*
4711  Description:
4712  Expert user tool to add a face from the edges's face array.
4713  Remarks:
4714  Does not modify the face. If the edge is not referenced in the face's edge array,
4715  then the edge must be inserted in the correct location in the faces array.
4716  If you are creating a non-manifold SubD, you must first reserve m_facex[]
4717  capacity by calling ON_SubD::GrowEdgeFaceArray().
4718  */
4719  bool AddFaceToArray(
4720  ON_SubDFacePtr face_ptr
4721  );
4722 
4723  const class ON_SubDVertex* Vertex(
4724  unsigned int i
4725  ) const;
4726 
4727  /*
4728  Description:
4729  Return the vertex at the other end of the edge.
4730  Parameters:
4731  vertex - [in]
4732  A vertex referenced in the edge's m_vertex[] array.
4733  Returns:
4734  If vertex is not nullptr and exactly one of m_vertex[] is equal to vertex,
4735  then the other m_vertex[] pointer is returned.
4736  In any other case, nullptr is returned.
4737  */
4738  const ON_SubDVertex* OtherEndVertex(
4739  const ON_SubDVertex* vertex
4740  ) const;
4741 
4742  /*
4743  Description:
4744  Return the neighboring face.
4745  Parameters:
4746  face - [in]
4747  A face referenced in the edge's m_face2[] array.
4748  bStopAtCrease - [in]
4749  If true and if m_edge_tag = ON_SubD::EdgeTag::Crease,
4750  then nullptr is returned.
4751  Returns:
4752  If the m_face_count = 2,
4753  m_edge_tag is smooth or x or passes the crease tag test,
4754  one of m_face2[0,1] points a face, then
4755  the neighboring face is returned.
4756  In any other case, nullptr is returned.
4757  */
4758  const ON_SubDFace* NeighborFace(
4759  const ON_SubDFace* face,
4760  bool bStopAtCrease
4761  ) const;
4762 
4763  /*
4764  Description:
4765  Return the neighboring face.
4766  Parameters:
4767  face - [in]
4768  A face referenced in the edge's m_face2[] array.
4769  bStopAtCrease - [in]
4770  If true and if m_edge_tag = ON_SubD::EdgeTag::Crease,
4771  then nullptr is returned.
4772  Returns:
4773  If the m_face_count = 2,
4774  m_edge_tag is smooth or x or passes the crease tag test,
4775  one of m_face2[0,1] points a face, then
4776  the neighboring face is returned.
4777  In any other case, ON_SubDFacePtr::Null is returned.
4778  */
4779  const ON_SubDFacePtr NeighborFacePtr(
4780  const ON_SubDFace* face,
4781  bool bStopAtCrease
4782  ) const;
4783 
4784 
4785 
4786  /*
4787  Returns:
4788  True if m_edge_tag is ON_SubD::EdgeTag::Smooth.
4789  bEdgeTagXresult if m_edge_tag is ON_SubD::EdgeTag::X.
4790  False in all other cases.
4791  */
4792  bool IsSmooth(
4793  bool bEdgeTagXresult
4794  ) const;
4795 
4796  /*
4797  Returns:
4798  True if m_edge_tag is ON_SubD::EdgeTag::Crease.
4799  bEdgeTagXresult if m_edge_tag is ON_SubD::EdgeTag::X.
4800  False in all other cases.
4801  */
4802  bool IsCrease(
4803  bool bEdgeTagXresult
4804  ) const;
4805 
4806  /*
4807  Returns:
4808  0: end vertices are not tagged as darts
4809  1: one end vertex is tagged as a dart.
4810  2: both end vertices are tagged as a darts.
4811  */
4812  unsigned int DartCount() const;
4813 
4814  /*
4815  Returns:
4816  bitwise or of applicable ON_ComponentAttributes::EdgeFlags values.
4817  */
4818  unsigned int EdgeFlags() const;
4819 
4820  /*
4821  Parameters:
4822  subdivision_point_type - [in]
4823  Selects subdivision algorithm. Must be either
4824  ON_SubD::SubDType::TriLoopWarren or ON_SubD::SubDType::QuadCatmullClark.
4825  bUseSavedSubdivisionPoint - [in]
4826  If there is a saved subdivision point and bUseSavedSubdivisionPoint
4827  is true, then the saved value is returned.
4828  subdivision_point - [out]
4829  Returns:
4830  true if successful
4831  */
4832  bool GetSubdivisionPoint(
4833  ON_SubD::SubDType subdivision_point_type,
4834  bool bUseSavedSubdivisionPoint,
4835  double subdivision_point[3]
4836  ) const;
4837 
4838  /*
4839  Parameters:
4840  edge_vertex_index - [in]
4841  0 or 1
4842  edge_ptr0 - [out]
4843  edge_ptr1 - [out]
4844  Crease edges that bound the sector containing this edge.
4845  The direction value of the edge pointer identifies the end
4846  of the sector boundary edge this->at m_vertex[edge_vertex_index].
4847  Returns:
4848  Number of faces in the sector.
4849  */
4850  unsigned int GetSectorBoundaryEdges(
4851  unsigned int edge_vertex_index,
4852  ON_SubDEdgePtr* edge_ptr0,
4853  ON_SubDEdgePtr* edge_ptr1
4854  ) const;
4855 
4856  /*
4857  Returns:
4858  0: m_vertex[0] is tagged and m_vertex[1] is not tagged.
4859  1: m_vertex[0] is tagged and m_vertex[1] is not tagged.
4860  2: m_vertex[0] and m_vertex[1] are both tagged.
4861  3: neither m_vertex[0] nor m_vertex[1] is tagged.
4862  */
4863  unsigned int TaggedEndIndex() const;
4864 
4865 private:
4866  static unsigned int GetFacePointSum(
4867  const ON_SubDFace* face,
4868  const ON_SubDEdge* edge,
4869  double* facePsum // sum of face vertex points not on the edge
4870  );
4871 
4872 private:
4873  friend class ON_SubDArchiveIdMap;
4874  void CopyFrom(
4875  const ON_SubDEdge* src,
4876  bool bReverseEdge,
4877  bool bCopyVertexArray,
4878  bool bCopyFaceArray
4879  );
4880 };
4881 
4882 //////////////////////////////////////////////////////////////////////////
4883 //
4884 // ON_SubDFace
4885 //
4886 class ON_SUBD_CLASS ON_SubDFace : public ON_SubDComponentBase
4887 {
4888 public:
4889  static const ON_SubDFace Empty;
4890 
4891  bool Write (
4892  class ON_BinaryArchive& archive
4893  ) const;
4894 
4895  static bool Read (
4896  class ON_BinaryArchive& archive,
4897  class ON_SubD& subd,
4898  class ON_SubDFace*& face
4899  );
4900 
4901  /*
4902  Description:
4903  Apply a tranxfomration matrix to vertex geometry information.
4904 
4905  Parameters:
4906  bTransformationSavedSubdivisionPoint - [in]
4907  If the transformation is being applied to every vertex, edge and
4908  face in every level of a subdivision object, and the transformation
4909  is an isometry (rotation, translation, ...), a uniform scale, or a
4910  composition of these types, then set
4911  bTransformationSavedSubdivisionPoint = true to apply the
4912  transformation to saved subdivision and saved limit point information.
4913  In all other cases, set bTransformationSavedSubdivisionPoint = false
4914  and any saved subdivision points or saved limit points will be
4915  deleted. When in doubt, pass false.
4916 
4917  xform - [in]
4918  */
4919  bool Transform(
4920  bool bTransformationSavedSubdivisionPoint,
4921  const class ON_Xform& xform
4922  );
4923 
4924  ON_BoundingBox ControlNetBoundingBox() const;
4925  ON_BoundingBox LimitSurfaceBoundingBox(
4926  const ON_SubD& subd
4927  ) const;
4928 
4929 
4930  ON_COMPONENT_INDEX ComponentIndex() const;
4931  ON_SubDComponentPtr ComponentPtr() const;
4932 
4933  /*
4934  Description:
4935  Call this function if the face is modified and it will clear any
4936  cached subdivision information that needs to be recalculated.
4937  */
4938  void FaceModifiedNofification() const;
4939 
4940 
4941 public:
4942  const class ON_SubDFace* m_prev_face = nullptr; // linked list of faces on this level
4943  const class ON_SubDFace* m_next_face = nullptr; // linked list of faces on this level
4944 
4945 public:
4946  unsigned int m_zero_face_id = 0; // id of level zero face
4947  unsigned int m_parent_face_id = 0; // id of previous level face
4948 
4949 private:
4950  unsigned int m_reserved = 0; // id of previous level face
4951 
4952 public:
4953  // Array of m_edge_count edges that form the boundary of the face.
4954  // The edges are in ordered to form a continuous loop.
4955  //
4956  // The first four are in m_edge4[0], ..., m_edge4[3].
4957  // When m_edge_count > 4, the fifth and additional edges
4958  // are in m_edgex[0], ..., m_edgex[m_edge_count-5];
4959  //
4960  // The value of ON_SubDEdgePtr.EdgeDirection() is 0 if the
4961  // edge's natural orientation from m_vertex[0] to m_vertex[1]
4962  // agrees with the face's boundary orientation.
4963  //
4964  // The value of ON_SubDEdgePtr.EdgeDirection() is 1 if the
4965  // edge's natural orientation from m_vertex[0] to m_vertex[1]
4966  // is opposited the face's boundary orientation.
4967  static const unsigned int MaximumEdgeCount;
4968  unsigned short m_edge_count = 0;
4969  unsigned short m_edgex_capacity = 0;
4970 
4971  ON_SubDEdgePtr m_edge4[4];
4972  ON_SubDEdgePtr* m_edgex = nullptr;
4973 
4974 public:
4975  unsigned int EdgeCount() const;
4976 
4977  ON_SubDEdgePtr EdgePtr(
4978  unsigned int i
4979  ) const;
4980 
4981  ON_SubDEdgePtr EdgePtr(
4982  const class ON_SubDEdge* e
4983  ) const;
4984 
4985  const class ON_SubDVertex* Vertex(
4986  unsigned int i
4987  ) const;
4988 
4989  unsigned int VertexIndex(
4990  const ON_SubDVertex* vertex
4991  ) const;
4992 
4993  const class ON_SubDEdge* Edge(
4994  unsigned int i
4995  ) const;
4996 
4997  ON__UINT_PTR EdgeDirection(
4998  unsigned int i
4999  ) const;
5000 
5001  unsigned int EdgeArrayIndex(
5002  const ON_SubDEdge* e
5003  ) const;
5004 
5005  /*
5006  Description:
5007  Expert user tool to remove an edge from the face's edge array.
5008  Remarks:
5009  Does not modify the edge. If the face is referenced in the edge's face array,
5010  then the face must be removed from the edge's face array.
5011  */
5012  bool RemoveEdgeFromArray(
5013  const ON_SubDEdge* e
5014  );
5015 
5016  /*
5017  Description:
5018  Expert user tool to remove an edge from the face's edge array.
5019  Remarks:
5020  Does not modify the edge. If the face is referenced in the edge's face array,
5021  then the face must be removed from the edge's face array.
5022  */
5023  bool RemoveEdgeFromArray(
5024  unsigned int i,
5025  ON_SubDEdgePtr& removed_edge
5026  );
5027 
5028  /*
5029  Description:
5030  Expert user tool to replace one edge with another in the face's edge array.
5031  Parameters:
5032  edge_to_remove - [in]
5033  edge_to_insert - [in]
5034  The inserted edge is assigned the same boundary orientation as the
5035  removed edge.
5036  Remarks:
5037  Does not modify the edge. The corresponding reference to this face must
5038  be removed from the first edge and added to the second edge.
5039  */
5040  bool ReplaceEdgeInArray(
5041  unsigned int fei0,
5042  ON_SubDEdge* edge_to_remove,
5043  ON_SubDEdge* edge_to_insert
5044  );
5045 
5046  /*
5047  Description:
5048  Expert user tool to replace one edge with another in the face's edge array.
5049  Parameters:
5050  edge_to_remove - [in]
5051  edge_to_insert - [in]
5052  The inserted edge is assigned the same boundary orientation specified
5053  in edgeptr_to_insert.
5054  Remarks:
5055  Does not modify the edge. The corresponding reference to this face must
5056  be removed from the first edge and added to the second edge.
5057  */
5058  bool ReplaceEdgeInArray(
5059  unsigned int fei0,
5060  ON_SubDEdge* edge_to_remove,
5061  ON_SubDEdgePtr edgeptr_to_insert
5062  );
5063 
5064  const ON_SubDEdge* PrevEdge(
5065  const ON_SubDEdge* edge
5066  ) const;
5067 
5068  const ON_SubDEdge* NextEdge(
5069  const ON_SubDEdge* edge
5070  ) const;
5071 
5072  unsigned int PrevEdgeArrayIndex(
5073  unsigned int edge_array_index
5074  ) const;
5075 
5076  unsigned int NextEdgeArrayIndex(
5077  unsigned int edge_array_index
5078  ) const;
5079 
5080  /*
5081  Description:
5082  If the face is a quad, get the opposite corner vertex.
5083  Parameters:
5084  vertex - [in]
5085  a vertex on this face.
5086  Returns:
5087  If the face is a quad and vertex is a vertex of the face, then
5088  the vertex on the opposite corner is returned.
5089  Otherwise, nullptr is returned.
5090  */
5091  const ON_SubDVertex* QuadOppositeVertex(
5092  const ON_SubDVertex* vertex
5093  ) const;
5094 
5095  /*
5096  Description:
5097  If the face is a quad, get the opposite side edge.
5098  Parameters:
5099  edge - [in]
5100  an edge on this face.
5101  Returns:
5102  If the face is a quad and edge is an edge of the face, then
5103  the edge on the opposite side is returned.
5104  Otherwise, nullptr is returned.
5105  */
5106  const ON_SubDEdge* QuadOppositeEdge(
5107  const ON_SubDEdge* edge
5108  ) const;
5109 
5110  ///*
5111  //Parameters:
5112  // subd_type - [in]
5113  // bTestFaces - [in]
5114  // If true, then false is returned if any neighboring face is not
5115  // a quad (ccquad subdivision type) or tri (lwtri subdivsion type).
5116  //*/
5117  //bool IsOrdinary(
5118  // ON_SubD::SubDType subd_type,
5119  // bool bTestFaces
5120  // ) const;
5121 
5122  /*
5123  Parameters:
5124  subdivision_point_type - [in]
5125  Selects subdivision algorithm. Must be either
5126  ON_SubD::SubDType::TriLoopWarren or ON_SubD::SubDType::QuadCatmullClark.
5127  bUseSavedSubdivisionPoint - [in]
5128  If there is a saved subdivision point and bUseSavedSubdivisionPoint
5129  is true, then the saved value is returned.
5130  subdivision_point - [out]
5131  The average of the face vertex locations.
5132  Returns:
5133  true if successful
5134  */
5135  bool GetSubdivisionPoint(
5136  ON_SubD::SubDType subdivision_point_type,
5137  bool bUseSavedSubdivisionPoint,
5138  double subdivision_point[3]
5139  ) const;
5140 
5141  /*
5142  Description:
5143  Reverse the order and orientation of the edges that form
5144  the boundary of this face.
5145  */
5146  bool ReverseEdgeList();
5147 
5148  /*
5149  Description:
5150  Get the bicubic b-spline control points for the limit surface.
5151  The corresponding knots are uniform.
5152  Parameters:
5153  vertex - [in]
5154  limit_surface_cv_stride0 - [int]
5155  limit_surface_cv_stride1 - [out]
5156  limit_surface_cv - [out]
5157  control points for a cubic spline surface
5158  CV[i][j][k] = limit_surface_cv[i*limit_bspline_cv_stride0 + j*limit_bspline_cv_stride1 + k]
5159  0 <= i < 4, 0 <= j < 4, 0 <= k < 3
5160  Returns:
5161  true if successful
5162  false if the limit surface for this face is not a cubic surface
5163  Remarks:
5164  The knots for the bicubic b-spline surface are uniform.
5165  */
5166  bool GetQuadLimitSurface(
5167  size_t limit_surface_cv_stride0,
5168  size_t limit_surface_cv_stride1,
5169  double* limit_surface_cv
5170  ) const;
5171 
5172  bool GetQuadLimitSurface(
5173  class ON_NurbsSurface& limit_surface
5174  ) const;
5175 
5176  bool GetQuadLimitSurface(
5177  class ON_BezierSurface& limit_surface
5178  ) const;
5179 
5180 private:
5181  friend class ON_SubDArchiveIdMap;
5182  void CopyFrom(
5183  const ON_SubDFace* src,
5184  bool bCopyEdgeArray
5185  );
5186 };
5187 
5188 //////////////////////////////////////////////////////////////////////////
5189 //
5190 // ON_SubDVertexArray
5191 //
5192 class ON_SUBD_CLASS ON_SubDVertexArray
5193 {
5194 public:
5195  ON_SubDVertexArray(
5196  const ON_SubD& subd
5197  );
5198  ON_SubDVertexArray() = default;
5199  ON_SubDVertexArray(const ON_SubDVertexArray&) = default;
5200  ON_SubDVertexArray& operator=(const ON_SubDVertexArray&) = default;
5201 
5202 #if defined(ON_HAS_RVALUEREF)
5203  // rvalue copy constructor
5204  ON_SubDVertexArray(ON_SubDVertexArray&&) ON_NOEXCEPT;
5205 
5206  // rvalue copy operator-=
5207  ON_SubDVertexArray& operator=(ON_SubDVertexArray&&);
5208 #endif
5209 
5210  const ON_SubD& SubD() const
5211  {
5212  return m_subd;
5213  }
5214 
5215  unsigned int VertexCount() const
5216  {
5217  return m_vertex_count;
5218  }
5219 
5220  const class ON_SubDVertex* operator[](unsigned int i) const
5221  {
5222  return (i < m_vertex_count) ? m_a[i] : nullptr;
5223  }
5224 
5225 private:
5226  ON_SubD m_subd;
5227  const class ON_SubDVertex*const* m_a = nullptr;
5228  unsigned int m_vertex_count = 0;
5229 
5230 #pragma ON_PRAGMA_WARNING_PUSH
5231 #pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
5232  // C4251: ... needs to have dll-interface to be used by clients of class ...
5233  // m_sp is private and all code that manages m_sp is explicitly implemented in the DLL.
5234 private:
5235  std::shared_ptr< const class ON_SubDVertex* > m_sp;
5236 #pragma ON_PRAGMA_WARNING_POP
5237 };
5238 
5239 //////////////////////////////////////////////////////////////////////////
5240 //
5241 // ON_SubDEdgeArray
5242 //
5243 class ON_SUBD_CLASS ON_SubDEdgeArray
5244 {
5245 public:
5246  ON_SubDEdgeArray(
5247  const ON_SubD& subd
5248  );
5249  ON_SubDEdgeArray() = default;
5250  ON_SubDEdgeArray(const ON_SubDEdgeArray&) = default;
5251  ON_SubDEdgeArray& operator=(const ON_SubDEdgeArray&) = default;
5252 
5253 #if defined(ON_HAS_RVALUEREF)
5254  // rvalue copy constructor
5255  ON_SubDEdgeArray(ON_SubDEdgeArray&&) ON_NOEXCEPT;
5256 
5257  // rvalue copy operator-=
5258  ON_SubDEdgeArray& operator=(ON_SubDEdgeArray&&);
5259 #endif
5260 
5261  const ON_SubD& SubD() const
5262  {
5263  return m_subd;
5264  }
5265 
5266  unsigned int EdgeCount() const
5267  {
5268  return m_edge_count;
5269  }
5270 
5271  const class ON_SubDEdge* operator[](unsigned int i) const
5272  {
5273  return (i < m_edge_count) ? m_a[i] : nullptr;
5274  }
5275 
5276 private:
5277  ON_SubD m_subd;
5278  const class ON_SubDEdge*const* m_a = nullptr;
5279  unsigned int m_edge_count = 0;
5280 
5281 #pragma ON_PRAGMA_WARNING_PUSH
5282 #pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
5283  // C4251: ... needs to have dll-interface to be used by clients of class ...
5284  // m_sp is private and all code that manages m_sp is explicitly implemented in the DLL.
5285 private:
5286  std::shared_ptr< const class ON_SubDEdge* > m_sp;
5287 #pragma ON_PRAGMA_WARNING_POP
5288 };
5289 
5290 //////////////////////////////////////////////////////////////////////////
5291 //
5292 // ON_SubDFaceArray
5293 //
5294 class ON_SUBD_CLASS ON_SubDFaceArray
5295 {
5296 public:
5297  ON_SubDFaceArray(
5298  const ON_SubD& subd
5299  );
5300  ON_SubDFaceArray() = default;
5301  ON_SubDFaceArray(const ON_SubDFaceArray&) = default;
5302  ON_SubDFaceArray& operator=(const ON_SubDFaceArray&) = default;
5303 
5304 #if defined(ON_HAS_RVALUEREF)
5305  // rvalue copy constructor
5306  ON_SubDFaceArray(ON_SubDFaceArray&&) ON_NOEXCEPT;
5307 
5308  // rvalue copy operator-=
5309  ON_SubDFaceArray& operator=(ON_SubDFaceArray&&);
5310 #endif
5311 
5312  const ON_SubD& SubD() const
5313  {
5314  return m_subd;
5315  }
5316 
5317  unsigned int FaceCount() const
5318  {
5319  return m_face_count;
5320  }
5321 
5322  const class ON_SubDFace* operator[](unsigned int i) const
5323  {
5324  return (i < m_face_count) ? m_a[i] : nullptr;
5325  }
5326 
5327 private:
5328  ON_SubD m_subd;
5329  const class ON_SubDFace*const* m_a = nullptr;
5330  unsigned int m_face_count = 0;
5331 
5332 #pragma ON_PRAGMA_WARNING_PUSH
5333 #pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
5334  // C4251: ... needs to have dll-interface to be used by clients of class ...
5335  // m_sp is private and all code that manages m_sp is explicitly implemented in the DLL.
5336 private:
5337  std::shared_ptr< const class ON_SubDFace* > m_sp;
5338 #pragma ON_PRAGMA_WARNING_POP
5339 };
5340 
5341 //////////////////////////////////////////////////////////////////////////
5342 //
5343 // ON_SubDVertexIterator
5344 //
5345 class ON_SUBD_CLASS ON_SubDVertexIterator
5346 {
5347 public:
5348  // The ON_SubD member function
5349  // ON_SubDVertexIterator ON_SubD::VertexIterator(subd_level_index)
5350  // is the best way to get a vertex iterator.
5351  ON_SubDVertexIterator(
5352  const class ON_SubD& subd
5353  );
5354  ON_SubDVertexIterator(
5355  const class ON_SubDRef& subd_ref
5356  );
5357 
5358  // Construct and interator that iterates over a single vertex.
5359  ON_SubDVertexIterator(
5360  const class ON_SubD& subd,
5361  const class ON_SubDVertex& vertex
5362  );
5363 
5364  // Construct and interator that iterates over a single vertex.
5365  ON_SubDVertexIterator(
5366  const class ON_SubDRef& subd_ref,
5367  const class ON_SubDVertex& vertex
5368  );
5369 
5370  // Construct and interator that iterates over the vertices of an edge.
5371  ON_SubDVertexIterator(
5372  const class ON_SubD& subd,
5373  const class ON_SubDEdge& edge
5374  );
5375 
5376  // Construct and interator that iterates over the vertices of an edge.
5377  ON_SubDVertexIterator(
5378  const class ON_SubDRef& subd_ref,
5379  const class ON_SubDEdge& edge
5380  );
5381 
5382  // Construct and interator that iterates over the vertices of a face.
5383  ON_SubDVertexIterator(
5384  const class ON_SubD& subd,
5385  const class ON_SubDFace& face
5386  );
5387 
5388  // Construct and interator that iterates over the vertices of a face.
5389  ON_SubDVertexIterator(
5390  const class ON_SubDRef& subd_ref,
5391  const class ON_SubDFace& face
5392  );
5393 
5394  ON_SubDVertexIterator() = default;
5395  ON_SubDVertexIterator(const ON_SubDVertexIterator&) = default;
5396  ON_SubDVertexIterator& operator=(const ON_SubDVertexIterator&) = default;
5397 
5398 #if defined(ON_HAS_RVALUEREF)
5399  // rvalue copy constructor
5400  ON_SubDVertexIterator( ON_SubDVertexIterator&& ) ON_NOEXCEPT;
5401  // rvalue assignment operator
5402  ON_SubDVertexIterator& operator=( ON_SubDVertexIterator&& );
5403 #endif
5404 
5405  /*
5406  Returns:
5407  The subD object for this iterator.
5408  */
5409  const class ON_SubD& SubD() const
5410  {
5411  return m_subd_ref.SubD();
5412  }
5413 
5414  const class ON_SubDRef& SubDRef() const
5415  {
5416  return m_subd_ref;
5417  }
5418 
5419  /*
5420  Description:
5421  Increment the iterator.
5422  Returns:
5423  Current vertex.
5424  Remarks:
5425  operator++ and NextVertex() behave differently.
5426  */
5427  const class ON_SubDVertex* operator++()
5428  {
5429  const class ON_SubDVertex* v = m_v_current;
5430  NextVertex();
5431  return v;
5432  }
5433 
5434  /*
5435  Return:
5436  Number of vertices this iterator will iterate through.
5437  */
5438  unsigned int VertexCount() const
5439  {
5440  return m_vertex_count;
5441  }
5442 
5443  /*
5444  Return:
5445  Interator index of the current vertex.
5446  */
5447  unsigned int CurrentVertexIndex() const
5448  {
5449  return m_vertex_index;
5450  }
5451 
5452  /*
5453  Description:
5454  Set the iterator to the beginning of the vertex list.
5455  Returns:
5456  First vertex in the list.
5457  */
5458  const class ON_SubDVertex* FirstVertex()
5459  {
5460  m_vertex_index = 0;
5461  return (m_v_current = m_v_first);
5462  }
5463 
5464  /*
5465  Description:
5466  Increment the iterator.
5467  Returns:
5468  Next vertex.
5469  Remarks:
5470  operator++ and NextVertex() behave differently.
5471  */
5472  const class ON_SubDVertex* NextVertex()
5473  {
5474  m_vertex_index++;
5475  if (m_vertex_index < m_vertex_count)
5476  {
5477  if (0 == m_component_ptr.m_ptr)
5478  {
5479  if (nullptr != m_v_current)
5480  m_v_current = m_v_current->m_next_vertex;
5481  }
5482  else
5483  {
5484  const ON_SubDEdge* edge = m_component_ptr.Edge();
5485  if (nullptr != edge)
5486  {
5487  m_v_current = edge->Vertex(m_vertex_index);
5488  }
5489  else
5490  {
5491  const ON_SubDFace* face = m_component_ptr.Face();
5492  if (nullptr != face)
5493  m_v_current = face->Vertex(m_vertex_index);
5494  else
5495  m_v_current = nullptr;
5496  }
5497  }
5498  }
5499  else
5500  {
5501  m_vertex_index = m_vertex_count;
5502  m_v_current = nullptr;
5503  }
5504  return m_v_current;
5505  }
5506 
5507  /*
5508  Returns:
5509  Current vertex;
5510  */
5511  const class ON_SubDVertex* CurrentVertex() const
5512  {
5513  return m_v_current;
5514  }
5515 
5516  /*
5517  Description:
5518  Set the iterator to the end of the vertex list.
5519  Returns:
5520  Last vertex in the list.
5521  */
5522  const class ON_SubDVertex* LastVertex()
5523  {
5524  m_vertex_index = (m_vertex_count > 0) ? (m_vertex_count - 1) : 0;
5525  return (m_v_current = m_v_last);
5526  }
5527 
5528 private:
5529  void Internal_Init(
5530  const ON_SubDRef& subd_ref,
5531  unsigned int vertex_count,
5532  const ON_SubDVertex* first,
5533  const ON_SubDVertex* last,
5534  ON_SubDComponentPtr component_ptr
5535  );
5536  ON_SubDRef m_subd_ref;
5537  const ON_SubDVertex* m_v_first = nullptr;
5538  const ON_SubDVertex* m_v_last = nullptr;
5539  const ON_SubDVertex* m_v_current = nullptr;
5540  unsigned int m_vertex_index = 0;
5541  unsigned int m_vertex_count = 0;
5542  ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
5543 };
5544 
5545 //////////////////////////////////////////////////////////////////////////
5546 //
5547 // ON_SubDEdgeIterator
5548 //
5549 class ON_SUBD_CLASS ON_SubDEdgeIterator
5550 {
5551 public:
5552  // The ON_SubD member function
5553  // ON_SubDEdgeIterator ON_SubD::EdgeIterator()
5554  // is the best way to get an edge iterator from an ON_SubD.
5555  ON_SubDEdgeIterator(
5556  const class ON_SubD& subd
5557  );
5558 
5559  // The ON_SubDRef member function
5560  // ON_SubDEdgeIterator ON_SubDRef::EdgeIterator()
5561  // is the best way to get an edge iterator from an ON_SubDRef.
5562  ON_SubDEdgeIterator(
5563  const class ON_SubDRef& subd_ref
5564  );
5565 
5566  // Construct and interator that iterates over a single edge.
5567  ON_SubDEdgeIterator(
5568  const class ON_SubD& subd,
5569  const class ON_SubDEdge& edge
5570  );
5571 
5572  // Construct and interator that iterates over a single edge.
5573  ON_SubDEdgeIterator(
5574  const class ON_SubDRef& subd_ref,
5575  const class ON_SubDEdge& edge
5576  );
5577 
5578  // Construct and interator that iterates over the edges of a vertex.
5579  ON_SubDEdgeIterator(
5580  const class ON_SubD& subd,
5581  const class ON_SubDVertex& vertex
5582  );
5583 
5584  // Construct and interator that iterates over the edges of a vertex.
5585  ON_SubDEdgeIterator(
5586  const class ON_SubDRef& subd_ref,
5587  const class ON_SubDVertex& vertex
5588  );
5589 
5590  // Construct and interator that iterates over the edges of a face.
5591  ON_SubDEdgeIterator(
5592  const class ON_SubD& subd,
5593  const class ON_SubDFace& face
5594  );
5595 
5596  // Construct and interator that iterates over the edges of a face.
5597  ON_SubDEdgeIterator(
5598  const class ON_SubDRef& subd_ref,
5599  const class ON_SubDFace& face
5600  );
5601 
5602  ON_SubDEdgeIterator() = default;
5603  ON_SubDEdgeIterator(const ON_SubDEdgeIterator&) = default;
5604  ON_SubDEdgeIterator& operator=(const ON_SubDEdgeIterator&) = default;
5605 
5606 #if defined(ON_HAS_RVALUEREF)
5607  // rvalue copy constructor
5608  ON_SubDEdgeIterator( ON_SubDEdgeIterator&& ) ON_NOEXCEPT;
5609  // rvalue assignment operator
5610  ON_SubDEdgeIterator& operator=( ON_SubDEdgeIterator&& );
5611 #endif
5612 
5613  /*
5614  Returns:
5615  The subD object for this iterator.
5616  */
5617  const class ON_SubD& SubD() const
5618  {
5619  return m_subd_ref.SubD();
5620  }
5621 
5622  const class ON_SubDRef& SubDRef() const
5623  {
5624  return m_subd_ref;
5625  }
5626 
5627  /*
5628  Description:
5629  Increment the iterator.
5630  Returns:
5631  Current edge.
5632  Remarks:
5633  operator++ and NextEdge() behave differently.
5634  */
5635  const class ON_SubDEdge* operator++()
5636  {
5637  const class ON_SubDEdge* e = m_e_current;
5638  NextEdge();
5639  return e;
5640  }
5641 
5642  /*
5643  Return:
5644  Number of edges this iterator will iterate through.
5645  */
5646  unsigned int EdgeCount() const
5647  {
5648  return m_edge_count;
5649  }
5650 
5651  /*
5652  Return:
5653  Interator index of the current edge.
5654  */
5655  unsigned int CurrentEdgeIndex() const
5656  {
5657  return m_edge_index;
5658  }
5659 
5660  /*
5661  Description:
5662  Set the iterator to the beginning of the edge list.
5663  Returns:
5664  First edge in the list.
5665  */
5666  const class ON_SubDEdge* FirstEdge()
5667  {
5668  m_edge_index = 0;
5669  return m_e_current = m_e_first;
5670  }
5671 
5672  /*
5673  Description:
5674  Increment the iterator.
5675  Returns:
5676  Next edge.
5677  Remarks:
5678  operator++ and NextEdge() behave differently.
5679  */
5680  const class ON_SubDEdge* NextEdge()
5681  {
5682  m_edge_index++;
5683  if (m_edge_index < m_edge_count)
5684  {
5685  if (0 == m_component_ptr.m_ptr)
5686  {
5687  if (nullptr != m_e_current)
5688  m_e_current = m_e_current->m_next_edge;
5689  }
5690  else
5691  {
5692  const ON_SubDVertex* vertex = m_component_ptr.Vertex();
5693  if (nullptr != vertex)
5694  {
5695  m_e_current = vertex->Edge(m_edge_index);
5696  }
5697  else
5698  {
5699  const ON_SubDFace* face = m_component_ptr.Face();
5700  if (nullptr != face)
5701  m_e_current = face->Edge(m_edge_index);
5702  else
5703  m_e_current = nullptr;
5704  }
5705  }
5706  }
5707  else
5708  {
5709  m_edge_index = m_edge_count;
5710  m_e_current = nullptr;
5711  }
5712  return m_e_current;
5713  }
5714 
5715  /*
5716  Returns:
5717  Current edge;
5718  */
5719  const class ON_SubDEdge* CurrentEdge() const
5720  {
5721  return m_e_current;
5722  }
5723 
5724  /*
5725  Description:
5726  Set the iterator to the end of the edge list.
5727  Returns:
5728  Last edge in the list.
5729  */
5730  const class ON_SubDEdge* LastEdge()
5731  {
5732  m_edge_index = (m_edge_count > 0) ? (m_edge_count - 1) : 0;
5733  return m_e_current = m_e_last;
5734  }
5735 
5736 private:
5737  void Internal_Init(
5738  const ON_SubDRef& subd_ref,
5739  unsigned int edge_count,
5740  const ON_SubDEdge* first,
5741  const ON_SubDEdge* last,
5742  ON_SubDComponentPtr component_ptr
5743  );
5744  ON_SubDRef m_subd_ref;
5745  const ON_SubDEdge* m_e_first = nullptr;
5746  const ON_SubDEdge* m_e_last = nullptr;
5747  const ON_SubDEdge* m_e_current = nullptr;
5748  unsigned int m_edge_index = 0;
5749  unsigned int m_edge_count = 0;
5750  ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
5751 };
5752 
5753 //////////////////////////////////////////////////////////////////////////
5754 //
5755 // ON_SubDFaceIterator
5756 //
5757 class ON_SUBD_CLASS ON_SubDFaceIterator
5758 {
5759 public:
5760  // The ON_SubD member function
5761  // ON_SubDFaceIterator ON_SubD::FaceIterator()
5762  // is the best way to get a face iterator from an ON_SubD.
5763  ON_SubDFaceIterator(
5764  const class ON_SubD& subd
5765  );
5766 
5767  // The ON_SubDRef member function
5768  // ON_SubDFaceIterator ON_SubDRef::FaceIterator()
5769  // is the best way to get a face iterator from an ON_SubDRef.
5770  ON_SubDFaceIterator(
5771  const class ON_SubDRef& subd_ref
5772  );
5773 
5774  // Construct and interator that iterates over the single face.
5775  ON_SubDFaceIterator(
5776  const class ON_SubD& subd,
5777  const class ON_SubDFace& face
5778  );
5779 
5780  // Construct and interator that iterates over the single face.
5781  ON_SubDFaceIterator(
5782  const class ON_SubDRef& subd_ref,
5783  const class ON_SubDFace& face
5784  );
5785 
5786  // Construct and interator that iterates over the faces of a vertex.
5787  ON_SubDFaceIterator(
5788  const class ON_SubD& subd,
5789  const class ON_SubDVertex& vertex
5790  );
5791 
5792  // Construct and interator that iterates over the faces of a vertex.
5793  ON_SubDFaceIterator(
5794  const class ON_SubDRef& subd_ref,
5795  const class ON_SubDVertex& vertex
5796  );
5797 
5798  // Construct and interator that iterates over the faces of an edge.
5799  ON_SubDFaceIterator(
5800  const class ON_SubD& subd,
5801  const class ON_SubDEdge& edge
5802  );
5803 
5804  // Construct and interator that iterates over the faces of an edge.
5805  ON_SubDFaceIterator(
5806  const class ON_SubDRef& subd_ref,
5807  const class ON_SubDEdge& edge
5808  );
5809 
5810  ON_SubDFaceIterator() = default;
5811  ON_SubDFaceIterator(const ON_SubDFaceIterator&) = default;
5812  ON_SubDFaceIterator& operator=(const ON_SubDFaceIterator&) = default;
5813 
5814 #if defined(ON_HAS_RVALUEREF)
5815  // rvalue copy constructor
5816  ON_SubDFaceIterator( ON_SubDFaceIterator&& ) ON_NOEXCEPT;
5817  // rvalue assignment operator
5818  ON_SubDFaceIterator& operator=( ON_SubDFaceIterator&& );
5819 #endif
5820 
5821  /*
5822  Returns:
5823  The subD object for this iterator.
5824  */
5825  const class ON_SubD& SubD() const
5826  {
5827  return m_subd_ref.SubD();
5828  }
5829 
5830  const class ON_SubDRef& SubDRef() const
5831  {
5832  return m_subd_ref;
5833  }
5834 
5835  /*
5836  Description:
5837  Returns the current face and increment the iterator.
5838  Returns:
5839  Current face.
5840  Remarks:
5841  operator++ and NextFace() behave differently.
5842  */
5843  const class ON_SubDFace* operator++()
5844  {
5845  const class ON_SubDFace* f = m_face_current;
5846  NextFace();
5847  return f;
5848  }
5849 
5850  /*
5851  Return:
5852  Number of faces this iterator will iterate through.
5853  */
5854  unsigned int FaceCount() const
5855  {
5856  return m_face_count;
5857  }
5858 
5859  /*
5860  Return:
5861  Interator index of the current face.
5862  */
5863  unsigned int CurrentFaceIndex() const
5864  {
5865  return m_face_index;
5866  }
5867 
5868 
5869  /*
5870  Description:
5871  Set the iterator to the beginning of the face list.
5872  Returns:
5873  First face in the list.
5874  */
5875  const class ON_SubDFace* FirstFace()
5876  {
5877  m_face_index = 0;
5878  return (m_face_current = m_face_first);
5879  }
5880 
5881  /*
5882  Description:
5883  Returns the next face and incrments the iterator.
5884  Returns:
5885  Next face.
5886  Remarks:
5887  operator++ and NextFace() behave differently.
5888  */
5889  const class ON_SubDFace* NextFace()
5890  {
5891  m_face_index++;
5892  if (m_face_index < m_face_count)
5893  {
5894  if (0 == m_component_ptr.m_ptr)
5895  {
5896  if (nullptr != m_face_current)
5897  m_face_current = m_face_current->m_next_face;
5898  }
5899  else
5900  {
5901  const ON_SubDVertex* vertex = m_component_ptr.Vertex();
5902  if (nullptr != vertex)
5903  {
5904  m_face_current = vertex->Face(m_face_index);
5905  }
5906  else
5907  {
5908  const ON_SubDEdge* edge = m_component_ptr.Edge();
5909  if (nullptr != edge)
5910  m_face_current = edge->Face(m_face_index);
5911  else
5912  m_face_current = nullptr;
5913  }
5914  }
5915  }
5916  else
5917  {
5918  m_face_index = m_face_count;
5919  m_face_current = nullptr;
5920  }
5921  return m_face_current;
5922  }
5923 
5924  /*
5925  Returns:
5926  Current face;
5927  */
5928  const class ON_SubDFace* CurrentFace() const
5929  {
5930  return m_face_current;
5931  }
5932 
5933  /*
5934  Description:
5935  Set the iterator to the end of the face list.
5936  Returns:
5937  Last face in the list.
5938  */
5939  const class ON_SubDFace* LastFace()
5940  {
5941  m_face_index = (m_face_count > 0) ? (m_face_count - 1) : 0;
5942  return (m_face_current = m_face_last);
5943  }
5944 
5945  unsigned int LimitSurfaceMeshFragmentCount(
5946  ON_SubD::FacetType facet_type
5947  ) const;
5948 
5949 private:
5950  void Internal_Init(
5951  const ON_SubDRef& subd_ref,
5952  unsigned int face_count,
5953  const ON_SubDFace* first,
5954  const ON_SubDFace* last,
5955  ON_SubDComponentPtr component_ptr
5956  );
5957  ON_SubDRef m_subd_ref;
5958  const ON_SubDFace* m_face_first = nullptr;
5959  const ON_SubDFace* m_face_last = nullptr;
5960  const ON_SubDFace* m_face_current = nullptr;
5961  unsigned int m_face_index = 0;
5962  unsigned int m_face_count = 0;
5963  ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
5964 };
5965 
5966 //////////////////////////////////////////////////////////////////////////
5967 //
5968 // ON_SubDComponentIterator
5969 //
5970 class ON_SUBD_CLASS ON_SubDComponentIterator
5971 {
5972 public:
5973  static const ON_SubDComponentIterator Empty;
5974 
5975  // The ON_SubD member function
5976  // ON_SubDComponentIterator ON_SubD::ComponentIterator(subd_level_index)
5977  // is the best way to get a component iterator for a subd level.
5978  ON_SubDComponentIterator(
5979  const class ON_SubD& subd
5980  );
5981  ON_SubDComponentIterator(
5982  const class ON_SubDRef& subd_ref
5983  );
5984 
5985  ON_SubDComponentIterator() = default;
5986  ON_SubDComponentIterator(const ON_SubDComponentIterator&) = default;
5987  ON_SubDComponentIterator& operator=(const ON_SubDComponentIterator&) = default;
5988 
5989 #if defined(ON_HAS_RVALUEREF)
5990  // rvalue copy constructor
5991  ON_SubDComponentIterator( ON_SubDComponentIterator&& ) ON_NOEXCEPT;
5992  // rvalue assignment operator
5993  ON_SubDComponentIterator& operator=( ON_SubDComponentIterator&& );
5994 #endif
5995 
5996  /*
5997  Returns:
5998  The subD object for this iterator.
5999  */
6000  const class ON_SubD& SubD() const
6001  {
6002  return m_subd_ref.SubD();
6003  }
6004 
6005  const class ON_SubDRef& SubDRef() const
6006  {
6007  return m_subd_ref;
6008  }
6009 
6010  /*
6011  Returns:
6012  The subD level for this iterator.
6013  */
6014  unsigned int SubDLevel() const
6015  {
6016  return m_subd_level;
6017  }
6018 
6019  /*
6020  Description:
6021  Returns the current component and increment the iterator.
6022  Returns:
6023  Current component.
6024  Remarks:
6025  operator++ and NextComponent() behave differently.
6026  */
6027  const class ON_SubDComponentPtr operator++()
6028  {
6029  const class ON_SubDComponentPtr cptr = m_cptr_current;
6030  NextComponent();
6031  return cptr;
6032  }
6033 
6034  /*
6035  Description:
6036  Set the iterator to the beginning of the component list.
6037  Returns:
6038  First component in the list.
6039  */
6040  const class ON_SubDComponentPtr FirstComponent();
6041 
6042  /*
6043  Description:
6044  Returns the next component and incrments the iterator.
6045  Returns:
6046  Next component.
6047  Remarks:
6048  operator++ and NextComponent() behave differently.
6049  */
6050  const class ON_SubDComponentPtr NextComponent();
6051 
6052  /*
6053  Returns:
6054  Current component;
6055  */
6056  const class ON_SubDComponentPtr CurrentComponent() const
6057  {
6058  return m_cptr_current;
6059  }
6060 
6061  /*
6062  Description:
6063  Set the iterator to the end of the component list.
6064  Returns:
6065  Last component in the list.
6066  */
6067  const class ON_SubDComponentPtr LastComponent();
6068 
6069 private:
6070  ON_SubDRef m_subd_ref;
6071  unsigned int m_subd_level = 0;
6072  const ON_SubDVertex* m_vertex_first = nullptr;
6073  const ON_SubDVertex* m_vertex_last = nullptr;
6074  const ON_SubDEdge* m_edge_first = nullptr;
6075  const ON_SubDEdge* m_edge_last = nullptr;
6076  const ON_SubDFace* m_face_first = nullptr;
6077  const ON_SubDFace* m_face_last = nullptr;
6078  ON_SubDComponentPtr m_cptr_current = ON_SubDComponentPtr::Null;
6079 };
6080 
6081 //////////////////////////////////////////////////////////////////////////
6082 //
6083 // ON_SubDSectorIterator
6084 //
6085 
6086 class ON_SUBD_CLASS ON_SubDSectorIterator
6087 {
6088 public:
6089  static const ON_SubDSectorIterator Empty;
6090 
6091  ON_SubDSectorIterator() = default;
6092  ~ON_SubDSectorIterator() = default;
6093  ON_SubDSectorIterator(const ON_SubDSectorIterator&) = default;
6094  ON_SubDSectorIterator& operator=(const ON_SubDSectorIterator&) = default;
6095 
6096  /*
6097  Parameters:
6098  center_vertex - [in]
6099  The vertex on initial_face that will be iterated around.
6100  center_vertex->Face(0) is used to select the sector.
6101  Returns:
6102  If input is valid, a pointer to the center vertex is returned.
6103  Otherwise, nullptr is returned.
6104  */
6105  const ON_SubDVertex* Initialize(
6106  const ON_SubDVertex* center_vertex
6107  );
6108 
6109  /*
6110  Parameters:
6111  initial_face - [in]
6112  iterator_orientation - [in]
6113  0: (more common)
6114  "next" means counter-clockwise with respect to the orientation of initial_face
6115  1: (less common)
6116  "next" means clockwise with respect to the orientation of initial_face
6117  center_vertex - [in]
6118  The vertex on initial_face that will be iterated around.
6119  Returns:
6120  If input is valid, a pointer to the center vertex is returned.
6121  Otherwise, nullptr is returned.
6122  */
6123  const ON_SubDVertex* Initialize(
6124  const ON_SubDFace* initial_face,
6125  ON__UINT_PTR iterator_orientation,
6126  const ON_SubDVertex* center_vertex
6127  );
6128 
6129  /*
6130  Parameters:
6131  initial_face - [in]
6132  iterator_orientation - [in]
6133  0: (more common)
6134  "next" means counter-clockwise with respect to the orientation of initial_face
6135  1: (less common)
6136  "next" means clockwise with respect to the orientation of initial_face
6137  face_vertex_index - [in]
6138  initial_face->Vertex(face_vertex_index) is the center vertex
6139  that will be iterated around.
6140  Returns:
6141  If input is valid, a pointer to the center vertex is returned.
6142  Otherwise, nullptr is returned.
6143  */
6144  const ON_SubDVertex* Initialize(
6145  const ON_SubDFace* initial_face,
6146  ON__UINT_PTR iterator_orientation,
6147  unsigned int face_vertex_index
6148  );
6149 
6150  bool InitializeToCurrentFace();
6151 
6152  void Initialize();
6153 
6154  /*
6155  Description:
6156  The current ring index reports the total increment from the
6157  start to the current state. It can be positive or negative.
6158  */
6159  int CurrentRingIndex() const;
6160 
6161  const ON_SubDVertex* CenterVertex() const;
6162 
6163  const ON_SubDFace* InitialFace() const;
6164 
6165  unsigned int InitialFaceCenterVertexIndex() const;
6166 
6167  const ON_SubDFace* CurrentFace() const;
6168 
6169  unsigned int CurrentFaceDirection() const;
6170 
6171  ON_SubDFacePtr CurrentFacePtr() const;
6172 
6173  unsigned int CurrentFaceCenterVertexIndex() const;
6174 
6175 
6176  /*
6177  Parameters:
6178  face_side_index - [in]
6179  0: Return the edge entering the center vertex.
6180  1: Return the edge leaving the center vertex.
6181  Returns:
6182  The requested edge.
6183  */
6184  ON_SubDEdgePtr CurrentEdgePtr(
6185  unsigned int face_side_index
6186  ) const;
6187 
6188  /*
6189  Description:
6190 
6191  CurrentEdge(1)
6192  |
6193  |
6194  NextFace() | CurrentFace()
6195  |
6196  |
6197  *------------- CurrentEdge(0)
6198  PrevFace()
6199 
6200  The asterisk (*) marks the center vertex.
6201  The diagram is With respect to the initial iterator orientation.
6202 
6203  Parameters:
6204  face_side_index - [in]
6205  CurrentEdge(0) = edge on the clockwise (PrevFace) side of the current face
6206  CurrentEdge(1) = edge on the counterclockwise (NextFace) side of the current face
6207  The directions "counterclockwise" and "clockwise" are with respect to the
6208  initial iterator orientation.
6209  Returns:
6210  The requested edge or nullptr if the iterator is not initialized,
6211  has terminated, or is not valid.
6212  */
6213  const ON_SubDEdge* CurrentEdge(
6214  unsigned int face_side_index
6215  ) const;
6216 
6217  ON__UINT_PTR CurrentEdgeDirection(
6218  unsigned int face_side_index
6219  ) const;
6220 
6221  /*
6222  Returns:
6223  The vertex on CurrentEdge(face_side_index) that is opposite
6224  the central vertex.
6225  */
6226  const ON_SubDVertex* CurrentEdgeRingVertex(
6227  unsigned int face_side_index
6228  ) const;
6229 
6230  /*
6231  Description:
6232  Advance the "current" face to the "next" face in the ring
6233  by "hopping across" CurrentEdge(1).
6234 
6235  If the current face is not reversed (1 == CurrentFaceDirection),
6236  then this rotation is counter-clockwise with respect to
6237  the current face's orientation.
6238 
6239  If the current face is reversed (1 == CurrentFaceDirection),
6240  then this rotation is clockwise with respect to
6241  the current face's orientation.
6242  Parameters:
6243  bStopAtCrease - [in]
6244  If true and CurrentEdge(1) is tagged ON_SubD:EdgeTag::crease,
6245  iteration terminates.
6246  Returns:
6247  When the input CurrentEdge(1) has exactly two faces and
6248  is not tagged as a crease or bStopAtCrease is false, the
6249  face on the other side of CurrentEdge(1) becomes the new
6250  current face and a pointer to this face is returned.
6251  Remarks:
6252  Identical to calling IncrementFace(+1,bStopAtCrease);
6253  */
6254  const ON_SubDFace* NextFace(
6255  bool bStopAtCrease
6256  );
6257 
6258  /*
6259  Description:
6260  Advance the "current" face to the "previous" face in the ring
6261  by "hopping across" CurrentEdge(0).
6262 
6263  If the current face is not reversed (0 == CurrentFaceDirection),
6264  then this rotation is clockwise with respect to
6265  the current face's orientation.
6266 
6267  If the current face is reversed (1 == CurrentFaceDirection),
6268  then this rotation is counter-clockwise with respect to
6269  the current face's orientation.
6270  Parameters:
6271  bStopAtCrease - [in]
6272  If true and CurrentEdge(0) is tagged ON_SubD:EdgeTag::crease,
6273  iteration terminates.
6274  Returns:
6275  When the input CurrentEdge(0) has exactly two faces and
6276  is not tagged as a crease or bStopAtCrease is false, the
6277  face on the other side of CurrentEdge(0) becomes the new
6278  current face and a pointer to this face is returned.
6279  In all other cases, nullptr is returned
6280  Remarks:
6281  Identical to calling IncrementFace(-1,bStopAtCrease);
6282  */
6283  const ON_SubDFace* PrevFace(
6284  bool bStopAtCrease
6285  );
6286 
6287  /*
6288  Description:
6289  Advance the "current" face by "hopping across" the edge
6290  CurrentEdge((increment_direction>0) ? 1 : 0).
6291 
6292  If the current face is not reversed (0 == CurrentFaceDirection),
6293  then increment_direction>0 rotates counter-clockwise with respect to
6294  the current face's orientation.
6295 
6296  If the current face is reversed (1 == CurrentFaceDirection),
6297  then increment_direction>0 rotates clockwise with respect to
6298  the current face's orientation.
6299  Parameters:
6300  increment_direction - [in]
6301  > 0 advance the "current" face to next face
6302  <= 0 advance the "current" face to previous face
6303  bStopAtCrease - [in]
6304  If true and the input value of CurrentEdge((increment_direction>0) ? 1 : 0)
6305  is tagged as ON_SubD:EdgeTag::crease, iteration terminates.
6306  When iteration terminates at a crease,
6307  CurrentFace() becomes nullptr
6308  CurrentEdge((increment_direction>0) ? 1 : 0) becomes nullptr
6309  CurrentEdge((increment_direction>0) ? 0 : 1) points at the crease
6310  and nullptr returned.
6311  Returns:
6312  nullptr if iteration terminates.
6313  */
6314  const ON_SubDFace* IncrementFace(
6315  int increment_direction,
6316  bool bStopAtCrease
6317  );
6318 
6319  /*
6320  Description:
6321  Increment the iterator until it reaches a face with
6322  a crease
6323  Parameters:
6324  increment_direction - [in]
6325  > 0 advance next until CurrentEdge(1) is a crease.
6326  <= 0 advance previous until CurrentEdge(0) is a crease.
6327  Returns:
6328  nullptr - the sector has no creases.
6329  not nullptr - incremented to a crease
6330  */
6331  const ON_SubDFace* IncrementToCrease(
6332  int increment_direction
6333  );
6334 
6335  /*
6336  Description:
6337  Reset iterator to initial face.
6338  */
6339  const ON_SubDFace* FirstFace();
6340 
6341  bool IsValid() const;
6342 
6343 private:
6344  const ON_SubDVertex* m_center_vertex = nullptr;
6345  const ON_SubDFace* m_initial_face = nullptr;
6346  const ON_SubDFace* m_current_face = nullptr;
6347 
6348  // m_current_eptr[0].Edge() = "prev" side edge
6349  // m_current_eptr[1].Edge() = "next" side edge
6350  // When m_current_eptr[i].Edge() is not null,
6351  // center vertex = m_current_eptr[i].Edge()->m_vertex[m_current_eptr[i].Direction()]
6352  ON_SubDEdgePtr m_current_eptr[2]; // default = { ON_SubDEdgePtr::Null, ON_SubDEdgePtr::Null };
6353 
6354  unsigned int m_initial_fvi = 0;
6355  unsigned int m_current_fvi = 0;
6356  unsigned int m_current_fei[2]; // default = { 0, 0 }; // "prev" and "next"
6357 
6358  // m_initial_face_dir
6359  // 0: "next" means clockwise with respect to the initial face's orientation.
6360  // 1: "next" means counter-clockwise with respect to the initial face's orientation.
6361  unsigned int m_initial_face_dir = 0;
6362 
6363  // m_current_face_dir
6364  // 0: "next" means clockwise with respect to the initial face's orientation.
6365  // 1: "next" means counter-clockwise with respect to the initial face's orientation.
6366  // When the subd faces around the center vertex are consistently oriented,
6367  // m_current_face_dir is always equal to m_initial_face_dir.
6368  unsigned int m_current_face_dir = 0;
6369 
6370  int m_current_ring_index = 0;
6371 };
6372 
6373 
6374 //////////////////////////////////////////////////////////////////////////
6375 //
6376 // ON_SubDFaceEdgeIterator
6377 //
6378 class ON_SUBD_CLASS ON_SubDFaceEdgeIterator
6379 {
6380 public:
6381  ON_SubDFaceEdgeIterator();
6382 
6383  /*
6384  Description:
6385  Construct an iterator for going around the edges on a face.
6386  Parameters:
6387  face - [in]
6388  first_edge - [in]
6389  starting edge for the iterator or nullptr to start at face->Edge(0).
6390  */
6391  ON_SubDFaceEdgeIterator(
6392  const ON_SubDFace* face
6393  );
6394 
6395  ON_SubDFaceEdgeIterator(
6396  const ON_SubDFace* face,
6397  const ON_SubDEdge* first_edge
6398  );
6399 
6400 
6401  /*
6402  Description:
6403  Initialize an iterator for going around the edges on a face.
6404  Parameters:
6405  face - [in]
6406  first_edge - [in]
6407  starting edge for the iterator or nullptr to start at face->Edge(0).
6408  */
6409  unsigned int Initialize(
6410  const ON_SubDFace* face
6411  );
6412 
6413  unsigned int Initialize(
6414  const ON_SubDFace* face,
6415  const ON_SubDEdge* first_edge
6416  );
6417 
6418  unsigned int EdgeCount() const;
6419 
6420  /*
6421  Returns:
6422  Resets the iterator and returns the first edge.
6423  */
6424  const ON_SubDEdge* FirstEdge();
6425 
6426  /*
6427  Description:
6428  Increments the iterator and returns the edge.
6429  */
6430  const ON_SubDEdge* NextEdge();
6431 
6432  /*
6433  Description:
6434  Decrements the iterator and returns the edge.
6435  */
6436  const ON_SubDEdge* PrevEdge();
6437 
6438  /*
6439  Returns:
6440  Current edge.
6441  */
6442  const ON_SubDEdge* CurrentEdge() const;
6443 
6444  unsigned int FirstEdgeIndex() const;
6445 
6446  unsigned int CurrentEdgeIndex() const;
6447 
6448 private:
6449  const ON_SubDFace* m_face;
6450  unsigned int m_edge_count;
6451  unsigned int m_edge_index0;
6452  unsigned int m_edge_index;
6453 };
6454 
6455 //////////////////////////////////////////////////////////////////////////
6456 //
6457 // ON_SubDFromMeshOptions
6458 //
6459 class ON_SUBD_CLASS ON_SubDFromMeshOptions
6460 {
6461 public:
6462 
6463  // Default construction is identical to ON_SubDFromMeshOptions::Smooth.
6464  ON_SubDFromMeshOptions() = default;
6465  ~ON_SubDFromMeshOptions() = default;
6466  ON_SubDFromMeshOptions(const ON_SubDFromMeshOptions&) = default;
6467  ON_SubDFromMeshOptions& operator=(const ON_SubDFromMeshOptions&) = default;
6468 
6469  ///////////////////////////////////////////////////////////////////////////////////////
6470  //
6471  // Crease options
6472  //
6473 
6474  // No interior creases and no corners.
6475  static const ON_SubDFromMeshOptions Smooth;
6476 
6477  // Create an interior sub-D crease along coincident input mesh edges
6478  // where the vertex normal directions at one end differ by at
6479  // least 30 degrees.
6480  static const ON_SubDFromMeshOptions InteriorCreaseAtMeshCrease;
6481 
6482  // Create an interior sub-D crease along all coincident input mesh edges.
6483  static const ON_SubDFromMeshOptions InteriorCreaseAtMeshEdge;
6484 
6485  ///////////////////////////////////////////////////////////////////////////////////////
6486  //
6487  // Custom interior crease options
6488  //
6489 #pragma region RH_C_SHARED_ENUM [SubD::InteriorCreaseOption] [Rhino.Geometry.SubD.InteriorCreaseOption] [nested:byte]
6490  ///<summary>
6491  ///Defines how interior creases are treated.
6492  ///</summary>
6493  enum class InteriorCreaseOption : unsigned char
6494  {
6495  ///<summary>The interior creases option is not defined.</summary>
6496  Unset = 0,
6497 
6498  ///<summary>No interior creases.</summary>
6499  None = 1,
6500 
6501  ///<summary>An interior subd crease will appear along coincident
6502  ///mesh edges where the angle between coindident vertex
6503  ///normals &gt;= MinimumCreaseAngleRadians().</summary>
6504  AtMeshCrease = 2,
6505 
6506  ///<summary>An interior subd crease will appear all coincident mesh edges.
6507  ///Input mesh vertex normals are ignored.</summary>
6508  AtMeshEdge = 3
6509  };
6510 #pragma endregion
6511 
6512  static ON_SubDFromMeshOptions::InteriorCreaseOption InteriorCreaseOptionFromUnsigned(
6513  unsigned int interior_crease_option_as_unsigned
6514  );
6515 
6516  /*
6517  Parameters:
6518  interior_crease_option - [in]
6519  */
6520  void SetInteriorCreaseOption(
6521  ON_SubDFromMeshOptions::InteriorCreaseOption interior_crease_option
6522  );
6523 
6524  /*
6525  Returns:
6526  The interior crease option.
6527  */
6528  ON_SubDFromMeshOptions::InteriorCreaseOption InteriorCreaseTest() const;
6529 
6530 
6531  /*
6532  Description:
6533  When the interior crease option is
6534  ON_SubDFromMeshOptions::InteriorCreaseOption::AtMeshCreases,
6535  the value of MinimumCreaseAngleRadians() determines which
6536  coincident input mesh edges generate sub-D creases.
6537 
6538  If the input mesh has vertex normals, and the angle between
6539  vertex normals is > MinimumCreaseAngleRadians() at an end
6540  of a coincident input mesh edge, the the correspondeing sub-D
6541  edge will be a crease.
6542 
6543  Parameters:
6544  minimum_crease_angle_radians - [in]
6545  >= 0.0 and < ON_PI
6546  */
6547  void SetMinimumCreaseAngleRadians(
6548  double minimum_crease_angle_radians
6549  );
6550 
6551  /*
6552  Description:
6553  When the interior crease option is
6554  ON_SubDFromMeshOptions::InteriorCreaseOption::AtMeshCreases,
6555  the value of MinimumCreaseAngleRadians() determines which
6556  coincident input mesh edges generate sub-D creases.
6557 
6558  If the input mesh has vertex normals, and the angle between
6559  vertex normals is > MinimumCreaseAngleRadians() at an end
6560  of a coincident input mesh edge, the the correspondeing sub-D
6561  edge will be a crease.
6562  Returns:
6563  Current value of
6564  */
6565  double MinimumCreaseAngleRadians() const;
6566 
6567  /*
6568  Description:
6569  Copy all interior crease option settings from source_options to this.
6570  Parameters:
6571  source_options - [in]
6572  Returns:
6573  The currently selected interior crease option.
6574  */
6575  ON_SubDFromMeshOptions::InteriorCreaseOption CopyInteriorCreaseTest(
6576  ON_SubDFromMeshOptions source_options
6577  );
6578 
6579 
6580  ///////////////////////////////////////////////////////////////////////////////////////
6581  //
6582  // Convex corner options
6583  //
6584 
6585  // Look for convex corners at sub-D vertices with 2 edges
6586  // that have an included angle <= 90 degrees.
6587  static const ON_SubDFromMeshOptions ConvexCornerAtMeshCorner;
6588 
6589  ///////////////////////////////////////////////////////////////////////////////////////
6590  //
6591  // Custom convex corner options
6592  //
6593 #pragma region RH_C_SHARED_ENUM [SubD::ConvexCornerOption] [Rhino.Geometry.SubD.ConvexCornerOption] [nested:byte]
6594  ///<summary>
6595  ///Defines how convex corners are treated.
6596  ///</summary>
6597  enum class ConvexCornerOption : unsigned char
6598  {
6599  ///<summary>The option is not set.</summary>
6600  Unset = 0,
6601 
6602  ///<summary>No convex coners.</summary>
6603  None = 1,
6604 
6605  ///<summary>A convext subd corner will appear at input mesh/ boundary vertices
6606  /// where the corner angle &lt;= MaximumConvexCornerAngleRadians() and
6607  /// the number of edges the end at the vertex is &lt;= MaximumConvexCornerEdgeCount().
6608  ///</summary>
6609  AtMeshCorner = 2
6610  };
6611 #pragma endregion
6612 
6613  static ON_SubDFromMeshOptions::ConvexCornerOption ConvexCornerOptionFromUnsigned(
6614  unsigned int convex_corner_option_as_unsigned
6615  );
6616 
6617  /*
6618  Parameters:
6619  convex_corner_option - [in]
6620  */
6621  void SetConvexCornerOption(
6622  ON_SubDFromMeshOptions::ConvexCornerOption convex_corner_option
6623  );
6624 
6625  /*
6626  Returns:
6627  The currently selected convex corner option.
6628  */
6629  ON_SubDFromMeshOptions::ConvexCornerOption ConvexCornerTest() const;
6630 
6631  /*
6632  Description:
6633  If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
6634  input mesh boundary vertex becomes a sub-D corner when the number of
6635  edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
6636  and the corner angle is <= MaximumConvexCornerAngleRadians().
6637  Parameters:
6638  maximum_convex_corner_edge_count - [in]
6639  */
6640  void SetMaximumConvexCornerEdgeCount(
6641  unsigned int maximum_convex_corner_edge_count
6642  );
6643 
6644  /*
6645  Description:
6646  If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
6647  input mesh boundary vertex becomes a sub-D corner when the number of
6648  edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
6649  and the corner angle is <= MaximumConvexCornerAngleRadians().
6650  Returns:
6651  The maximum number of edges at a convex corner vertex.
6652  */
6653  unsigned int MaximumConvexCornerEdgeCount() const;
6654 
6655  /*
6656  Description:
6657  If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
6658  input mesh boundary vertex becomes a sub-D corner when the number of
6659  edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
6660  and the corner angle is <= MaximumConvexCornerAngleRadians().
6661  Parameters:
6662  maximum_convex_corner_angle_radians - [in]
6663  > 0.0 and < ON_PI
6664  */
6665  void SetMaximumConvexCornerAngleRadians(
6666  double maximum_convex_corner_angle_radians
6667  );
6668 
6669  /*
6670  Description:
6671  If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
6672  input mesh boundary vertex becomes a sub-D corner when the number of
6673  edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
6674  and the corner angle is <= MaximumConvexCornerAngleRadians().
6675  Returns:
6676  The maximum corner angle.
6677  */
6678  double MaximumConvexCornerAngleRadians() const;
6679 
6680  /*
6681  Description:
6682  Copy all convex corner option settings from source_options to this.
6683  Parameters:
6684  source_options - [in]
6685  Returns:
6686  The currently selected convex corner option.
6687  */
6688  ON_SubDFromMeshOptions::ConvexCornerOption CopyConvexCornerTest(
6689  ON_SubDFromMeshOptions source_parameters
6690  );
6691 
6692 
6693  ///////////////////////////////////////////////////////////////////////////////////////
6694  //
6695  // Sub-D type option
6696  //
6697  ON_SubD::SubDType SubDType() const;
6698 
6699  void SetSubDType(
6700  ON_SubD::SubDType subd_type
6701  );
6702 
6703 private:
6704  ON_SubD::SubDType m_subd_type = ON_SubD::SubDType::Unset;
6705  unsigned char m_reserved1 = 0;
6706  unsigned short m_reserved2 = 0;
6707 
6708  ON_SubDFromMeshOptions::InteriorCreaseOption m_interior_crease_option = ON_SubDFromMeshOptions::InteriorCreaseOption::None;
6709  ON_SubDFromMeshOptions::ConvexCornerOption m_convex_corner_option = ON_SubDFromMeshOptions::ConvexCornerOption::None;
6710  unsigned short m_maximum_convex_corner_edge_count = 2U;
6711 
6712  double m_minimum_crease_angle_radians = ON_PI/6.0; // 30 degrees in radians
6713  double m_maximum_convex_corner_angle_radians = 0.501*ON_PI; // 90 degrees (+ a smidge) in radians
6714 };
6715 
6716 //////////////////////////////////////////////////////////////////////////
6717 //
6718 // ON_SubDComponentRef
6719 //
6720 // Used when an ON_SubD vertex, edge or face needs to be sent around as
6721 // a piece of ON_Geometry.
6722 //
6723 class ON_SUBD_CLASS ON_SubDComponentRef : public ON_Geometry
6724 {
6725  ON_OBJECT_DECLARE(ON_SubDComponentRef);
6726 public:
6727  static const ON_SubDComponentRef Empty;
6728 
6729  ON_SubDComponentRef() = default;
6730  ~ON_SubDComponentRef() = default;
6731  ON_SubDComponentRef(const ON_SubDComponentRef&) ON_NOEXCEPT;
6732  ON_SubDComponentRef& operator=(const ON_SubDComponentRef&);
6733 
6734 #if defined(ON_HAS_RVALUEREF)
6735  // rvalue copy constructor
6736  ON_SubDComponentRef( ON_SubDComponentRef&& ) ON_NOEXCEPT;
6737 
6738  // The rvalue assignment operator calls ON_Object::operator=(ON_Object&&)
6739  // which could throw exceptions. See the implementation of
6740  // ON_Object::operator=(ON_Object&&) for details.
6741  ON_SubDComponentRef& operator=( ON_SubDComponentRef&& );
6742 #endif
6743 
6744  /*
6745  Parameters:
6746  subd_ref - [in]
6747  component_index - [in]
6748  bLimitSurface - [in]
6749  true - the reference is to the limit surface location
6750  false - the reference is to the control net location
6751  */
6752  static ON_SubDComponentRef Create(
6753  const ON_SubDRef& subd_ref,
6754  ON_COMPONENT_INDEX component_index,
6755  ON_SubDComponentLocation component_location
6756  );
6757 
6758  static ON_SubDComponentRef Create(
6759  const ON_SubDRef& subd_ref,
6760  ON_SubDComponentPtr component_ptr,
6761  ON_SubDComponentLocation component_location
6762  );
6763 
6764  static ON_SubDComponentRef Create(
6765  const ON_SubDRef& subd_ref,
6766  const class ON_SubDVertex* vertex,
6767  ON_SubDComponentLocation component_location
6768  );
6769 
6770  static ON_SubDComponentRef Create(
6771  const ON_SubDRef& subd_ref,
6772  const class ON_SubDEdge* edge,
6773  ON_SubDComponentLocation component_location
6774  );
6775 
6776  static ON_SubDComponentRef Create(
6777  const ON_SubDRef& subd_ref,
6778  const class ON_SubDFace* face,
6779  ON_SubDComponentLocation component_location
6780  );
6781 
6782  void Clear();
6783 
6784  ON_SubDRef SubDRef() const;
6785 
6786  const class ON_SubD& SubD() const;
6787 
6788  ON_COMPONENT_INDEX ComponentIndex() const override;
6789 
6790  ON_SubDComponentPtr ComponentPtr() const;
6791 
6792  ON_SubDComponentLocation ComponentLocation() const;
6793 
6794  const class ON_SubDVertex* Vertex() const;
6795 
6796  const class ON_SubDEdge* Edge() const;
6797 
6798  const class ON_SubDFace* Face() const;
6799 
6800 private:
6801  ON_SubDRef m_subd_ref;
6802  ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
6803  ON_COMPONENT_INDEX m_component_index = ON_COMPONENT_INDEX::UnsetComponentIndex;
6804  ON_SubDComponentLocation m_component_location = ON_SubDComponentLocation::Unset;
6805 
6806 public:
6807  // overrides of virtual ON_Object functions
6808  bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
6809  void Dump( ON_TextLog& ) const override;
6810  unsigned int SizeOf() const override;
6811  ON::object_type ObjectType() const override;
6812 
6813  // overrides of virtual ON_Geometry functions
6814  int Dimension() const override;
6815 
6816  // virtual ON_Geometry GetBBox override
6817  bool GetBBox( double* boxmin, double* boxmax, bool bGrowBox = false ) const override;
6818 };
6819 
6820 //////////////////////////////////////////////////////////////////////////
6821 //
6822 // ON_SubDComponentPoint
6823 //
6824 // Used in selection tests to return a point and parameters on a component.
6825 //
6826 class ON_SUBD_CLASS ON_SubDComponentPoint
6827 {
6828 public:
6829  static const ON_SubDComponentPoint Unset;
6830 
6831  ON_SubDComponentPoint() = default;
6832  ~ON_SubDComponentPoint() = default;
6833  ON_SubDComponentPoint(const ON_SubDComponentPoint&) = default;
6834  ON_SubDComponentPoint& operator=(const ON_SubDComponentPoint&) = default;
6835 
6836  /*
6837  Description:
6838  Compares the m_component_ptr values. This function is useful for sorting
6839  arrays of ON_SubDComponentPoint values remove duplicates.
6840  */
6841  static int CompareComponentPtr(
6842  const ON_SubDComponentPoint* a,
6843  const ON_SubDComponentPoint* b
6844  );
6845 
6846  // m_component_ptr will be face, edge or vertex
6847  ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
6848 
6849  //// If the point is on a a face that does not have the ordinary number of
6850  //// edges for the subdivision type, then m_face_corner_index identifies the
6851  //// subfragment corner.
6852  //unsigned int m_face_corner_index = ON_UNSET_UINT_INDEX;
6853 
6854  //// If m_level_index is ON_UNSET_UINT_INDEX, the point is on the limit surface.
6855  //// Otherwise the point is on the control net at the specified level.
6856  //unsigned int m_level_index = ON_UNSET_UINT_INDEX;
6857 
6858  ON_PickPoint m_pick_point = ON_PickPoint::Unset;
6859 };
6860 
6861 //////////////////////////////////////////////////////////////////////////
6862 //
6863 // ON_SubDMatrix
6864 //
6865 class ON_SUBD_CLASS ON_SubDMatrix
6866 {
6867 public:
6868  ON_SubDMatrix() = default;
6869 
6870  static const ON_SubDMatrix Empty;
6871 
6872  /*
6873  Description:
6874  Precise evaluation of cos(a) and cos(a) where a = i/n pi.
6875  These values are required for high qualitiy limit surface evaluation.
6876  Parameters:
6877  j - [in]
6878  n - [in]
6879  cos_theta - [out]
6880  cos(j/n pi)
6881  sin_theta - [out]
6882  sin(j/n pi)
6883  */
6884  static bool EvaluateCosAndSin(
6885  unsigned int j,
6886  unsigned int n,
6887  double* cos_theta,
6888  double* sin_theta
6889  );
6890 
6891  bool IsValid() const;
6892 
6893  bool IsValidPointRing(
6894  size_t point_ring_count,
6895  size_t point_ring_stride,
6896  const double* point_ring
6897  ) const;
6898 
6899  bool EvaluateSubdivisionPoint(
6900  unsigned int component_index,
6901  size_t point_ring_count,
6902  size_t point_ring_stride,
6903  const double* point_ring,
6904  double subd_point[3]
6905  ) const;
6906 
6907  bool EvaluateLimitPoint(
6908  size_t point_ring_count,
6909  size_t point_ring_stride,
6910  const double* point_ring,
6911  double limit_point[3],
6912  double limit_tangent1[3],
6913  double limit_tangent2[3],
6914  double limit_normal[3]
6915  ) const;
6916 
6917  bool EvaluateLimitPoint(
6918  size_t point_ring_count,
6919  size_t point_ring_stride,
6920  const double* point_ring,
6921  class ON_SubDSectorLimitPoint& limit_point
6922  ) const;
6923 
6924  /*
6925  Description:
6926  Get the subdivision matrix information for the case specified
6927  by the input parameters. This information is retrieved from
6928  a cache. In some cases, it will be calculated the first time
6929  it is needed.
6930  Parameters:
6931  facet_type - [in]
6932  vertex_tag - [in]
6933  valence - [in]
6934  The input parameters identify the subdivision case.
6935  Remarks:
6936  Every member function of ON_SubDMatrix, including this one
6937  is thread safe.
6938  */
6939  static const ON_SubDMatrix& FromCache(
6940  ON_SubDSectorType sector_type
6941  );
6942 
6943  ON_SubDSectorType m_sector_type;
6944 
6945  unsigned int m_R = 0; // the matrix m_S is m_R x m_R (m_R = m_sector_type.PointRingCount())
6946 
6947  // The term "standard vertex ring points" is used below.
6948  //
6949  // If "C" is an interior vertex (m_vertex_tag is smooth or dart),
6950  // (E[0], ...., E[N-1]) is a radially sorted list of its edges,
6951  // (F[0], ..., F[N-1]) is a radially sorted list of its faces,
6952  // and (P[0], ..., P[N-1]) is a list of the edge vertices opposite C,
6953  // E0type = smooth for a smooth vertex and crease for a dart vertex,
6954  // then C is "standard" if E[0] has type E0type, every other
6955  // edge E[i] is smooth, every outer vertex/ P[i] is smooth, and every
6956  // face F[i] has the stadard facet type (tri or quad) for the subdivision
6957  // algorithm.
6958  //
6959  // If If "C" is a boundary vertex (m_vertex_tag is crease or corner), the conditions
6960  // listed above are satisified except
6961  // E[0] and E[N-1] are tagged as crease edges,
6962  // P[0] and P[N-1] are tagged as crease vertices (NOT corners),
6963  // and there are N-2 faces,
6964  // then "C" is a standard boundary vertex.
6965  //
6966  // If the facet type is triangle and C is a standard interior or boundary vertex,
6967  // then the "standard vertex ring" is the list of N+1 points
6968  // (C, P[0], ...., P[N-1]).
6969  //
6970  // If the facet type is quad, and C is a standard interior vertex,
6971  // then the "standard vertex ring" is the list of 2*N+1 points
6972  // (C, P[0], Q[0], ...., P[N-1], Q[N-1]), where Q[I] is the average of the
6973  // four corners of the quad F[i].
6974  //
6975  // If the facet type is quad, and C is a standard boundary vertex,
6976  // then the "standard vertex ring" is the list of 2*N points
6977  // (C, P[0], Q[0], ...., P[N-1]).
6978 
6979  // m_S = R x R subdivision matrix
6980  // If (vertexR[0], ..., vertexR[R-1]) is a list of standard vertex ring points,
6981  // then then the location of the subdivided ring points
6982  // (vertexR1[0], ..., vertexR1[R-1]) can be calculated from m_S.
6983  // vertexR1[i] = m_S[i][0]*vertexR[0] + ... + m_S[i][R-1]*vertexR[R-1]
6984  const double* const* m_S = nullptr;
6985 
6986  // m_LP[] = limit point evaluation vector.
6987  // The array m_LP[] has m_R elements.
6988  // If (vertexR[0], ..., vertexR[R-1]) is a list of standard vertex ring points,
6989  // then Limit point = m_LP[0]*vertexR[0] + ... + m_LP[R-1]*vertexR[R-1].
6990  // m_LP is the eigenvector of Transpose(m_S) with eigenvalue = 1.
6991  // Length(m_LP) = 1.
6992  const double* m_LP = nullptr;
6993 
6994  // m_L1 and m_L2 = tangent space evaluation vectors.
6995  // The arrays m_L1[] and m_L2[] have m_R elements.
6996  // If (vertexR[0], ..., vertexR[R-1]) is a list of standard vertex ring points,
6997  // then the two vectors
6998  // V1 = m_L1[0]*vertexR[0] + ... + m_L1[R-1]*vertexR[R-1].
6999  // V2 = m_L2[0]*vertexR[0] + ... + m_L2[R-1]*vertexR[R-1].
7000  // span the tangent plane and
7001  // N = V1 x V2 is perpindicular to the limit tangent plane.
7002  // In general and almost always in practice, V1 and V2 are not unit vectors
7003  // and it is best to noramalize V1 and V2 before taking the cross product.
7004  // m_L1 and m_L2 are subdominant eigenvectors of Transpose(m_S).
7005  // When the subdominant eigenvalue has geometric multiplicity 2,
7006  // m_L1 and m_L2 span the same space as m_E1 and m_E2.
7007  // The values stored in m_L1 and m_L2 are chosen to provide accurate
7008  // evaluation. In come common cases m_L1 and m_L2 are equal to m_E1 and m_E2,
7009  // but not in all cases.
7010  const double* m_L1 = nullptr;
7011  const double* m_L2 = nullptr;
7012 
7013  /*
7014  Description:
7015  Set the values in this ON_SubDMatrix so the information
7016  can be used to evaluate the case identified by the input
7017  parameters.
7018  Parameters:
7019  facet_type - [in]
7020  vertex_tag - [in]
7021  sector_edge_count - [in]
7022  The input parameters identify the subdivision case.
7023  Returns:
7024  R > 0: Success. The matrix is R x R.
7025  0: Failure.
7026  */
7027  unsigned int SetFromSectorType(
7028  ON_SubDSectorType sector_type
7029  );
7030 
7031  /*
7032  Returns:
7033  ON_UNSET_VALUE - serious error
7034  >= 0:
7035  Maximum value of numbers that should be zero in and ideal world.
7036  When the matrices, eigenvalues and eigenvectors are correctly calculated,
7037  this returned value is in the range from 1e-16 to 5e-13 as valence goes
7038  from 3 to 100.
7039  For valences < 100, if a value larger than 1.0e-12 occurs, there is a bug in the code.
7040  */
7041  double TestMatrix() const;
7042 
7043  /*
7044  Description:
7045  Run evaluation tests on this subdivision case.
7046  Returns:
7047  >= 0.0: Test passed. Maximum deviation found in any test is returned.
7048  ON_UNSET_VALUE: Test failed.
7049  */
7050  double TestEvaluation() const;
7051 
7052  /*
7053  Description:
7054  Run evaluation tests on a range of subdivision cases.
7055  Parameters:
7056  sector_type - [in]
7057  If ON_SubDSectorType::Empty, then all supported sector types types are tested.
7058  minimum_sector_face_count - [in]
7059  If 0, then testing begins at ON_SubDSectorType::MinimumSectorFaceCount(vertex_tag)
7060  when testing vertex_tag types
7061  maximum_sector_face_count - [in]
7062  If 0, then testing stops at ON_SubD::maximum_evaluation_valence.
7063  text_log - [out]
7064  If not nullptr, then a brief written report is printed for each test case.
7065  Returns:
7066  >= 0.0: Test passed. Maximum deviation found in any test is returned.
7067  ON_UNSET_VALUE: Test failed.
7068  */
7069  static double TestEvaluation(
7070  ON_SubDSectorType sector_type,
7071  unsigned int minimum_sector_face_count,
7072  unsigned int maximum_sector_face_count,
7073  ON_TextLog* text_log
7074  );
7075 
7076  double TestComponentRing(
7077  size_t component_ring_count,
7078  const ON_SubDComponentPtr* component_ring
7079  ) const;
7080 
7081  /*
7082  Description:
7083  Test cached subdivision matrix on sector identified by sit.
7084  Parameters:
7085  subd_type - [in]
7086  subd_recursion_count - [in]
7087  number of times to subdivide
7088  sit - [in]
7089  vertex to subdivide
7090  component_ring - [out]
7091  subd_points - [out]
7092  limit_point - [out]
7093  limit_tangent0 - [out]
7094  limit_tangent1 - [out]
7095  limit_normal - [out]
7096  */
7097  static double TestEvaluation(
7098  ON_SubD::SubDType subd_type,
7099  const unsigned int subd_recursion_count,
7100  ON_SubDSectorIterator sit,
7101  ON_SimpleArray<ON_SubDComponentPtr>& component_ring,
7102  ON_SimpleArray< ON_3dPoint >& subd_points,
7103  class ON_SubDSectorLimitPoint& limit_point
7104  );
7105 
7106 private:
7107  unsigned int m__max_R = 0;
7108  ON_Matrix m__S; // m_S matrix memory
7109  ON_SimpleArray<double> m__buffer; // m_LP, m_L1, m_L2, m_E1, m_E2 memory
7110 };
7111 
7112 //////////////////////////////////////////////////////////////////////////
7113 //
7114 // ON_SubD_FixedSizeHeap
7115 //
7116 
7117 class ON_SUBD_CLASS ON_SubD_FixedSizeHeap
7118 {
7119 private:
7120  static unsigned int m__sn_factory;
7121 
7122 public:
7123  // The serial number is used for debugging purposes.
7124  const unsigned int m_sn = ++m__sn_factory;
7125 
7126 public:
7127  ON_SubD_FixedSizeHeap() = default;
7128  ~ON_SubD_FixedSizeHeap();
7129 
7130  /*
7131  Description:
7132  Reserve enough room to accomodate a face
7133  with one extraordinary vertex.
7134  Parameters:
7135  subd_type - [in]
7136  extraordinary_valence - [in]
7137  */
7138  bool ReserveSubDWorkspace(
7139  ON_SubD::SubDType subd_type,
7140  unsigned int extraordinary_valence
7141  );
7142 
7143  bool ReserveSubDWorkspace(
7144  size_t vertex_capacity,
7145  size_t edge_capacity,
7146  size_t face_capacity,
7147  size_t array_capacity
7148  );
7149 
7150  /*
7151  Description:
7152  Reset this ON_SubD_FixedSizeHeap so it can be used again.
7153  */
7154  void Reset();
7155 
7156  /*
7157  Description:
7158  Deallocate all reserved heap.
7159  */
7160  void Destroy();
7161 
7162  bool InUse() const;
7163 
7164  ON_SubDVertex* AllocateVertex(
7165  const double vertexP[3],
7166  unsigned int edge_capacity,
7167  unsigned int face_capacity
7168  );
7169 
7170  ON_SubDVertex* AllocateVertex(
7171  const ON_SubDVertex* vertex0,
7172  ON_SubD::SubDType subd_type,
7173  bool bUseSavedSubdivisionPoint,
7174  unsigned int edge_capacity,
7175  unsigned int face_capacity
7176  );
7177 
7178  ON_SubDVertex* AllocateVertex(
7179  const ON_SubDEdge* edge0,
7180  ON_SubD::SubDType subd_type,
7181  bool bUseSavedSubdivisionPoint,
7182  unsigned int edge_capacity,
7183  unsigned int face_capacity
7184  );
7185 
7186  ON_SubDVertex* AllocateVertex(
7187  const ON_SubDFace* face0,
7188  ON_SubD::SubDType subd_type,
7189  bool bUseSavedSubdivisionPoint,
7190  unsigned int edge_capacity,
7191  unsigned int face_capacity
7192  );
7193 
7194  /*
7195  Parameters:
7196  v0 - [in]
7197  v0_sector_weight - [in]
7198  If v0 null or ON_SubD::VertexTag::Smooth == v0->m_vertex_tag, and v1 is null or tagged,
7199  then m_sector_weight[0] is set to v0_sector_weight.
7200  In all other cases the value of v0_sector_weight is ignored and m_sector_weight[0]
7201  is set to ON_SubDSectorType::IgnoredSectorWeight.
7202  v1 - [in]
7203  v1_sector_weight - [in]
7204  If v1 null or ON_SubD::VertexTag::Smooth == v1->m_vertex_tag, and v0 is null or tagged,
7205  then m_sector_weight[1] is set to v1_sector_weight.
7206  In all other cases the value of v1_sector_weight is ignored and m_sector_weight[1]
7207  is set to ON_SubDSectorType::IgnoredSectorWeight.
7208  Returns:
7209  An edge.
7210  The vertex parameter information is used to set the ON_SubDEdge.m_vertex[]
7211  and ON_SubDEdge.m_sector_weight[] values.
7212  If v0 and v1 are not null and both are tagged, then ON_SubDEdge.m_edge_tag is
7213  set to ON_SubD::EdgeTag::Crease.
7214  In all other cases, ON_SubDEdge.m_edge_tag is set to ON_SubD::EdgeTag::Smooth.
7215  If v0 or v1 is not null, then ON_SubDEdge.m_level is set to the
7216  maximum of v0->m_level or v1->m_level.
7217  */
7218  ON_SubDEdge* AllocateEdge(
7219  ON_SubDVertex* v0,
7220  double v0_sector_weight,
7221  ON_SubDVertex* v1,
7222  double v1_sector_weight
7223  );
7224 
7225  /*
7226  Returns:
7227  A face with all field values zero (same values as ON_SubDEdge::Face), except ON_SubDFace.m_id.
7228  */
7229  ON_SubDFace* AllocateFace(
7230  unsigned int zero_face_id,
7231  unsigned int parent_face_id
7232  );
7233 
7234  ON_SubDFace* AllocateQuad(
7235  unsigned int zero_face_id,
7236  unsigned int parent_face_id,
7237  const ON_SubDEdgePtr eptrs[4]
7238  );
7239 
7240  ON_SubDFace* AllocateTri(
7241  unsigned int zero_face_id,
7242  unsigned int parent_face_id,
7243  const ON_SubDEdgePtr eptrs[3]
7244  );
7245 
7246  /*
7247  Parameters:
7248  capacity - [in]
7249  desired array size
7250  bZeroMemory - [in]
7251  If true, all array element values are zero.
7252  If false, array element values are undefined.
7253  Returns:
7254  An array of capacity ON__UINT_PTR pointers.
7255  */
7256  ON__UINT_PTR* AllocatePtrArray(
7257  unsigned int capacity,
7258  bool bZeroMemory
7259  );
7260 
7261  /*
7262  Description:
7263  Return the most recent array obtained from AllocatePtrArray().
7264  so it can be reused.
7265  Returns:
7266  True:
7267  Success.
7268  False:
7269  Failure. The array was not the most recent array obtained
7270  from AllocatePtrArray().
7271  */
7272  bool ReturnPtrArray(
7273  unsigned int capacity,
7274  void* p
7275  );
7276 
7277 private:
7278  //unsigned int m_max_valence = 0;
7279 
7280  ON_SubDVertex* m_v = nullptr;
7281  unsigned int m_v_capacity = 0;
7282  unsigned int m_v_index = 0;
7283 
7284  ON_SubDEdge* m_e = nullptr;
7285  unsigned int m_e_capacity = 0;
7286  unsigned int m_e_index = 0;
7287 
7288  ON_SubDFace* m_f = nullptr;
7289  unsigned int m_f_capacity = 0;
7290  unsigned int m_f_index = 0;
7291 
7292  ON__UINT_PTR* m_p = nullptr;
7293  unsigned int m_p_capacity = 0;
7294  unsigned int m_p_index = 0;
7295 
7296 private:
7297  // copies not supported
7298  ON_SubD_FixedSizeHeap(const ON_SubD_FixedSizeHeap&) = delete;
7299  ON_SubD_FixedSizeHeap& operator=(const ON_SubD_FixedSizeHeap&) = delete;
7300 };
7301 
7302 #if defined(ON_COMPILING_OPENNURBS)
7303 /*
7304 The ON_SubDAsUserData class is used to attach a subd to it proxy mesh
7305 when writing V6 files in commerical rhino.
7306 */
7307 class ON_SubDMeshProxyUserData : public ON_UserData
7308 {
7309 public:
7310  /*
7311  Returns:
7312  A pointer to a mesh that now manages subd.
7313  */
7314  static ON_Mesh* MeshProxyFromSubD(
7315  const ON_SubD* subd
7316  );
7317 
7318  /*
7319  Returns:
7320  A pointer to a subd and deletes mesh.
7321  */
7322  static ON_SubD* SubDFromMeshProxy(
7323  const ON_Mesh* mesh
7324  );
7325 
7326  /*
7327  Returns:
7328  A pointer to a subd and deletes mesh.
7329  */
7330  static bool IsSubDMeshProxy(
7331  const ON_Mesh* mesh
7332  );
7333 
7334  static const ON_SubDDisplayParameters MeshProxyDisplayParameters();
7335 
7336 private:
7337  ON_OBJECT_DECLARE(ON_SubDMeshProxyUserData);
7338 
7339 public:
7340  ON_SubDMeshProxyUserData();
7341  ~ON_SubDMeshProxyUserData();
7342  ON_SubDMeshProxyUserData(const ON_SubDMeshProxyUserData&);
7343  ON_SubDMeshProxyUserData& operator=(const ON_SubDMeshProxyUserData&);
7344 
7345 private:
7346  // ON_Object overrides
7347  bool Write(ON_BinaryArchive& archive) const override;
7348  bool Read(ON_BinaryArchive& archive) override;
7349  bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
7350 
7351  bool ParentMeshValid() const;
7352 
7353 private:
7354  // ON_UserData overrides
7355  bool GetDescription(ON_wString& description) override;
7356  bool WriteToArchive(
7357  const class ON_BinaryArchive& archive,
7358  const class ON_Object* parent_object
7359  ) const override;
7360 
7361 private:
7362  // The subd
7363  mutable ON_SubD* m_subd = nullptr;
7364 
7365 private:
7366  // information used to see if the parent mesh has been modified.
7367  mutable unsigned int m_mesh_face_count = 0;
7368  mutable unsigned int m_mesh_vertex_count = 0;
7369  mutable ON_SHA1_Hash m_mesh_face_array_sha1 = ON_SHA1_Hash::EmptyContentHash;
7370  mutable ON_SHA1_Hash m_mesh_vertex_array_sha1 = ON_SHA1_Hash::EmptyContentHash;
7371 
7372 private:
7373  void Internal_CopyFrom(const ON_SubDMeshProxyUserData& src);
7374  void Internal_Destroy();
7375  static const bool Internal_MeshHasFaces(const ON_Mesh* mesh);
7376  static const ON_SHA1_Hash Internal_FaceSHA1(const ON_Mesh* mesh);
7377  static const ON_SHA1_Hash Internal_VertexSHA1(const ON_Mesh* mesh);
7378 };
7379 #endif
7380 
7381 #endif
7382 
7383 #endif
Definition: opennurbs_progress_reporter.h:25
static const ON_SHA1_Hash EmptyContentHash
Definition: opennurbs_sha1.h:23
Definition: opennurbs_nurbssurface.h:62
Definition: opennurbs_rtree.h:398
static const ON_Interval ZeroToOne
Definition: opennurbs_point.h:50
Definition: opennurbs_array.h:36
Definition: opennurbs_sha1.h:19
Definition: opennurbs_string.h:2020
static const ON_PickPoint Unset
Definition: opennurbs_xform.h:1323
Base class for all geometry classes that must provide runtime class id. Provides interface for common...
Definition: opennurbs_geometry.h:37
Definition: opennurbs_xform.h:1320
Definition: opennurbs_compstat.h:396
Definition: opennurbs_bounding_box.h:25
Definition: opennurbs_xform.h:28
Definition: opennurbs_mesh.h:2188
Definition: opennurbs_compstat.h:88
Definition: opennurbs_matrix.h:22
Definition: opennurbs_brep.h:1472
Pure virtual base class for all classes that must provide runtime class id or support object level 3D...
Definition: opennurbs_object.h:460
Definition: opennurbs_terminator.h:20
Definition: opennurbs_textlog.h:20
Definition: opennurbs_archive.h:1783
Definition: opennurbs_bezier.h:1061
Definition: opennurbs_userdata.h:20
static const ON_ComponentStatus NoneSet
Definition: opennurbs_compstat.h:92
Definition: opennurbs_objref.h:163
Definition: opennurbs_point.h:460
Definition: opennurbs_point.h:46