mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-03 13:17:00 +08:00
Co-authored-by: Andrew Le Bihan <andy@mcneel.com> Co-authored-by: Dale Fugier <dale@mcneel.com> Co-authored-by: Dale Lear <dalelear@mcneel.com> Co-authored-by: David Eränen <deranen@gmail.com> Co-authored-by: Greg Arden <greg@mcneel.com> Co-authored-by: Jussi Aaltonen <jussi@mcneel.com> Co-authored-by: Lowell <lowell@mcneel.com> Co-authored-by: Mikko Oksanen <mikko@mcneel.com> Co-authored-by: Pierre Cuvilliers <pierre@mcneel.com> Co-authored-by: Steve Baer <steve@mcneel.com> Co-authored-by: chuck <chuck@mcneel.com> Co-authored-by: piac <giulio@mcneel.com> Co-authored-by: wfcook <wfcook@mcneel.com>
18165 lines
537 KiB
C++
18165 lines
537 KiB
C++
/* $NoKeywords: $ */
|
|
/*
|
|
//
|
|
// Copyright (c) 1993-2014 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
|
|
#if 0
|
|
#define ON_SUBD_CENSUS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_CensusCounter
|
|
//
|
|
// This tool is used to study memory leaks and other shared ptr issues.
|
|
// The classes have no size but effect performance. Use only in
|
|
// debugging situations. Never ship a release with ON_SUBD_CENSUS defined.
|
|
//
|
|
class ON_CLASS ON_CensusCounter
|
|
{
|
|
public:
|
|
enum class Class : unsigned int
|
|
{
|
|
unset = 0,
|
|
subd = 1,
|
|
subd_impl = 2,
|
|
subd_limit_mesh = 3,
|
|
subd_limit_mesh_impl = 4,
|
|
subd_ref = 5,
|
|
|
|
count
|
|
};
|
|
|
|
static void RegisterBirth(ON_CensusCounter::Class,ON__UINT_PTR);
|
|
|
|
static void RegisterDeath(ON_CensusCounter::Class,ON__UINT_PTR);
|
|
|
|
static void CensusReport(
|
|
class ON_TextLog&
|
|
);
|
|
|
|
static void Clear();
|
|
};
|
|
|
|
class ON_CLASS ON_SubDCensusCounter
|
|
{
|
|
public:
|
|
ON_SubDCensusCounter() ON_NOEXCEPT;
|
|
~ON_SubDCensusCounter() ON_NOEXCEPT;
|
|
ON_SubDCensusCounter(const ON_SubDCensusCounter&) ON_NOEXCEPT;
|
|
ON_SubDCensusCounter& operator=(const ON_SubDCensusCounter&) = default;
|
|
//ON_SubDCensusCounter( ON_SubDCensusCounter&& ) ON_NOEXCEPT;
|
|
//ON_SubDCensusCounter& operator=( ON_SubDCensusCounter&& ) ON_NOEXCEPT;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDRefCensusCounter
|
|
{
|
|
public:
|
|
ON_SubDRefCensusCounter() ON_NOEXCEPT;
|
|
~ON_SubDRefCensusCounter() ON_NOEXCEPT;
|
|
ON_SubDRefCensusCounter(const ON_SubDRefCensusCounter&) ON_NOEXCEPT;
|
|
ON_SubDRefCensusCounter& operator=(const ON_SubDRefCensusCounter&) = default;
|
|
//ON_SubDRefCensusCounter( ON_SubDRefCensusCounter&& ) ON_NOEXCEPT;
|
|
//ON_SubDRefCensusCounter& operator=( ON_SubDRefCensusCounter&& ) ON_NOEXCEPT;
|
|
};
|
|
|
|
|
|
class ON_CLASS ON_SubDImpleCensusCounter
|
|
{
|
|
public:
|
|
ON_SubDImpleCensusCounter() ON_NOEXCEPT;
|
|
~ON_SubDImpleCensusCounter() ON_NOEXCEPT;
|
|
ON_SubDImpleCensusCounter(const ON_SubDImpleCensusCounter&) ON_NOEXCEPT;
|
|
ON_SubDImpleCensusCounter& operator=(const ON_SubDImpleCensusCounter&) = default;
|
|
//ON_SubDImplCensusCounter( ON_SubDImplCensusCounter&& ) ON_NOEXCEPT;
|
|
//ON_SubDImplCensusCounter& operator=( ON_SubDImplCensusCounter&& ) ON_NOEXCEPT;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDMeshCensusCounter
|
|
{
|
|
public:
|
|
ON_SubDMeshCensusCounter() ON_NOEXCEPT;
|
|
~ON_SubDMeshCensusCounter() ON_NOEXCEPT;
|
|
ON_SubDMeshCensusCounter(const ON_SubDMeshCensusCounter&) ON_NOEXCEPT;
|
|
ON_SubDMeshCensusCounter& operator=(const ON_SubDMeshCensusCounter&) = default;
|
|
//ON_SubDMeshCensusCounter( ON_SubDMeshCensusCounter&& ) ON_NOEXCEPT;
|
|
//ON_SubDMeshCensusCounter& operator=( ON_SubDMeshCensusCounter&& ) ON_NOEXCEPT;
|
|
};
|
|
|
|
|
|
class ON_CLASS ON_SubDMeshCensusCounter
|
|
{
|
|
public:
|
|
ON_SubDMeshCensusCounter() ON_NOEXCEPT;
|
|
~ON_SubDMeshCensusCounter() ON_NOEXCEPT;
|
|
ON_SubDMeshCensusCounter(const ON_SubDMeshCensusCounter&) ON_NOEXCEPT;
|
|
ON_SubDMeshCensusCounter& operator=(const ON_SubDMeshCensusCounter&) ON_NOEXCEPT;
|
|
ON_SubDMeshCensusCounter( ON_SubDMeshCensusCounter&& ) ON_NOEXCEPT;
|
|
ON_SubDMeshCensusCounter& operator=( ON_SubDMeshCensusCounter&& ) ON_NOEXCEPT;
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Definition of subdivision surface
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#if !defined(OPENNURBS_SUBD_INC_)
|
|
#define OPENNURBS_SUBD_INC_
|
|
|
|
/// <summary>
|
|
/// ON_SubDGetControlNetMeshPriority specifies what type of ON_SubD information
|
|
/// is most important to transfer to the ON_Mesh.
|
|
/// </summary>
|
|
enum class ON_SubDGetControlNetMeshPriority : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Create a mesh that can be used to reliably transfer SubD control net geometry,
|
|
/// topology, and interior edge crease information. Use this option when the mesh
|
|
/// will be used to create a Catmull-Clark subdivision surface. SubD texture
|
|
/// coordinates cannot be recovered from the mesh.
|
|
///</summary>
|
|
Geometry = 0,
|
|
|
|
///<summary>
|
|
/// Create a mesh that has the shape of the SubD control net and
|
|
/// includes SubD texture coordinate information.
|
|
/// Use this option when the mesh will be used to create an image of the
|
|
/// SubD control net that relies on texture coordinates. SubD interior edge
|
|
/// crease inforation cannot be recovered from the mesh. Most applications will
|
|
/// not be able to use the mesh to recreate a Catmull-Clark subdivision surface.
|
|
///</summary>
|
|
TextureCoordinates = 1
|
|
};
|
|
|
|
|
|
/// <summary>
|
|
/// ON_SubDTextureCoordinateType identifies the way ON_SubDMeshFragment texture coordinates are set from an ON_SubDFace.
|
|
/// </summary>
|
|
enum class ON_SubDTextureCoordinateType : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Texture domains are not set.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// Each SubDFace uses the unit square in texture space.
|
|
///</summary>
|
|
Unpacked = 1,
|
|
|
|
///<summary>
|
|
/// The face's pack rect is used to set fragment texture coordintes.
|
|
/// When possible, adjacent quads with the same ON_SubDFace::PackId() value are assigned adjacent
|
|
/// rectangles in texture space.
|
|
///</summary>
|
|
Packed = 2,
|
|
|
|
///<summary>
|
|
/// All ON_SubDMeshFragment texture coordinate values are zero.
|
|
///</summary>
|
|
Zero = 3,
|
|
|
|
///<summary>
|
|
/// All ON_SubDMeshFragment texture coordinate values are ON_DBL_QNAN.
|
|
///</summary>
|
|
Nan = 4,
|
|
|
|
///<summary>
|
|
/// All ON_SubDMeshFragment texture coordinate values are set by
|
|
/// barycentric interpolation of ON_SubDFace.TexturePoint() values.
|
|
///</summary>
|
|
FromFaceTexturePoints = 6,
|
|
|
|
///<summary>
|
|
/// Texture coordinates are set from an ON_TextureMapping and transformation specificed
|
|
/// by ON_SubD::TextureMappingTag(). In all other cases, ON_SubD::TextureMappingTag()
|
|
/// can be set, but is ignored.
|
|
///</summary>
|
|
FromMapping = 7,
|
|
};
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDVertexTag] [Rhino.Geometry.SubDVertexTag] [byte]
|
|
/// <summary>
|
|
/// ON_SubDVertexTag identifies the type of subdivision vertex. Different tags use
|
|
/// different subdivision algorithms to determine where the subdivision point and
|
|
/// limit point are located. There are toplological constraints that restrict which
|
|
/// tags can be assigned.
|
|
/// </summary>
|
|
enum class ON_SubDVertexTag : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Not a valid vertex tag and the default value for ON_SubDVertex.m_vertex_tag.
|
|
/// This encourages developers to thoughtfully initialize ON_SubDVertex.m_vertex_tag
|
|
/// or use ON_SubD.UpdateAllTagsAndSectorCoefficients() to automatically set the
|
|
/// m_vertex_tag values at an appropriate time.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// Must be an interior vertex.
|
|
/// All edges attached to a smooth vertex must be tagged as ON_SubDEdgeTag::Smooth
|
|
/// and must have 2 faces.
|
|
///</summary>
|
|
Smooth = 1,
|
|
|
|
///<summary>
|
|
/// Can be an interior or a boundary vertex.
|
|
/// Exactly two edges ending at a crease vertex must be tagged as ON_SubDEdgeTag::Crease and may
|
|
/// have 1 or 2 faces.
|
|
/// All other edges ending at a crease must be tagged as tagON_SubD::EdgeTag::Smooth and have 2 faces.
|
|
/// Below P = ON_SubDVertex.ControlNetPoint() and Ai = ON_SubDVertex.Edge(i)->OtherEndVertex()->ControlNetPoint().
|
|
/// A crease vertex subdivision point is (6*P + A1 + A2)/8.
|
|
/// A crease vertex limit surface point is (4*P + A1 + A2)/6.
|
|
///</summary>
|
|
Crease = 2,
|
|
|
|
///<summary>
|
|
/// Can be an interior, boundary, nonmanifold, or isolated vertex.
|
|
/// The location of a corner vertex is fixed.
|
|
/// The all subdivision points and the limit point are at the initial vertex location.
|
|
/// The edges ending at a corner vertex can be smooth or crease edges.
|
|
/// A corner vertex subdivision point is P where P = ON_SubDVertex.ControlNetPoint().
|
|
/// A corner vertex limit surface point is P where P = ON_SubDVertex.ControlNetPoint().
|
|
///</summary>
|
|
Corner = 3,
|
|
|
|
///<summary>
|
|
/// Must be an interior vertex.
|
|
/// Every edge attached to a dart vertex must have 2 faces.
|
|
/// Exactly one edge attached to a dart vertex must be tagged as ON_SubDEdgeTag::Crease
|
|
/// and every other attached edge must be tagged as ON_SubDEdgeTag::smooth.
|
|
///</summary>
|
|
Dart = 4
|
|
};
|
|
#pragma endregion
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDEdgeTag] [Rhino.Geometry.SubDEdgeTag] [byte]
|
|
/// <summary>
|
|
/// ON_SubDEdgeTag identifies the type of subdivision edge. Different tags use
|
|
/// different subdivision algorithms to calculate the subdivision point.
|
|
/// </summary>
|
|
enum class ON_SubDEdgeTag : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Not a valid edge tag and the default value for ON_SubDEdge.m_edge_tag.
|
|
/// This encourages developers to thoughtfully initialize ON_SubDEdge.m_edge_tag.
|
|
/// or use ON_SubD.UpdateAllTagsAndSectorCoefficients() to automatically set the
|
|
/// m_edge_tag values at an appropriate time.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// At least one the edge's vertices must be tagged as ON_SubDVertexTag::Smooth.
|
|
/// The edge must have exactly two faces.
|
|
/// The edge's subdivision point is (A1 + A2 + S(f1) + S(f2))/4, where
|
|
/// Ai = ON_SubDEdge.Vertex(i)->ControlNetPoint() and
|
|
/// S(fi) = ON_SubDEdge.Face(i)->SubdivisionPoint().
|
|
///</summary>
|
|
Smooth = 1,
|
|
|
|
///<summary>
|
|
/// Both of the edge's vertices must be tagged as ON_SubDVertexTag::Dart,
|
|
/// ON_SubDVertexTag::Crease, or ON_SubDVertexTag::Corner.
|
|
/// (The vertex tags can be different.) The edge can have any number of faces.
|
|
/// The edge's subdivision point is (A1+A2)/2 where Ai = ON_SubDEdge.Vertex(i)->ControlNetPoint().
|
|
///</summary>
|
|
Crease = 2,
|
|
|
|
///<summary>
|
|
/// This tag appears only on level 0 edges that have exactly two neighboring faces
|
|
/// and both of the edge's vertices are tagged as ON_SubDVertexTag::Dart,
|
|
/// ON_SubDVertexTag::Crease, or ON_SubDVertexTag::Corner.
|
|
/// The level 1 subdivision point for a level 0 edge tagged as ON_SubDEdgeTag::SmoothX
|
|
/// is the standard smooth edge subdivision point.
|
|
/// When subdivided, the new subdivision vertex will be tagged
|
|
/// as ON_SubDVertexTag::Smooth and the subdivided edges will
|
|
/// be tagged as ON_SubDEdgeTag::Smooth.
|
|
/// The tag ON_SubDEdgeTag::SmoothX can only appear on a level 0 edge.
|
|
/// This tag exists because the ON_SubD subdivision
|
|
/// algorithm requires any edge with both end vertices
|
|
/// tagged as not smooth must be subdivided at its midpoint.
|
|
/// Sector iterators treat "SmoothX" edges as smooth.
|
|
/// Both edge m_sector_coefficient[] values must be set so the smooth subdivided edges will be valid.
|
|
///</summary>
|
|
SmoothX = 4
|
|
};
|
|
#pragma endregion
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDHashType] [Rhino.Geometry.SubDHashType] [byte]
|
|
/// <summary>
|
|
/// ON_SubDHashType used used to specify what type of SubD information is hashed (topology or geometry).
|
|
/// </summary>
|
|
enum class ON_SubDHashType : unsigned char
|
|
{
|
|
/// <summary>
|
|
/// Unset indicates the hash type still needs to be selected. It is not a valid type
|
|
/// for calculating a hash.
|
|
/// </summary>
|
|
Unset = 0,
|
|
|
|
/// <summary>
|
|
/// The Topology hash includes component ids, and all topological relationships
|
|
/// between vertices, edges, and faces. If two SubDs have the same topology hash,
|
|
/// then the the have identical labeled control net topology.
|
|
/// </summary>
|
|
Topology = 3,
|
|
|
|
/// <summary>
|
|
/// The TopologyAndEdgeCreases includes all information in a Topology hash.
|
|
/// The TopologyAndEdgeCreases adds edge crease/smooth attributes.
|
|
/// Many contexts, including face packing and exploding, take edge creases
|
|
/// into account when partitioning a SubD into regions.
|
|
/// </summary>
|
|
TopologyAndEdgeCreases = 1,
|
|
|
|
/// <summary>
|
|
/// A geometry hash includes all information in a TopologyAndEdgeCreases hash.
|
|
/// The Geometry hash adds vertex tags, vertex control net points,
|
|
/// and nonzero subdivision displacements on vertices, edges, and faces.
|
|
/// If two SubDs have the same geometry hash, then they have identical surface geometry.
|
|
/// </summary>
|
|
Geometry = 2
|
|
};
|
|
#pragma endregion
|
|
|
|
ON_DECL
|
|
ON_SubDHashType ON_SubDHashTypeFromUnsigned(
|
|
unsigned int subd_hash_type_as_unsigned
|
|
);
|
|
|
|
ON_DECL
|
|
const ON_wString ON_SubDHashTypeToString(
|
|
ON_SubDHashType subd_hash_type,
|
|
bool bVerbose
|
|
);
|
|
|
|
/// <summary>
|
|
/// ON_SubDHash provides a simple way to save a SubD's vertex, edge, and face SHA1 hashes.
|
|
/// Typically it is used when a calculation needs to know if the current SubD has is geometrically
|
|
/// identical to a previous SubD. When speed is not important, comparing the current value of
|
|
/// ON_SubD::GeometryHash() to a previously save value of ON_SubD::GeometryHash() is functionally
|
|
/// identical but typically much slower when the SubDs are different.
|
|
/// </summary>
|
|
class ON_CLASS ON_SubDHash
|
|
{
|
|
public:
|
|
ON_SubDHash() = default;
|
|
~ON_SubDHash() = default;
|
|
ON_SubDHash(const ON_SubDHash&) = default;
|
|
ON_SubDHash& operator=(const ON_SubDHash&) = default;
|
|
|
|
public:
|
|
/// <summary>
|
|
/// All counts are zero and all hashes are ON_SHA1::EmptyContentHash.
|
|
/// </summary>
|
|
static const ON_SubDHash Empty;
|
|
|
|
// Saves the counts and hashs of the specified type
|
|
|
|
|
|
/// <summary>
|
|
/// Saves the counts and hashs of the specified type.
|
|
/// </summary>
|
|
/// <param name="hash_type"></param>
|
|
/// <param name="subd"></param>
|
|
/// <returns></returns>
|
|
static const ON_SubDHash Create(ON_SubDHashType hash_type, const class ON_SubD& subd );
|
|
|
|
static const ON_SubDHash Create(ON_SubDHashType hash_type, const class ON_SubDimple* subdimple);
|
|
|
|
/// <summary>
|
|
/// Dictionary compare of VertexCount(), EdgeCount(), FaceCount(), VertexHash(), EdgeHash(), and FaceHash() in that order.
|
|
///
|
|
/// NOTE WELL:
|
|
/// SubDRuntimeSerialNumber() and SubdGeometryContentSerialNumber() are not compared because the reason this
|
|
/// class exists is for it to be used to see if two different SubDs have identical content.
|
|
/// </summary>
|
|
/// <param name="lhs"></param>
|
|
/// <param name="rhs"></param>
|
|
/// <returns>
|
|
/// -1: lhs < rhs
|
|
/// 0: lhs == rsh
|
|
/// 1: lhs > rhs
|
|
/// </returns>
|
|
static int Compare(const ON_SubDHash& lhs, const ON_SubDHash& rhs);
|
|
|
|
/*
|
|
Returns:
|
|
True if vertex count is 0 or HashType is unset.
|
|
*/
|
|
bool IsEmpty() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if vertex count is > 0 and HashType is geometry or toplology.
|
|
*/
|
|
bool IsNotEmpty() const;
|
|
|
|
ON_SubDHashType HashType() const;
|
|
|
|
/// <summary>
|
|
/// The runtime serial number can be used to identify the SubD that was hashed to created this ON_SubDHash.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// If this hash was created from an ON_SubD, then the value of subd.RuntimeSerialNumber() is returned.
|
|
/// Otherwise, 0 is returned.
|
|
/// </returns>
|
|
ON__UINT64 SubDRuntimeSerialNumber() const;
|
|
|
|
/// <summary>
|
|
/// The geometry content serial number can be used to quickly determine if a SubD is exactly the instance used
|
|
/// to create this ON_SubDHash. If the geometry content serial numbers are equal, then the SubD is identical
|
|
/// to the one use to create the hash. If the geometry content serial numbers differ, the current SubD hashes
|
|
/// need to be checked against this to see what, if anything, changed. For example, moving a vertex will not
|
|
/// change a topology hash.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// Returns:
|
|
/// If this hash was created from an ON_SubD, then the value of subd.GeometryContentSerialNumber() at the
|
|
/// at the instant this hash was created is returned.
|
|
/// Otherwise, 0 is returned.
|
|
/// </returns>
|
|
ON__UINT64 SubDGeometryContentSerialNumber() const;
|
|
|
|
/// <summary>
|
|
/// Copied from the SubD when the hash is created.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// Number of hashed vertices.
|
|
/// </returns>
|
|
unsigned int VertexCount() const;
|
|
|
|
/// <summary>
|
|
/// Copied from the SubD when the hash is created.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// Number of hashed edges.
|
|
/// </returns>
|
|
unsigned int EdgeCount() const;
|
|
|
|
/// <summary>
|
|
/// Copied from the SubD when the hash is created.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// Number of hashed faces.
|
|
/// </returns>
|
|
unsigned int FaceCount() const;
|
|
|
|
/// <summary>
|
|
/// If two SubDs have identical VertexHash() values,
|
|
/// then the SubD vertex information associated with HashType() is identical.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A SHA1 hash of the SubD's vertex information associated with HashType().
|
|
/// </returns>
|
|
const ON_SHA1_Hash VertexHash() const;
|
|
|
|
/// <summary>
|
|
/// If two SubDs have identical EdgeHash() values,
|
|
/// then the SubD edge information associated with HashType() is identical.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A SHA1 hash of the SubD's edge information associated with HashType().
|
|
/// </returns>
|
|
const ON_SHA1_Hash EdgeHash() const;
|
|
|
|
/// <summary>
|
|
/// If two SubDs have identical FaceHash() values,
|
|
/// then the SubD face information associated with HashType() is identical.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A SHA1 hash of the SubD's face information associated with HashType().
|
|
/// </returns>
|
|
const ON_SHA1_Hash FaceHash() const;
|
|
|
|
/// <summary>
|
|
/// If two SubDs have identical SubDHash() values,
|
|
/// then the SubD vertex, edge, and face information associated with HashType() is identical.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A SHA1 hash of the SubD's vertex, edge, and face information associated with HashType().
|
|
/// </returns>
|
|
const ON_SHA1_Hash SubDHash() const;
|
|
|
|
void Dump(ON_TextLog&) const;
|
|
bool Write(class ON_BinaryArchive&) const;
|
|
bool Read(class ON_BinaryArchive&);
|
|
|
|
private:
|
|
friend class ON_SubDimple;
|
|
ON_SubDHashType m_hash_type = ON_SubDHashType::Unset;
|
|
unsigned int m_vertex_count = 0;
|
|
unsigned int m_edge_count = 0;
|
|
unsigned int m_face_count = 0;
|
|
ON__UINT64 m_subd_runtime_serial_number = 0;
|
|
ON__UINT64 m_subd_geometry_content_serial_number = 0;
|
|
ON_SHA1_Hash m_vertex_hash = ON_SHA1_Hash::EmptyContentHash;
|
|
ON_SHA1_Hash m_edge_hash = ON_SHA1_Hash::EmptyContentHash;
|
|
ON_SHA1_Hash m_face_hash = ON_SHA1_Hash::EmptyContentHash;
|
|
};
|
|
|
|
bool operator==(const ON_SubDHash& lhs, const ON_SubDHash& rhs);
|
|
|
|
bool operator!=(const ON_SubDHash& lhs, const ON_SubDHash& rhs);
|
|
|
|
|
|
class ON_CLASS ON_SubDToBrepParameters
|
|
{
|
|
public:
|
|
ON_SubDToBrepParameters() = default;
|
|
~ON_SubDToBrepParameters() = default;
|
|
ON_SubDToBrepParameters(const ON_SubDToBrepParameters&) = default;
|
|
ON_SubDToBrepParameters& operator=(const ON_SubDToBrepParameters&) = default;
|
|
|
|
/*
|
|
Description:
|
|
Default ON_SubDToBrepParameters settings.
|
|
Remarks:
|
|
These are the settings used by ON_SubD::BrepForm()
|
|
*/
|
|
static const ON_SubDToBrepParameters Default;
|
|
|
|
/*
|
|
Description:
|
|
Default ON_SubDToBrepParameters settings for creating an unpacked brep.
|
|
*/
|
|
static const ON_SubDToBrepParameters DefaultUnpacked;
|
|
|
|
/*
|
|
Description:
|
|
Default ON_SubDToBrepParameters settings for creating an packed brep.
|
|
*/
|
|
static const ON_SubDToBrepParameters DefaultPacked;
|
|
|
|
static int Compare(
|
|
const ON_SubDToBrepParameters& lhs,
|
|
const ON_SubDToBrepParameters& rhs
|
|
);
|
|
static int CompareFromPointers(
|
|
const ON_SubDToBrepParameters* lhs,
|
|
const ON_SubDToBrepParameters* rhs
|
|
);
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDToBrepParameters::VertexProcess] [Rhino.Geometry.SubDToBrepOptions.ExtraordinaryVertexProcessOption] [nested:byte]
|
|
/// <summary>
|
|
/// ON_SubDToBrepParameters::Vertex identifies the options for post processing extraorindary vertices.
|
|
/// </summary>
|
|
enum class VertexProcess : unsigned char
|
|
{
|
|
///<summary>
|
|
/// The NURBS patches are used as is.
|
|
/// At extraordinary vertices, the brep vertex may not be G1.
|
|
/// Typically the deviation bewtween the brep and SubD surface is smallest with this option.
|
|
///</summary>
|
|
None = 0,
|
|
|
|
///<summary>
|
|
/// At extraordinary vertices, the NURBS patches are modified so they are G1 at the extraordinary vertex.
|
|
/// Typically the deviation bewtween the brep and SubD surface is larger than None and smaller than
|
|
/// LocalG1x and LocalG2.
|
|
///</summary>
|
|
LocalG1 = 1,
|
|
|
|
///<summary>
|
|
/// At extraordinary vertices, the NURBS patches are modified so they are G2 at the extraordinary vertex.
|
|
/// Typically the deviation bewtween the brep and SubD surface is larger than LocalG1 and LocalG1x.
|
|
///</summary>
|
|
LocalG2 = 2,
|
|
|
|
///<summary>
|
|
/// At extraordinary vertices, the NURBS patches are modified so they are G1 at the extraordinary vertex
|
|
/// and tend to be closer to G1 along edges near the extraordinary vertex.
|
|
/// Typically the deviation bewtween the brep and SubD surface is larger than LocalG1 and smaller than LocalG2.
|
|
///</summary>
|
|
LocalG1x = 3,
|
|
};
|
|
#pragma endregion
|
|
|
|
static ON_SubDToBrepParameters::VertexProcess VertexProcessFromUnsigned(
|
|
unsigned int vertex_process_as_unsigned
|
|
);
|
|
|
|
static const ON_wString VertexProcessToString(
|
|
ON_SubDToBrepParameters::VertexProcess vertex_process
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Option used for post processing extraorindary vertices.
|
|
*/
|
|
ON_SubDToBrepParameters::VertexProcess ExtraordinaryVertexProcess() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the ExtraordinaryVertexProcess() property.
|
|
Parameters:
|
|
ev_process - [in]
|
|
*/
|
|
void SetExtraordinaryVertexProcess(
|
|
ON_SubDToBrepParameters::VertexProcess ev_process
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
If true, then quad packs of SubD faces are returned as a single brep face.
|
|
Otherwise each SubD face generates a brep face.
|
|
Remarks:
|
|
SubD n-gons with n != 4 always generate n brep faces.
|
|
*/
|
|
bool PackFaces() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the PackFaces() property.
|
|
Parameters:
|
|
bPackFaces - [in]
|
|
*/
|
|
void SetPackFaces(
|
|
bool bPackFaces
|
|
);
|
|
|
|
const ON_wString ToString(
|
|
bool bVerbose
|
|
) const;
|
|
|
|
bool Read(ON_BinaryArchive& archive);
|
|
|
|
bool Write(ON_BinaryArchive& archive) const;
|
|
|
|
private:
|
|
bool m_bPackFaces = false;
|
|
ON_SubDToBrepParameters::VertexProcess m_extraordinary_vertex_process = ON_SubDToBrepParameters::VertexProcess::LocalG1x;
|
|
unsigned short m_reserved1 = 0;
|
|
unsigned int m_reserved2 = 0;
|
|
double m_reserved3 = 0.0;
|
|
};
|
|
|
|
bool operator==(const ON_SubDToBrepParameters& lhs, const ON_SubDToBrepParameters& rhs);
|
|
bool operator!=(const ON_SubDToBrepParameters& lhs, const ON_SubDToBrepParameters& rhs);
|
|
|
|
class ON_CLASS ON_SubDVertexPtr
|
|
{
|
|
public:
|
|
// For performance reasons, m_ptr is not initialized and no constructors are declared
|
|
// or implemented. If you require initialization, then use x = ON_SubDVertexPtr::Null
|
|
// or x = ON_SubDVertexPtr::Create(...).
|
|
ON__UINT_PTR m_ptr;
|
|
|
|
static const ON_SubDVertexPtr Null;
|
|
|
|
bool IsNull() const;
|
|
bool IsNotNull() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Vertex() is not nullptr, Vertex()->m_id is returned.
|
|
Otherwise, 0 is returned.
|
|
*/
|
|
unsigned int VertexId() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this vertex is active in its parent subd or other
|
|
relevent context.
|
|
Remarks:
|
|
When a component is in use, IsActive() = true.
|
|
If was used and then deleted, IsActive() is false.
|
|
*/
|
|
bool IsActive() const;
|
|
|
|
class ON_SubDVertex* Vertex() const;
|
|
|
|
ON__UINT_PTR VertexDirection() const;
|
|
|
|
const ON_ComponentStatus Status() const;
|
|
|
|
static const ON_SubDVertexPtr Create(
|
|
const class ON_SubDVertex* vertex
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
vertex - [in]
|
|
vertex_direction - [in]
|
|
zero or one
|
|
*/
|
|
static const ON_SubDVertexPtr Create(
|
|
const class ON_SubDVertex* vertex,
|
|
ON__UINT_PTR vertex_direction
|
|
);
|
|
|
|
static const ON_SubDVertexPtr Create(
|
|
const class ON_SubDComponentPtr& vertex_component
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The current value of the component mark ( m_status->RuntimeMark() ).
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
*/
|
|
bool Mark() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears (sets to false) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool ClearMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets (sets to true) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the value of the component mark to bMark.
|
|
Parameter:
|
|
bMark - [in]
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark(
|
|
bool bMark
|
|
) const;
|
|
|
|
|
|
ON__UINT8 MarkBits() const;
|
|
|
|
ON__UINT8 SetMarkBits(
|
|
ON__UINT8 mark_bits
|
|
) const;
|
|
|
|
ON__UINT8 ClearMarkBits() const;
|
|
|
|
void ClearSavedSubdivisionPoints() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this component.
|
|
Parameters:
|
|
bClearNeighborhood - [in]
|
|
If true, all components attached to this component are also cleared.
|
|
*/
|
|
void ClearSavedSubdivisionPoints(
|
|
bool bClearNeighborhood
|
|
) const;
|
|
|
|
};
|
|
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDVertexPtr>;
|
|
#endif
|
|
|
|
class ON_CLASS ON_SubDEdgePtr
|
|
{
|
|
public:
|
|
// For performance reasons, m_ptr is not initialized and no constructors are declared
|
|
// or implemented. If you require initialization, then use x = ON_SubDEdgePtr::Null
|
|
// or x = ON_SubDEdgePtr::Create(...).
|
|
ON__UINT_PTR m_ptr;
|
|
|
|
static const ON_SubDEdgePtr Null;
|
|
|
|
/*
|
|
Returns:
|
|
True if this->Edge() is nullptr.
|
|
*/
|
|
bool IsNull() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this->Edge() is not nullptr.
|
|
*/
|
|
bool IsNotNull() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
True if this->Edge() is not nullptr and both vertex pointers are not null as well.
|
|
*/
|
|
bool IsNotNullAndVerticesAreNotNull() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this edge is active in its parent subd or other
|
|
relevent context.
|
|
Remarks:
|
|
When a component is in use, IsActive() = true.
|
|
If was used and then deleted, IsActive() is false.
|
|
*/
|
|
bool IsActive() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
The ON_SubDEdge this points at.
|
|
*/
|
|
class ON_SubDEdge* Edge() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Edge() is not nullptr, Edge()->m_id is returned.
|
|
Otherwise, 0 is returned.
|
|
*/
|
|
unsigned int EdgeId() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Edge() is not nullptr, Edge()->FaceCount() is returned.
|
|
Otherwise, 0 is returned.
|
|
*/
|
|
unsigned int EdgeFaceCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Edge() is not nullptr, Edge()->IsSmooth() is returned.
|
|
Otherwise, false is returned.
|
|
*/
|
|
bool EdgeIsSmooth() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Edge() is not nullptr, Edge()->IsCrease() is returned.
|
|
Otherwise, false is returned.
|
|
*/
|
|
bool EdgeIsCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Edge() is not nullptr, Edge()->IsHardCrease() is returned.
|
|
Otherwise, false is returned.
|
|
*/
|
|
bool EdgeIsHardCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Edge() is not nullptr, Edge()->IsDartCrease() is returned.
|
|
Otherwise, false is returned.
|
|
*/
|
|
bool EdgeIsDartCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Edge() is not nullptr, Edge()->HasInteriorEdgeTopology(bRequireOppositeFaceDirections) is returned.
|
|
Otherwise, false is returned.
|
|
*/
|
|
bool HasInteriorEdgeTopology(
|
|
bool bRequireOppositeFaceDirections
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
0: this ON_SubDEdgePtr is oriented from Edge()->Vertex(0) to Edge()->Vertex(1).
|
|
1: this ON_SubDEdgePtr is oriented from Edge()->Vertex(1) to Edge()->Vertex(0).
|
|
*/
|
|
ON__UINT_PTR EdgeDirection() const;
|
|
|
|
/*
|
|
Parameters:
|
|
relative_vertex_index - [in]
|
|
0: return Edge()->Vertex(EdgeDirection())
|
|
1: return Edge()->Vertex(1-EdgeDirection())
|
|
Returns:
|
|
The requested vertex with EdgeDirection() taken into account.
|
|
nullptr if relative_vertex_index, Edge() is nullptr, or Edge()->Vertex() is nullptr.
|
|
*/
|
|
const class ON_SubDVertex* RelativeVertex(
|
|
int relative_vertex_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
relative_vertex_index - [in]
|
|
0: return Edge()->Vertex(EdgeDirection())
|
|
1: return Edge()->Vertex(1-EdgeDirection())
|
|
Returns:
|
|
The requested id of the vertex with EdgeDirection() taken into account.
|
|
0 if relative_vertex_index, Edge() is nullptr, or Edge()->Vertex() is nullptr.
|
|
*/
|
|
unsigned RelativeVertexId(
|
|
int relative_vertex_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
relative_vertex_index - [in]
|
|
0: return Edge()->Vertex(EdgeDirection())
|
|
1: return Edge()->Vertex(1-EdgeDirection())
|
|
Returns:
|
|
The requested vertex control net point EdgeDirection() taken into account.
|
|
ON_3dPoint::NanPoint if relative_vertex_index, Edge() is nullptr, or Edge()->Vertex() is nullptr.
|
|
*/
|
|
const ON_3dPoint RelativeControlNetPoint(
|
|
int relative_vertex_index
|
|
) const;
|
|
|
|
bool RelativeVertexMark(
|
|
int relative_vertex_index,
|
|
bool missing_vertex_return_value
|
|
) const;
|
|
|
|
ON__UINT8 RelativeVertexMarkBits(
|
|
int relative_vertex_index,
|
|
ON__UINT8 missing_vertex_return_value
|
|
) const;
|
|
|
|
const ON_Line RelativeControlNetLine() const;
|
|
|
|
const ON_3dVector RelativeControlNetDirection() const;
|
|
|
|
/*
|
|
Parameters:
|
|
relative_vertex_index - [in]
|
|
Returns:
|
|
If Edge() not nullptr, then
|
|
If (relative_vertex_index = 0), returns Edge()->m_sector_coefficient(EdgeDirection())
|
|
If (relative_vertex_index = 0), returns Edge()->m_sector_coefficient(1-EdgeDirection())
|
|
Otherwise ON_SubDSectorType::ErrorSectorCoefficient is returned.
|
|
Remarks:
|
|
The name "sector coefficient" is used because is is a property of the
|
|
vertex's sector (every edge in vertex sector has the same value at the tagged vertex).
|
|
The sector coefficient does not change which a subdivision is applied.
|
|
*/
|
|
double RelativeSectorCoefficient(
|
|
int relative_vertex_index
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the face on the left or right side of an oriented manifold or boundary edge.
|
|
A face is on the "left side" if this ON_SubDEdgePtr is oriented so it
|
|
points in the same direction as the face's oriented boundary.
|
|
A face is on the "right side" if this ON_SubDEdgePtr is oriented so it
|
|
points in the opposite direction as the face's oriented boundary.
|
|
If an edge is nonmanifold (3 or more faces), then nullptr is always returned.
|
|
If an edge has two faces that do not attach to this edge with opposite orientations
|
|
(nonoriented manifold edge), then nullptr is returned.
|
|
Parameters:
|
|
relative_face_index - [in]
|
|
0: return face on the left side of the edge with respect to EdgeOrientation().
|
|
1: return face on the right side of the edge with respect to EdgeOrientation().
|
|
Returns:
|
|
The requested face.
|
|
*/
|
|
const class ON_SubDFace* RelativeFace(
|
|
int relative_face_index
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
this->RelativeFace(relative_face_index)->Mark();
|
|
*/
|
|
bool RelativeFaceMark(
|
|
int relative_face_index,
|
|
bool missing_face_return_value
|
|
) const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
this->RelativeFace(relative_face_index)->MarkBits();
|
|
*/
|
|
ON__UINT8 RelativeFaceMarkBits(
|
|
int relative_face_index,
|
|
ON__UINT8 missing_face_return_value
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
The vector from RelativeVertex(0)->ControlNetPoint() to RelativeVertex(1)->ControlNetPoint(),
|
|
or ON_3dVector::NanVector if the relative vertex pointers are nullptr.
|
|
*/
|
|
const ON_3dVector RelativeDirection() const;
|
|
|
|
/*
|
|
Returns:
|
|
this->Edge()->m_status.
|
|
*/
|
|
const ON_ComponentStatus Status() const;
|
|
|
|
/*
|
|
Returns:
|
|
A ON_SubDEdgePtr pointing at the same edge with the direction reversed from this.
|
|
*/
|
|
const ON_SubDEdgePtr Reversed() const;
|
|
|
|
void ClearSavedSubdivisionPoints() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this component.
|
|
Parameters:
|
|
bClearNeighborhood - [in]
|
|
If true, all components attached to this component are also cleared.
|
|
*/
|
|
void ClearSavedSubdivisionPoints(
|
|
bool bClearNeighborhood
|
|
) const;
|
|
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
edge - [in]
|
|
Returns:
|
|
An ON_SubDEdgePtr pointing at edge with direction = 0 (not reversed).
|
|
*/
|
|
static const ON_SubDEdgePtr Create(
|
|
const class ON_SubDEdge* edge
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge - [in]
|
|
direction - [in]
|
|
0: not reversed
|
|
1: reversed
|
|
Returns:
|
|
An ON_SubDEdgePtr pointing at edge with the specified direction.
|
|
*/
|
|
static const ON_SubDEdgePtr Create(
|
|
const class ON_SubDEdge* edge,
|
|
ON__UINT_PTR direction
|
|
);
|
|
|
|
static const ON_SubDEdgePtr Create(
|
|
const class ON_SubDComponentPtr& edge_component
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge - [in]
|
|
start_vertex - [in]
|
|
One of the edge's vertices.
|
|
Returns:
|
|
An ON_SubDEdgePtr pointing at edge with RelativeVertex(0) = start_vertex.
|
|
*/
|
|
static const ON_SubDEdgePtr CreateFromStartVertex(
|
|
const class ON_SubDEdge* edge,
|
|
const ON_SubDVertex* start_vertex
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge - [in]
|
|
end_vertex - [in]
|
|
One of the edge's vertices.
|
|
Returns:
|
|
An ON_SubDEdgePtr pointing at edge with RelativeVertex(1) = end_vertex.
|
|
*/
|
|
static const ON_SubDEdgePtr CreateFromEndVertex(
|
|
const class ON_SubDEdge* edge,
|
|
const ON_SubDVertex* end_vertex
|
|
);
|
|
|
|
|
|
/*
|
|
Returns:
|
|
The current value of the component mark ( m_status->RuntimeMark() ).
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
*/
|
|
bool Mark() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears (sets to false) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool ClearMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets (sets to true) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the value of the component mark to bMark.
|
|
Parameter:
|
|
bMark - [in]
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark(
|
|
bool bMark
|
|
) const;
|
|
|
|
ON__UINT8 MarkBits() const;
|
|
|
|
ON__UINT8 SetMarkBits(
|
|
ON__UINT8 mark_bits
|
|
) const;
|
|
|
|
ON__UINT8 ClearMarkBits() const;
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDEdgePtr>;
|
|
#endif
|
|
|
|
class ON_CLASS ON_SubDFacePtr
|
|
{
|
|
public:
|
|
// For performance reasons, m_ptr is not initialized and no constructors are declared
|
|
// or implemented. If you require initialization, then use x = ON_SubDFacePtr::Null
|
|
// or x = ON_SubDFacePtr::Create(...).
|
|
ON__UINT_PTR m_ptr;
|
|
|
|
static const ON_SubDFacePtr Null;
|
|
|
|
bool IsNull() const;
|
|
|
|
bool IsNotNull() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this face is active in its parent subd or other
|
|
relevent context.
|
|
Remarks:
|
|
When a component is in use, IsActive() = true.
|
|
If was used and then deleted, IsActive() is false.
|
|
*/
|
|
bool IsActive() const;
|
|
|
|
|
|
class ON_SubDFace* Face() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Face() is not nullptr, Face()->m_id is returned.
|
|
Otherwise, 0 is returned.
|
|
*/
|
|
unsigned int FaceId() const;
|
|
|
|
/*
|
|
Returns:
|
|
If Face() is not nullptr, Face()->EdgeCount() is returned.
|
|
Otherwise, 0 is returned.
|
|
*/
|
|
unsigned int FaceEdgeCount() const;
|
|
|
|
ON__UINT_PTR FaceDirection() const;
|
|
|
|
const ON_ComponentStatus Status() const;
|
|
|
|
/*
|
|
Returns:
|
|
A ON_SubDFacePtr pointing at the same face with the direction reversed from this.
|
|
*/
|
|
const ON_SubDFacePtr Reversed() const;
|
|
|
|
static const ON_SubDFacePtr Create(
|
|
const class ON_SubDFace* face,
|
|
ON__UINT_PTR direction
|
|
);
|
|
|
|
static const ON_SubDFacePtr Create(
|
|
const class ON_SubDComponentPtr& face_component
|
|
);
|
|
|
|
static int Compare(
|
|
const ON_SubDFacePtr* lhs,
|
|
const ON_SubDFacePtr* rhs
|
|
);
|
|
|
|
static int CompareFacePointer(
|
|
const ON_SubDFacePtr* lhs,
|
|
const ON_SubDFacePtr* rhs
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The current value of the component mark ( m_status->RuntimeMark() ).
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
*/
|
|
bool Mark() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears (sets to false) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool ClearMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets (sets to true) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the value of the component mark to bMark.
|
|
Parameter:
|
|
bMark - [in]
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark(
|
|
bool bMark
|
|
) const;
|
|
|
|
ON__UINT8 MarkBits() const;
|
|
|
|
ON__UINT8 SetMarkBits(
|
|
ON__UINT8 mark_bits
|
|
) const;
|
|
|
|
ON__UINT8 ClearMarkBits() const;
|
|
|
|
void ClearSavedSubdivisionPoints() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this component.
|
|
Parameters:
|
|
bClearNeighborhood - [in]
|
|
If true, all components attached to this component are also cleared.
|
|
*/
|
|
void ClearSavedSubdivisionPoints(
|
|
bool bClearNeighborhood
|
|
) const;
|
|
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDFacePtr>;
|
|
#endif
|
|
|
|
|
|
class ON_CLASS ON_SubDComponentPtr
|
|
{
|
|
public:
|
|
// For performance reasons, m_ptr is not initialized and no constructors are declared
|
|
// or implemented. If you require initialization, then use x = ON_SubDComponentPtr::Null
|
|
// or x = ON_SubDComponentPtr::Create(...).
|
|
ON__UINT_PTR m_ptr;
|
|
|
|
static const ON_SubDComponentPtr Null; // // nullptr, type = unset, mark = 0
|
|
|
|
/// <summary>
|
|
/// ON_SubDComponentPtr::Type identifies the type of subdivision component referenced by
|
|
/// the ON_SubDComponentPtr.
|
|
/// </summary>
|
|
enum class Type : unsigned char
|
|
{
|
|
Unset = 0,
|
|
Vertex = 2,
|
|
Edge = 4,
|
|
Face = 6
|
|
};
|
|
|
|
static ON_SubDComponentPtr::Type ComponentPtrTypeFromUnsigned(
|
|
unsigned int component_pointer_type_as_unsigned
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
ON_SubDComponentPtr::Type::Vertex
|
|
< ON_SubDComponentPtr::Type::Edge
|
|
< ON_SubDComponentPtr::Type::Face
|
|
< ON_SubDComponentPtr::Type::Unset
|
|
< invalid
|
|
*/
|
|
static int CompareComponentPtrType(
|
|
ON_SubDComponentPtr::Type a,
|
|
ON_SubDComponentPtr::Type b
|
|
);
|
|
|
|
static int CompareType(
|
|
const ON_SubDComponentPtr* a,
|
|
const ON_SubDComponentPtr* b
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compares type and ComponentBase() pointer as an unsigned.
|
|
*/
|
|
static int CompareComponent(
|
|
const ON_SubDComponentPtr* a,
|
|
const ON_SubDComponentPtr* b
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compares type, ComponentBase() pointer as an unsigned,
|
|
and ComponentDirection().
|
|
*/
|
|
static int CompareComponentAndDirection(
|
|
const ON_SubDComponentPtr* a,
|
|
const ON_SubDComponentPtr* b
|
|
);
|
|
|
|
|
|
/*
|
|
Returns:
|
|
True if the ComponentBase() pointer is nullptr. Note that type and mark may be set.
|
|
*/
|
|
bool IsNull() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if type is set and ComponentBase() pointer is not nullptr. Note that mark may be set as well.
|
|
*/
|
|
bool IsNotNull() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this component is active in its parent subd or other
|
|
relevent context.
|
|
Remarks:
|
|
When a component is in use, IsActive() = true.
|
|
If was used and then deleted, IsActive() is false.
|
|
*/
|
|
bool IsActive() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this component is marked as a primary motif component.
|
|
Remarks:
|
|
You must use ON_SubD SymmetrySet memeber functions to get symmetry set contents.
|
|
*/
|
|
bool IsSymmetrySetPrimaryMotif() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this component is marked being in a symmetry set.
|
|
Remarks:
|
|
You must use ON_SubD SymmetrySet memeber functions to get symmetry set contents.
|
|
*/
|
|
bool InSymmetrySet() const;
|
|
|
|
ON_SubDComponentPtr::Type ComponentType() const;
|
|
|
|
class ON_SubDComponentBase* ComponentBase() const;
|
|
|
|
/*
|
|
type_filter - [in]
|
|
If is ON_SubDComponentPtr::Type::Unset, then any type of component will be returned.
|
|
Otherwise only a component of the specified type will be returned.
|
|
*/
|
|
class ON_SubDComponentBase* ComponentBase(ON_SubDComponentPtr::Type type_filter) const;
|
|
|
|
class ON_SubDVertex* Vertex() const;
|
|
class ON_SubDEdge* Edge() const;
|
|
class ON_SubDFace* Face() const;
|
|
|
|
const ON_SubDVertexPtr VertexPtr() const;
|
|
const ON_SubDEdgePtr EdgePtr() const;
|
|
const ON_SubDFacePtr FacePtr() const;
|
|
|
|
const bool IsVertex() const;
|
|
const bool IsEdge() const;
|
|
const bool IsFace() const;
|
|
|
|
void ClearSavedSubdivisionPoints() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this component.
|
|
Parameters:
|
|
bClearNeighborhood - [in]
|
|
If true, all components attached to this component are also cleared.
|
|
*/
|
|
void ClearSavedSubdivisionPoints(
|
|
bool bClearNeighborhood
|
|
) const;
|
|
|
|
unsigned int ComponentId() const;
|
|
|
|
const ON_COMPONENT_INDEX ComponentIndex() const;
|
|
|
|
const ON_3dPoint ControlNetCenterPoint() const;
|
|
const ON_BoundingBox ControlNetBoundingBox() const;
|
|
|
|
/*
|
|
Returns:
|
|
A value suitable for hash table used based on the component type and id.
|
|
*/
|
|
ON__UINT16 Hash16FromTypeAndId() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
A value suitable for hash table used based on the value of ComponentBase().
|
|
*/
|
|
ON__UINT32 Hash32FromPointer() const;
|
|
|
|
/*
|
|
Returns:
|
|
0 or 1.
|
|
A runtime bit property on this ON_SubDComponentPtr.
|
|
The use of this value varies depending on the context.
|
|
Frequently, 0 means the referenced component is being used with its
|
|
natural orientation and 1 means the referenced component is being used
|
|
with the reverse of its natrual oreientation.
|
|
*/
|
|
ON__UINT_PTR ComponentDirection() const;
|
|
|
|
/*
|
|
Returns:
|
|
An ON_SubDComponentPtr referencing the same ON_SubDComponentBase
|
|
with ON_SubDComponentPtr.ComponentDirection() = 0.
|
|
*/
|
|
const ON_SubDComponentPtr ClearComponentDirection() const;
|
|
|
|
/*
|
|
Returns:
|
|
An ON_SubDComponentPtr referencing the same ON_SubDComponentBase
|
|
with ON_SubDComponentPtr.ComponentDirection() = 1.
|
|
*/
|
|
const ON_SubDComponentPtr SetComponentDirection() const;
|
|
|
|
/*
|
|
Returns:
|
|
An ON_SubDComponentPtr referencing the same ON_SubDComponentBase
|
|
with ON_SubDComponentPtr.ComponentDirection() = 1.
|
|
*/
|
|
const ON_SubDComponentPtr SetComponentDirection(ON__UINT_PTR dir) const;
|
|
|
|
/*
|
|
Returns:
|
|
An ON_SubDComponentPtr referencing the same ON_SubDComponentBase
|
|
with ComponentDirection() = 1 - this->ComponentDirection().
|
|
*/
|
|
const ON_SubDComponentPtr Reversed() const;
|
|
|
|
const ON_ComponentStatus Status() const;
|
|
|
|
/*
|
|
Returns:
|
|
1: status changed.
|
|
0: status not changed.
|
|
*/
|
|
unsigned int SetStates(
|
|
ON_ComponentStatus states_to_set
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
1: status changed.
|
|
0: status not changed.
|
|
*/
|
|
unsigned int ClearStates(
|
|
ON_ComponentStatus states_to_clear
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Makes "this" an exact copy of status.
|
|
Parameters:
|
|
status - [in]
|
|
Returns:
|
|
1: status changed.
|
|
0: status not changed.
|
|
*/
|
|
unsigned int SetStatus(
|
|
ON_ComponentStatus status
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The current value of the component mark ( m_status->RuntimeMark() ).
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
*/
|
|
bool Mark() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears (sets to false) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool ClearMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets (sets to true) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the value of the component mark to bMark.
|
|
Parameter:
|
|
bMark - [in]
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark(
|
|
bool bMark
|
|
) const;
|
|
|
|
ON__UINT8 MarkBits() const;
|
|
|
|
ON__UINT8 SetMarkBits(
|
|
ON__UINT8 mark_bits
|
|
) const;
|
|
|
|
ON__UINT8 ClearMarkBits() const;
|
|
|
|
/*
|
|
Parameters:
|
|
null_component_value - [in]
|
|
Value to return if the component is null.
|
|
Returns:
|
|
If this is not null, the group id of the component is returned.
|
|
Otherwise null_component_value is returned.
|
|
*/
|
|
unsigned int GroupId(
|
|
unsigned int null_component_value
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Sets ON_SubDComponentBase.m_group_id.
|
|
Parameters:
|
|
group_id - [in]
|
|
Value to return if the component is null.
|
|
Returns:
|
|
True if the component is not null and the group id was set.
|
|
False if the component is null.
|
|
*/
|
|
bool SetGroupId(
|
|
unsigned int group_id
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr CreateNull(
|
|
ON_SubDComponentPtr::Type component_type,
|
|
ON__UINT_PTR component_direction
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
const class ON_SubDVertex* vertex
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
const class ON_SubDEdge* edge
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
const class ON_SubDFace* face
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
const class ON_SubDVertex* vertex,
|
|
ON__UINT_PTR vertex_direction
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
const class ON_SubDEdge* edge,
|
|
ON__UINT_PTR edge_direction
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
const class ON_SubDFace* face,
|
|
ON__UINT_PTR face_direction
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
ON_SubDVertexPtr vertexptr
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
ON_SubDEdgePtr edgeptr
|
|
);
|
|
|
|
static
|
|
const ON_SubDComponentPtr Create(
|
|
ON_SubDFacePtr faceptr
|
|
);
|
|
|
|
wchar_t* ToString(
|
|
wchar_t* s,
|
|
size_t s_capacity
|
|
) const;
|
|
|
|
const ON_wString ToString() const;
|
|
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDComponentPtr>;
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentPtrAndNumber
|
|
//
|
|
|
|
class ON_CLASS ON_SubDComponentAndNumber
|
|
{
|
|
public:
|
|
ON_SubDComponentAndNumber() = default;
|
|
~ON_SubDComponentAndNumber() = default;
|
|
ON_SubDComponentAndNumber(const ON_SubDComponentAndNumber&) = default;
|
|
ON_SubDComponentAndNumber& operator=(const ON_SubDComponentAndNumber&) = default;
|
|
|
|
public:
|
|
static const ON_SubDComponentAndNumber NullAndNan;
|
|
static const ON_SubDComponentAndNumber NullAndZero;
|
|
static const ON_SubDComponentAndNumber Create(
|
|
ON_SubDComponentPtr cptr,
|
|
double x
|
|
);
|
|
|
|
static const ON_SubDComponentAndNumber Create(
|
|
const ON_SubDVertex* v,
|
|
double x
|
|
);
|
|
static const ON_SubDComponentAndNumber Create(
|
|
const ON_SubDEdge* e,
|
|
double x
|
|
);
|
|
static const ON_SubDComponentAndNumber Create(
|
|
const ON_SubDFace* f,
|
|
double x
|
|
);
|
|
|
|
static const ON_SubDComponentAndNumber Create(
|
|
const ON_SubDVertexPtr vptr,
|
|
double x
|
|
);
|
|
|
|
static const ON_SubDComponentAndNumber Create(
|
|
const ON_SubDEdgePtr eptr,
|
|
double x
|
|
);
|
|
|
|
static const ON_SubDComponentAndNumber Create(
|
|
const ON_SubDFacePtr fptr,
|
|
double x
|
|
);
|
|
|
|
public:
|
|
|
|
/*
|
|
Description:
|
|
Compare Component() using ON_SubDComponentPtr::CompareComponent().
|
|
*/
|
|
static int CompareComponent(
|
|
const ON_SubDComponentAndNumber* a,
|
|
const ON_SubDComponentAndNumber* b
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Compare Component() using ON_SubDComponentPtr::CompareComponentAndDirection().
|
|
*/
|
|
static int CompareComponentAndDirection(
|
|
const ON_SubDComponentAndNumber* a,
|
|
const ON_SubDComponentAndNumber* b
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Compare Number() nans are treated as equal and sort last.
|
|
*/
|
|
static int CompareNumber(
|
|
const ON_SubDComponentAndNumber* a,
|
|
const ON_SubDComponentAndNumber* b
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare Component() and Number() in that order.
|
|
*/
|
|
static int CompareComponentAndNumber(
|
|
const ON_SubDComponentAndNumber* a,
|
|
const ON_SubDComponentAndNumber* b
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare using ON_SubDComponentAndNumber::CompareComponentAndDirection() and ON_SubDComponentAndNumber::Number() in that order.
|
|
*/
|
|
static int CompareComponentAndDirectionAndNumber(
|
|
const ON_SubDComponentAndNumber* a,
|
|
const ON_SubDComponentAndNumber* b
|
|
);
|
|
|
|
|
|
public:
|
|
const ON_SubDComponentPtr Component() const;
|
|
void SetComponent(ON_SubDComponentPtr cptr);
|
|
|
|
double Number() const;
|
|
void SetNumber(double x);
|
|
|
|
public:
|
|
ON_SubDComponentPtr m_cptr = ON_SubDComponentPtr::Null;
|
|
double m_x = ON_DBL_QNAN;
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDComponentAndNumber>;
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentAndPoint
|
|
//
|
|
|
|
class ON_CLASS ON_SubDComponentAndPoint
|
|
{
|
|
public:
|
|
ON_SubDComponentAndPoint() = default;
|
|
~ON_SubDComponentAndPoint() = default;
|
|
ON_SubDComponentAndPoint(const ON_SubDComponentAndPoint&) = default;
|
|
ON_SubDComponentAndPoint& operator=(const ON_SubDComponentAndPoint&) = default;
|
|
|
|
public:
|
|
static const ON_SubDComponentAndPoint NullAndNan;
|
|
static const ON_SubDComponentAndPoint NullAndOrigin;
|
|
static const ON_SubDComponentAndPoint Create(
|
|
ON_SubDComponentPtr cptr,
|
|
ON_3dPoint P
|
|
);
|
|
|
|
static const ON_SubDComponentAndPoint Create(
|
|
const ON_SubDVertex* v,
|
|
ON_3dPoint P
|
|
);
|
|
static const ON_SubDComponentAndPoint Create(
|
|
const ON_SubDEdge* e,
|
|
ON_3dPoint P
|
|
);
|
|
static const ON_SubDComponentAndPoint Create(
|
|
const ON_SubDFace* f,
|
|
ON_3dPoint P
|
|
);
|
|
|
|
static const ON_SubDComponentAndPoint Create(
|
|
const ON_SubDVertexPtr vptr,
|
|
ON_3dPoint P
|
|
);
|
|
|
|
static const ON_SubDComponentAndPoint Create(
|
|
const ON_SubDEdgePtr eptr,
|
|
ON_3dPoint P
|
|
);
|
|
|
|
static const ON_SubDComponentAndPoint Create(
|
|
const ON_SubDFacePtr fptr,
|
|
ON_3dPoint P
|
|
);
|
|
|
|
public:
|
|
|
|
/*
|
|
Description:
|
|
Compare Component() using ON_SubDComponentPtr::CompareComponent().
|
|
*/
|
|
static int CompareComponent(
|
|
const ON_SubDComponentAndPoint* lhs,
|
|
const ON_SubDComponentAndPoint* rhs
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Compare Component() using ON_SubDComponentPtr::CompareComponentAndDirection().
|
|
*/
|
|
static int CompareComponentAndDirection(
|
|
const ON_SubDComponentAndPoint* lhs,
|
|
const ON_SubDComponentAndPoint* rhs
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Compare Point() uses ON_3dPoint::Compare() to compare lhs and rhs Point() values.
|
|
*/
|
|
static int ComparePoint(
|
|
const ON_SubDComponentAndPoint* lhs,
|
|
const ON_SubDComponentAndPoint* rhs
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare Component() and Point() in that order.
|
|
*/
|
|
static int CompareComponentAndPoint(
|
|
const ON_SubDComponentAndPoint* lhs,
|
|
const ON_SubDComponentAndPoint* rhs
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare using ON_SubDComponentAndPoint::CompareComponentAndDirection() and ON_SubDComponentAndPoint::Point() in that order.
|
|
*/
|
|
static int CompareComponentAndDirectionAndPoint(
|
|
const ON_SubDComponentAndPoint* lhs,
|
|
const ON_SubDComponentAndPoint* rhs
|
|
);
|
|
|
|
|
|
public:
|
|
const ON_SubDComponentPtr Component() const;
|
|
void SetComponent(ON_SubDComponentPtr cptr);
|
|
|
|
const ON_3dPoint Point() const;
|
|
void SetPoint(ON_3dPoint P);
|
|
|
|
public:
|
|
ON_SubDComponentPtr m_cptr = ON_SubDComponentPtr::Null;
|
|
ON_3dPoint m_P = ON_3dPoint::NanPoint;
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDComponentAndPoint>;
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentTest
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
ON_SubDComponentTest is used in contexts where custom testing or filtering of
|
|
SubD components is required.
|
|
*/
|
|
class ON_CLASS ON_SubDComponentTest
|
|
{
|
|
public:
|
|
ON_SubDComponentTest() = default;
|
|
virtual ~ON_SubDComponentTest();
|
|
ON_SubDComponentTest(const ON_SubDComponentTest&) = default;
|
|
ON_SubDComponentTest& operator=(const ON_SubDComponentTest&) = default;
|
|
|
|
/*
|
|
Sets m_ptr=ptr
|
|
*/
|
|
ON_SubDComponentTest(ON__UINT_PTR ptr);
|
|
|
|
/*
|
|
Description:
|
|
Typically, a derived class overrides this function, uses it to inspect vertex properties,
|
|
and returns true or false.
|
|
Parameters:
|
|
v - [in] vertex being tested.
|
|
Returns:
|
|
true if the vertex "passes" the test.
|
|
false if the vertex "fails" the text.
|
|
Remarks:
|
|
The default implementation returns (cptr.IsNotNull() && 0 != m_ptr);
|
|
*/
|
|
virtual bool Passes(const ON_SubDComponentPtr cptr) const;
|
|
|
|
/*
|
|
Returns:
|
|
this->Passes(nullptr != v ? v->ComponentPtr() : ON_SubDComponentPtr::Null);
|
|
*/
|
|
bool Passes(const class ON_SubDVertex* v) const;
|
|
|
|
/*
|
|
Returns:
|
|
this->Passes(nullptr != e ? e->ComponentPtr() : ON_SubDComponentPtr::Null);
|
|
*/
|
|
bool Passes(const class ON_SubDEdge* e) const;
|
|
|
|
/*
|
|
Returns:
|
|
this->Passes(nullptr != f ? f->ComponentPtr() : ON_SubDComponentPtr::Null);
|
|
*/
|
|
bool Passes(const class ON_SubDFace* f) const;
|
|
|
|
// Passes() returns true for every non nullptr component.
|
|
static const ON_SubDComponentTest AllPass;
|
|
|
|
// Passes() returns false for every component.
|
|
static const ON_SubDComponentTest AllFail;
|
|
|
|
protected:
|
|
// classes derived from ON_SubDVertexFilter may use m_ptr as they see fit including to completely ignore it.
|
|
ON__UINT_PTR m_ptr = 0;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDComponentId
|
|
{
|
|
public:
|
|
|
|
// type = unset and id = 0;
|
|
static const ON_SubDComponentId Unset;
|
|
|
|
ON_SubDComponentId() = default;
|
|
~ON_SubDComponentId() = default;
|
|
ON_SubDComponentId(const ON_SubDComponentId&) = default;
|
|
ON_SubDComponentId& operator=(const ON_SubDComponentId&) = default;
|
|
|
|
ON_SubDComponentId(ON_SubDComponentPtr::Type component_type, unsigned int component_id);
|
|
ON_SubDComponentId(ON_SubDComponentPtr cptr);
|
|
ON_SubDComponentId(const class ON_SubDVertex* v);
|
|
ON_SubDComponentId(const class ON_SubDEdge* e);
|
|
ON_SubDComponentId(const class ON_SubDFace* f);
|
|
|
|
static int CompareTypeAndId(const ON_SubDComponentId& lhs, const ON_SubDComponentId& rhs);
|
|
static int CompareTypeAndIdFromPointer(const ON_SubDComponentId* lhs, const ON_SubDComponentId* rhs);
|
|
|
|
unsigned int ComponentId() const;
|
|
ON_SubDComponentPtr::Type ComponentType() const;
|
|
|
|
/*
|
|
Returns:
|
|
true if type is not unset and id > 0
|
|
*/
|
|
bool IsSet() const;
|
|
|
|
private:
|
|
unsigned int m_id = 0;
|
|
ON_SubDComponentPtr::Type m_type = ON_SubDComponentPtr::Type::Unset;
|
|
unsigned char m_reserved1 = 0;
|
|
unsigned short m_reserved2 = 0;
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDComponentId>;
|
|
#endif
|
|
|
|
class ON_CLASS ON_SubDComponentIdList : public ON_SubDComponentTest
|
|
{
|
|
public:
|
|
ON_SubDComponentIdList() = default;
|
|
~ON_SubDComponentIdList() = default;
|
|
ON_SubDComponentIdList(const ON_SubDComponentIdList&) = default;
|
|
ON_SubDComponentIdList& operator=(const ON_SubDComponentIdList&) = default;
|
|
|
|
/*
|
|
Returns:
|
|
returns InListPassesResult() when cptr id is in the list.
|
|
returns !InListPassesResult() when cptr id is not the list.
|
|
Remarks:
|
|
AddId is safe to use in multithreaded contexts.
|
|
*/
|
|
bool Passes(const ON_SubDComponentPtr cptr) const override;
|
|
|
|
void SetInListPassesResult(bool bInListPassesResult);
|
|
|
|
// Value Passes(cptr) returns when cptr is in the list
|
|
bool InListPassesResult() const;
|
|
|
|
void AddId(ON_SubDComponentId cid);
|
|
|
|
void AddId(ON_SubDComponentPtr cptr);
|
|
|
|
/*
|
|
Parameters:
|
|
cid - in
|
|
Returns:
|
|
true if cid is in this list.
|
|
*/
|
|
bool InList(ON_SubDComponentId cid) const;
|
|
|
|
/*
|
|
Parameters:
|
|
cptr - in
|
|
Returns:
|
|
true if cptr's id is in this list.
|
|
*/
|
|
bool InList(ON_SubDComponentPtr cptr) const;
|
|
|
|
private:
|
|
unsigned int m_reserved1 = 0;
|
|
private:
|
|
unsigned short m_reserved2 = 0;
|
|
private:
|
|
bool m_bInListPassesResult = true;
|
|
private:
|
|
mutable bool m_bSorted = false;
|
|
mutable ON_SimpleArray<ON_SubDComponentId> m_id_list;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDComponentPtrPair
|
|
{
|
|
public:
|
|
// For performance reasons, m_ptrpair is not initialized and no constructors are declared
|
|
// or implemented. If you require initialization, then use x = ON_SubDComponentPtrPair::Null
|
|
// or x = ON_SubDComponentPtr::Create(first_ptr,second_ptr).
|
|
ON_SubDComponentPtr m_pair[2];
|
|
|
|
public:
|
|
static const ON_SubDComponentPtrPair Create(ON_SubDComponentPtr first_ptr, ON_SubDComponentPtr second_ptr);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary order compare using ON_SubDComponentPtr::CompareComponent() on each element.
|
|
*/
|
|
static int CompareComponent(const ON_SubDComponentPtrPair * lhs, const ON_SubDComponentPtrPair * rhs);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary order compare using ON_SubDComponentPtr::CompareComponentAndDirection() on each element.
|
|
*/
|
|
static int CompareComponentAndDirection(const ON_SubDComponentPtrPair * lhs, const ON_SubDComponentPtrPair * rhs);
|
|
|
|
/*
|
|
Description:
|
|
Compare first pointer value.
|
|
*/
|
|
static int CompareFirstPointer(const ON_SubDComponentPtrPair * lhs, const ON_SubDComponentPtrPair * rhs);
|
|
|
|
/*
|
|
Returns:
|
|
A pair with components in the opposite order
|
|
*/
|
|
const ON_SubDComponentPtrPair SwapPair() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
A pair with components reversed.
|
|
*/
|
|
const ON_SubDComponentPtrPair ReversedPair() const;
|
|
|
|
/*
|
|
Returns:
|
|
First ON_SubDComponentPt in the pair.
|
|
*/
|
|
const ON_SubDComponentPtr First() const;
|
|
|
|
/*
|
|
Returns:
|
|
Second ON_SubDComponentPt in the pair.
|
|
*/
|
|
const ON_SubDComponentPtr Second() const;
|
|
|
|
/*
|
|
Returns:
|
|
If both points have the same type, that type is returned.
|
|
Otherwise ON_SubDComponentPtr::Type::Unset is returned.
|
|
*/
|
|
ON_SubDComponentPtr::Type ComponentType() const;
|
|
|
|
/*
|
|
Returns FIrst().IsNull().
|
|
*/
|
|
bool FirstIsNull() const;
|
|
|
|
/*
|
|
Returns Second().IsNull().
|
|
*/
|
|
bool SecondIsNull() const;
|
|
|
|
/*
|
|
Returns First().IsNull() && Second().IsNull().
|
|
*/
|
|
bool BothAreNull() const;
|
|
|
|
/*
|
|
Returns First().IsNotNull().
|
|
*/
|
|
bool FirstIsNotNull() const;
|
|
|
|
/*
|
|
Returns Second().IsNotNull().
|
|
*/
|
|
bool SecondIsNotNull() const;
|
|
|
|
/*
|
|
Returns FirstIsNotNull() && SecondIsNotNull().
|
|
*/
|
|
bool BothAreNotNull() const;
|
|
|
|
public:
|
|
static const ON_SubDComponentPtrPair Null;
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDComponentPtrPair>;
|
|
#endif
|
|
|
|
class ON_CLASS ON_SubDComponentPtrPairHashTable : ON_Hash32Table
|
|
{
|
|
public:
|
|
ON_SubDComponentPtrPairHashTable();
|
|
|
|
ON_SubDComponentPtrPairHashTable(const class ON_SubD& subd);
|
|
|
|
~ON_SubDComponentPtrPairHashTable() = default;
|
|
|
|
bool AddComponentPair(
|
|
ON_SubDComponentPtr first_component,
|
|
ON_SubDComponentPtr second_component
|
|
);
|
|
|
|
bool AddVertexPair(
|
|
const class ON_SubDVertex* first_v,
|
|
const class ON_SubDVertex* second_v
|
|
);
|
|
|
|
bool AddEdgePair(
|
|
const class ON_SubDEdge* first_e,
|
|
const class ON_SubDEdge* second_e
|
|
);
|
|
|
|
bool AddEdgePair(
|
|
const class ON_SubDEdge* first_e,
|
|
const ON_SubDEdgePtr second_eptr
|
|
);
|
|
|
|
bool AddFacePair(
|
|
const class ON_SubDFace* first_f,
|
|
const class ON_SubDFace* second_f
|
|
);
|
|
|
|
const ON_SubDComponentPtrPair PairFromSecondComponentPtr(
|
|
ON_SubDComponentPtr second_component
|
|
);
|
|
|
|
const ON_SubDComponentPtrPair PairFromSecondVertex(
|
|
const class ON_SubDVertex* second_v
|
|
);
|
|
|
|
const ON_SubDComponentPtrPair PairFromSecondEdge(
|
|
const class ON_SubDEdge* second_e
|
|
);
|
|
|
|
private:
|
|
ON_FixedSizePool m_pairs_fsp;
|
|
|
|
private:
|
|
ON_SubDComponentPtrPairHashTable(const ON_SubDComponentPtrPairHashTable&) = delete;
|
|
ON_SubDComponentPtrPairHashTable& operator=(const ON_SubDComponentPtrPairHashTable&) = delete;
|
|
};
|
|
|
|
/// <summary>
|
|
/// Simple arrays of ON_SubD_ComponentIdTypeAndTag elements are used to save
|
|
/// original tag values so the can be retrieved after complex editing operations.
|
|
/// </summary>
|
|
class ON_CLASS ON_SubD_ComponentIdTypeAndTag
|
|
{
|
|
public:
|
|
static const ON_SubD_ComponentIdTypeAndTag Unset;
|
|
|
|
/*
|
|
Returns:
|
|
If v is no nullptr and v->m_id > 0, a ON_SubD_ComponentIdTypeAndTag with VertexTag() = v->m_vertex_tag is returned.
|
|
Otherwise ON_SubD_ComponentIdTypeAndTag::Unset is returned.
|
|
*/
|
|
static const ON_SubD_ComponentIdTypeAndTag CreateFromVertex(const class ON_SubDVertex* v);
|
|
|
|
/*
|
|
Returns:
|
|
If vertex_id > 0, a ON_SubD_ComponentIdTypeAndTag with VertexTag() = vtag is returned.
|
|
Otherwise ON_SubD_ComponentIdTypeAndTag::Unset is returned.
|
|
*/
|
|
static const ON_SubD_ComponentIdTypeAndTag CreateFromVertexId(unsigned vertex_id, ON_SubDVertexTag vtag);
|
|
|
|
/*
|
|
Parameters:
|
|
e - [in]
|
|
If e->m_edge_tag is ON_SubDEdgeTag::SmoothX, the ON_SubD_ComponentIdTypeAndTag EdgeTag() will be ON_SubDEdgeTag::Smoooth.
|
|
Returns:
|
|
If e is not nullptr and e->m_id > 0, a ON_SubD_ComponentIdTypeAndTag with EdgeTag() = e->m_edge_tag is returned.
|
|
Otherwise ON_SubD_ComponentIdTypeAndTag::Unset is returned.
|
|
*/
|
|
static const ON_SubD_ComponentIdTypeAndTag CreateFromEdge(const class ON_SubDEdge* e);
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
edge_id - [in]
|
|
etag - [in]
|
|
If etag is ON_SubDEdgeTag::SmoothX, the ON_SubD_ComponentIdTypeAndTag EdgeTag() will be ON_SubDEdgeTag::Smoooth.
|
|
Returns:
|
|
If edge_id > 0, a ON_SubD_ComponentIdTypeAndTag with EdgeTag() = etag is returned.
|
|
Otherwise ON_SubD_ComponentIdTypeAndTag::Unset is returned.
|
|
*/
|
|
static const ON_SubD_ComponentIdTypeAndTag CreateFromEdgeId(unsigned edge_id, ON_SubDEdgeTag etag);
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
f - [in]
|
|
ftag - [in]
|
|
Any value and the interpretation is up to the context using the ON_SubD_ComponentIdTypeAndTag.
|
|
Returns:
|
|
If f is no nullptr and f->m_id > 0, a ON_SubD_ComponentIdTypeAndTag with FaceTag() = ftag is returned.
|
|
Otherwise ON_SubD_ComponentIdTypeAndTag::Unset is returned.
|
|
Remarks:
|
|
SubD faces do not have a tag in the sense that vertices and edges do, but in complex editing tasks
|
|
it is sometimes useful to include faces in an array of ON_SubD_ComponentIdTypeAndTag elements.
|
|
*/
|
|
static const ON_SubD_ComponentIdTypeAndTag CreateFromFace(const class ON_SubDFace* f, unsigned char ftag);
|
|
|
|
/*
|
|
Parameters:
|
|
face_id - [in]
|
|
ftag - [in]
|
|
Any value and the interpretation is up to the context using the ON_SubD_ComponentIdTypeAndTag.
|
|
Returns:
|
|
If face_id > 0, a ON_SubD_ComponentIdTypeAndTag with FaceTag() = vtag is returned.
|
|
Otherwise ON_SubD_ComponentIdTypeAndTag::Unset is returned.
|
|
Remarks:
|
|
SubD faces do not have a tag in the sense that vertices and edges do, but in complex editing tasks
|
|
it is sometimes useful to include faces in an array of ON_SubD_ComponentIdTypeAndTag elements.
|
|
*/
|
|
static const ON_SubD_ComponentIdTypeAndTag CreateFromFaceId(unsigned face_id, unsigned char ftag);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare on ComponentType() and ComponentId() in that order.
|
|
*/
|
|
static int CompareTypeAndId(const ON_SubD_ComponentIdTypeAndTag* lhs, const ON_SubD_ComponentIdTypeAndTag* rhs);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare on ComponentType(), ComponentId(), and tag in that order.
|
|
*/
|
|
static int CompareTypeAndIdAndTag(const ON_SubD_ComponentIdTypeAndTag* lhs, const ON_SubD_ComponentIdTypeAndTag* rhs);
|
|
|
|
/*
|
|
Parameters:
|
|
v - [in]
|
|
sorted_tags[] - [in]
|
|
Array sorted by ON_SubD_ComponentIdTypeAndTag::CompareTypeAndId().
|
|
Returns:
|
|
If v is in sorted_tags[], the VertexTag() from from sorted_tags[] is returned.
|
|
Otherwise v->m_vertex_tag is returned.
|
|
*/
|
|
static ON_SubDVertexTag OriginalVertexTag(
|
|
const class ON_SubDVertex* v,
|
|
const ON_SimpleArray< ON_SubD_ComponentIdTypeAndTag>& sorted_tags
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
vertex_id - [in]
|
|
sorted_tags[] - [in]
|
|
Array sorted by ON_SubD_ComponentIdTypeAndTag::CompareTypeAndId().
|
|
Returns:
|
|
If vertex_id is in sorted_tags[], the VertexTag() from from sorted_tags[] is returned.
|
|
Otherwise ON_SubDVertexTag::Unset is returned.
|
|
*/
|
|
static ON_SubDVertexTag OriginalVertexTag(
|
|
unsigned vertex_id,
|
|
const ON_SimpleArray< ON_SubD_ComponentIdTypeAndTag>& sorted_tags
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
e - [in]
|
|
sorted_tags[] - [in]
|
|
Array sorted by ON_SubD_ComponentIdTypeAndTag::CompareTypeAndId().
|
|
Returns:
|
|
If e is in sorted_tags[], the EdgeTag() from from sorted_tags[] is returned.
|
|
Otherwise e->m_edge_tag is returned.
|
|
*/
|
|
static ON_SubDEdgeTag OriginalEdgeTag(
|
|
const class ON_SubDEdge* e,
|
|
const ON_SimpleArray< ON_SubD_ComponentIdTypeAndTag>& sorted_tags
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge_id - [in]
|
|
sorted_tags[] - [in]
|
|
Array sorted by ON_SubD_ComponentIdTypeAndTag::CompareTypeAndId().
|
|
Returns:
|
|
If edge_id is in sorted_tags[], the EdgeTag() from from sorted_tags[] is returned.
|
|
Otherwise ON_SubDEdgeTag::Unset is returned.
|
|
*/
|
|
static ON_SubDEdgeTag OriginalEdgeTag(
|
|
unsigned edge_id,
|
|
const ON_SimpleArray< ON_SubD_ComponentIdTypeAndTag>& sorted_tags
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
f - [in]
|
|
sorted_tags[] - [in]
|
|
Array sorted by ON_SubD_ComponentIdTypeAndTag::CompareTypeAndId().
|
|
Returns:
|
|
If f is in sorted_tags[], the FaceTag() from from sorted_tags[] is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
static unsigned char OriginalFaceTag(
|
|
const class ON_SubDFace* f,
|
|
const ON_SimpleArray< ON_SubD_ComponentIdTypeAndTag>& sorted_tags
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
face_id - [in]
|
|
sorted_tags[] - [in]
|
|
Array sorted by ON_SubD_ComponentIdTypeAndTag::CompareTypeAndId().
|
|
Returns:
|
|
If face_id is in sorted_tags[], the FaceTag() from from sorted_tags[] is returned.
|
|
Otherwise ON_SubDFaceTag::Unset is returned.
|
|
*/
|
|
static unsigned char OriginalFaceTag(
|
|
unsigned face_id,
|
|
const ON_SimpleArray< ON_SubD_ComponentIdTypeAndTag>& sorted_tags
|
|
);
|
|
|
|
ON_SubDComponentPtr::Type ComponentType() const;
|
|
|
|
ON_SubDVertexTag VertexTag() const;
|
|
|
|
unsigned VertexId() const;
|
|
|
|
/*
|
|
Returns:
|
|
ON_SubDEdgeTag::Unset, ON_SubDEdgeTag::Smooth, or ON_SubDEdgeTag::Crease.
|
|
*/
|
|
ON_SubDEdgeTag EdgeTag() const;
|
|
|
|
unsigned EdgeId() const;
|
|
|
|
unsigned char FaceTag() const;
|
|
|
|
unsigned FaceId() const;
|
|
|
|
const ON_wString ToString() const;
|
|
|
|
private:
|
|
ON_SubDComponentPtr m_cptr = ON_SubDComponentPtr::Null;
|
|
unsigned m_id = 0;
|
|
ON_SubDComponentPtr::Type m_type = ON_SubDComponentPtr::Type::Unset;
|
|
unsigned char m_tag = 0;
|
|
unsigned char m_bits = 0;
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubD_ComponentIdTypeAndTag>;
|
|
#endif
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDSectorId
|
|
//
|
|
|
|
class ON_CLASS ON_SubDSectorId
|
|
{
|
|
public:
|
|
ON_SubDSectorId() = default;
|
|
~ON_SubDSectorId() = default;
|
|
ON_SubDSectorId(const ON_SubDSectorId&) = default;
|
|
ON_SubDSectorId& operator=(const ON_SubDSectorId&) = default;
|
|
|
|
public:
|
|
// VertexId(), MinimumFaceId(), and SectorFaceCount() are all zero.
|
|
static const ON_SubDSectorId Zero;
|
|
|
|
// VertexId() and MinimumFaceId() are zero. SectorFaceCount() = 0xFFFFFFFF;
|
|
static const ON_SubDSectorId Invalid;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Dictionary compare of VertexId() and MinimumFaceId() in that order.
|
|
*/
|
|
static int CompareVertexIdAndMinimumFaceId(ON_SubDSectorId lhs, ON_SubDSectorId rhs);
|
|
|
|
static int CompareVertexId(ON_SubDSectorId lhs, ON_SubDSectorId rhs);
|
|
static int CompareMinimumFaceId(ON_SubDSectorId lhs, ON_SubDSectorId rhs);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare of VertexId() and MinimumFaceId() in that order.
|
|
*/
|
|
static int CompareVertexIdAndMinimumFaceIdFromPointers(const ON_SubDSectorId* lhs, const ON_SubDSectorId* rhs);
|
|
|
|
static int CompareVertexIdFromPointers(const ON_SubDSectorId* lhs, const ON_SubDSectorId* rhs);
|
|
static int CompareMinimumFaceIdFromPointers(const ON_SubDSectorId* lhs, const ON_SubDSectorId* rhs);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare of VertexId(), MinimumFaceId(), and SectorFaceCount() in that order.
|
|
*/
|
|
static int Compare(ON_SubDSectorId lhs, ON_SubDSectorId rhs);
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare of VertexId(), MinimumFaceId(), and SectorFaceCount() in that order.
|
|
*/
|
|
static int CompareFromPointers(const ON_SubDSectorId* lhs, const ON_SubDSectorId* rhs);
|
|
|
|
// No initialized construction for performance reasons.
|
|
// If initialization is required, then use sector_id = ON_SubDSectorId::Zero or sector_id = ON_SubDSectorId::Create(...).
|
|
|
|
/*
|
|
Description:
|
|
Create a sector id from a vertex and face in the sector. A sector id uniquely identifies
|
|
a sector in the context of a single ON_SubD.
|
|
Parameters:
|
|
vertex - [in]
|
|
face - [in]
|
|
A face in the sector.
|
|
If vertex->IsSingleSectorVertex() is true, then face can be nullptr.
|
|
Returns:
|
|
If the vertex and face are not nullptr and the face is in a sector of the vertex,
|
|
a nonzero zector id is returned. Otherwise ON_SubDSectorId::Invalid is returned.
|
|
*/
|
|
static const ON_SubDSectorId Create(
|
|
const class ON_SubDVertex* vertex,
|
|
const class ON_SubDFace* face
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This function is used to create ON_SubDSectorId values for searching or comparing
|
|
to values from ON_SubDSectorId::Create(). Use ON_SubDSectorId::Create() for all
|
|
other uses.
|
|
Parameters:
|
|
vertex - [in]
|
|
face - [in]
|
|
A face in the sector.
|
|
Returns:
|
|
A ON_SubDSectorId with the specified values for vertex_id and minimum_face_id.
|
|
The sector face count will be zero.
|
|
*/
|
|
static const ON_SubDSectorId CreateFromIds(
|
|
unsigned int vertex_id,
|
|
unsigned int minimum_face_id
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The sector's center vertex id.
|
|
Remarks:
|
|
Either SectorId(), VertexId(), and MinimumFaceId() are all zero or are all nonzero.
|
|
*/
|
|
const unsigned int VertexId() const;
|
|
|
|
/*
|
|
Returns:
|
|
The sector's minimum face id.
|
|
*/
|
|
const unsigned int MinimumFaceId() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of faces in the sector.
|
|
*/
|
|
const unsigned int SectorFaceCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this sector id is zero.
|
|
*/
|
|
bool IsZero() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if VertexId(), MinimumFaceId(), and SectorFaceCount() are all not zero.
|
|
*/
|
|
bool IsSet() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bVerbose - [in]
|
|
If true, the returned string begins with ON_SubDSectorId.
|
|
Returns:
|
|
"Zero", "Invalid", or "vX.fYxN" where X is VertexId(), Y is MinimumFaceId(), and N is the SectorFaceCount().
|
|
*/
|
|
const ON_wString ToString(bool bVerbose) const;
|
|
|
|
/*
|
|
Parameters:
|
|
s - [in]
|
|
beginning of string buffer
|
|
s_capacity
|
|
wchar_t element capacity of the string buffer
|
|
Returns:
|
|
nullptr if ther is not enough room in the buffer.
|
|
Otherwise a pointer to the null terminator of the returned string.
|
|
Remarks
|
|
The returned string will be "0" for a zero sector id, "X" for an invalid sector id,
|
|
or "vX.fYxN" where X is VertexId(), Y is MinimumFaceId(), and N is the SectorFaceCount().
|
|
*/
|
|
wchar_t* ToString(
|
|
wchar_t* s,
|
|
size_t s_capacity
|
|
) const;
|
|
|
|
private:
|
|
unsigned int m_vertex_id = 0;
|
|
// minimum face id in the sector. Since a face can be in only one sector, the
|
|
// combination of m_vertex_id and m_minimum_face_id uniquely identify a sector
|
|
// in the context of a single ON_SubD.
|
|
unsigned int m_minimum_face_id = 0;
|
|
// number of faces in the sector
|
|
unsigned int m_sector_face_count = 0;
|
|
};
|
|
|
|
ON_DECL
|
|
bool operator==(ON_SubDSectorId, ON_SubDSectorId);
|
|
|
|
ON_DECL
|
|
bool operator!=(ON_SubDSectorId, ON_SubDSectorId);
|
|
|
|
ON_DECL
|
|
bool operator>(ON_SubDSectorId, ON_SubDSectorId);
|
|
|
|
ON_DECL
|
|
bool operator<(ON_SubDSectorId, ON_SubDSectorId);
|
|
|
|
ON_DECL
|
|
bool operator>=(ON_SubDSectorId, ON_SubDSectorId);
|
|
|
|
ON_DECL
|
|
bool operator<=(ON_SubDSectorId, ON_SubDSectorId);
|
|
|
|
class ON_CLASS ON_SubDVertexSurfacePointCoefficient
|
|
{
|
|
public:
|
|
ON_SubDVertexSurfacePointCoefficient() = default;
|
|
~ON_SubDVertexSurfacePointCoefficient() = default;
|
|
ON_SubDVertexSurfacePointCoefficient(const ON_SubDVertexSurfacePointCoefficient&) = default;
|
|
ON_SubDVertexSurfacePointCoefficient& operator=(const ON_SubDVertexSurfacePointCoefficient&) = default;
|
|
|
|
public:
|
|
|
|
// ON_SubDVertexSurfacePointCoefficient::Zero.m_c = 0.0
|
|
static const ON_SubDVertexSurfacePointCoefficient Zero;
|
|
|
|
// ON_SubDVertexSurfacePointCoefficient::Nan.m_c = ON_DBL_QNAN
|
|
static const ON_SubDVertexSurfacePointCoefficient Nan;
|
|
|
|
// ON_SubDVertexSurfacePointCoefficient::Unset.m_c = ON_UNSET_VALUE
|
|
static const ON_SubDVertexSurfacePointCoefficient Unset;
|
|
|
|
static const ON_SubDVertexSurfacePointCoefficient Create(
|
|
const ON_SubDVertex* limit_point_vertex,
|
|
const ON_SubDVertex* ring_vertex,
|
|
double x
|
|
);
|
|
|
|
public:
|
|
static int CompareSurfacePointVertexId(
|
|
const ON_SubDVertexSurfacePointCoefficient* lhs,
|
|
const ON_SubDVertexSurfacePointCoefficient* rhs
|
|
);
|
|
|
|
static int CompareRingVertexId(
|
|
const ON_SubDVertexSurfacePointCoefficient* lhs,
|
|
const ON_SubDVertexSurfacePointCoefficient* rhs
|
|
);
|
|
|
|
static int CompareSurfacePointAndRingVertexId(
|
|
const ON_SubDVertexSurfacePointCoefficient* lhs,
|
|
const ON_SubDVertexSurfacePointCoefficient* rhs
|
|
);
|
|
|
|
static int CompareRingAndSurfacePointVertexId(
|
|
const ON_SubDVertexSurfacePointCoefficient* lhs,
|
|
const ON_SubDVertexSurfacePointCoefficient* rhs
|
|
);
|
|
|
|
|
|
public:
|
|
const ON_SubDVertex* m_limit_point_vertex = nullptr;
|
|
const ON_SubDVertex* m_ring_vertex = nullptr;
|
|
// The limit point of m_limit_point_vertex
|
|
// = sum of m_c*m_ring_vertex->ControlNetPoint()
|
|
// for every point in the ring of m_limit_point_vertex, including m_limit_point_vertex.
|
|
double m_c = 0.0;
|
|
|
|
public:
|
|
unsigned int SurfacePointVertexId() const;
|
|
unsigned int RingVertexId() const;
|
|
double Coefficient() const;
|
|
};
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDVertexSurfacePointCoefficient>;
|
|
#endif
|
|
|
|
class ON_CLASS ON_SubDComponentRegionIndex
|
|
{
|
|
public:
|
|
ON_SubDComponentRegionIndex() = default;
|
|
~ON_SubDComponentRegionIndex() = default;
|
|
ON_SubDComponentRegionIndex(const ON_SubDComponentRegionIndex&) = default;
|
|
ON_SubDComponentRegionIndex& operator=(const ON_SubDComponentRegionIndex&) = default;
|
|
|
|
public:
|
|
enum : unsigned short
|
|
{
|
|
/// Capacity of the m_index[] array;
|
|
IndexCapacity = 9
|
|
};
|
|
|
|
// All values are zero
|
|
static const ON_SubDComponentRegionIndex Zero;
|
|
|
|
// All values are 0xFFFF
|
|
static const ON_SubDComponentRegionIndex Unset;
|
|
|
|
/*
|
|
Description:
|
|
Compares subdivision counts. If the counts are the same, compares m_indices[].
|
|
*/
|
|
static int Compare(
|
|
const ON_SubDComponentRegionIndex* lhs,
|
|
const ON_SubDComponentRegionIndex* rhs
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Compares subdivision indices for minimum(lhs->m_subdivision_count,rhs->m_subdivision_count).
|
|
*/
|
|
static int CompareMinimumSubregion(
|
|
const ON_SubDComponentRegionIndex* lhs,
|
|
const ON_SubDComponentRegionIndex* rhs
|
|
);
|
|
|
|
unsigned short Index(
|
|
unsigned short i
|
|
) const;
|
|
|
|
unsigned short m_subdivision_count = 0;
|
|
|
|
// If m_subdivision_count > 0, then m_index[0], ..., m_index[m_subdivision_count-1]
|
|
// identifies a subregion of the level 0 component.
|
|
//
|
|
// Faces with quad subdivision:
|
|
// m_index[n] is the subdivision quad for the region that contains
|
|
// the parent face's corner at face->m_vertex[m_index[n]].
|
|
// Edges
|
|
// m_region_index[n] = 0 indicates the beginning half of the parent edge.
|
|
// (begins at edge->Vertex(0))
|
|
// m_region_index[n] = 1 indicates the ending half of the parent edge.
|
|
// (ends at edge->Vertex(1))
|
|
//
|
|
// When a component is created during a subdivision step, the value 0xFFFF
|
|
// is used to mark the non-existent regions at earlier subdivision levels.
|
|
// For example, if a level 1 edge is created by connecting
|
|
// a level0 edge subdivision point (middle-ish of the edge)
|
|
// to a level0 face subdivision point (center-ish of the face),
|
|
// then the level 1 edge would have
|
|
// m_level0_component = ON_SubDComponentPtr::CreateNull(ON_SubDComponentPtr::Type::Edge, bReversed),
|
|
// (m_level0_component.IsNull() will be true)
|
|
// m_level0_component_id = ON_SubDComponentRegion::NewTransientId()
|
|
// m_subdivision_count = 1,
|
|
// m_region_index[0] = 0xFFFF.
|
|
//
|
|
unsigned short m_index[ON_SubDComponentRegionIndex::IndexCapacity] = {};
|
|
|
|
void Push(
|
|
unsigned int region_index
|
|
);
|
|
|
|
void Pop();
|
|
|
|
/*
|
|
Description:
|
|
Get a string of the form .a.b.c .a.b.c = m_index[] values.
|
|
*/
|
|
wchar_t* ToString(
|
|
wchar_t* s,
|
|
size_t s_capacity
|
|
) const;
|
|
|
|
const ON_wString ToString() const;
|
|
|
|
/*
|
|
Description:
|
|
Encodes ON_SubDComponentRegionIndex information in 32 bits.
|
|
(m_subdivision_count) << 24
|
|
| (0x00FF0000 & ((m_region_index[0]) << 16))
|
|
| (m_region_index[1] & 0x0003) << (14)
|
|
| (m_region_index[2] & 0x0003) << (12)
|
|
...
|
|
| (m_index[m_subdivision_count] & 0x0003) <<(16-(2*m_subdivision_count))
|
|
Remarks:
|
|
This is useful when quick compare and sorting of regions is required,
|
|
m_subdivision_count < 256, m_index[0] < 256, m_index[1] < 4, ..., m_index[m_subdivision_count] < 4
|
|
Regions of N-gons with N < 256 and regions of edges
|
|
satisify these condition when m_subdivision_count < 256
|
|
(which is always in real world situations).
|
|
*/
|
|
ON__UINT32 ToCompressedRegionIndex() const;
|
|
|
|
static const ON_SubDComponentRegionIndex FromCompressedRegionIndex(
|
|
ON__UINT32 compressed_region_index
|
|
);
|
|
|
|
static ON__UINT32 ToCompressedRegionIndex(
|
|
unsigned short subdivision_count,
|
|
const unsigned short* region_index
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Decompress a 32-bit region.
|
|
Parameters:
|
|
region32 - [in]
|
|
Value returned from To32BitRegion().
|
|
subdivision_count - [out]
|
|
Subdivision count
|
|
region_index[] - out
|
|
Region indices. The region_index[] array must have a capcity of at
|
|
least ON_SubDComponentRegion::region_index_capacity elements.
|
|
*/
|
|
static void FromCompressedRegionIndex(
|
|
ON__UINT32 compressed_region_index,
|
|
unsigned short* subdivision_count,
|
|
unsigned short* region_index
|
|
);
|
|
};
|
|
|
|
class ON_CLASS ON_SubDComponentRegion
|
|
{
|
|
public:
|
|
ON_SubDComponentRegion() = default;
|
|
~ON_SubDComponentRegion() = default;
|
|
ON_SubDComponentRegion(const ON_SubDComponentRegion&) = default;
|
|
ON_SubDComponentRegion& operator=(const ON_SubDComponentRegion&) = default;
|
|
|
|
public:
|
|
static const ON_SubDComponentRegion Create(
|
|
const class ON_SubDFace* level0_face
|
|
);
|
|
|
|
static const ON_SubDComponentRegion Create(
|
|
unsigned int component_id,
|
|
ON_SubDComponentPtr::Type component_type,
|
|
bool bComponentMark
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Creates a region that can be used to identify a component
|
|
created at a certain level of subdivision that does not
|
|
come from dividing a component from the previous level.
|
|
For example, Catmull Clark subdivision edges on level N+1
|
|
that run from the level N edge subdivision point to the
|
|
level N face subdivision point.
|
|
|
|
m_level0_component = ON_SubDComponentPtr::CreateNull(component_type, bComponentDirection?1:0),
|
|
(m_level0_component.IsNull() will be true)
|
|
m_level0_component_id = ON_SubDComponentRegion::NewTransientId()
|
|
m_subdivision_count = subdivision_count,
|
|
m_region_index[0, ..., (subdivision_count-1)] = 0xFFFF.
|
|
|
|
*/
|
|
static const ON_SubDComponentRegion CreateSubdivisionRegion(
|
|
ON_SubDComponentPtr::Type component_type,
|
|
bool bComponentDirection,
|
|
unsigned short subdivision_count,
|
|
bool bAssignTransientId
|
|
);
|
|
|
|
public:
|
|
static const ON_SubDComponentRegion Empty;
|
|
|
|
public:
|
|
ON_SubDComponentPtr m_level0_component = ON_SubDComponentPtr::Null;
|
|
|
|
unsigned int m_level0_component_id = 0;
|
|
|
|
unsigned short SubdivisionCount() const;
|
|
|
|
ON_SubDComponentRegionIndex m_region_index;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_level0_component_id is a transient id.
|
|
*/
|
|
bool IsTransientId() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_level0_component_id is the id of a persistent ON_SubD level 0 component.
|
|
*/
|
|
bool IsPersistentId() const;
|
|
|
|
/*
|
|
Description:
|
|
Compares
|
|
m_level0_component.ComponentType(),
|
|
m_level0_component_id,
|
|
m_level0_component.ComponentDirection(),
|
|
the entire sub region,
|
|
and m_level0_component.m_ptr.
|
|
*/
|
|
static int Compare(
|
|
const ON_SubDComponentRegion* lhs,
|
|
const ON_SubDComponentRegion* rhs
|
|
);
|
|
|
|
/*
|
|
Descriptions:
|
|
Compares
|
|
m_level0_component.ComponentType(),
|
|
m_level0_component_id,
|
|
m_level0_component.ComponentDirection().
|
|
*/
|
|
static int CompareTypeIdDirection(
|
|
const ON_SubDComponentRegion* lhs,
|
|
const ON_SubDComponentRegion* rhs
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Compares
|
|
m_level0_component.ComponentType(),
|
|
m_level0_component_id,
|
|
m_level0_component.ComponentDirection(),
|
|
and the m_region_index[] values for the
|
|
minimum subdivision count lhs and rhs.
|
|
*/
|
|
static int CompareTypeIdDirectionMinimumSubregion(
|
|
const ON_SubDComponentRegion* lhs,
|
|
const ON_SubDComponentRegion* rhs
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Compares
|
|
m_level0_component.ComponentType(),
|
|
m_level0_component_id,
|
|
m_level0_component.ComponentDirection(),
|
|
and the entire sub region.
|
|
*/
|
|
static int CompareTypeIdDirectionSubregion(
|
|
const ON_SubDComponentRegion* lhs,
|
|
const ON_SubDComponentRegion* rhs
|
|
);
|
|
|
|
void SetLevel0Component(
|
|
ON_SubDComponentPtr component_ptr
|
|
);
|
|
|
|
void SetLevel0Face(
|
|
const ON_SubDFace* face
|
|
);
|
|
|
|
void SetLevel0EdgePtr(
|
|
const ON_SubDEdgePtr edge_ptr
|
|
);
|
|
|
|
void SetLevel0Vertex(
|
|
const ON_SubDVertex* vertex
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
region_index - [in]
|
|
If m_level0_component identifies an edge, region_index is 0 or 1,
|
|
and the edge is reversed (1=m_level0_component.ComponentMark()),
|
|
then PushAbsolute(1-region_index) is called.
|
|
In every other case, PushAbsolute(region_index) is called.
|
|
*/
|
|
void PushAdjusted(
|
|
unsigned int region_index
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
region_index - [in]
|
|
If m_level0_component identifies a face, then region_index is the index of the
|
|
corner vertex for the subdivision quad.
|
|
If m_level0_component identifies an edge, then region_index must be 0 or 1.
|
|
Description:
|
|
Increments if m_subdivision_count and appends region_index to m_region_index[]
|
|
(m_region_index[m_subdivision_count++] = region_index)
|
|
*/
|
|
void PushAbsolute(
|
|
unsigned int region_index
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Get a string of the form fN.a.b.c where N = m_level0_face-m_id, a.b.c = m_region_index[] values.
|
|
*/
|
|
wchar_t* ToString(
|
|
wchar_t* s,
|
|
size_t s_capacity
|
|
) const;
|
|
|
|
const ON_wString ToString() const;
|
|
|
|
void Pop();
|
|
|
|
bool IsEmptyRegion() const;
|
|
|
|
enum : unsigned int
|
|
{
|
|
TransientIdBit = 0x80000000U
|
|
};
|
|
|
|
|
|
/*
|
|
Returns:
|
|
A value that can be used to identify transient subdivision components that do not
|
|
exist in the persistent levels of a SubD.
|
|
Transient ids always satisfy (ON_SubDComponentRegion::TransientIdBit & transient_id) is not zero and
|
|
(~ON_SubDComponentRegion::TransientIdBit & transient_id) is not zero.
|
|
Remarks:
|
|
Transient ids are used to identify subdivision components at levels that do
|
|
not persist in the ON_SubD. They are unique within the context where they are
|
|
being used. They generally vary with each repetition of a calcultion in that
|
|
context.
|
|
*/
|
|
static const unsigned int NewTransientId();
|
|
|
|
/*
|
|
Description:
|
|
Resets the value used to generate transient ids.
|
|
This is useful during debugging session so that transient id
|
|
values are predictable. Otherwise, use of this function
|
|
should be avoided.
|
|
*/
|
|
static void ResetTransientId();
|
|
|
|
/*
|
|
Parameters:
|
|
id - [in]
|
|
Value to test to see if it is a transient subd component id.
|
|
Returns:
|
|
True if (ON_SubDComponentRegion::TransientIdBit & id) is not zero and
|
|
(~ON_SubDComponentRegion::TransientIdBit & id) is not zero.
|
|
Remarks:
|
|
Transient ids are used to identify subdivision components at levels that do
|
|
not persist in the ON_SubD. They are unique within the context where they are
|
|
being used. They generally vary with each repetition of a calcultion in that
|
|
context.
|
|
*/
|
|
static bool IsTransientId(unsigned int id);
|
|
|
|
/*
|
|
Parameters:
|
|
id - [in]
|
|
Value to test to see if it is a transient subd component id.
|
|
Returns:
|
|
If the id is a transient id, then its id value is returned.
|
|
Otherwise, 0 is returned.
|
|
Remarks:
|
|
Transient ids are used to identify subdivision components at levels that do
|
|
not persist in the ON_SubD. They are unique within the context where they are
|
|
being used. They generally vary with each repetition of a calcultion in that
|
|
context.
|
|
*/
|
|
static unsigned int TransientId(unsigned int id);
|
|
|
|
/*
|
|
Parameters:
|
|
id - [in]
|
|
Value to test to see if it is a persitsent subd component id.
|
|
Returns:
|
|
True if (ON_SubDComponentRegion::TransientIdBit & id) is not zero and
|
|
(~ON_SubDComponentRegion::TransientIdBit & id) is not zero.
|
|
Remarks:
|
|
Transient ids are used to identify subdivision components at levels that do
|
|
not persist in the ON_SubD. They are unique within the context where they are
|
|
being used. They generally vary with each repetition of a calcultion in that
|
|
context.
|
|
*/
|
|
static bool IsPersistentId(unsigned int id);
|
|
};
|
|
|
|
class ON_CLASS ON_SubDFaceRegion
|
|
{
|
|
public:
|
|
ON_SubDFaceRegion() = default;
|
|
~ON_SubDFaceRegion() = default;
|
|
ON_SubDFaceRegion(const ON_SubDFaceRegion&) = default;
|
|
ON_SubDFaceRegion& operator=(const ON_SubDFaceRegion&) = default;
|
|
|
|
static const ON_SubDFaceRegion Empty;
|
|
|
|
public:
|
|
// Identifies a region of an ON_SubDFace
|
|
ON_SubDComponentRegion m_face_region;
|
|
|
|
const ON_SubDFace* Level0Face() const;
|
|
|
|
// When the face region is a quad, m_edge_region[4] identifies regions of ON_SubDEdge elements.
|
|
// When the face region is a sub-quad, these edges may be null or have null ON_SubDEdge pointers
|
|
// and the ids will be zero or ON_SubDComponentRegion::IsTransientId() will be true.
|
|
// When ON_SubDComponentRegion::IsTransientId() is true, the id does not identify
|
|
// a persistent edge in the ON_SubD.
|
|
ON_SubDComponentRegion m_edge_region[4];
|
|
|
|
unsigned int m_level0_edge_count = 0;
|
|
|
|
private:
|
|
unsigned int m_reserved = 0;
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
If vertex_id > 0 and there is a unique element of m_vertex_id[] with the same value,
|
|
the index of that element is returned (0,1,2 or 3).
|
|
Otherwise ON_UNSET_UNINT_INDEX is returned.
|
|
*/
|
|
unsigned int CornerIndexFromVertexId(
|
|
unsigned int vertex_id
|
|
) const;
|
|
|
|
|
|
// If set, these are the vertice ids at the region's limit surface corners.
|
|
// m_vertex_id[] is mutable because these values appear during recursive calculations.
|
|
// When the face region is a sub-quad, these ids will be zero or ON_SubDComponentRegion::IsTransientId()
|
|
// will be true.
|
|
// When ON_SubDComponentRegion::IsTransientId() is true, the id does not identify
|
|
// a persistent vertex in the ON_SubD.
|
|
mutable unsigned int m_vertex_id[4] = {};
|
|
|
|
// When a vertex is exceptional, a NURBS conversion is typically an approximation
|
|
// of the SubD around the exceptional vertex. There are a variety of post processes
|
|
// that can be applied in this case and the processes need to be applied
|
|
// sector by sector.
|
|
// Note well that when a level zero face is an N-gon with N != 4,
|
|
// the face subdivision point is an exceptional smooth vertex with valence = N.
|
|
// In this case the corresponding m_vertex_id[] value will be zero.
|
|
mutable ON_SubDSectorId m_sector_id[4];
|
|
|
|
public:
|
|
void Push(unsigned int quadrant_index);
|
|
|
|
bool IsValid(
|
|
bool bSilentError
|
|
) const;
|
|
|
|
wchar_t* ToString(
|
|
wchar_t* s,
|
|
size_t s_capacity
|
|
) const;
|
|
|
|
const ON_wString ToString() const;
|
|
};
|
|
|
|
|
|
class ON_CLASS ON_SubDFaceRegionAndNurbs
|
|
{
|
|
public:
|
|
ON_SubDFaceRegionAndNurbs() = default;
|
|
~ON_SubDFaceRegionAndNurbs() = default;
|
|
ON_SubDFaceRegionAndNurbs(const ON_SubDFaceRegionAndNurbs&) = default;
|
|
ON_SubDFaceRegionAndNurbs& operator=(const ON_SubDFaceRegionAndNurbs&) = default;
|
|
|
|
static const ON_SubDFaceRegionAndNurbs Empty;
|
|
|
|
public:
|
|
ON_SubDFaceRegion m_face_region;
|
|
// This pointer is not managed by ON_SubDFaceRegionAndNurbs
|
|
class ON_NurbsSurface* m_nurbs_surface = nullptr;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDFromMeshParameters
|
|
//
|
|
class ON_CLASS ON_SubDFromSurfaceParameters
|
|
{
|
|
public:
|
|
|
|
// Default construction is identical to ON_SubDFromMeshParameters::Smooth.
|
|
ON_SubDFromSurfaceParameters() = default;
|
|
~ON_SubDFromSurfaceParameters() = default;
|
|
ON_SubDFromSurfaceParameters(const ON_SubDFromSurfaceParameters&) = default;
|
|
ON_SubDFromSurfaceParameters& operator=(const ON_SubDFromSurfaceParameters&) = default;
|
|
|
|
static const ON_SubDFromSurfaceParameters Default;
|
|
static const ON_SubDFromSurfaceParameters DefaultWithCorners;
|
|
static const ON_SubDFromSurfaceParameters ControlNet;
|
|
static const ON_SubDFromSurfaceParameters ControlNetWithCorners;
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDFromSurfaceParameters::Methods] [Rhino.Geometry.SubDFromSurfaceMethods] [byte]
|
|
/// <summary>
|
|
/// ON_SubDFromSurfaceParameters::Method are ways to create a SubD from a surface.
|
|
/// </summary>
|
|
enum class Methods : unsigned char
|
|
{
|
|
/// <summary>
|
|
/// Used to indicate the method is not set.
|
|
/// </summary>
|
|
Unset = 0,
|
|
|
|
/// <summary>
|
|
/// The surface is approximated with a SubD friendly NURBS surface and the SubD is created
|
|
/// to match the subd friendly nurbs surface.
|
|
/// If the input surface is a subd friendly NURBS surface, the subd and surface have the same geometry.
|
|
/// </summary>
|
|
SubDFriendlyFit = 1,
|
|
|
|
/// <summary>
|
|
/// The surface is converted to a NURBS surface and then a subd with one face per NURBS bispan
|
|
/// is created by using an appropriate subset of the NURBS surface control net.
|
|
/// If the input surface is a subd friendly NURBS surface, the subd and surface have the same geometry.
|
|
/// </summary>
|
|
FromNurbsControlNet = 2
|
|
};
|
|
#pragma endregion
|
|
|
|
ON_SubDFromSurfaceParameters::Methods Method() const;
|
|
|
|
void SetMethod(
|
|
ON_SubDFromSurfaceParameters::Methods method
|
|
);
|
|
|
|
bool Corners() const;
|
|
|
|
void SetCorners(
|
|
bool bCorners
|
|
);
|
|
|
|
private:
|
|
ON_SubDFromSurfaceParameters::Methods m_method = ON_SubDFromSurfaceParameters::Methods::SubDFriendlyFit;
|
|
bool m_bCorners = false;
|
|
unsigned short m_reserved1 = 0;
|
|
unsigned int m_reserved2 = 0;
|
|
double m_reserved3 = 0.0;
|
|
double m_reserved4 = 0.0;
|
|
};
|
|
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDEndCapStyle] [Rhino.Geometry.SubDEndCapStyle] [byte]
|
|
/// <summary>
|
|
/// ON_SubDEndCapStyle enumerates the type of end caps functions like ON_SubD::CreateCylinder will create.
|
|
/// Use ON_SubDEndCapStyleFromUnsigned(integer value) to convert integer values to an ON_SubDEndCapStyle.
|
|
/// Use ON_SubDEndCapStyleToString(end_cap_style) to convert ON_SubDEndCapStyle values to string descriptions.
|
|
/// </summary>
|
|
enum class ON_SubDEndCapStyle : unsigned char
|
|
{
|
|
/// <summary>
|
|
/// Used to indicate the end cap style is not set.
|
|
/// </summary>
|
|
Unset = 0,
|
|
|
|
/// <summary>
|
|
/// Ends are not capped.
|
|
/// </summary>
|
|
None = 1,
|
|
|
|
/// <summary>
|
|
/// Ends are capped with triangles.
|
|
/// </summary>
|
|
Triangles = 2,
|
|
|
|
/// <summary>
|
|
/// When the end has an even number of edges, is will be capped with quads. Otherwise it will be capped with triangles.
|
|
/// </summary>
|
|
Quads = 3,
|
|
|
|
/// <summary>
|
|
/// Ends are capped with a n-gon. This is a poor choice when there are a large number of edges in the end boundary.
|
|
/// </summary>
|
|
Ngon = 4
|
|
};
|
|
#pragma endregion
|
|
|
|
|
|
/// <summary>
|
|
/// Convert an integer value to an ON_SubDEndCapStyle enum value.
|
|
/// </summary>
|
|
/// <param name="subd_cap_style_as_unsigned"></param>
|
|
/// If subd_cap_style_as_unsigned is not valid, then ON_SubDEndCapStyle::Unset is returned.
|
|
/// <returns></returns>
|
|
ON_DECL
|
|
ON_SubDEndCapStyle ON_SubDEndCapStyleFromUnsigned(
|
|
unsigned int subd_cap_style_as_unsigned
|
|
);
|
|
|
|
/// <summary>
|
|
/// Convert subd_cap_style to a string description.
|
|
/// </summary>
|
|
/// <param name="subd_cap_style"></param>
|
|
/// <returns></returns>
|
|
ON_DECL
|
|
const ON_wString ON_SubDEndCapStyleToString(
|
|
ON_SubDEndCapStyle subd_cap_style
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubD
|
|
//
|
|
//// ON_WIP_SDK
|
|
//// This class is in the WIP SDK but the [[deprecated]] tag is
|
|
//// failing to compile in tl_precompiledheader.cpp
|
|
class ON_CLASS ON_SubDExpandEdgesParameters
|
|
{
|
|
public:
|
|
ON_SubDExpandEdgesParameters() = default;
|
|
~ON_SubDExpandEdgesParameters() = default;
|
|
ON_SubDExpandEdgesParameters(const ON_SubDExpandEdgesParameters&) = default;
|
|
ON_SubDExpandEdgesParameters& operator=(const ON_SubDExpandEdgesParameters&) = default;
|
|
|
|
static const ON_SubDExpandEdgesParameters Default;
|
|
|
|
/// <summary>
|
|
/// ON_SubDExpandEdgesParameters::Style specifies options for how faces are inserted along input edges.
|
|
/// </summary>
|
|
enum class Style : unsigned char
|
|
{
|
|
/// <summary>
|
|
/// Indicates the variable has not be initialized.
|
|
/// </summary>
|
|
Unset = 0,
|
|
|
|
/// <summary>
|
|
/// One quad replaces each input manifold edge. Corner cases where three or more edges meet
|
|
/// receive special handling.
|
|
/// </summary>
|
|
Single = 1,
|
|
|
|
/// <summary>
|
|
/// Two quads are added for each input manifold edge. Corner cases where three or more edges meet
|
|
/// receive special handling.
|
|
/// </summary>
|
|
Double = 2,
|
|
|
|
/// <summary>
|
|
/// This option applies only when the the input is an array of ON_SubDEdgePtrs
|
|
/// that form a single oriented edge chain of manifold interior edges.
|
|
/// A single quad is added to the left of the input edges.
|
|
/// (The left side of of an oriented interior manifold edge is the face
|
|
/// whose natural boundary orientation is the same as with the ON_SubDEdgePtr direction.)
|
|
/// </summary>
|
|
HalfLeft = 3,
|
|
|
|
/// <summary>
|
|
/// This option applies only when the the input is an array of ON_SubDEdgePtrs
|
|
/// that form a single oriented edge chain of manifold interior edges.
|
|
/// A single quad is added to the right of the input edges.
|
|
/// (The right side of of an oriented interior manifold edge is the face
|
|
/// whose natural boundary orientation is opposite the ON_SubDEdgePtr direction.)
|
|
/// </summary>
|
|
HalfRight = 4,
|
|
};
|
|
|
|
public:
|
|
/// OffsetTolerance = 0.001
|
|
static const double OffsetTolerance;
|
|
|
|
/// Minimum permitted offset value (0.05)
|
|
static const double MinimumOffset;
|
|
|
|
/// Maximum permitted offset value (0.95)
|
|
static const double MaximumOffset;
|
|
|
|
/// Small offset value (0.125)
|
|
static const double SmallOffset;
|
|
|
|
/// Medium offset value (0.25)
|
|
static const double MediumOffset;
|
|
|
|
/// Large offset value (0.5)
|
|
static const double LargeOffset;
|
|
|
|
public:
|
|
/// <summary>
|
|
/// This SHA1 hash can be used to determine if sets of parameters are the same.
|
|
/// </summary>
|
|
/// <returns>A SHA1 hash of all parameter values.</returns>
|
|
const ON_SHA1_Hash Hash() const;
|
|
|
|
public:
|
|
static double CleanupOffset(double x);
|
|
|
|
|
|
/// <summary>
|
|
/// Normalized constant offset parameter for inserting edges parallel to an input edge.
|
|
/// Smaller values create narrower offsets.
|
|
/// </summary>
|
|
/// <returns>Offset value in the range ON_SubDExpandEdgesParameters::MinimumOffset to ON_SubDExpandEdgesParameters::MaximumOffset.</returns>
|
|
double ConstantOffset() const;
|
|
|
|
/// <summary>
|
|
/// Set the constant offset value. Values within OffsetTolerance of a
|
|
/// predefined offset value are set to the predefined offset value.
|
|
/// </summary>
|
|
/// <param name="offset">
|
|
/// ON_SubDExpandEdgesParameters::MinimumOffset <= offset <= ON_SubDExpandEdgesParameters::MaximumOffset;
|
|
/// </param>
|
|
/// <returns></returns>
|
|
void SetConstantOffset(double offset);
|
|
|
|
|
|
/// <summary>
|
|
/// Determine if the set of ON_SubDEdgePtrs can be sorted into a
|
|
/// single edge chain that supports half side offsets.
|
|
/// </summary>
|
|
/// <param name="edge_chain"></param>
|
|
/// <returns>True if variable offsets can be applied to edge_chain.</returns>
|
|
static bool IsValidForHalfOffset(
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& edges
|
|
);
|
|
|
|
/// <summary>
|
|
/// Determine if the set of ON_SubDEdgePtrs can be sorted into a
|
|
/// single open edge chain supports variable offsets.
|
|
/// </summary>
|
|
/// <param name="edge_chain"></param>
|
|
/// <returns>True if variable offsets can be applied to edge_chain.</returns>
|
|
static bool IsValidForVariableOffset(
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& edges
|
|
);
|
|
|
|
/// This option applies only when the the input is an array of ON_SubDEdgePtrs
|
|
/// that form a single oriented edge chain. You may use
|
|
/// ON_SubDExpandEdgesParameters::IsValidForVariableOffset() to determine if an
|
|
/// array of ON_SubDEdgePtrs meets the variable offset requirements.
|
|
/// In all other cases, the constant Offset() is used.
|
|
/// To apply variable offsets to several edge chains, expand them one at a time.
|
|
const ON_Interval VariableOffset() const;
|
|
|
|
/*
|
|
Description:
|
|
This option applies only when the the input is an array of ON_SubDEdgePtrs
|
|
that form a single oriented edge chain. You may use
|
|
ON_SubDExpandEdgesParameters::IsValidForVariableOffset() to determine if an
|
|
array of ON_SubDEdgePtrs meets the variable offset requirements.
|
|
In all other cases, the constant Offset() is used.
|
|
To apply variable offsets to several edge chains, expand them one at a time.
|
|
|
|
Parameters:
|
|
variable_offsets - [in]
|
|
The two values must be between 0 and 1 and differ by more than ON_SubDExpandEdgesParameters::OffsetTolerance.
|
|
*/
|
|
void SetVariableOffset(ON_Interval variable_offsets);
|
|
|
|
void ClearVariableOffset();
|
|
|
|
static bool IsValidConstantOffset(
|
|
double constant_offset_candidate
|
|
);
|
|
|
|
static bool IsValidVariableOffset(
|
|
ON_Interval variable_offset_candidate
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
True if variable offsets are set.
|
|
*/
|
|
bool IsVariableOffset() const;
|
|
|
|
|
|
ON_SubDExpandEdgesParameters::Style FaceStyle() const;
|
|
|
|
/// <summary>
|
|
/// Set the style for new faces.
|
|
/// </summary>
|
|
/// <param name="face_style"></param>
|
|
/// <returns>Style for new faces.</returns>
|
|
void SetFaceStyle(ON_SubDExpandEdgesParameters::Style face_style);
|
|
|
|
/// <returns>True if the FaceStyle() is HalfLeft of HalfRight.</returns>
|
|
bool IsHalfFaceStyle() const;
|
|
|
|
/// <returns>Per face color for new faces.</returns>
|
|
const ON_Color FaceColor() const;
|
|
|
|
/// <summary>
|
|
/// Set the perf face color for new faces.
|
|
/// </summary>
|
|
/// <param name="face_color">Color for new face. Pass ON_Color::Unset for no per face color.</param>
|
|
void SetFaceColor(ON_Color face_color);
|
|
|
|
/// <returns>Status for new faces.</returns>
|
|
const ON_ComponentStatus FaceStatus() const;
|
|
|
|
/// <summary>
|
|
/// Set the Mark(), MarkBits(), Selected(), and Highlighted() status for new faces.
|
|
/// </summary>
|
|
/// <param name="face_status">Status for new faces.</param>
|
|
void SetFaceStatus(ON_ComponentStatus face_status);
|
|
|
|
private:
|
|
double m_constant_offset = ON_SubDExpandEdgesParameters::MediumOffset;
|
|
ON_Interval m_variable_offsets = ON_Interval::Nan;
|
|
ON_Color m_face_color = ON_Color::UnsetColor;
|
|
ON_ComponentStatus m_face_status;
|
|
ON_SubDExpandEdgesParameters::Style m_face_style = ON_SubDExpandEdgesParameters::Style::Double;
|
|
|
|
private:
|
|
unsigned char m_reserved1 = 0;
|
|
|
|
private:
|
|
ON__UINT64 m_reserved2 = 0;
|
|
ON__UINT64 m_reserved3 = 0;
|
|
};
|
|
|
|
bool operator==(const ON_SubDExpandEdgesParameters& lhs, const ON_SubDExpandEdgesParameters& rhs);
|
|
bool operator!=(const ON_SubDExpandEdgesParameters& lhs, const ON_SubDExpandEdgesParameters& rhs);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubD
|
|
//
|
|
class ON_CLASS ON_SubD : public ON_Geometry
|
|
{
|
|
ON_OBJECT_DECLARE(ON_SubD);
|
|
|
|
#if defined(ON_SUBD_CENSUS)
|
|
private:
|
|
ON_SubDCensusCounter m_census_counter;
|
|
#endif
|
|
|
|
public:
|
|
static const ON_SubD Empty;
|
|
|
|
enum : unsigned int
|
|
{
|
|
maximum_subd_level = 128 // uses as a sanity check on input parameters
|
|
};
|
|
|
|
/*
|
|
Returns:
|
|
A runtime serial number identifying this subd.
|
|
Remarks:
|
|
ON_SubD is a shared pointer to an implementation. As such, there can
|
|
be multiple ON_SubD instances that reference the same implementation.
|
|
The runtime serial number uniquely identifies a particular instance
|
|
of an implementation.
|
|
The empty subd has runtime serial number = 0.
|
|
*/
|
|
ON__UINT64 RuntimeSerialNumber() const;
|
|
|
|
/*
|
|
Returns:
|
|
A runtime serial number that is changed every time a the active level,
|
|
vertex location, vertex or edge flag, or subd topology is changed.
|
|
*/
|
|
ON__UINT64 GeometryContentSerialNumber() const;
|
|
|
|
/*
|
|
Returns:
|
|
A runtime serial number that is incremented every time a component status
|
|
(locked, hidden, selected, highlighted, ...) is changed.
|
|
*/
|
|
ON__UINT64 ComponentStatusSerialNumber() const;
|
|
|
|
/*
|
|
Description:
|
|
Change the geoemtry content serial number to indicate something affecting
|
|
the geometric shape of the subd has changed. This includes topologial changes,
|
|
vertex and edge tag changes, and changes to vertex control net locations.
|
|
Parameters:
|
|
bChangePreservesSymmetry - [in]
|
|
When in doubt, pass false.
|
|
If the change preserves global symmtery, then pass true.
|
|
(For example, a global subdivide preserves all types of symmetry.)
|
|
Note well:
|
|
Transformations do not preserve symmetries that are
|
|
set with respect to world coordinate systems.
|
|
Returns:
|
|
The new value of GeometryConentSerialNumber().
|
|
Remarks:
|
|
The value can change by any amount.
|
|
Changing the geometry content serial number automatically changes
|
|
the render content serial number.
|
|
*/
|
|
ON__UINT64 ChangeGeometryContentSerialNumberForExperts(
|
|
bool bChangePreservesSymmetry
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
The render content serial number changes whenever a change the might effect
|
|
rendered appearance changes. This includes both geometry changes and
|
|
changes that affect rendered appeance including changes to per face colors,
|
|
per face materials, texture coordinates, and texture mappings.
|
|
*/
|
|
ON__UINT64 RenderContentSerialNumber() const;
|
|
|
|
/*
|
|
Description:
|
|
Change the render content serial number to indicate something affecting
|
|
only rendered appearance has changed. This includes changes to per face colors,
|
|
per face materials, texture coordinates, and texture mappings.
|
|
Remarks:
|
|
Changing the geometry content serial number automatically changes
|
|
the render content serial number. If you call ChangeGeometryContentSerialNumberForExperts(),
|
|
there is no need to also call ChangeRenderContentSerialNumber().
|
|
*/
|
|
ON__UINT64 ChangeRenderContentSerialNumber() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get a hash that uniquely identifies the topology or geometry of this SubD.
|
|
Parameters:
|
|
hash_type - [in]
|
|
To see what is included in the various hashes, read the documentation for the ON_SubDHashType enum.
|
|
bForceUpdate - [in]
|
|
When in doubt pass false.
|
|
The SubD hashes are mutable and cached. When code properly manages GeometryContentSerialNumber(),
|
|
then SubDHash(hash_type,false) will always return the correct answer. This is the expected behavior.
|
|
If code directly modifies SubD components and fails to call ChangeGeometryContentSerialNumberForExperts(),
|
|
then it is possible a stale hash will be returned. Setting bForceUpdate = true forces the SHA1
|
|
values to be recalculated from scratch. For extremely large SubDs, this recalculation can be time consuming.
|
|
*/
|
|
const ON_SubDHash SubDHash(
|
|
ON_SubDHashType hash_type,
|
|
bool bForceUpdate
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
If two SubDs have identical values of GeometryHash(), then they have
|
|
identical surface geometry.
|
|
Returns:
|
|
this->SubDHash(ON_SubDHashType::Geometry,false).SubDHash().
|
|
Remarks:
|
|
If the geometry hashes are equal, the topology hashes are equal.
|
|
*/
|
|
const ON_SHA1_Hash GeometryHash() const;
|
|
|
|
/*
|
|
Description:
|
|
If two SubDs have identical values of TopologyHash(), then they have
|
|
identical labeled control net topology. The labels are the vertex, edge,
|
|
and face ids.
|
|
Returns:
|
|
this->SubDHash(ON_SubDHashType::Topology,false).SubDHash().
|
|
Remarks:
|
|
Two SubDs can have the same topology hash but different geometry hashes.
|
|
*/
|
|
const ON_SHA1_Hash TopologyHash() const;
|
|
|
|
/*
|
|
Description:
|
|
Get the SubD appearance (surface or control net);
|
|
Returns:
|
|
ON_SubDComponentLocation::Surface or ON_SubDComponentLocation::ControlNet.
|
|
*/
|
|
ON_SubDComponentLocation SubDAppearance() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the SubD appearance (surface or control net).
|
|
Parameters:
|
|
subd_appearance - [in]
|
|
ON_SubDComponentLocation::Surface or ON_SubDComponentLocation::ControlNet.
|
|
Remarks:
|
|
This makes no changes to the information that defines the SubD.
|
|
It does not require regeneration of the ON_SubDMeshFragments.
|
|
Application display will need to be updated.
|
|
*/
|
|
void SetSubDAppearance(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the SubD appearance (surface or control net);
|
|
Returns:
|
|
ON_SubDComponentLocation::Surface or ON_SubDComponentLocation::ControlNet.
|
|
*/
|
|
static ON_SubDComponentLocation ToggleSubDAppearanceValue(ON_SubDComponentLocation subd_appearance);
|
|
static const ON_SubDComponentLocation DefaultSubDAppearance; // = ON_SubDComponentLocation::Surface
|
|
static const ON_SubDTextureCoordinateType DefaultTextureCoordinateType; // = ON_SubDTextureCoordinateType::Packed
|
|
|
|
|
|
public:
|
|
static ON_SubD* CreateCylinder(
|
|
const class ON_Cylinder& cylinder,
|
|
unsigned circumference_face_count,
|
|
unsigned height_face_count,
|
|
ON_SubDEndCapStyle end_cap_style,
|
|
ON_SubDEdgeTag end_cap_edge_tag,
|
|
ON_SubDComponentLocation radius_location,
|
|
ON_SubD* destination_subd
|
|
);
|
|
|
|
public:
|
|
static ON_SubDVertexTag VertexTagFromUnsigned(
|
|
unsigned int vertex_tag_as_unsigned
|
|
);
|
|
|
|
|
|
/*
|
|
Paramters:
|
|
vertex_tag - [in]
|
|
bVerbose - [in]
|
|
If verbose, the tag name is preceded with "ON_SubDVertexTag::".
|
|
Returns:
|
|
vertex_tag as a string.
|
|
*/
|
|
static const ON_wString VertexTagToString(
|
|
ON_SubDVertexTag vertex_tag,
|
|
bool bVertose
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
vertex_tag - [in]
|
|
Returns:
|
|
True if vertex_tag is Smooth, Crease, Corner, or Dart.
|
|
False otherwise.
|
|
*/
|
|
static bool VertexTagIsSet(
|
|
ON_SubDVertexTag vertex_tag
|
|
);
|
|
|
|
|
|
#if 0
|
|
// .NET code that generates enums in hash pragma region R-H_C_S-H-ARED_ENUM cannot handle if 0.
|
|
///<summary>
|
|
/// Reserved for version 2 of the ON_SubD project.
|
|
/// Currently this tag is not used and is invalid.
|
|
///
|
|
/// FUTURE: The edge is a "soft crease" or "semi-sharp".
|
|
/// At lease one end vertex must be tagged as ON_SubDVertexTag::Smooth
|
|
/// The edge must have exactly two faces.
|
|
/// The value of ON_SubDEdge::m_sharpness controls how
|
|
/// soft/hard the edge appears.
|
|
/// ON_SubDEdge::m_sharpness = 0 is identical to ON_SubDEdgeTag::Smooth.
|
|
/// ON_SubDEdge::m_sharpness = 1 is identical to ON_SubDEdgeTag::Crease.
|
|
///</summary>
|
|
Sharp = 3,
|
|
#endif
|
|
|
|
static ON_SubDEdgeTag EdgeTagFromUnsigned(
|
|
unsigned int edge_tag_as_unsigned
|
|
);
|
|
|
|
|
|
/*
|
|
Paramters:
|
|
edge_tag - [in]
|
|
bVerbose - [in]
|
|
If verbose, the tag name is preceded with "ON_SubDEdgeTag::".
|
|
Returns:
|
|
edge_tag as a string.
|
|
*/
|
|
static const ON_wString EdgeTagToString(
|
|
ON_SubDEdgeTag edge_tag,
|
|
bool bVertose
|
|
);
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
edge_tag - [in]
|
|
Returns:
|
|
True if edge_tag is Smooth, Crease, Sharp, or X.
|
|
False otherwise.
|
|
*/
|
|
static bool EdgeTagIsSet(
|
|
ON_SubDEdgeTag edge_tag
|
|
);
|
|
|
|
|
|
//enum class VertexEdgeOrder : unsigned char
|
|
//{
|
|
// unset = 0,
|
|
// radial, // The ON_SubDVertex edge and face information satisfies:
|
|
// // 1) m_face_count = m_edge_count or m_face_count+1 == m_edge_count
|
|
// // 2) m_faces[i] is between m_edges[i] and m_edges[(i+1)%m_edge_count]
|
|
// // 3) When 0 < i < m_edge_count-1, m_edges[i].m_edge_count = 2
|
|
// // and m_edges[i].m_face2[] references m_faces[i-1] and m_faces[i]
|
|
// // in an unspecified order.
|
|
// notradial // one of the conditions conditions for radial is not satisfied.
|
|
//};
|
|
|
|
//static ON_SubD::VertexEdgeOrder VertexEdgeOrderFromUnsigned(
|
|
// unsigned int vertex_edge_order_as_unsigned
|
|
// );
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubD::VertexFacetType] [Rhino.Geometry.SubDVertexFacetType] [byte]
|
|
/// <summary>
|
|
/// Summarizes the number of edges in faces in the whole object.
|
|
/// </summary>
|
|
enum class VertexFacetType : unsigned char
|
|
{
|
|
///<summary>Not a valid vertex face type.</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>All faces are triangular.</summary>
|
|
Tri = 3,
|
|
|
|
///<summary>All faces are quads.</summary>
|
|
Quad = 4,
|
|
|
|
///<summary>Edge count of faces is constant and > 4.</summary>
|
|
Ngon = 5,
|
|
|
|
///<summary>Edge count of faces is not constant.</summary>
|
|
Mixed = 0xFF
|
|
};
|
|
#pragma endregion
|
|
|
|
static ON_SubD::VertexFacetType VertexFacetTypeFromUnsigned(
|
|
unsigned int vertex_facet_type_as_unsigned
|
|
);
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubD::ChainType] [Rhino.Geometry.SubDChainType] [byte]
|
|
/// <summary>
|
|
/// SubD::ChainType specifies what edge and vertex tag tests are used when creating edge chains.
|
|
/// </summary>
|
|
enum class ChainType : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Unset.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// All types of edges and vertices can be in the chain.
|
|
///</summary>
|
|
MixedTag = 1,
|
|
|
|
///<summary>
|
|
/// Every edge in an edge chain has the same smooth/crease property.
|
|
///</summary>
|
|
EqualEdgeTag = 2,
|
|
|
|
///<summary>
|
|
/// Every edge in an edge chain has the same smooth/crease edge tag
|
|
/// and interior vertices have the corresponding smooth/crease vertex tag.
|
|
///</summary>
|
|
EqualEdgeAndVertexTag = 3,
|
|
|
|
///<summary>
|
|
/// Every edge in an edge chain has the same smooth/crease property
|
|
/// and every edge has the same number of faces.
|
|
/// If the edges have 1 face, then interior vertices have valence = 3.
|
|
/// If the edges have 2 faces, then interior vertices have valence = 4.
|
|
///</summary>
|
|
EqualEdgeTagAndOrdinary = 4,
|
|
|
|
///<summary>
|
|
/// Every edge in an edge chain has the same smooth/crease edge tag,
|
|
/// every edge has the same number of faces,
|
|
/// and interior vertices have the corresponding smooth/crease vertex tag.
|
|
/// If the edges have 1 face, then interior vertices have valence = 3.
|
|
/// If the edges have 2 faces, then interior vertices have valence = 4.
|
|
///</summary>
|
|
EqualEdgeAndVertexTagAndOrdinary = 5
|
|
};
|
|
#pragma endregion
|
|
|
|
/*
|
|
Parameters:
|
|
sit - [in]
|
|
vertex sector iterator
|
|
component_ring - [out]
|
|
A sorted list of ON_SubDComponentPtr values are returned in component_ring[]
|
|
component_ring[0] is the central vertex.
|
|
component_ring[1] and subsequent components with odd indices are sector edges.
|
|
component_ring[2] and subsequent components with even indices are sector faces.
|
|
For edge components (i is odd), component_ring[i].ComponentMark() is the index of
|
|
the center vertex in ON_SubDEge.m_vertex[].
|
|
component_ring_capacity - [in]
|
|
capacity of component_ring[] array
|
|
1 + center_vertex.m_edge_count + center_vertex.m_face_count
|
|
will be large enough.
|
|
Returns:
|
|
Number of components set in component_ring[].
|
|
|
|
0: failure
|
|
|
|
>= 4 and even:
|
|
component_ring[0] = center vertex
|
|
component_ring[1] = starting crease edge
|
|
component_ring[2] = starting face
|
|
... zero or more interior smooth edge, face pairs ...
|
|
component_ring[component_count-1] = ending crease edge
|
|
|
|
>= 5 and odd:
|
|
component_ring[0] = vit.CenterVertex()
|
|
component_ring[1] = first edge (smooth)
|
|
component_ring[2] = first face
|
|
... zero or more smooth edge, face, pairs ...
|
|
component_ring[component_count-2] = last edge (smooth)
|
|
component_ring[component_count-1] = last face
|
|
|
|
Example:
|
|
unsigned int component_ring_count = GetVertexComponentRing(vit,component_ring);
|
|
unsigned int N = component_ring_count/2; // number of edges in ring
|
|
const bool bSectorHasCreaseBoundary = (0 == (component_ring_count % 2));
|
|
*/
|
|
static unsigned int GetSectorComponentRing(
|
|
const class ON_SubDSectorIterator& sit,
|
|
ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_capacity
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
sit - [in]
|
|
vertex sector iterator
|
|
component_ring - [out]
|
|
A sorted listof ON_SubDComponentPtr values are returned in component_ring[]
|
|
|
|
|
|
|
|
Returns:
|
|
Number of components set in component_ring[].
|
|
|
|
0: failure
|
|
|
|
>= 4 and even:
|
|
component_ring[0] = vit.CenterVertex()
|
|
component_ring[1] = starting crease edge
|
|
component_ring[2] = starting face
|
|
... zero or more interior smooth edge, face pairs ...
|
|
component_ring[component_count-1] = ending crease edge
|
|
|
|
>= 5 and odd:
|
|
component_ring[0] = center vertex
|
|
component_ring[1] = first edge (smooth)
|
|
component_ring[2] = first face
|
|
... zero or more smooth edge, face, pairs ...
|
|
component_ring[component_count-2] = last edge (smooth)
|
|
component_ring[component_count-1] = last face
|
|
|
|
Example:
|
|
unsigned int component_ring_count = GetVertexComponentRing(vit,component_ring);
|
|
unsigned int N = component_ring_count/2; // number of edges in ring
|
|
const bool bSectorHasCreaseBoundary = (0 == (component_ring_count % 2));
|
|
*/
|
|
static unsigned int GetSectorComponentRing(
|
|
const class ON_SubDSectorIterator& sit,
|
|
ON_SimpleArray<ON_SubDComponentPtr>& component_ring
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of edges in an component ring returned by ON_SubD::GetVertexComponentRing();
|
|
*/
|
|
static unsigned int ComponentRingEdgeCount(
|
|
size_t component_ring_count
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of faces in an component ring returned by ON_SubD::GetVertexComponentRing();
|
|
*/
|
|
static unsigned int ComponentRingFaceCount(
|
|
size_t component_ring_count
|
|
);
|
|
|
|
static bool ComponentRingIsValid(
|
|
const ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_count
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of points in the subdivision ring or 0 if the call fails.
|
|
*/
|
|
static unsigned int GetSectorSubdivsionPointRing(
|
|
const ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_count,
|
|
double* point_ring,
|
|
size_t point_ring_capacity,
|
|
size_t point_ring_stride
|
|
);
|
|
|
|
static unsigned int GetSectorSubdivisionPointRing(
|
|
const ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_count,
|
|
ON_SimpleArray<ON_3dPoint>& subd_point_ring
|
|
);
|
|
|
|
static unsigned int GetSectorPointRing(
|
|
bool bSubdivideIfNeeded,
|
|
const ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_count,
|
|
double* subd_point_ring,
|
|
size_t subd_point_ring_capacity,
|
|
size_t subd_point_ring_stride
|
|
);
|
|
|
|
static unsigned int GetSectorPointRing(
|
|
bool bSubdivideIfNeeded,
|
|
size_t component_ring_count,
|
|
const ON_SubDComponentPtr* component_ring,
|
|
ON_SimpleArray<ON_3dPoint>& point_ring
|
|
);
|
|
|
|
static unsigned int GetSectorPointRing(
|
|
bool bSubdivideIfNeeded,
|
|
const class ON_SubDSectorIterator& sit,
|
|
double* point_ring,
|
|
size_t point_ring_capacity,
|
|
size_t point_ring_stride
|
|
);
|
|
|
|
static unsigned int GetSectorPointRing(
|
|
bool bSubdivideIfNeeded,
|
|
const class ON_SubDSectorIterator& sit,
|
|
ON_SimpleArray<ON_3dPoint>& point_ring
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
subd_type - [in]
|
|
A quad based subdivision algorithm.
|
|
bFirstPass - [in]
|
|
If bFirstPass is true and the components are in standard form for the vertex
|
|
and subdivision type, then locations of the component vertices opposite the
|
|
center vertex are returned in the point ring.
|
|
bSecondPass - [in]
|
|
If bSecondtPass is true and the first pass is disable or does not succeed,
|
|
then the component subdivision locations are returned in the point ring.
|
|
vertex0 - [in]
|
|
If not null, then vertex0->m_edges and vertex0->m_faces must
|
|
be radially sorted and span a single sector and component_ring[]
|
|
is ignored.
|
|
component_ring_count - [in]
|
|
If vertex0 is null, then component_ring_count specifies the number
|
|
of components in the component_ring[] array.
|
|
component_ring[] - [in]
|
|
If vertex0 is null, then component_ring[0] is the central vertex,
|
|
component_ring[1] and subsequent components with odd indices are
|
|
sector edges, component_ring[2] and subsequent components with even
|
|
indices are sector faces, all sorted radially.
|
|
point_ring_stride - [in]
|
|
point_ring - [out]
|
|
point locations are returned here.
|
|
Returns:
|
|
Number of points in the subdivision ring or 0 if the call fails.
|
|
The number of points is
|
|
1 + ON_SubD::ComponentRingEdgeCount(component_ring_count) + ON_SubD::ComponentRingFaceCount(component_ring_count).
|
|
Remarks:
|
|
No validation checking is performed. This function will crash
|
|
if the input is not valid. Call GetSubdivisionPointRing() if
|
|
you want a crash proof call.
|
|
*/
|
|
static unsigned int GetQuadSectorPointRing(
|
|
bool bFirstPass,
|
|
bool bSecondPass,
|
|
const class ON_SubDVertex* vertex0,
|
|
const class ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_count,
|
|
double* point_ring,
|
|
size_t point_ring_stride
|
|
);
|
|
|
|
static const class ON_SubDVertex* SubdivideSector(
|
|
const class ON_SubDVertex* center_vertex,
|
|
const class ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_count,
|
|
class ON_SubD_FixedSizeHeap& fsh
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
true if sector_edge_count is valid for the vertex type
|
|
*/
|
|
static bool IsValidSectorEdgeCount(
|
|
ON_SubDVertexTag vertex_tag,
|
|
unsigned int sector_edge_count
|
|
);
|
|
|
|
static bool IsValidSectorFaceCount(
|
|
ON_SubDVertexTag vertex_tag,
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubD::SubDFriendlyKnotType] [Rhino.Geometry.SubDFriendlyKnotType] [byte]
|
|
/// <summary>
|
|
/// ON_SubD::SubDFriendlyKnotType identifies the types of subd friendly NURBS knot vectors.
|
|
/// SubD friendly NURBS curves and surfacaes are always cubic and nonrational.
|
|
/// Any time there is a multiple knot, the 2nd derivative is zero at the corresponding parameter.
|
|
/// SubD friendly NURBS curves are either periodic or have zero 2nd derivative at the ends.
|
|
/// </summary>
|
|
enum class SubDFriendlyKnotType : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Not a valid type. Used to indicate the type has not been set and to encourage developers to explicitly specify a type.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// NURBS knot vector is an unclamped uniform cubic knot vector.
|
|
/// Every knot interval has the same length.
|
|
/// Every knot has multiplicity 1.
|
|
///</summary>
|
|
UnclampedUniform = 1,
|
|
|
|
///<summary>
|
|
/// NURBS knot vector is a clamped uniform cubic knot vector.
|
|
/// Every interior knot interval has the same length.
|
|
/// End knots have multiplicity 3 and interior knots have multiplicity 1.
|
|
///</summary>
|
|
ClampedUniform = 2,
|
|
|
|
///<summary>
|
|
/// NURBS knot vector is a clamped piecewise uniform cubic knot vector.
|
|
/// All nonzero knot intervals have the same length.
|
|
/// End knots have multiplicity 3 and interior knots have multiplicity 1 or 3.
|
|
/// Interior knots with multiplicity 3 correspond to interior SubD creases.
|
|
///</summary>
|
|
ClampedPiecewiseUniform = 4,
|
|
|
|
///<summary>
|
|
/// NURBS knot vector is not subd friendly.
|
|
///</summary>
|
|
Unfriendly = 127
|
|
};
|
|
#pragma endregion
|
|
|
|
/*
|
|
Parameters:
|
|
order - [in]
|
|
NURBS knot vector order.
|
|
cv_count - [in]
|
|
Number of NURBS knot vector control points.
|
|
knots - [in]
|
|
NURBS knot vector. This is an array of (cv_count+2) knot values.
|
|
Returns:
|
|
SubD friendly knot vector type.
|
|
Remarks:
|
|
If order is not 4, cv_count is not valid, or knot is nullptr, then
|
|
ON_SubD::SubDFriendlyKnotType::Unfriendly is returned.
|
|
*/
|
|
static ON_SubD::SubDFriendlyKnotType NurbsKnotType(
|
|
int order,
|
|
int cv_count,
|
|
const double* knots
|
|
);
|
|
|
|
static ON_SubD::SubDFriendlyKnotType NurbsKnotType(
|
|
int order,
|
|
int cv_count,
|
|
const double* knots,
|
|
ON_SimpleArray<double>* triple_knots
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
point_count - [in] >= 3
|
|
Number of control points in a regular planar SubD ngon with creased edges.
|
|
control_point_radius - [in]
|
|
Distance from an ngon control point to the ngon center.
|
|
Returns:
|
|
Distance from an ngon surface point to the ngon center.
|
|
See Also:
|
|
ON_SubD::SurfacePointRadiusFromControlPointRadius()
|
|
*/
|
|
static double SurfacePointRadiusFromControlPointRadius(
|
|
unsigned int point_count,
|
|
double control_point_radius
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
point_count - [in] >= 3
|
|
Number of control points in a regular planar SubD ngon with creased edges.
|
|
surface_radius - [in]
|
|
Distance from an ngon surface point to the ngon center.
|
|
Returns:
|
|
Distance from an ngon control point to the ngon center.
|
|
See Also:
|
|
ON_SubD::ControlPointRadiusFromSurfacePointRadius()
|
|
*/
|
|
static double ControlPointRadiusFromSurfacePointRadius(
|
|
unsigned int point_count,
|
|
double surface_point_radius
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ON_SubD() ON_NOEXCEPT;
|
|
virtual ~ON_SubD();
|
|
|
|
|
|
|
|
/*
|
|
Description:
|
|
Creates an independent copy of src.
|
|
*/
|
|
ON_SubD( const ON_SubD& src );
|
|
|
|
/*
|
|
Description:
|
|
Creates an independent copy of src.
|
|
*/
|
|
ON_SubD& operator=(const ON_SubD& src);
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubD( ON_SubD&& ) ON_NOEXCEPT;
|
|
|
|
// The rvalue assignment operator calls ON_Object::operator=(ON_Object&&)
|
|
// which could throw exceptions. See the implementation of
|
|
// ON_Object::operator=(ON_Object&&) for details.
|
|
ON_SubD& operator=( ON_SubD&& );
|
|
#endif
|
|
|
|
/*
|
|
Description:
|
|
The subdivision information referenced by src_subd will be shared with this
|
|
Remarks:
|
|
ON_Geometry base class information, like ON_UserData, is not copied or shared.
|
|
*/
|
|
void ShareContentsFrom(
|
|
ON_SubD& subd
|
|
);
|
|
|
|
static void SwapContents(
|
|
ON_SubD& a,
|
|
ON_SubD& b
|
|
);
|
|
|
|
//virtual
|
|
void MemoryRelocate() override;
|
|
|
|
//virtual
|
|
bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
|
|
|
|
//virtual
|
|
void Dump(
|
|
ON_TextLog&
|
|
) const override;
|
|
|
|
//virtual
|
|
unsigned int SizeOf() const override;
|
|
|
|
/*
|
|
Description:
|
|
This is a debugging too used to study how efficiently SubDs are using memory.
|
|
Returns:
|
|
Total operating system heap (in bytes) used by this SubD's ON_FixedSizePools, inlcude the mesh fragments pool.
|
|
Remarks:
|
|
SizeOfAllElements() = SizeOfActiveElements() + SizeOfUnusedElements().
|
|
*/
|
|
size_t SizeOfAllElements() const;
|
|
|
|
/*
|
|
Description:
|
|
This is a debugging too used to study how efficiently SubDs are using memory.
|
|
Returns:
|
|
Total operating system heap (in bytes) of memory in this SubD's ON_FixedSizePools
|
|
that is currently used by active elements, including active mesh fragments.
|
|
Remarks:
|
|
SizeOfAllElements() = SizeOfActiveElements() + SizeOfUnusedElements().
|
|
*/
|
|
size_t SizeOfActiveElements() const;
|
|
|
|
/*
|
|
Description:
|
|
This is a debugging too used to study how efficiently SubDs are using memory.
|
|
Returns:
|
|
Total operating system heap (in bytes) of memory in this SubD's ON_FixedSizePools
|
|
that is reserved but not currently used, including unused mesh fragments.
|
|
Remarks:
|
|
SizeOfAllElements() = SizeOfActiveElements() + SizeOfUnusedElements().
|
|
*/
|
|
size_t SizeOfUnusedElements() const;
|
|
|
|
/*
|
|
Description:
|
|
Tool for debugging mesh fragments memory use.
|
|
Returns:
|
|
Total operating system heap memory (in bytes) used by the mesh fragments pool.
|
|
Remarks:
|
|
SizeOfAllMeshFragments() = SizeOfActiveMeshFragments() + SizeOfUnusedMeshFragments().
|
|
*/
|
|
size_t SizeOfAllMeshFragments() const;
|
|
|
|
/*
|
|
Description:
|
|
Tool for debugging mesh fragments memory use.
|
|
Returns:
|
|
Operating system heap memory (in bytes) that are used by active mesh fragments.
|
|
Remarks:
|
|
SizeOfAllMeshFragments() = SizeOfActiveMeshFragments() + SizeOfUnusedMeshFragments().
|
|
*/
|
|
size_t SizeOfActiveMeshFragments() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Tool for debugging mesh fragments memory use.
|
|
Returns:
|
|
Operating system heap memory (in bytes) that has been reserved for mesh fragments
|
|
but is not currently used by active mesh fragments.
|
|
Remarks:
|
|
SizeOfAllMeshFragments() = SizeOfActiveMeshFragments() + SizeOfUnusedMeshFragments().
|
|
*/
|
|
size_t SizeOfUnusedMeshFragments() const;
|
|
|
|
//virtual
|
|
ON__UINT32 DataCRC(
|
|
ON__UINT32 current_remainder
|
|
) const override;
|
|
|
|
//virtual
|
|
bool Write(
|
|
ON_BinaryArchive& archive
|
|
) const override;
|
|
|
|
//virtual
|
|
bool Read(
|
|
ON_BinaryArchive& archive
|
|
) override;
|
|
|
|
//virtual
|
|
ON::object_type ObjectType() const override;
|
|
|
|
|
|
//virtual
|
|
unsigned int ClearComponentStates(
|
|
ON_ComponentStatus states_to_clear
|
|
) const override;
|
|
|
|
//virtual
|
|
unsigned int GetComponentsWithSetStates(
|
|
ON_ComponentStatus states_filter,
|
|
bool bAllEqualStates,
|
|
ON_SimpleArray< ON_COMPONENT_INDEX >& components
|
|
) const override;
|
|
|
|
//virtual
|
|
unsigned int SetComponentStates(
|
|
ON_COMPONENT_INDEX component_index,
|
|
ON_ComponentStatus states_to_set
|
|
) const override;
|
|
|
|
//virtual
|
|
unsigned int ClearComponentStates(
|
|
ON_COMPONENT_INDEX component_index,
|
|
ON_ComponentStatus states_to_clear
|
|
) const override;
|
|
|
|
//virtual
|
|
unsigned int SetComponentStatus(
|
|
ON_COMPONENT_INDEX component_index,
|
|
ON_ComponentStatus status_to_copy
|
|
) const override;
|
|
|
|
//virtual
|
|
ON_AggregateComponentStatus AggregateComponentStatus() const override;
|
|
|
|
//virtual
|
|
void MarkAggregateComponentStatusAsNotCurrent() const override;
|
|
|
|
//virtual
|
|
bool DeleteComponents(
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count
|
|
) override;
|
|
|
|
/*
|
|
Remarks:
|
|
For ON_SubD objects, ClearBoundingBox() and DestroyRuntimeCache()
|
|
are identical.
|
|
*/
|
|
//virtual
|
|
void DestroyRuntimeCache(
|
|
bool bDelete = true
|
|
) override;
|
|
|
|
//virtual
|
|
int Dimension() const override;
|
|
|
|
// virtual ON_Geometry GetBBox override
|
|
bool GetBBox( double* boxmin, double* boxmax, bool bGrowBox = false ) const override;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Clears all saved information that depends on vertex locations,
|
|
subdivision algorithms, vertex or edge tags, or control net topology.
|
|
If you modify any of the above, then call ClearBoundingBox().
|
|
Remarks:
|
|
For ON_SubD objects, ClearBoundingBox() and DestroyRuntimeCache()
|
|
are identical.
|
|
*/
|
|
//virtual
|
|
void ClearBoundingBox() override;
|
|
|
|
//virtual
|
|
bool Transform(
|
|
const ON_Xform& xform
|
|
) override;
|
|
|
|
//virtual
|
|
bool IsDeformable() const override;
|
|
|
|
//virtual
|
|
bool MakeDeformable() override;
|
|
|
|
//virtual
|
|
bool SwapCoordinates(
|
|
int i,
|
|
int j
|
|
) override;
|
|
|
|
|
|
//virtual
|
|
bool HasBrepForm() const override;
|
|
|
|
//virtual
|
|
/*
|
|
Returns:
|
|
GetSurfaceBrep( ON_SubDToBrepParameters::Default, nullptr );
|
|
*/
|
|
ON_Brep* BrepForm(
|
|
ON_Brep* brep = nullptr
|
|
) const override;
|
|
|
|
//virtual
|
|
ON_COMPONENT_INDEX ComponentIndex() const override;
|
|
|
|
//virtual
|
|
bool EvaluatePoint(
|
|
const class ON_ObjRef& objref,
|
|
ON_3dPoint& P
|
|
) const override;
|
|
|
|
/*
|
|
Description:
|
|
Uses the input mesh to define the level zero control polygon.
|
|
Parameters:
|
|
level_zero_mesh - [in]
|
|
from_mesh_parameters - [in]
|
|
To get the smoothest possible result, pass nullptr
|
|
or ON_SubDFromMeshParameters::Smooth. To get a sub-D with interior
|
|
creases use other static ON_SubDFromMeshParameters values or
|
|
create one with custom settings.
|
|
*/
|
|
static ON_SubD* CreateFromMesh(
|
|
const class ON_Mesh* level_zero_mesh,
|
|
const class ON_SubDFromMeshParameters* from_mesh_parameters,
|
|
ON_SubD* subd
|
|
);
|
|
|
|
public:
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubD::AutomaticMeshToSubDContext] [Rhino.Geometry.SubDAutomaticMeshToSubDContext] [byte]
|
|
/// <summary>
|
|
/// ON_SubD::AutomaticMeshToSubDContext indentifies a context where meshes can automatically
|
|
/// be converted to subds.
|
|
/// </summary>
|
|
enum class AutomaticMeshToSubDContext : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Indicates the context has not been initialized.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// A mesh in a Rhino 5 3dm file that is a representation of a box mode T-spline.
|
|
/// By default, these meshes are automatically converted to subds.
|
|
///</summary>
|
|
Rhino5BoxModeTSpline = 1,
|
|
|
|
///<summary>
|
|
/// A mesh in an FBX file that has nonzero values for either preview division levels or render division levels.
|
|
/// Some FBX files created by Maya save subdivision objects as meshes with nonzero division level values.
|
|
/// By default, FBX division levels are ignored.
|
|
///</summary>
|
|
FBXMeshWithDivisionLevels = 2
|
|
};
|
|
#pragma endregion
|
|
|
|
/*
|
|
Returns:
|
|
true if SubDs are automatically created when an ON_Mesh is found in the specified context.
|
|
false otherwise.
|
|
*/
|
|
static bool AutomaticMeshToSubD(
|
|
ON_SubD::AutomaticMeshToSubDContext context
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
context - [in]
|
|
Situation where an ON_Mesh can automatically be converted into a subd.
|
|
bAutomaticallyCreateSubD - [in]
|
|
true if SubDs are automatically created when an ON_Mesh is found in the specified context.
|
|
false otherwise.
|
|
*/
|
|
static void SetAutomaticMeshToSubD(
|
|
ON_SubD::AutomaticMeshToSubDContext context,
|
|
bool bAutomaticallyCreateSubD
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
context - [in]
|
|
If context is ON_SubD::AutomaticMeshToSubDContext::Unset, all defaults will be restored.
|
|
Otherwise, the default for the specific context will be restored.
|
|
*/
|
|
static void AutomaticMeshToSubDRestoreDefaults(
|
|
ON_SubD::AutomaticMeshToSubDContext context
|
|
);
|
|
|
|
private:
|
|
static const bool AutomaticRhino5BoxModeTSplineToSubDDefault; // = true
|
|
static const bool AutomaticFBXMeshWithDivisionLevelsToSubDDefault; // = false
|
|
static bool AutomaticRhino5BoxModeTSplineToSubD; // current setting
|
|
static bool AutomaticFBXMeshWithDivisionLevelsToSubD; // current setting
|
|
|
|
private:
|
|
static ON_SubD* Internal_CreateFromMeshWithValidNgons(
|
|
const class ON_Mesh* level_zero_mesh_with_valid_ngons,
|
|
const class ON_SubDFromMeshParameters* from_mesh_parameters,
|
|
ON_SubD* subd
|
|
);
|
|
|
|
public:
|
|
|
|
/*
|
|
Description:
|
|
Creates a SubD box
|
|
Parameters:
|
|
corners - [in]
|
|
Box corners.
|
|
The bottom quad is specified by the first 4 points
|
|
and the top quad specified by the last 4 points.
|
|
edge_tag - [in]
|
|
If edge_tag = ON_SubDEdgeTag::Crease, then the box will have
|
|
creases and corners. Otherwise the box will be smooth.
|
|
facecount_x - [in] Number of faces in x direction
|
|
facecount_y - [in] Number of faces in y direction
|
|
facecount_z - [in] Number of faces in z direction
|
|
destination_subd [out] -
|
|
If destination_subd is not null, make the SubD box there
|
|
Returns:
|
|
Pointer to the resulting SubD if successful
|
|
Null for error
|
|
*/
|
|
static ON_SubD* CreateSubDBox(
|
|
const ON_3dPoint corners[8],
|
|
ON_SubDEdgeTag edge_tag,
|
|
unsigned int facecount_x,
|
|
unsigned int facecount_y,
|
|
unsigned int facecount_z,
|
|
ON_SubD* destination_subd
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Creates a SubD sphere with 24 quad faces
|
|
Parameters:
|
|
sphere - [in]
|
|
Location, size and orientation of the sphere
|
|
destination_subd [out] -
|
|
If destination_subd is not null, make the SubD box there
|
|
Returns:
|
|
Pointer to the resulting SubD if successful
|
|
Null for error
|
|
*/
|
|
//static ON_SubD* CreateSubDSphere(
|
|
// const ON_Sphere sphere,
|
|
// ON_SubD* destination_subd);
|
|
|
|
/*
|
|
Description:
|
|
Creates a SubD cylinder
|
|
Parameters:
|
|
box - [in]
|
|
Location, size and orientation of the cylinder
|
|
facecount_around - [in] Number of faces around the cylinder
|
|
facecount_length - [in] Number of faces in the axis direction
|
|
facecouont_z - [in] Number of faces in z direction
|
|
destination_subd [out] -
|
|
If destination_subd is not null, make the SubD box there
|
|
Returns:
|
|
Pointer to the resulting SubD if successful
|
|
Null for error
|
|
*/
|
|
//static ON_SubD* CreateSubDCylinder(
|
|
// const ON_Cylinder& cylinder,
|
|
// unsigned int facecount_around,
|
|
// unsigned int facecount_length,
|
|
// ON_SubD* destination_subd);
|
|
|
|
/*
|
|
Description:
|
|
Creates a SubD cone
|
|
Parameters:
|
|
cone - [in]
|
|
Location, size and orientation of the cone
|
|
facecount_around - [in] Number of faces around the cone
|
|
facecount_length - [in] Number of faces in the axis direction
|
|
destination_subd [out] -
|
|
If destination_subd is not null, make the SubD cone there
|
|
Returns:
|
|
Pointer to the resulting SubD if successful
|
|
Null for error
|
|
*/
|
|
//static ON_SubD* CreateSubDCone(
|
|
// const ON_Cone& cone,
|
|
// unsigned int facecount_around,
|
|
// unsigned int facecount_length,
|
|
// ON_SubD* destination_subd);
|
|
|
|
/*
|
|
Description:
|
|
Creates a SubD truncated cone
|
|
Parameters:
|
|
cone - [in]
|
|
Location, size and orientation of the cone
|
|
truncate_param - [in] 0.0 < truncate_param <= 1.0
|
|
Normalized parameter for truncation
|
|
0.0: Base of cone
|
|
1.0: Tip of cone
|
|
facecount_around - [in] Number of faces around the cone
|
|
facecount_length - [in] Number of faces in the axis direction
|
|
destination_subd [out] -
|
|
If destination_subd is not null, make the SubD cone there
|
|
Returns:
|
|
Pointer to the resulting SubD if successful
|
|
Null for error
|
|
*/
|
|
//static ON_SubD* CreateSubDTruncatedCone(
|
|
// const ON_Cone& cone,
|
|
// const double truncate_param,
|
|
// unsigned int facecount_around,
|
|
// unsigned int facecount_length,
|
|
// ON_SubD* destination_subd);
|
|
|
|
/*
|
|
Description:
|
|
Creates a SubD torus
|
|
Parameters:
|
|
torus - [in]
|
|
Location, size and orientation of the torus
|
|
major_facecount - [in] Number of faces around the major axis
|
|
minor_facecount - [in] Number of faces around the minor axis
|
|
destination_subd [out] -
|
|
If destination_subd is not null, make the SubD torus there
|
|
Returns:
|
|
Pointer to the resulting SubD if successful
|
|
Null for error
|
|
*/
|
|
//static ON_SubD* CreaptSubDTorus(
|
|
// ON_Torus& torus,
|
|
// unsigned int major_facecount,
|
|
// unsigned int minor_facecount,
|
|
// ON_SubD* destination_subd);
|
|
|
|
unsigned int DumpTopology(
|
|
ON_TextLog&
|
|
) const;
|
|
|
|
unsigned int DumpTopology(
|
|
ON_2udex vertex_id_range,
|
|
ON_2udex edge_id_range,
|
|
ON_2udex face_id_range,
|
|
ON_TextLog&
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Discard all contents of this ON_SubD.
|
|
Remarks:
|
|
More efficient than Destroy() if this ON_SubD will be reused soon.
|
|
*/
|
|
void Clear();
|
|
|
|
/*
|
|
Description:
|
|
Delete all contents release all memory used by this ON_SubD.
|
|
*/
|
|
void Destroy();
|
|
|
|
/*
|
|
Returns:
|
|
The number of explicitly computed levels that are currently available.
|
|
A value of 0 indicates this SubD is empty.
|
|
*/
|
|
unsigned int LevelCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
If the SubD is not empty, then the index of the active level is returned. This value will be < LevelCount().
|
|
If the SubD is empty, then ON_UNSET_UINT_INDEX is returned.
|
|
*/
|
|
unsigned int ActiveLevelIndex() const;
|
|
|
|
/*
|
|
Description:
|
|
Remove subdivision levels
|
|
Paramters:
|
|
max_level_index - [in]
|
|
Remove all levels after max_level_index
|
|
Returns:
|
|
Number of removed levels.
|
|
*/
|
|
unsigned int ClearHigherSubdivisionLevels(
|
|
unsigned int max_level_index
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Remove subdivision levels
|
|
Paramters:
|
|
min_level_index - [in]
|
|
Remove all levels before min_level_index
|
|
Returns:
|
|
Number of removed levels.
|
|
*/
|
|
unsigned int ClearLowerSubdivisionLevels(
|
|
unsigned int min_level_index
|
|
);
|
|
|
|
/*
|
|
Remove all levels except the active level.
|
|
Returns:
|
|
Number of removed levels.
|
|
*/
|
|
unsigned ClearInactiveLevels();
|
|
|
|
bool IsEmpty() const;
|
|
bool IsNotEmpty() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get aggregate edge demographics for the subd.
|
|
Returns:
|
|
Bitwise or of ON_ComponentAttributes::EdgeAttributes values for every edge in the subd.
|
|
*/
|
|
unsigned int AggregateEdgeAttributes() const;
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Component (Vertex, Edge, Face) access
|
|
//
|
|
const ON_SubDComponentPtr ComponentPtrFromComponentIndex(
|
|
ON_COMPONENT_INDEX component_index
|
|
) const;
|
|
|
|
unsigned int ComponentPtrFromComponentIndex(
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count,
|
|
ON_SimpleArray<ON_SubDComponentPtr>& cptr_list
|
|
) const;
|
|
|
|
unsigned int ComponentPtrFromComponentIndex(
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count,
|
|
bool bIncludeVertices,
|
|
bool bIncludeEdges,
|
|
bool bIncludeFaces,
|
|
ON_SimpleArray<ON_SubDComponentPtr>& cptr_list
|
|
) const;
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Membership query
|
|
//
|
|
bool InSubD(const class ON_SubDVertex* vertex) const;
|
|
bool InSubD(const class ON_SubDEdge* edge) const;
|
|
bool InSubD(const class ON_SubDFace* face) const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
ON_SubDComponentPtr::Type::Unset if b is not in this SubD.
|
|
Otherwise the type of the component is returned.
|
|
*/
|
|
bool InSubD(ON_SubDComponentPtr cptr) const;
|
|
|
|
/*
|
|
Returns:
|
|
If b is in this SubD, a ON_SubDComponentPtr to b is returned.
|
|
Otherwise ON_SubDComponentPtr::Null is returned.
|
|
Remarks:
|
|
This function is the slowest of the InSubD() overrides.
|
|
When b is an unknown component type, this function can be used to
|
|
safely determine what type of component (vertex/edge/face).
|
|
*/
|
|
const ON_SubDComponentPtr InSubD(const class ON_SubDComponentBase* b) const;
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Vertex access
|
|
//
|
|
|
|
/*
|
|
Returns:
|
|
Number of vertices in the active level.
|
|
*/
|
|
unsigned int VertexCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
hash_type - [in]
|
|
All hashes include vertex id.
|
|
Geometry hashes include vertex tag, vertex control point, and vertex displacement.
|
|
Returns:
|
|
A SHA1 hash of the SubD's vertices.
|
|
*/
|
|
const ON_SHA1_Hash VertexHash( ON_SubDHashType hash_type ) const;
|
|
|
|
const class ON_SubDVertex* FirstVertex() const;
|
|
const class ON_SubDVertex* LastVertex() const;
|
|
|
|
/*
|
|
Example:
|
|
ON_SubDVertexIterator vit = subd.VertexIterator();
|
|
for ( const ON_SubDVertex* v = vit.FirstVertex(); nullptr != v; v = vit.NextVertex())
|
|
{
|
|
...
|
|
}
|
|
*/
|
|
class ON_SubDVertexIterator VertexIterator() const;
|
|
|
|
/*
|
|
Description:
|
|
Avoid using this class. It is more efficient to use
|
|
an ON_SubDVertexIterator returned by VertexIterator().
|
|
*/
|
|
class ON_SubDVertexArray VertexArray() const;
|
|
|
|
/*
|
|
Parameters:
|
|
vertex_id - [in]
|
|
Returns:
|
|
If vertex_id identifies a valid vertex in this ON_SubD, then
|
|
a pointer to that vertex is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const class ON_SubDVertex* VertexFromId(
|
|
unsigned int vertex_id
|
|
) const;
|
|
|
|
const class ON_SubDVertex* VertexFromComponentIndex(
|
|
ON_COMPONENT_INDEX component_index
|
|
) const;
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Edge access
|
|
//
|
|
|
|
/*
|
|
Returns:
|
|
Number of edges in the active level.
|
|
*/
|
|
unsigned int EdgeCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
hash_type - [in]
|
|
All hashes include edge id, edge vertex ids in order, the edge crease/smooth attribute.
|
|
Geometry hashes include edge displacements.
|
|
Returns:
|
|
A SHA1 hash of the SubD's edges.
|
|
*/
|
|
const ON_SHA1_Hash EdgeHash(ON_SubDHashType hash_type) const;
|
|
|
|
const class ON_SubDEdge* FirstEdge() const;
|
|
const class ON_SubDEdge* LastEdge() const;
|
|
|
|
/*
|
|
Example:
|
|
ON_SubDEdgeIterator eit = subd.EdgeIterator();
|
|
for ( const ON_SubDEdge* e = eit.FirstEdge(); nullptr != e; e = eit.NextEdge())
|
|
{
|
|
...
|
|
}
|
|
*/
|
|
class ON_SubDEdgeIterator EdgeIterator() const;
|
|
|
|
/*
|
|
Description:
|
|
Avoid using this class. It is more efficient to use
|
|
an ON_SubDEdgeIterator returned by EdgeIterator().
|
|
*/
|
|
class ON_SubDEdgeArray EdgeArray() const;
|
|
|
|
/*
|
|
Parameters:
|
|
edge_id - [in]
|
|
Returns:
|
|
If edge_id identifies a valid edge in this ON_SubD, then
|
|
a pointer to that edge is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const class ON_SubDEdge* EdgeFromId(
|
|
unsigned int edge_id
|
|
) const;
|
|
|
|
const class ON_SubDEdge* EdgeFromComponentIndex(
|
|
ON_COMPONENT_INDEX component_index
|
|
) const;
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Face access
|
|
//
|
|
|
|
/*
|
|
Returns:
|
|
Number of faces in the active level.
|
|
*/
|
|
unsigned int FaceCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
hash_type - [in]
|
|
Returns:
|
|
A SHA1 hash of the SubD's faces.
|
|
*/
|
|
const ON_SHA1_Hash FaceHash(ON_SubDHashType hash_type) const;
|
|
|
|
const class ON_SubDFace* FirstFace() const;
|
|
const class ON_SubDFace* LastFace() const;
|
|
|
|
/*
|
|
Example:
|
|
ON_SubDFaceIterator fit = subd.FaceIterator();
|
|
for ( const ON_SubDFace* f = fit.FirstFace(); nullptr != f; f = fit.NextFace())
|
|
{
|
|
...
|
|
}
|
|
*/
|
|
class ON_SubDFaceIterator FaceIterator() const;
|
|
|
|
/*
|
|
Description:
|
|
Avoid using this class. It is more efficient to use
|
|
an ON_SubDFaceIterator returned by FaceIterator().
|
|
*/
|
|
class ON_SubDFaceArray FaceArray() const;
|
|
|
|
/*
|
|
Parameters:
|
|
face_id - [in]
|
|
Returns:
|
|
If face_id identifies a valid face in this ON_SubD, then
|
|
a pointer to that face is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const class ON_SubDFace* FaceFromId(
|
|
unsigned int face_id
|
|
) const;
|
|
|
|
|
|
const class ON_SubDFace* FaceFromComponentIndex(
|
|
ON_COMPONENT_INDEX component_index
|
|
) const;
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Component (vertex, edge, face) state ( selected, highlighted, ... ) tools
|
|
// NOTE:
|
|
// All component status settings are mutable
|
|
// All are copied.
|
|
// None are saved.
|
|
//
|
|
|
|
/*
|
|
Parameters:
|
|
states_filter - [in]
|
|
bAllEqualStates - [in]
|
|
If a state is set in states_filter, all active level components
|
|
with the same state set will be included in the
|
|
components_with_set_states[] array.
|
|
If bAllEqualStates is true, then ON_ComponentStatus::AllEqualStates()
|
|
is used to test for inclusion.
|
|
If bAllEqualStates is false, then ON_ComponentStatus::SomeEqualStates()
|
|
is used to test for inclusion.
|
|
components_with_set_states - [out]
|
|
Returns:
|
|
Number of returned components.
|
|
*/
|
|
unsigned int GetComponentsWithSetStates(
|
|
ON_ComponentStatus states_filter,
|
|
bool bAllEqualStates,
|
|
ON_SimpleArray< ON_SubDComponentPtr >& components_with_set_states
|
|
) const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Set states on an individual component.
|
|
Parameters:
|
|
component_ptr - [in]
|
|
The states will be set on this component.
|
|
states_to_set - [in]
|
|
If a state is set in the states_to_set parameter, the same
|
|
state will be set on the component.
|
|
Returns:
|
|
0: no state settings changed on the component.
|
|
1: some state setting changed on the component.
|
|
*/
|
|
unsigned int SetComponentStates(
|
|
ON_SubDComponentPtr component_ptr,
|
|
ON_ComponentStatus states_to_set
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Clear states on an individual component.
|
|
Parameters:
|
|
component_ptr - [in]
|
|
The states will be cleared on this component.
|
|
states_to_clear - [in]
|
|
If a state is set in the states_to_clear parameter, the same
|
|
state will be cleared on the component.
|
|
Returns:
|
|
0: no state settings changed on the component.
|
|
1: some state setting changed on the component.
|
|
*/
|
|
unsigned int ClearComponentStates(
|
|
ON_SubDComponentPtr component_ptr,
|
|
ON_ComponentStatus states_to_clear
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Copy status settings to an individual component.
|
|
Parameters:
|
|
component_ptr - [in]
|
|
The states will be copied to this component.
|
|
status_to_copy - [in]
|
|
Returns:
|
|
1: some state settings changed on the component.
|
|
1: some state setting changed on the component.
|
|
*/
|
|
unsigned int SetComponentStatus(
|
|
ON_SubDComponentPtr component_ptr,
|
|
ON_ComponentStatus status_to_copy
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Delete components in cptr_list[].
|
|
If a vertex is in cptr_list[], the vertex and every edge and face attached
|
|
to the vertex are deleted.
|
|
If an edge is in cptr_list[], the edge and every face attached
|
|
to the edge are deleted.
|
|
If a face is in cptr_list[], the face is deleted.
|
|
Parameters:
|
|
cptr_list - [in]
|
|
cptr_count - [in]
|
|
length of cptr_list[] array.
|
|
bMarkDeletedFaceEdges - [in]
|
|
If true, surviving edges attached to delete faces
|
|
have their runtmime mark set.
|
|
Returns:
|
|
1: some state settings changed on the component.
|
|
1: some state setting changed on the component.
|
|
*/
|
|
bool DeleteComponents(
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count,
|
|
bool bMarkDeletedFaceEdges
|
|
);
|
|
|
|
bool DeleteComponents(
|
|
const ON_SimpleArray<ON_SubDComponentPtr>& cptr_list,
|
|
bool bMarkDeletedFaceEdges
|
|
);
|
|
|
|
bool DeleteComponentsForExperts(
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count,
|
|
bool bDeleteIsolatedEdges,
|
|
bool bUpdateTagsAndCoefficients,
|
|
bool bMarkDeletedFaceEdges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Delete marked components.
|
|
Parameters:
|
|
bDeleteMarkedComponents - [in]
|
|
If true, marked components are deleted.
|
|
If false, unmarked components are deleted.
|
|
mark_bits - [in]
|
|
A component is marked if component.m_status.IsMarked(mark_bits) is true.
|
|
*/
|
|
bool DeleteMarkedComponents(
|
|
bool bDeleteMarkedComponents,
|
|
ON__UINT8 mark_bits,
|
|
bool bMarkDeletedFaceEdges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Delete marked components.
|
|
Parameters:
|
|
bDeleteMarkedComponents - [in]
|
|
If true, marked components are deleted.
|
|
If false, unmarked components are deleted.
|
|
mark_bits - [in]
|
|
A component is marked if component.m_status.IsMarked(mark_bits) is true.
|
|
*/
|
|
bool DeleteMarkedComponentsForExperts(
|
|
bool bDeleteMarkedComponents,
|
|
ON__UINT8 mark_bits,
|
|
bool bDeleteIsolatedEdges,
|
|
bool bUpdateTagsAndCoefficients,
|
|
bool bMarkDeletedFaceEdges
|
|
);
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Removes all per face material channel index overrides on the active level.
|
|
Returns:
|
|
Number of changed faces.
|
|
Remarks:
|
|
Per face material channel indices are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetMaterialChannelIndex().
|
|
*/
|
|
unsigned int ClearPerFaceMaterialChannelIndices();
|
|
|
|
/*
|
|
Returns:
|
|
True if one or more faces on the active level have per face material channel index overrides.
|
|
Remarks:
|
|
Per face material channel indices are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetMaterialChannelIndex().
|
|
*/
|
|
bool HasPerFaceMaterialChannelIndices() const;
|
|
|
|
/*
|
|
Description:
|
|
Removes all per face color overrides on the active level.
|
|
Returns:
|
|
Number of changed faces.
|
|
Remarks:
|
|
Per face colors are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetPerFaceColor().
|
|
*/
|
|
unsigned int ClearPerFaceColors() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if one or more faces on the active level have per face color overrides.
|
|
Remarks:
|
|
Per face colors are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetPerFaceColor().
|
|
*/
|
|
bool HasPerFaceColors() const;
|
|
|
|
/*
|
|
Description:
|
|
If a face has a nonzero PackId(), then its per face color is set to ON_Color::RandomColor(f->PackId()).
|
|
Otherwise, its per face color is cleared.
|
|
*/
|
|
void SetPerFaceColorsFromPackId() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if per face colors were set by SetPerFaceColorsFromPackId().
|
|
*/
|
|
bool HasPerFaceColorsFromPackId() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
If a SubD is symmetric and a face belongs to a symmetry set, then per face color is
|
|
set according to the motif the face belongs to.
|
|
Otherwise, its per face color is cleared.
|
|
*/
|
|
void SetPerFaceColorsFromSymmetryMotif() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if per face colors were set by SetPerFaceColorsFromSymmetryMotif().
|
|
*/
|
|
bool HasPerFaceColorsFromSymmetryMotif() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets ON_SubDComponent MarkBits() to
|
|
0: component is not in a symmetry set motif
|
|
n>=1:
|
|
The component is the the n-th element in the symmetry set
|
|
with n=1 indicating the component in the primary motif.
|
|
*/
|
|
void SetComponentMarkBitsFromSymmetryMotif() const;
|
|
|
|
|
|
///*
|
|
//Description:
|
|
// The ON__INT_PTRs in the tree are const ON_SubDMeshFragment* pointers.
|
|
// The bounding boxes are from the surface points.
|
|
//*/
|
|
//ON_RTreeRef FragmentTree() const;
|
|
|
|
///*
|
|
//Description:
|
|
// If the tree is not needed and memory resources are tight, then call ClearTree()
|
|
// to remove the RTree.
|
|
//*/
|
|
//void ClearFragmentTree();
|
|
|
|
///*
|
|
//Description:
|
|
// The ON__INT_PTRs in the tree are const ON_SubDComponentPtrs.
|
|
// The bounding boxs are based on the subd
|
|
//*/
|
|
//ON_RTreeRef ControlNetComponentTree(
|
|
// bool bIncludeVertices,
|
|
// bool bIncludeEdges,
|
|
// bool bIncludeFaces
|
|
// ) const;
|
|
|
|
///*
|
|
//Description:
|
|
// If the tree is not needed and memory resources are tight, then call ClearTree()
|
|
// to remove the RTree.
|
|
//*/
|
|
//void ClearControlNetComponentTree();
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Topology Queries
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
Determine solid orientation of the active level.
|
|
Returns:
|
|
+2 subd is a solid but orientation cannot be computed
|
|
+1 subd is a solid with outward facing normals
|
|
-1 subd is a solid with inward facing normals
|
|
0 subd is not a solid
|
|
See Also:
|
|
ON_SubD::IsSolid
|
|
*/
|
|
int SolidOrientation() const;
|
|
|
|
/*
|
|
Description:
|
|
Test subd to see if the active level is a solid.
|
|
A "solid" is a closed oriented manifold.
|
|
Returns:
|
|
true subd is a solid
|
|
fals subd is not a solid
|
|
See Also:
|
|
ON_SubDp::SolidOrientation
|
|
ON_SubDp::IsManifold
|
|
*/
|
|
bool IsSolid() const;
|
|
|
|
/*
|
|
Description:
|
|
Test subd to see if the active level is an oriented manifold.
|
|
Parameters:
|
|
bIsOriented - [out]
|
|
True if every edge that has two faces is oriented.
|
|
Note that non-manifold edges are ignored.
|
|
bHasBoundary - [in]
|
|
True if there is at least one edge with a single face.
|
|
Returns:
|
|
True if the subd is a manifold (has at lease one face and every edge has 1 or 2 faces).
|
|
False if the subd is not a manifold (has no faces or at least one edge with 0 or 3 or more faces)
|
|
See Also:
|
|
ON_SubDp::IsSolid
|
|
*/
|
|
bool IsManifold(
|
|
bool& bIsOriented,
|
|
bool& bHasBoundary
|
|
) const;
|
|
|
|
bool IsManifold() const;
|
|
|
|
|
|
|
|
/*
|
|
Description:
|
|
Automatically get a boundary from a seed edge.
|
|
Parameters:
|
|
first_edge - [in]
|
|
An edge with FaceCount() <= 1.
|
|
The search for the second edge occurs and first_edge.RelativeVertex(1)
|
|
and all edges added to boundary_edge_chain[] have FaceCount() = first_edge.Edge()->FaceCount().
|
|
bUseEdgeMarks -[in]
|
|
If true, only unmarked edges will be added to boundary_edge_chain[]
|
|
and they will be marked when added to boundary_edge_chain[].
|
|
boundary_edge_chain - [out]
|
|
Edge chain beginning with first_edge.
|
|
When true is returned, boundary_edge_chain[] has 3 or more edges and is a closed loop.
|
|
When false is returned, boundary_edge_chain[] will contain an open chain with 0 or more edges.
|
|
Returns:
|
|
true if boundary_edge_chain[] is a closed loop of 3 or more boundary edges.
|
|
*/
|
|
static bool GetBoundaryEdgeChain(
|
|
ON_SubDEdgePtr first_edge,
|
|
bool bUseEdgeMarks,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& boundary_edge_chain
|
|
);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Editing tools
|
|
//
|
|
|
|
unsigned int MergeColinearEdges(
|
|
bool bMergeBoundaryEdges,
|
|
bool bMergeInteriorCreaseEdges,
|
|
bool bMergeInteriorSmoothEdges,
|
|
double distance_tolerance,
|
|
double maximum_aspect,
|
|
double sin_angle_tolerance
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Merge consecutive edges into a single edge.
|
|
eptr0 - [in]
|
|
first edge (will not be deleted)
|
|
eptr1 - [in]
|
|
second edge (will be deleted if edges can be merged)
|
|
Returns:
|
|
Merged edge (eptr0) or ON_SubDEdgePtr::Null if edges could not be merged
|
|
*/
|
|
ON_SubDEdgePtr MergeConsecutiveEdges(
|
|
ON_SubDEdgePtr eptr0,
|
|
ON_SubDEdgePtr eptr1
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
True if eptr0.RelativeVetex(1) == eptr1.RelativeVetex(0) and both edges
|
|
have the same set of faces.
|
|
*/
|
|
static bool EdgesAreConsecutive(
|
|
ON_SubDEdgePtr eptr0,
|
|
ON_SubDEdgePtr eptr1
|
|
);
|
|
|
|
// returns true if all facets are consistently oriented
|
|
bool IsOriented() const;
|
|
|
|
// reverses the orientation of all facets
|
|
bool ReverseOrientation() const;
|
|
|
|
// Attempts to orient all facet to match the first facet.
|
|
bool Orient() const;
|
|
|
|
/*
|
|
Description:
|
|
Divide an edge into two contiguous edges.
|
|
The input edge is modifed to terminate at the new vertex.
|
|
The new edge begins at the new vertex and ends at the orginal edge's m_vertex[1].
|
|
edge - [in]
|
|
edge to split.
|
|
vertex_location - [in]
|
|
location of the new vertex vertex.
|
|
If vertex_location == ON_ON_3dPoint::UnsetPoint,
|
|
then the edge's midpoint is used.
|
|
Returns:
|
|
A pointer to the new edge or nullptr if the input is not valid.
|
|
Remarks:
|
|
After all editing operations are completed, you must call this->UpdateEdgeSectorCoefficients(true) before
|
|
evaluation.
|
|
*/
|
|
const class ON_SubDEdge* SplitEdge(
|
|
class ON_SubDEdge* edge,
|
|
ON_3dPoint vertex_location
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Divide an edge into two contiguous edges.
|
|
edge - [in]
|
|
edge to split.
|
|
vertex_location - [in]
|
|
location of the new vertex vertex.
|
|
If vertex_location == ON_ON_3dPoint::UnsetPoint,
|
|
then the edge's midpoint is used.
|
|
new_edge_end - [in]
|
|
This paratmer is 0 or 1 and dtermines where the new edge is inserted.
|
|
Below v0 = input eptr.RelativeVertex(0), v1 = new vertex, v2 = input eptr.RelativeVertex(1),
|
|
and new_eptr = returned edge pointer.
|
|
If edge_end is 0, new_eptr is first: v0 = new_eptr.RelativeVertex(0), v1 = new_eptr.RelativeVertex(1)=eptr.RelativeVertex(0), v2 = eptr.RelativeVertex(1).
|
|
If edge_end is 1, new_eptr is last: v0 = eptr.RelativeVertex(0), v1 = eptr.RelativeVertex(1)=new_eptr.RelativeVertex(0), v2 = new_eptr.RelativeVertex(1).
|
|
Returns:
|
|
A pointer to the new edge or ON_SubDEdgePtr::Null if the input is not valid.
|
|
Remarks:
|
|
After all editing operations are completed, you must clear the evaluation cache
|
|
and call this->UpdateEdgeSectorCoefficients(true).
|
|
*/
|
|
const ON_SubDEdgePtr SplitEdge(
|
|
ON_SubDEdgePtr eptr,
|
|
ON_3dPoint vertex_location,
|
|
unsigned new_edge_end
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Divide a face into two faces by inserting an edge connecting the specified vertices.
|
|
Parameters:
|
|
face - [in]
|
|
A face with at least four edges.
|
|
fvi0 - [in]
|
|
fvi1 - [in]
|
|
Face vertex indices of the inserted edge's ends.
|
|
Returns:
|
|
A pointer to the inserted edge.
|
|
The inserted edge runs from face->Vertex(fvi0) to face->Vertex(fvi1).
|
|
ON_SubDEdge.Face(0) is the original face and ON_SubDEdge::Face(1) is
|
|
the added face.
|
|
The first edge of both faces is the inserted edge.
|
|
*/
|
|
const class ON_SubDEdge* SplitFace(
|
|
class ON_SubDFace* face,
|
|
unsigned int fvi0,
|
|
unsigned int fvi1
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Divide a face into two faces by inserting an edge connecting the specified vertices.
|
|
Parameters:
|
|
face - [in]
|
|
A face with at least four edges.
|
|
v0 - [in]
|
|
v1 - [in]
|
|
Face vertices of the inserted edge's ends.
|
|
Returns:
|
|
A pointer to the inserted edge.
|
|
The inserted edge runs from v0 to v1.
|
|
ON_SubDEdge.Face(0) is the original face and ON_SubDEdge::Face(1) is
|
|
the added face.
|
|
The first edge of the input face remains the first edge of face.
|
|
The inserted edge is the first edge of the added face.
|
|
*/
|
|
const class ON_SubDEdge* SplitFace(
|
|
class ON_SubDFace* face,
|
|
const class ON_SubDVertex* v0,
|
|
const class ON_SubDVertex* v1
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Divide a face into two faces by inserting an edge connecting the specified vertices.
|
|
Parameters:
|
|
face - [in]
|
|
A face with at least four edges.
|
|
fvi0 - [in]
|
|
fvi1 - [in]
|
|
Face vertex indices of the inserted edge's ends.
|
|
new_face_side - [in]
|
|
0: The new face will be on the left side of the inserted edge.
|
|
0: The new face will be on the right side of the inserted edge.
|
|
Returns:
|
|
The edge and edgeptr are both being af both oriented
|
|
The inserted edge and returned edge ptr runs from face->Vertex(fvi0) to face->Vertex(fvi1).
|
|
the new face is SplitFace(...).RelativeFace(new_face_side) and the original face is SplitFace(...).RelativeFace(new_face_side).
|
|
*/
|
|
const ON_SubDEdgePtr SplitFace(
|
|
class ON_SubDFace* face,
|
|
unsigned int fvi0,
|
|
unsigned int fvi1,
|
|
unsigned new_face_side
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Divide a face into two faces by inserting an edge connecting the specified vertices.
|
|
Parameters:
|
|
face - [in]
|
|
A face with at least four edges.
|
|
v0 - [in]
|
|
v1 - [in]
|
|
Face vertices of the inserted edge's ends.
|
|
new_face_side - [in]
|
|
0: The new face will be on the left side of the inserted edge.
|
|
0: The new face will be on the right side of the inserted edge.
|
|
Returns:
|
|
The edge and edgeptr are both being af both oriented
|
|
The inserted edge and returned edge ptr runs from face->Vertex(fvi0) to face->Vertex(fvi1).
|
|
the new face is SplitFace(...).RelativeFace(new_face_side) and the original face is SplitFace(...).RelativeFace(new_face_side).
|
|
*/
|
|
const ON_SubDEdgePtr SplitFace(
|
|
class ON_SubDFace* face,
|
|
const class ON_SubDVertex* v0,
|
|
const class ON_SubDVertex* v1,
|
|
unsigned new_face_side
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Replace a face with a triangle fan by adding a single new vertex at fan_center_point
|
|
and adding tringle made from the face's edes to the center point.
|
|
Parameters:
|
|
face - [in]
|
|
This face is replaced with a triangle fan and becomes the first triangle in the fan.
|
|
fan_center_point - [in]
|
|
If valid, this point is used as the fan's center.
|
|
Otherwise the centriod of the face's vertices is used s the fan's center.
|
|
When in doubt, pass ON_3dPoint::UnsetPoint.
|
|
bMarkFaces - [in]
|
|
If true, face and new triangles are marked.
|
|
Existing marks are not modified.
|
|
Returns:
|
|
If successfull, the new vertex at the center of the triangle fan.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const class ON_SubDVertex* ReplaceFaceWithTriangleFan(
|
|
class ON_SubDFace* face,
|
|
ON_3dPoint fan_center_point,
|
|
bool bMarkFaces
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Description:
|
|
When finished editing a SubD, call this function to delete all cached evaluation
|
|
values and update all vertex tag, edge tags, edge sector coefficients.
|
|
Remarks:
|
|
This function is the most reliable (and heavy handed) way to update SubD component
|
|
information. Expert users can choose to be more selective when certain about
|
|
exactly what needs to be modified.
|
|
*/
|
|
void SubDModifiedNofification();
|
|
|
|
|
|
/*
|
|
Description:
|
|
Updates vertex tag, edge tag, and edge coefficient values
|
|
on the active level.
|
|
|
|
After completing custom editing operations that modify the
|
|
topology of the SubD control net or changing values of
|
|
vertex or edge tags, the tag and sector coefficients
|
|
information on nearby components in the edited areas
|
|
need to be updated.
|
|
|
|
Parameters:
|
|
bUnsetValuesOnly - [in]
|
|
If true, the update is restricted to vertices tagged as
|
|
ON_SubDVertexTag::Unset and edges tagged as ON_SubDEdgeTag::Unset.
|
|
|
|
Returns:
|
|
Number of vertices and edges that were changed during the update.
|
|
*/
|
|
unsigned int UpdateAllTagsAndSectorCoefficients(
|
|
bool bUnsetValuesOnly
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This tool if for expert users writing advanced editing tools.
|
|
After completing custom editing operations that modify the
|
|
topology of the SubD control net or changing values of
|
|
vertex or edge tags, the tag and sector coefficients
|
|
information on nearby components in the edited areas
|
|
need to be updated.
|
|
Parameters:
|
|
bUnsetTagsOnly - [in]
|
|
If bUnsetTagsOnly is true, then only unset tags and
|
|
ill be updated.
|
|
If bUnsetTagsOnly is false, then all tags and
|
|
will be checked and updated as needed.
|
|
Returns:
|
|
Number of vertices that changed during the update.
|
|
Remarks:
|
|
It is easiest to call UpdateAllTagsAndSectorCoefficients().
|
|
*/
|
|
unsigned int UpdateVertexTags(
|
|
bool bUnsetVertexTagsOnly
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This tool if for expert users writing advanced editing tools.
|
|
After completing custom editing operations that modify the
|
|
topology of the SubD control net or changing values of
|
|
vertex or edge tags, the tag and sector coefficients
|
|
information on nearby components in the edited areas
|
|
need to be updated.
|
|
Parameters:
|
|
bUnsetValuesOnly - [in]
|
|
If bUnsetValuesOnly is true, then only unset tags and
|
|
sector weights will be updated.
|
|
If bUnsetValuesOnly is false, then all tags and
|
|
sector weights will be checked and updated as needed.
|
|
Returns:
|
|
Number of edges that had a tag value changed or sector
|
|
coefficient set to ON_SubDSectorType::UnsetSectorCoefficient.
|
|
Remarks:
|
|
It is easiest to call UpdateAllTagsAndSectorCoefficients().
|
|
*/
|
|
unsigned int UpdateEdgeTags(
|
|
bool bUnsetEdgeTagsOnly
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This tool if for expert users writing advanced editing tools.
|
|
After completing custom editing operations that modify the
|
|
topology of the SubD control net or changing values of
|
|
vertex or edge tags, the tag and sector coefficients
|
|
information on nearby components in the edited areas
|
|
need to be updated.
|
|
Parameters:
|
|
bUnsetValuesOnly - [in]
|
|
If bUnsetValuesOnly is true, then only unset tags and
|
|
sector weights will be updated.
|
|
If bUnsetValuesOnly is false, then all tags and
|
|
sector weights will be checked and updated as needed.
|
|
Returns:
|
|
Number of edges that had a tag value changed or sector
|
|
coefficient set to ON_SubDSectorType::UnsetSectorCoefficient.
|
|
Remarks:
|
|
It is easiest to call UpdateAllTagsAndSectorCoefficients().
|
|
*/
|
|
unsigned int UpdateEdgeSectorCoefficients(
|
|
bool bUnsetSectorCoefficientsOnly
|
|
) const;
|
|
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_group_id value to 0 for every vertex, edge and face.
|
|
Returns:
|
|
Number of marks that were cleared.
|
|
*/
|
|
unsigned int ClearGroupIds() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_group_id value to 0 for every vertex.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearVertexGroupIds() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_group_id value to 0 for every edge.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearEdgeGroupIds() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_group_id value to 0 for every face.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearFaceGroupIds() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_group_id value to 0 for the specified components.
|
|
Parameters:
|
|
bClearVertexGroupIds - [in]
|
|
If true, m_group_id for every vertex is set to zero.
|
|
bClearEdgeGroupIds - [in]
|
|
If true, m_group_id for every edge is set to zero.
|
|
bClearFaceGroupIds - [in]
|
|
If true, m_group_id for every face is set to zero.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearComponentGroupIds(
|
|
bool bClearVertexGroupIds,
|
|
bool bClearEdgeGroupIds,
|
|
bool bClearFaceGroupIds
|
|
) const;
|
|
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_status.MarkBits() value to 0 for every vertex, edge and face.
|
|
Returns:
|
|
Number of marks that were cleared.
|
|
*/
|
|
unsigned int ClearMarkBits() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_status.MarkBits() value to 0 for every vertex.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearVertexMarkBits() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_status.MarkBits() value to 0 for every edge.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearEdgeMarkBits() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_status.MarkBits() value to 0 for every face.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearFaceMarkBits() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Sets the m_status.MarkBits() value to 0 for the specified components.
|
|
Parameters:
|
|
bClearVertexMarkBits - [in]
|
|
If true, m_status.MarkBits() for every vertex is set to zero.
|
|
bClearEdgeMarkBits - [in]
|
|
If true, m_status.MarkBits() for every edge is set to zero.
|
|
bClearFaceMarkBits - [in]
|
|
If true, m_status.MarkBits() for every face is set to zero.
|
|
Returns:
|
|
Number of group id values that were changed.
|
|
*/
|
|
unsigned int ClearComponentMarkBits(
|
|
bool bClearVertexMarkBits,
|
|
bool bClearEdgeMarkBits,
|
|
bool bClearFaceMarkBits
|
|
) const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Clears the m_status.RuntimeMark() for every vertex, edge and face.
|
|
Returns:
|
|
Number of marks that were cleared.
|
|
*/
|
|
unsigned int ClearComponentMarks() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Clears the m_status.RuntimeMark() for every vertex.
|
|
Returns:
|
|
Number of marks that were cleared.
|
|
*/
|
|
unsigned int ClearVertexMarks() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Clears the m_status.RuntimeMark() for every edge.
|
|
Returns:
|
|
Number of marks that were cleared.
|
|
*/
|
|
unsigned int ClearEdgeMarks() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Clears the m_status.RuntimeMark() for every face.
|
|
Returns:
|
|
Number of marks that were cleared.
|
|
*/
|
|
unsigned int ClearFaceMarks() const;
|
|
|
|
/*
|
|
Descripiton:
|
|
Selectively clear m_status.RuntimeMark()
|
|
Parameters:
|
|
bClearVertexMarks - [in]
|
|
If true, m_status.ClearRuntimeMark() is called for every vertex.
|
|
bClearEdgeMarks - [in]
|
|
If true, m_status.ClearRuntimeMark() is called for every edge.
|
|
bClearFaceMarks - [in]
|
|
If true, m_status.ClearRuntimeMark() is called for every face.
|
|
marked_component_list - [out]
|
|
If not nullptr, then pointer to components that were marked
|
|
are returned in this marked_component_list[]
|
|
Returns:
|
|
Number of marks that were cleared.
|
|
*/
|
|
unsigned int ClearComponentMarks(
|
|
bool bClearVertexMarks,
|
|
bool bClearEdgeMarks,
|
|
bool bClearFaceMarks,
|
|
ON_SimpleArray< const class ON_SubDComponentBase* >* marked_component_list
|
|
) const;
|
|
|
|
unsigned int SetComponentMarks(
|
|
bool bClearBeforeSet,
|
|
const ON_SimpleArray< const class ON_SubDComponentBase* >& marked_component_list
|
|
) const;
|
|
|
|
unsigned int GetMarkedComponents(
|
|
bool bIncludeVertices,
|
|
bool bIncludeEdges,
|
|
bool bIncludeFaces,
|
|
ON_SimpleArray< const class ON_SubDComponentBase* >& marked_component_list
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
bAddMarkedComponents - [in]
|
|
If true, marked components are added to component_list[].
|
|
If false, unmarked components are added to component_list[].
|
|
mark_bits - [in]
|
|
If mark_bits is zero, then a component is "marked" if component.Mark() is true.
|
|
Otherwise a component is "marked" if mark_bits = component.MarkBits().
|
|
*/
|
|
unsigned int GetMarkedComponents(
|
|
bool bAddMarkedComponents,
|
|
ON__UINT8 mark_bits,
|
|
bool bIncludeVertices,
|
|
bool bIncludeEdges,
|
|
bool bIncludeFaces,
|
|
ON_SimpleArray< class ON_SubDComponentPtr >& component_list
|
|
) const;
|
|
|
|
unsigned int UnselectComponents(
|
|
bool bUnselectAllVertices,
|
|
bool bUnselectAllEdges,
|
|
bool bUnselectAllFaces
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Save the current component status of the indictated subd components.
|
|
Parameters:
|
|
bGetVertexStatus - [in]
|
|
bGetEdgeStatus - [in]
|
|
bGetFaceStatus - [in]
|
|
bClearStatus - [in]
|
|
If true, the bits in status_mask will also be cleared for the components.
|
|
status_mask - [in]
|
|
Status bits to save.
|
|
component_list - [out]
|
|
status_list - [out]
|
|
component_list[] and status_list[] are parallel arrays for components with
|
|
a matching status bit set.
|
|
*/
|
|
unsigned int GetComponentStatus(
|
|
bool bGetVertexStatus,
|
|
bool bGetEdgeStatus,
|
|
bool bGetFaceStatus,
|
|
bool bClearStatus,
|
|
ON_ComponentStatus status_mask,
|
|
ON_SimpleArray< const class ON_SubDComponentBase* >& component_list,
|
|
ON_SimpleArray< ON_ComponentStatus >& status_list
|
|
) const;
|
|
|
|
unsigned int SetComponentStatus(
|
|
ON_ComponentStatus status_mask,
|
|
const ON_SimpleArray< const class ON_SubDComponentBase* >& component_list,
|
|
const ON_SimpleArray< ON_ComponentStatus >& status_list
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Transforms the SubD components in ci_list[].
|
|
Parameters:
|
|
xform - [in]
|
|
ci_list - [in]
|
|
ci_count - [in]
|
|
component_location - [in]
|
|
Select between applying the tranform to the control net (faster)
|
|
or the surface points (slower).
|
|
Returns:
|
|
Number of vertex locations that changed.
|
|
*/
|
|
unsigned int TransformComponents(
|
|
const ON_Xform& xform,
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count,
|
|
ON_SubDComponentLocation component_location
|
|
);
|
|
|
|
unsigned int TransformComponents(
|
|
const ON_Xform& xform,
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count,
|
|
ON_SubDComponentLocation component_location
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Extrude entire subd bay adding a ring of faces around the boundary and moving the original subd.
|
|
*/
|
|
unsigned int Extrude(
|
|
const ON_Xform& xform
|
|
);
|
|
|
|
unsigned int ExtrudeComponents(
|
|
const ON_Xform& xform,
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count
|
|
);
|
|
|
|
unsigned int ExtrudeComponents(
|
|
const ON_Xform& xform,
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count
|
|
);
|
|
|
|
unsigned int ExtrudeComponents(
|
|
const ON_Xform& xform,
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count,
|
|
bool bExtrudeBoundaries,
|
|
bool bPermitNonManifoldEdgeCreation
|
|
);
|
|
|
|
unsigned int ExtrudeComponents(
|
|
const ON_Xform& xform,
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count,
|
|
bool bExtrudeBoundaries,
|
|
bool bPermitNonManifoldEdgeCreation
|
|
);
|
|
|
|
private:
|
|
unsigned int Internal_ExtrudeComponents(
|
|
const ON_Xform& xform,
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count,
|
|
bool bExtrudeBoundaries,
|
|
bool bPermitNonManifoldEdgeCreation
|
|
);
|
|
|
|
public:
|
|
|
|
/*
|
|
Parameters:
|
|
ci_list - [in]
|
|
Array of ci_count ON_COMPONENT_INDEX values that identify the vertices.
|
|
Elements that do not identifiy a SubD vertex are ignored.
|
|
ci_count - [in]
|
|
Number of elements in the ci_list[] array.
|
|
vertex_tag - [in]
|
|
Desired tag. If a vertex has the desired tag or cannot accept the desired tag,
|
|
then that vertex is skipped.
|
|
If vertex_tag is ON_SubDVertexTag::Corner, then every edge touching
|
|
that vertex is converted to a crease.
|
|
Returns:
|
|
number of vertex tags that were changed.
|
|
*/
|
|
unsigned int SetVertexTags(
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count,
|
|
ON_SubDVertexTag vertex_tag
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
ci_list - [in]
|
|
Array of ci_count ON_COMPONENT_INDEX values that identify the vertices.
|
|
Elements that do not identifiy a SubD vertex are ignored.
|
|
ci_count - [in]
|
|
Number of elements in the ci_list[] array.
|
|
vertex_tag - [in]
|
|
Desired tag. If a vertex has the desired tag or cannot accept the desired tag,
|
|
then that vertex is skipped.
|
|
If vertex_tag is ON_SubDVertexTag::Corner, then every edge touching
|
|
that vertex is converted to a crease.
|
|
Returns:
|
|
number of vertex tags that were changed.
|
|
*/
|
|
unsigned int SetVertexTags(
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count,
|
|
ON_SubDVertexTag vertex_tag
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
number of tags that were changed.
|
|
*/
|
|
unsigned int SetEdgeTags(
|
|
const ON_COMPONENT_INDEX* ci_list,
|
|
size_t ci_count,
|
|
ON_SubDEdgeTag edge_tag
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
number of tags that were changed.
|
|
*/
|
|
unsigned int SetEdgeTags(
|
|
const ON_SubDComponentPtr* cptr_list,
|
|
size_t cptr_count,
|
|
ON_SubDEdgeTag edge_tag
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Remove all interior creases.
|
|
Returns:
|
|
Number of edges converted from crease to smooth.
|
|
*/
|
|
unsigned int RemoveAllCreases();
|
|
|
|
/*
|
|
Description:
|
|
Apply the Catmull-Clark subdivision algorithm and save the results
|
|
in this ON_SubD.
|
|
Parameters:
|
|
level_index - [in]
|
|
Level where subdivision starts
|
|
count - [in] > 0
|
|
Number of times to subdivide.
|
|
Returns:
|
|
Number of subdivision steps that succeeded.
|
|
(= count when everything works, < count when input is not valid)
|
|
*/
|
|
bool GlobalSubdivide(
|
|
unsigned int count
|
|
);
|
|
|
|
bool GlobalSubdivide();
|
|
|
|
/*
|
|
Description:
|
|
Apply the Catmull-Clark subdivision algorithm to the faces in face_list[].
|
|
Parameters:
|
|
face_list - [in]
|
|
faces to subdivide
|
|
face_count - [in]
|
|
number of components.
|
|
Returns:
|
|
true if successful.
|
|
*/
|
|
bool LocalSubdivide(
|
|
class ON_SubDFace const*const* face_list,
|
|
size_t face_count
|
|
);
|
|
|
|
bool LocalSubdivide(
|
|
const ON_SimpleArray< const class ON_SubDFace* >& face_list
|
|
);
|
|
|
|
bool LocalSubdivide(
|
|
const ON_SimpleArray<ON_COMPONENT_INDEX>& face_list
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Adds a vertex with tag = ON_SubDVertexTag::Unset.
|
|
*/
|
|
class ON_SubDVertex* AddVertex(
|
|
const double* P
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Adds a vertex with specified tag.
|
|
*/
|
|
class ON_SubDVertex* AddVertex(
|
|
ON_SubDVertexTag vertex_tag,
|
|
const double* P
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to add a vertex with specified information. This function
|
|
is useful when copying portions of an existing SubD to a new SubD.
|
|
Parameters:
|
|
candidate_vertex_id - [in]
|
|
If candidate_vertex_id is > 0 and is available,
|
|
the returned value with have id = candidate_vertex_id.
|
|
Otherwise a new id will be assigned.
|
|
vertex_tag - [in]
|
|
Pass ON_SubDVertexTag::Unset if not known.
|
|
P - [in]
|
|
nullptr or a 3d point.
|
|
initial_edge_capacity - [in]
|
|
Initial capacity of the m_edges[] array. Pass 0 if unknown.
|
|
initial_face_capacity - [in]
|
|
Initial capacity of the m_faces[] array. Pass 0 if unknown.
|
|
*/
|
|
class ON_SubDVertex* AddVertexForExperts(
|
|
unsigned int candidate_vertex_id,
|
|
ON_SubDVertexTag vertex_tag,
|
|
const double* P,
|
|
unsigned int initial_edge_capacity,
|
|
unsigned int initial_face_capacity
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
v - [in]
|
|
A vertex with zero edge and zero faces.
|
|
*/
|
|
bool ReturnVertexForExperts(
|
|
ON_SubDVertex* v
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Search for a vertex with a specificed control net point.
|
|
Parameters:
|
|
control_net_point - [in]
|
|
Look for a vertex with this value for ControlNetPoint().
|
|
tolerance - [in]
|
|
Use 0.0 when in doubt.
|
|
If > 0.0, then the vertex closest to control_net_point
|
|
will be returned if the distance from that vertex to control_net_point
|
|
is <= distance_tolerance.
|
|
Returns:
|
|
An ON_SubDVertex pointer or nullptr if none exists.
|
|
*/
|
|
const class ON_SubDVertex* FindVertex(
|
|
const double* control_net_point,
|
|
double distance_tolerance
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Search for a vertex with a specificed control net point. If one does not
|
|
exist, add a new one.
|
|
Parameters:
|
|
control_net_point - [in]
|
|
Look for a vertex with this value for ControlNetPoint().
|
|
tolerance - [in]
|
|
Use 0.0 when in doubt.
|
|
If > 0.0, then the vertex closest to control_net_point
|
|
will be returned if the distance from that vertex to control_net_point
|
|
is <= distance_tolerance.
|
|
Returns:
|
|
An ON_SubDVertex pointer or nullptr if none exists.
|
|
*/
|
|
const class ON_SubDVertex* FindOrAddVertex(
|
|
const double* control_net_point,
|
|
double distance_tolerance
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge_face_count - [in]
|
|
Number of faces the edge will eventually have.
|
|
Pass 0 if the value is not known.
|
|
v0 - [in]
|
|
starting vertex
|
|
v1 - [in]
|
|
ending vertex
|
|
Returns:
|
|
If edge_face_count > 0x7FFFU, then ON_SubDEdgeTag::Unset is returned.
|
|
|
|
If edge_face_count is 1 or >= 3, then ON_SubDEdgeTag::Crease is returned.
|
|
|
|
If both vertex tags are ON_SubDVertexTag::Smooth, then ON_SubDEdgeTag::Smooth is returned.
|
|
|
|
If edge_face_count is 1 and both vertex tags are ON_SubDVertexTag::Crease or ON_SubDVertexTag::Corner,
|
|
then ON_SubDEdgeTag::Crease is returned.
|
|
|
|
If edge_face_count is 2 and both vertex tags are set and both are not ON_SubDVertexTag::Smooth,
|
|
then ON_SubDEdgeTag::SmoothX is returned.
|
|
|
|
Otherwise, ON_SubDEdgeTag::Unset is returned.
|
|
*/
|
|
static ON_SubDEdgeTag EdgeTagFromContext(
|
|
unsigned int edge_face_count,
|
|
const ON_SubDVertexTag v0_tag,
|
|
const ON_SubDVertexTag v1_tag
|
|
);
|
|
|
|
static ON_SubDEdgeTag EdgeTagFromContext(
|
|
unsigned int edge_face_count,
|
|
const ON_SubDVertex* v0,
|
|
const ON_SubDVertex* v1
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Add an edge with tag = ON_SubDEdgeTag::Unset to the subd.
|
|
Parameters:
|
|
v0 - [in]
|
|
v1 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
The edge will be on the same level as the vertices.
|
|
Returns:
|
|
Pointer to the allocated edge.
|
|
Remarks:
|
|
ON_SubD::EdgeTagFromContext() can be used to determine edge
|
|
tag values in simple situations.
|
|
*/
|
|
class ON_SubDEdge* AddEdge(
|
|
class ON_SubDVertex* v0,
|
|
class ON_SubDVertex* v1
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Search for an edge connecting v0 and v1.
|
|
Parameters:
|
|
v0 - [in]
|
|
v1 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
The edge will be on the same level as the vertices.
|
|
Returns:
|
|
An ON_SubDEdgePtr to a connecting edge or ON_SubDEdgePtr::Null if none exists.
|
|
*/
|
|
const ON_SubDEdgePtr FindEdge(
|
|
const class ON_SubDVertex* v0,
|
|
const class ON_SubDVertex* v1
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Search for an edge connecting v0 and v1. If none exists, then add one.
|
|
Parameters:
|
|
v0 - [in]
|
|
v1 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
The edge will be on the same level as the vertices.
|
|
Returns:
|
|
An ON_SubDEdgePtr to a connecting edge or ON_SubDEdgePtr::Null if none exists.
|
|
*/
|
|
const ON_SubDEdgePtr FindOrAddEdge(
|
|
class ON_SubDVertex* v0,
|
|
class ON_SubDVertex* v1
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Add an edge to the subd.
|
|
Parameters:
|
|
edge_tag - [in]
|
|
ON_SubDEdgeTag::Unset
|
|
Edge tag is not known at this time.
|
|
ON_SubDEdgeTag::Smooth
|
|
Smooth edge. If both vertices are tagged as not smooth, the
|
|
tag on the returned edge will be ON_SubDEdgeTag::SmoothX. This
|
|
tag is changed to ON_SubDEdgeTag::Smooth on the first
|
|
subdivision step.
|
|
ON_SubDEdgeTag::Crease.
|
|
Crease edge. Both vertices must be tagged as not smooth.
|
|
v0 - [in]
|
|
v1 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
The edge will be on the same level as the vertices.
|
|
Returns:
|
|
Pointer to the allocated edge.
|
|
Remarks:
|
|
ON_SubD::EdgeTagFromContext() can be used to determine edge
|
|
tag values in simple situations.
|
|
*/
|
|
class ON_SubDEdge* AddEdge(
|
|
ON_SubDEdgeTag edge_tag,
|
|
class ON_SubDVertex* v0,
|
|
class ON_SubDVertex* v1
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert use tool to add an edge with precomputed sector coefficients.
|
|
Parameters:
|
|
edge_tag - [in]
|
|
This expert user function does not automatically set the edge tag.
|
|
v0 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
v0_sector_coefficient - [in]
|
|
Pass ON_SubDSectorType::UnsetSectorCoefficient if unknown.
|
|
v1 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
v1_sector_coefficient - [in]
|
|
Pass ON_SubDSectorType::UnsetSectorCoefficient if unknown.
|
|
*/
|
|
class ON_SubDEdge* AddEdgeWithSectorCoefficients(
|
|
ON_SubDEdgeTag edge_tag,
|
|
class ON_SubDVertex* v0,
|
|
double v0_sector_coefficient,
|
|
class ON_SubDVertex* v1,
|
|
double v1_sector_coefficient
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to add an edge with specified information. This function
|
|
is useful when copying portions of an existing SubD to a new SubD.
|
|
Parameters:
|
|
candidate_edge_id - [in]
|
|
If candidate_edge_id is > 0 and is available,
|
|
the returned edge with have id = candidate_edge_id.
|
|
Otherwise a new id will be assigned.
|
|
edge_tag - [in]
|
|
Pass ON_SubDEdgeTag::Unset if not known.
|
|
v0 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
v0_sector_coefficient - [in]
|
|
Pass ON_SubDSectorType::UnsetSectorCoefficient if unknown.
|
|
v1 - [in]
|
|
The edge begins at v0 and ends at v1.
|
|
v1_sector_coefficient - [in]
|
|
Pass ON_SubDSectorType::UnsetSectorCoefficient if unknown.
|
|
initial_face_capacity - [in]
|
|
Initial face capacity. Pass 0 if unknown.
|
|
*/
|
|
class ON_SubDEdge* AddEdgeForExperts(
|
|
unsigned int candidate_edge_id,
|
|
ON_SubDEdgeTag edge_tag,
|
|
class ON_SubDVertex* v0,
|
|
double v0_sector_coefficient,
|
|
class ON_SubDVertex* v1,
|
|
double v1_sector_coefficient,
|
|
unsigned int initial_face_capacity
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
e - [in]
|
|
An edge in this subd with no vertices or faces.
|
|
*/
|
|
bool ReturnEdgeForExperts(
|
|
ON_SubDEdge* e
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge0 - [in]
|
|
edge1 - [in]
|
|
edge2 - [in]
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edge0, edge1, edge2).
|
|
Consecutive edges must have a single common vertex.
|
|
The orientations of the ON_SubDEdgePtr elements in the
|
|
face's edge list are automatically calculated.
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddTriangleFace(
|
|
class ON_SubDEdge* edge0,
|
|
class ON_SubDEdge* edge1,
|
|
class ON_SubDEdge* edge2
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge_count - [in]
|
|
Must be >= 3.
|
|
edge0 - [in]
|
|
edge1 - [in]
|
|
edge2 - [in]
|
|
The ON_SubDEdgePtr parameters must be oriented so that for consecutive pairs of edges,
|
|
edge0.RelativeVertex(1) and edges1.RelativeVertex(0) are same vertex.
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edge0, edge1, edge2).
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddTriangleFace(
|
|
ON_SubDEdgePtr edge0,
|
|
ON_SubDEdgePtr edge1,
|
|
ON_SubDEdgePtr edge2
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge0 - [in]
|
|
edge1 - [in]
|
|
edge2 - [in]
|
|
edge3 - [in]
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edge0, edge1, edge2. edge3).
|
|
Consecutive edges must have a single common vertex.
|
|
The orientations of the ON_SubDEdgePtr elements in the
|
|
face's edge list are automatically calculated.
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddQuadFace(
|
|
class ON_SubDEdge* edge0,
|
|
class ON_SubDEdge* edge1,
|
|
class ON_SubDEdge* edge2,
|
|
class ON_SubDEdge* edge3
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge_count - [in]
|
|
Must be >= 3.
|
|
edge0 - [in]
|
|
edge1 - [in]
|
|
edge2 - [in]
|
|
edge3 - [in]
|
|
The ON_SubDEdgePtr parameters must be oriented so that for consecutive pairs of edges,
|
|
edge0.RelativeVertex(1) and edges1.RelativeVertex(0) are same vertex.
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edge0, edge1, edge2,edge3).
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddQuadFace(
|
|
ON_SubDEdgePtr edge0,
|
|
ON_SubDEdgePtr edge1,
|
|
ON_SubDEdgePtr edge2,
|
|
ON_SubDEdgePtr edge3
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edges[] - [in]
|
|
edges[] must have 3 or more elements.
|
|
edges[i] and edges[(i+1)%edge_count] must have a single common vertex.
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edges[0], edges[1], ..., edges[edge_count-1]).
|
|
The orientations of the ON_SubDEdgePtr elements in the
|
|
face's edge list are automatically calculated.
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddFace(
|
|
const ON_SimpleArray<ON_SubDEdge*>& edges
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edges[] - [in]
|
|
edges[] must have 3 or more elements.
|
|
The ON_SubDEdgePtr parameters must be oriented so that
|
|
edges[i].RelativeVertex(1) and edges[(i+1)%edge_count].RelativeVertex(0)
|
|
are the same vertex.
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edges[0], edges[1], ..., edges[edge_count-1]).
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddFace(
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& edges
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge_count - [in]
|
|
Must be >= 3.
|
|
edges[] - [in]
|
|
edges[i] and edges[(i+1)%edge_count] must have a single common vertex.
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edges[0], edges[1], ..., edges[edge_count-1]).
|
|
The orientations of the ON_SubDEdgePtr elements in the
|
|
face's edge list are automatically calculated.
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddFace(
|
|
class ON_SubDEdge * const * edges,
|
|
unsigned int edge_count
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
edge_count - [in]
|
|
Must be >= 3.
|
|
edges[] - [in]
|
|
The ON_SubDEdgePtr parameters must be oriented so that
|
|
edges[i].RelativeVertex(1) and edges[(i+1)%edge_count].RelativeVertex(0)
|
|
are the same vertex.
|
|
The face will be oriented so the boundary has the edges
|
|
in the order (edges[0], edges[1], ..., edges[edge_count-1]).
|
|
Returns:
|
|
A pointer to the added face.
|
|
The returned face is managed by the subd.
|
|
*/
|
|
class ON_SubDFace* AddFace(
|
|
const class ON_SubDEdgePtr* edges,
|
|
unsigned int edge_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Finds an existing face or adds a new face with corners at face_vertices[].
|
|
Parameters:
|
|
new_edge_tag - [in]
|
|
If an edge needs to be added, this tag is assigned to the new edge.
|
|
When in doubt, pass ON_SubDEdgeTag::Unset and call this->UpdateAllTagsAndSectorCoefficients(true)
|
|
after you are finished modifying the SubD.
|
|
face_vertices - [in]
|
|
Array of vertices at the face corners in counter-clockwise order.
|
|
face_vertex_count - [in]
|
|
Number of vertices in face_vertices[]
|
|
Returns:
|
|
If the input is not valid, nullptr is returned.
|
|
If there is a face with the specified corners exists, then it is returned.
|
|
Otherwise a new face is added and returned.
|
|
*/
|
|
class ON_SubDFace* FindOrAddFace(
|
|
ON_SubDEdgeTag new_edge_tag,
|
|
const class ON_SubDVertex* face_vertices[],
|
|
size_t face_vertex_count
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
candidate_face_id - [in]
|
|
If candidate_face_id is > 0 and is available,
|
|
the returned face with have id = candidate_face_id.
|
|
Otherwise a new id will be assigned.
|
|
edge[] - [in]
|
|
The edge[] array must be sorted and correct oriented
|
|
(edge[i].RelativeVertex(1) == edge[(i+1)%edge_count].RelativeVertex(0)).
|
|
edge_count - [in]
|
|
Must be >= 3.
|
|
*/
|
|
class ON_SubDFace* AddFaceForExperts(
|
|
unsigned candidate_face_id,
|
|
const class ON_SubDEdgePtr* edge,
|
|
unsigned int edge_count
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
f - [in]
|
|
A face with zero edges
|
|
*/
|
|
bool ReturnFaceForExperts(
|
|
ON_SubDFace* f
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Add texture points to a face.
|
|
Parameters:
|
|
texture_points - [in]
|
|
An array of face->EdgeCount() points.
|
|
texture_points_count - [in]
|
|
number of elements in texture_points[].
|
|
Must be >= face->EdgeCount().
|
|
Returns:
|
|
True if texture points were set.
|
|
Remarks:
|
|
This function automatically handles the management of face texture point storage.
|
|
Texture points are a mutable property on ON_SubDFace.
|
|
*/
|
|
bool AddFaceTexturePoints(
|
|
const class ON_SubDFace* face,
|
|
const class ON_3dPoint* texture_points,
|
|
size_t texture_points_count
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Add texture point storage capacity to a face.
|
|
Parameters:
|
|
face - [in]
|
|
The ability to store at least face->EdgeCount() texture points will be added to this face.
|
|
Returns:
|
|
Number of texture points that can be set (>= face->EdgeCount()).
|
|
*/
|
|
unsigned int AllocateFaceTexturePoints(
|
|
const class ON_SubDFace* face
|
|
) const;
|
|
|
|
public:
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubD::PatchStyle] [Rhino.Geometry.SubDPatchStyle] [byte]
|
|
/// <summary>
|
|
/// SubD::PatchStyle identifies the style of patch used to fill holes.
|
|
/// </summary>
|
|
enum class PatchStyle : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Not a valid style.
|
|
/// This encourages developers to thoughtfully select a patch style and can
|
|
/// be used to indicate a UI control is not initialized.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// Automatically choose a patch style that will generally create a good looking result.
|
|
/// If a hole boundary is not convex, it is triangulated. Otherwise:
|
|
/// If a hole has 3 edges, a single triangle face is used.
|
|
/// If a hole has 4 edges, a single quad face is used.
|
|
/// If a hole has 5 or more edges and an odd number of edges, a triangle fan is used.
|
|
/// If a hole has 6 or more edges and an even number of edges, a quad fan is used.
|
|
///</summary>
|
|
Automatic = 1,
|
|
|
|
///<summary>
|
|
/// A single face is used under all conditions.
|
|
///</summary>
|
|
SingleFace = 2,
|
|
|
|
///<summary>
|
|
/// A triangle fan used under all conditions. The center of the fan
|
|
/// is the average of the hole boundary vertex control net points.
|
|
///</summary>
|
|
TriangleFan = 3,
|
|
|
|
///<summary>
|
|
/// If the hole boundary has an even mumber of edges, a quad fan is used.
|
|
/// Otherwise a triangle fan is used. The center of the fan
|
|
/// is the average of the hole boundary vertex control net points.
|
|
///</summary>
|
|
QuadOrTriangleFan = 4,
|
|
|
|
///<summary>
|
|
/// The hole boundary is triangluated.
|
|
/// Typically this style is selected when a boundary not convex
|
|
/// and the other styles produce faces with overlapping regions.
|
|
///</summary>
|
|
Triangulated = 5
|
|
};
|
|
#pragma endregion
|
|
|
|
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Expert user tool to insert an edge in the face's edge array.
|
|
Parameters:
|
|
face - [in]
|
|
edge - [in]
|
|
edge_direction -[in]
|
|
i - [in]
|
|
index where the edge should be inserted.
|
|
Returns:
|
|
true if successful.
|
|
Remarks:
|
|
This tool is used during construction or editing of a SubD and the
|
|
connection is added even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool AddFaceEdgeConnection(
|
|
ON_SubDFace* face,
|
|
unsigned int i,
|
|
ON_SubDEdge* edge,
|
|
ON__UINT_PTR edge_direction
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to insert an edge in the face's edge array.
|
|
Parameters:
|
|
face - [in]
|
|
eptr - [in]
|
|
direction must be set correctly
|
|
i - [in]
|
|
index where the edge should be inserted.
|
|
Returns:
|
|
true if successful.
|
|
Remarks:
|
|
This tool is used during construction or editing of a SubD and the
|
|
connection is added even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool AddFaceEdgeConnection(
|
|
ON_SubDFace* face,
|
|
unsigned int i,
|
|
ON_SubDEdgePtr eptr
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to insert an edge in the face's edge array.
|
|
Parameters:
|
|
face - [in]
|
|
i - [in]
|
|
index where the edge should be inserted.
|
|
eptr - [in]
|
|
direction must be set correctly
|
|
bAddFaceToRelativeVertex0 - [in]
|
|
If true, face is appended to the eptr.RelativeVertex(0)'s face array.
|
|
bAddFaceToRelativeVertex1 - [in]
|
|
If true, face is appended to the eptr.RelativeVertex(0)'s face array.
|
|
Returns:
|
|
true if successful.
|
|
Remarks:
|
|
This tool is used during construction or editing of a SubD and the
|
|
connection is added even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool AddFaceEdgeConnection(
|
|
ON_SubDFace* face,
|
|
unsigned int i,
|
|
ON_SubDEdgePtr eptr,
|
|
bool bAddbAddFaceToRelativeVertex0,
|
|
bool bAddbAddFaceToRelativeVertex1
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to set a face's boundary.
|
|
Parameters:
|
|
face - [in]
|
|
Face that is in the subd with no edges.
|
|
edges - [in]
|
|
Array of edge_count pointers that form a loop.
|
|
Caller is responsible for insuring edges and vertices appear only
|
|
one time in the loop.
|
|
edge_count - [in]
|
|
Number of edges in the boundary.
|
|
Returns:
|
|
True if successful (all edge-face and vertex-face connections are set).
|
|
False otherwise.
|
|
Remarks:
|
|
This tool is used during construction or editing of a SubD and the
|
|
connection is added even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool SetFaceBoundary(
|
|
ON_SubDFace* face,
|
|
const ON_SubDEdgePtr* edges,
|
|
size_t edge_count
|
|
);
|
|
|
|
bool SetFaceBoundary(
|
|
ON_SubDFace* face,
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& edges
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to insert an edge in the face's edge array.
|
|
Parameters:
|
|
face - [in]
|
|
edge - [in]
|
|
edge to remove
|
|
Returns:
|
|
true if successful.
|
|
Remarks:
|
|
This tool is used during construction or editing of a SubD and the
|
|
connection is removed even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool RemoveFaceEdgeConnection(
|
|
ON_SubDFace* face,
|
|
ON_SubDEdge* edge
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove the connection between and edge and face.
|
|
Parameters:
|
|
face - [in]
|
|
i - [in]
|
|
index where the edge should be removed.
|
|
0 <= i < face->EdgeCount()
|
|
removed_edge - [out]
|
|
removed edge
|
|
Remarks:
|
|
This tool is used during construction or editing of a SubD and the
|
|
connection is removed even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool RemoveFaceEdgeConnection(
|
|
ON_SubDFace* face,
|
|
unsigned int i
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove the connection between and edge and face.
|
|
Parameters:
|
|
face - [in]
|
|
i - [in]
|
|
index where the edge should be removed.
|
|
removed_edge - [out]
|
|
removed edge
|
|
Remarks:
|
|
This tool is used during construction or editing of a SubD and the
|
|
connection is removed even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool RemoveFaceEdgeConnection(
|
|
ON_SubDFace* face,
|
|
unsigned int i,
|
|
ON_SubDEdgePtr& removed_edge
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove a connection beteen an edge and vertex
|
|
Parameters:
|
|
e - [in]
|
|
An edge with zero attached faces.
|
|
v - [in]
|
|
A vertex attached to the e.
|
|
Returns:
|
|
If successful, true is returned.
|
|
Otherwise false is returned.
|
|
*/
|
|
bool RemoveEdgeVertexConnection(
|
|
ON_SubDEdge* e,
|
|
ON_SubDVertex* v
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove a connection beteen an edge and edge->vertex[evi]
|
|
Parameters:
|
|
e - [in]
|
|
An edge with zero attached faces.
|
|
evi - [in]
|
|
0 or 1 specifying which vertex to remove.
|
|
Returns:
|
|
If successful, a pointer to the removed vertex is returned.
|
|
Otherwise nullptr is returned.
|
|
*/
|
|
ON_SubDVertex* RemoveEdgeVertexConnection(
|
|
ON_SubDEdge* e,
|
|
unsigned evi
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove all edge and vertex connnections from a face
|
|
Parameters:
|
|
face - [in]
|
|
Remarks:
|
|
This tool is used during editing of a SubD and the
|
|
connections are removed even if the result is an invalid face or edge.
|
|
It is up to the expert user to make enough changes to create a valid SubD.
|
|
*/
|
|
bool RemoveFaceConnections(
|
|
ON_SubDFace* face
|
|
);
|
|
|
|
bool GrowVertexEdgeArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
);
|
|
bool GrowVertexFaceArray(
|
|
ON_SubDVertex* v,
|
|
size_t capacity
|
|
);
|
|
bool GrowEdgeFaceArray(
|
|
ON_SubDEdge* e,
|
|
size_t capacity
|
|
);
|
|
bool GrowFaceEdgeArray(
|
|
ON_SubDFace* f,
|
|
size_t capacity
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Clear all cached evaluation information (meshes, surface points, boundiang boxes, ...)
|
|
that depends on edge tags, vertex tags, and the location of vertex control points.
|
|
*/
|
|
void ClearEvaluationCache() const;
|
|
|
|
/*
|
|
Description:
|
|
This function copies cached evaluations of component subdivision points and limit
|
|
surface information from src to this. Typically this is done for performance critical
|
|
sitations like control point editing.
|
|
*/
|
|
bool CopyEvaluationCacheForExperts(const ON_SubD& src);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get a mesh representation of the ON_SubD control net.
|
|
Parameters:
|
|
mesh - [in]
|
|
If not null, the returned mesh will be stored on
|
|
the input class.
|
|
|
|
priority - [in]
|
|
Specifies what type of SubD information is most important to transfer to the mesh.
|
|
For more details, see the comments for ON_SubDGetControlNetMeshPriority.
|
|
|
|
Returns:
|
|
A mesh representation of the ON_SubD control net.
|
|
*/
|
|
class ON_Mesh* GetControlNetMesh(
|
|
class ON_Mesh* mesh,
|
|
ON_SubDGetControlNetMeshPriority priority
|
|
) const;
|
|
|
|
private:
|
|
bool Internal_GetGeometryControlNetMesh(
|
|
const class ON_SubDLevel& level,
|
|
class ON_SubDLevelComponentIdIterator& vit_by_id,
|
|
class ON_SubDLevelComponentIdIterator& fit_by_id,
|
|
class ON_Mesh& mesh
|
|
) const;
|
|
bool Internal_GetTextureCoordinatesGeometryControlNetMesh(
|
|
const class ON_SubDLevel& level,
|
|
class ON_Mesh& mesh
|
|
) const;
|
|
public:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubD::NurbsSurfaceType] [Rhino.Geometry.SubD.NurbsSurfaceType] [nested:byte]
|
|
/// <summary>
|
|
/// ON_SubD::NurbsSurfaceType specifies what type of NURBS surfaces are returned by ON_SubD.GetSurfaceNurbsFragments()
|
|
/// </summary>
|
|
enum class NurbsSurfaceType : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Not a valid type. Used to indicate the type has not been set and to encourage developers to explicitly specify a type.
|
|
/// When in doubt, specify NurbsSurfaceType::Large.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// Onee NURBS surface will be generated for each SubD quad.
|
|
/// N NURBS surfaces will be generated for each SubD N-gon (N = 3, 5 or more). ON_Brepface may cover multiple
|
|
/// Near extraordinary vertices, the surfaces may have lots of knots.
|
|
///</summary>
|
|
Large = 1,
|
|
|
|
///<summary>
|
|
/// NURBS surfaces will be as large as possible without the addition of extra knots.
|
|
/// Near extraordinary vertices, the surfaces may have lots of knots.
|
|
/// This option is prefered when a user wants larger NURBS surfaces but not at the cost of addtional NURBS control points.
|
|
///</summary>
|
|
Medium = 2,
|
|
|
|
///<summary>
|
|
/// NURBS surfaces will not be merged and will have clamped knots.
|
|
///</summary>
|
|
Small = 3,
|
|
|
|
///<summary>
|
|
/// NURBS surfaces will not be merged and will have unclamped uniform knots.
|
|
/// This is useful as a starting point for customized merging and modifying
|
|
/// continuity at extraordinary vertices.
|
|
///</summary>
|
|
Unprocessed = 4
|
|
};
|
|
#pragma endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
/*
|
|
Parameters:
|
|
minimum_rectangle_count - [in]
|
|
>= 1 minimum number of rectangles in texture domain
|
|
image_width - [in]
|
|
image_height = [in]
|
|
If a texture image size is known, pass it here. Otherwise pass 0.0 for both parameters.
|
|
Returns:
|
|
Suggested way to partition a texture coodinate domain into rectangles.
|
|
ON_2udex.i = "x" count
|
|
ON_2udex.j = "y" count
|
|
For example (3,2) would mean divide the 2d texture domain into 3 segments across and 2 segments vertically.
|
|
*/
|
|
static const ON_2udex TextureDomainGridSize(
|
|
unsigned minimum_rectangle_count,
|
|
double image_width,
|
|
double image_height
|
|
);
|
|
|
|
enum : unsigned int
|
|
{
|
|
/// <summary>
|
|
/// ON_SUbDFace packing rectangle information is calculated so that there is at least
|
|
/// one unused pixel between adjacent packing rectangles when a texture image size is
|
|
/// TextureImageSuggestedMinimumSize x TextureImageSuggestedMinimumSize
|
|
/// pixels or larger.
|
|
/// Core subd code assumes TextureImageSuggestedMinimumSize is a power of 2 and >= 512.
|
|
/// </summary>
|
|
TextureImageSuggestedMinimumSize = 1024
|
|
};
|
|
|
|
static ON_SubDTextureCoordinateType TextureCoordinateTypeFromUnsigned(
|
|
unsigned int texture_coordinate_type_as_unsigned
|
|
);
|
|
|
|
static ON_SubDTextureCoordinateType TextureCoordinateTypeFromObsoleteTextureDomainType(
|
|
unsigned int obsolete_texture_domain_type_as_unsigned
|
|
);
|
|
|
|
static unsigned char ObsoleteTextureDomainTypeFromTextureCoordinateType(
|
|
ON_SubDTextureCoordinateType texture_coordinate_type
|
|
);
|
|
|
|
|
|
static const ON_wString TextureCoordinateTypeToString(
|
|
ON_SubDTextureCoordinateType texture_domain_type
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Set the texture coordinate type.
|
|
Parameters:
|
|
texture_coordinate_type - [in]
|
|
Type of texture coordinates.
|
|
If ON_SubDTextureCoordinateType::Unset or ON_SubDTextureCoordinateType::Custom,
|
|
is passed, the type setting is changed but no changes are made to texture coordinates.
|
|
Remarks:
|
|
Call SetTextureCoordinates() to restore them to the default values.
|
|
|
|
If texture_coordinate_type is ON_SubDTextureCoordinateType::FromMapping, then
|
|
the mapping this->TextureCoordinateMapping() is used. You may call
|
|
this->SetTextureCoordinateMapping() to set the mapping.
|
|
|
|
Calling this->SetTextureCoordinateType() does not change existing cached
|
|
texture coordinates. At an approprite time, call SetFragmentTextureCoordinates()
|
|
to update texture coordinates on any cached fragments.
|
|
|
|
SubD texture coordinate type and fragment texture coordinates are a mutable property.
|
|
They can be changed by rendering applications as needed.
|
|
*/
|
|
void SetTextureCoordinateType(
|
|
ON_SubDTextureCoordinateType texture_coordinate_type
|
|
) const;
|
|
|
|
ON_SubDTextureCoordinateType TextureCoordinateType() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of faces with ON_SubDFace.TexturePointsAreSet() = true.
|
|
*/
|
|
unsigned int TexturePointsAreSet() const;
|
|
|
|
/*
|
|
Description:
|
|
Delete texture points from faces.
|
|
Returns:
|
|
Number of faces that had texture points.
|
|
*/
|
|
unsigned int ClearTexturePoints() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bIgnoreTextureCoordinateType - [in]
|
|
If true, the current texture mapping tag is returned.
|
|
If false, the current texture mapping tag is returned only when ON_SubDTextureCoordinateType::FromMapping = TextureCoordinateType().
|
|
Returns:
|
|
The current texture mapping tag.
|
|
Remarks:
|
|
The texture mapping tag should be applied only when this->TextureCoordinateType()
|
|
is ON_SubDTextureCoordinateType::FromMapping.
|
|
SubD texture domains and coordinates are a mutable property.
|
|
They can be changed by rendering applications as needed.
|
|
*/
|
|
const ON_MappingTag TextureMappingTag(
|
|
bool bIgnoreTextureCoordinateType
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Set the texture mapping tag.
|
|
Remarks:
|
|
The texture mapping tag should be applied only when this->TextureCoordinateType()
|
|
is ON_SubDTextureCoordinateType::FromMapping.
|
|
|
|
Calling this->SetTextureMappingTag() does not change existing cached
|
|
texture coordinates. At an approprite time, call this->SetFragmentTextureCoordinates()
|
|
to update texture coordinates on any cached fragments.
|
|
|
|
SubD texture domains and coordinates are a mutable property.
|
|
They can be changed by rendering applications as needed.
|
|
*/
|
|
void SetTextureMappingTag(const class ON_MappingTag&) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if setting texture coordinates requires a set ON_TextureMapping mapping.
|
|
Remarks:
|
|
An explict texture mapping is required when TextureCoordinateType() is
|
|
ON_SubDTextureCoordinateType::FromMapping and TextureMappingTag()
|
|
is set and not ON_MappingTag::SurfaceParameterMapping or an equivalent
|
|
surface parameter mapping.
|
|
*/
|
|
bool TextureMappingRequired() const;
|
|
|
|
/*
|
|
Parameters:
|
|
texture_coordinate_type - [in]
|
|
texture_mapping_tag - [in]
|
|
If texture_coordinate_type is ON_SubDTextureCoordinateType::Custom, then
|
|
then texture_mapping_tag information is included in the hash.
|
|
Otherwise, texture_mapping_tag is ignored.
|
|
Returns:
|
|
A hash that uniquely identifies the information in TextureCoordinateType() and
|
|
TextureMappingTag() that applies to the current subd.
|
|
*/
|
|
static const ON_SHA1_Hash TextureSettingsHash(
|
|
ON_SubDTextureCoordinateType texture_coordinate_type,
|
|
const class ON_MappingTag& texture_mapping_tag
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
ON_SubD::TextureSettingsHash(this->TextureCoordinateType(),this->TextureMappingTag());
|
|
Remarks:
|
|
Comparing with this->FragmentTextureCoordinatesTextureSettingsHash() can tell you
|
|
if the current fragment texture coordinates were calculated using the same settings.
|
|
*/
|
|
const ON_SHA1_Hash TextureSettingsHash() const;
|
|
|
|
/*
|
|
Description:
|
|
If needed, set the frament texture coordinates.
|
|
Parameters:
|
|
mapping - [in]
|
|
If ON_SubD::TextureMappingRequired() is true, then you must
|
|
pass a mapping with a tag that matches ON_SubDTextureMappingTag().
|
|
Otherwise, mapping is ignored and you may pass ON_TextureMapping::Unset.
|
|
bLazy - [in]
|
|
If true and the m_T[] values were set using the same
|
|
mapping parameters, then no calculation is performed.
|
|
Returns:
|
|
True if successful.
|
|
Remarks:
|
|
SubD texture domains and coordinates are a mutable property.
|
|
They can be changed by rendering applications as needed.
|
|
Call SetTextureCoordinatesFromFaceDomains() to restore them to the default values.
|
|
*/
|
|
bool SetFragmentTextureCoordinates(
|
|
const class ON_TextureMapping& mapping,
|
|
bool bLazy
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
The value of ON_SubD::TextureSettingsHash(texture_coordinate_type,texture_mapping_tag)
|
|
for the texture_coordinate_type and texture_mapping_tag used to set the current
|
|
fragment texture coordinates. If no fragments exist or the coordinates are not set,
|
|
then ON_SHA1_Hash::EmptyContentHash is returned.
|
|
*/
|
|
const ON_SHA1_Hash FragmentTextureCoordinatesTextureSettingsHash() const;
|
|
|
|
/*
|
|
Description:
|
|
If a change requires existing fragment texture coordinates to be recalculated,
|
|
then call ClearFragmentTextureCoordinatesTextureSettingsHash().
|
|
*/
|
|
void ClearFragmentTextureCoordinatesTextureSettingsHash() const;
|
|
|
|
private:
|
|
/*
|
|
Description:
|
|
Unconditionally sets fragment texture coordinates when a mapping is not required or is not available.
|
|
*/
|
|
bool Internal_SetFragmentTextureCoordinatesWithoutMapping() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the value returned by FragmentTextureCoordinatesTextureSettingsHash()
|
|
*/
|
|
void Internal_SetFragmentTextureCoordinatesTextureSettingsHash(ON_SHA1_Hash hash) const;
|
|
|
|
ON_SubDTextureCoordinateType Internal_BestChoiceTextureCoordinateType(
|
|
const class ON_TextureMapping& available_mapping
|
|
) const;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Use a callback to set the vertex colros in m_C[].
|
|
Parameters:
|
|
bLazySet - [in]
|
|
If bLazySet is true and fragment_colors_settings_hash and the current
|
|
FragmentColorsSettingsHash() are equal, then nothing is changed.
|
|
fragment_colors_settings_hash - [in]
|
|
A that uniquely identifies the method and parameters being
|
|
used to set the fragment vertex colors. In general this hash
|
|
should depend on the value of this->GeometryContentSerialNumber(),
|
|
color_callback, and all values in the callback_context that
|
|
determine vertex colors. Under no circumstances should this
|
|
hash depend on this->RenderContentSerialNumber().
|
|
fragment_colors_mapping_tag - [in]
|
|
If not applicable, pass ON_MappingTag::Unset.
|
|
A mapping tag indentifying what is setting the fragment colors.
|
|
This is the only property that persists in SubD copies and saves in 3dm archives.
|
|
Typically:
|
|
m_mapping_id is an id you make up that identifies what is setting the colors (thickness, curvature, ...).
|
|
m_mapping_type will be ON_TextureMapping::TYPE::false_colors.
|
|
m_mapping_crc is a field from the 1990s that the SHA1 hash handles better now and setting
|
|
m_mapping_crc = ON_CRC32(0, sizeof(fragment_colors_settings_hash), &fragment_colors_settings_hash)
|
|
works well.
|
|
works well.
|
|
Typically, m_mapping_type = TYPE::false_colors.
|
|
callback_context - [in]
|
|
first parameter passed to color_callback()
|
|
color_callback - [i]
|
|
A callback function used to set the fragment vertex colors.
|
|
*/
|
|
bool SetFragmentColorsFromCallback(
|
|
bool bLazySet,
|
|
ON_SHA1_Hash fragment_colors_settings_hash,
|
|
ON_MappingTag fragment_colors_mapping_tag,
|
|
ON__UINT_PTR callback_context,
|
|
const ON_Color(*color_callback)(
|
|
ON__UINT_PTR callback_context,
|
|
const ON_MappingTag& mapping_tag,
|
|
const ON_SubD& subd,
|
|
ON_SubDComponentPtr cptr,
|
|
const ON_3dPoint& P,
|
|
const ON_3dVector& N,
|
|
const ON_3dPoint& T,
|
|
const ON_SurfaceCurvature& K
|
|
)
|
|
) const;
|
|
|
|
/*
|
|
Descrption:
|
|
Clear all fragment vertex colors
|
|
Parameters:
|
|
bClearFragmentColorsMappingTag - [in]
|
|
When in doubt, pass true.
|
|
If true, the mapping tag associated with the fragment vertex colors is unset as well.
|
|
*/
|
|
void ClearFragmentColors(
|
|
bool bClearFragmentColorsMappingTag
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
hash identifying the way the fragment vertex colors were set.
|
|
*/
|
|
const ON_SHA1_Hash FragmentColorsSettingsHash() const;
|
|
|
|
/*
|
|
Returns:
|
|
The current fragment vertex colors mapping tag.
|
|
*/
|
|
const ON_MappingTag FragmentColorsMappingTag() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the fragment colors mapping tag.
|
|
Remarks:
|
|
Calling this->SetFragmentColorsMappingTag() does not change existing cached
|
|
fragment vertex colors. At an approprite time, call this->SetFragmentColorsFromCallback()
|
|
to update fragment vertex colors on any cached fragments.
|
|
|
|
SubD fragment vertex tag and colors are a mutable property.
|
|
They can be changed by rendering applications as needed.
|
|
*/
|
|
void SetFragmentColorsMappingTag(const class ON_MappingTag&) const;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Pretend this function and ON_SubDimple do not exist.
|
|
Returns:
|
|
Something that you are pretending does not exist.
|
|
Remarks:
|
|
It is intentional that the definition of ON_SubDimple class is not
|
|
available in the opennurbs library interface (not in a header file).
|
|
The size and design of ON_SubDimple will change constantly.
|
|
If you choose to hack and whack so you can dereference an
|
|
ON_SubDimple* pointer, then your code will crash unpredictably.
|
|
*/
|
|
const class ON_SubDimple* SubDimple() const;
|
|
const class ON_SubDLevel& ActiveLevel() const;
|
|
unsigned int SubDimpleUseCount() const;
|
|
|
|
void ShareDimple(const ON_SubD&);
|
|
void SwapDimple(ON_SubD&);
|
|
|
|
void ShareDimple(const class ON_SubDMeshImpl&);
|
|
void SwapDimple(class ON_SubDMeshImpl& );
|
|
|
|
private:
|
|
class ON_SubDimple* SubDimple(bool bCreateIfNeeded);
|
|
class ON_SubDLevel const * ActiveLevelConstPointer() const;
|
|
class ON_SubDLevel* ActiveLevelPointer();
|
|
|
|
void CopyHelper(const ON_SubD&);
|
|
|
|
private:
|
|
class ON_SubDHeap* Internal_Heap() const;
|
|
|
|
public:
|
|
|
|
/*
|
|
Returns:
|
|
True if every face has a nonzero PackId and a set PackRect.
|
|
*/
|
|
bool FacesArePacked() const;
|
|
|
|
/*
|
|
Description:
|
|
Validates the face packing.
|
|
|
|
If a face pack contains more than one face, then all of the following are required
|
|
for that face pack to be valid.
|
|
- Every face in the pack is a quad.
|
|
- The quads form a rectangular grid.
|
|
- All faces in the rectangular grid are quads.
|
|
- All interior edges in the rectangular grid are smooth.
|
|
- All interior vertices in the rectangular grid are smooth and have 4 edge and 4 faces.
|
|
- All edges on the sides of the rectangular grid are either creases or are attached to
|
|
exactly one face in the rectangular grid.
|
|
|
|
Parameters:
|
|
bPermitWrapping - [in]
|
|
If true, then the face pack is allowed to wrap.
|
|
For example, if bPermitWrapping is true, then a SubD cylinder that is a regular quad grid
|
|
can have a single face pack.
|
|
bIfValidThenUpdateFacePackingTopologyHash - [in]
|
|
When in doubt, pass false to test if all of the current face packing information is
|
|
completely valid.
|
|
|
|
If you are using an add/remove creases edit approach to modify an initially valid packing,
|
|
then pass true. Otherwise pass false.
|
|
|
|
If this parameter is true, the packing is valid, and this->FacePackingSubDTopologyHash()
|
|
does not match this->SubDTopologyHash(), then this->FacePackingSubDTopologyHash() is updated
|
|
to the current value of this->SubDTopologyHash().
|
|
|
|
If this paramter is false and and this->FacePackingSubDTopologyHash()
|
|
does not match this->SubDTopologyHash(), then the function returns false.
|
|
Returns:
|
|
True if FacesArePacked() is true, the quad grids meet all the conditions described above,
|
|
this->FacePackingId() is not nil, and either this->FacePackingSubDTopologyHash() is equal to
|
|
this->SubDTopologyHash() or bIfValidThenUpdateFacePackingTopologyHash is true.
|
|
*/
|
|
bool FacePackingIsValid(
|
|
bool bIfValidThenUpdateFacePackingTopologyHash
|
|
) const;
|
|
|
|
private:
|
|
/*
|
|
Returns:
|
|
True if all of the following are satisfied.
|
|
1. All quads are packed into rectangular grids.
|
|
2. The pack id is used in those grids is not used by any other face.
|
|
3. The rectangular grids do not have interior creases.
|
|
4. The rectangular grids have 4 boundaries (no wrapping).
|
|
5. Non quads have pack ids that are zero or not shared with a quad.
|
|
*/
|
|
bool QuadPackingIsValid() const;
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// The fast and simple face packing uses topology, vertex tags, and edge tags to
|
|
/// group quads into rectangular grids. It does not perform geometric feature analysis.
|
|
/// {C3D8DD54-F8C8-4455-BB0E-2A2F4988EC81}
|
|
/// </summary>
|
|
static const ON_UUID FastAndSimpleFacePackingId;
|
|
|
|
|
|
// ADD NEW PackFaces ids above this comment and below FastAndSimplePackFacesId.
|
|
|
|
|
|
/// <summary>
|
|
/// ON_SubD::DefaultFacePackingId ideitifies the default face packing.
|
|
/// Code that wants to use the built-in face packing that is currently
|
|
/// the best option for general use, will specify ON_SubD::DefaultFacePackingId.
|
|
///
|
|
/// Currently this id is ON_SubD::FastAndSimpleFacePackingId.
|
|
/// In the future it may be changed to another id. Code that wants to
|
|
/// always apply the same face packing will explicitly specify one of
|
|
/// the built-in face pack ids defined above.
|
|
/// </summary>
|
|
static const ON_UUID DefaultFacePackingId;
|
|
|
|
static bool IsBuiltInFacePackingId(
|
|
ON_UUID candidate_id
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
An id that identifies the algorithm used to pack the faces in this subd.
|
|
*/
|
|
const ON_UUID FacePackingId() const;
|
|
|
|
/*
|
|
Returns:
|
|
The value of ON_SubDHash::Create(ON_SubDHashType::TopologyAndEdgeCrease, *this) when the faces were packed.
|
|
*/
|
|
const ON_SubDHash FacePackingTopologyHash() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the FacePackingTopologyHash() property to Empty.
|
|
Experts may need to do this when modifying a face packing.
|
|
After calling ClearFacePackingTopologyHashForExperts(), call
|
|
FacePackingIsValid(true) to make sure the modified packing was
|
|
actually valid and update the FacePackingTopologyHash().
|
|
*/
|
|
void ClearFacePackingTopologyHashForExperts() const;
|
|
|
|
/*
|
|
Description:
|
|
When a custom algorithm that is not built into ON_SubD is used to pack the
|
|
faces, this function must be called with an id that uniquely identifies the
|
|
custom algorithm. The present SubD geometry will be used to set the value
|
|
of FacePackingTopologyHash().
|
|
Returns:
|
|
True if faces are properly packed and custom_packing_id is not nil and unique.
|
|
Otherwise the packing is reset to the default and false is returned.
|
|
*/
|
|
bool SetFacePackingIdForExperts(
|
|
ON_UUID custom_packing_id
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Clear all face pack ids and related information.
|
|
*/
|
|
void ClearFacePackIds();
|
|
|
|
|
|
|
|
private:
|
|
friend class ON_SubDRef;
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
|
|
// C4251: ... needs to have dll-interface to be used by clients of class ...
|
|
// m_subdimple_sp is private and all code that manages m_subdimple_sp is explicitly implemented in the DLL.
|
|
private:
|
|
std::shared_ptr<class ON_SubDimple> m_subdimple_sp;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
|
|
public:
|
|
// The ON_SubD code increments ON_SubD::ErrorCount everytime something
|
|
// unexpected happens. This is useful for debugging.
|
|
static unsigned int ErrorCount;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDRef
|
|
//
|
|
class ON_CLASS ON_SubDRef
|
|
{
|
|
#if defined(ON_SUBD_CENSUS)
|
|
private:
|
|
ON_SubDRefCensusCounter m_census_counter;
|
|
#endif
|
|
|
|
public:
|
|
static const ON_SubDRef Empty;
|
|
|
|
ON_SubDRef() ON_NOEXCEPT;
|
|
~ON_SubDRef();
|
|
ON_SubDRef(const ON_SubDRef& src) ON_NOEXCEPT;
|
|
ON_SubDRef& operator=(const ON_SubDRef& src);
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDRef( ON_SubDRef&& ) ON_NOEXCEPT;
|
|
// rvalue assignment operator
|
|
ON_SubDRef& operator=( ON_SubDRef&& );
|
|
#endif
|
|
|
|
const class ON_SubD& SubD() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of references to the managed ON_SubD, including the one by this ON_SubDRef.
|
|
*/
|
|
unsigned int ReferenceCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Allocates a new empty ON_SubD and has this ON_SubDRef reference it.
|
|
*/
|
|
class ON_SubD& NewSubD();
|
|
|
|
/*
|
|
Description:
|
|
Allocates a new ON_SubD and has this ON_SubDRef reference it.
|
|
Parameters:
|
|
src - [in]
|
|
The new ON_SubD managed by this ON_SubDRef will be a copy of src.SubD().
|
|
Returns:
|
|
A reference to the new ON_SubD managed by this ON_SubDRef.
|
|
*/
|
|
class ON_SubD& CopySubD(
|
|
const ON_SubDRef& src
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Allocates a new ON_SubD and has this ON_SubDRef reference it.
|
|
Parameters:
|
|
src - [in]
|
|
The new ON_SubD managed by this ON_SubDRef will be a copy of src.
|
|
Returns:
|
|
A reference to the new ON_SubD managed by this ON_SubDRef.
|
|
*/
|
|
class ON_SubD& CopySubD(
|
|
const ON_SubD& src
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
If ReferenceCount() > 1, then have this ON_SubDRef reference a
|
|
new copy. Otherwise do nothing. The result being that this will
|
|
be the unique reference to the ON_SubD managed by this ON_SubDRef.
|
|
Returns:
|
|
A reference to the ON_SubD uniquely managed by this ON_SubDRef.
|
|
*/
|
|
class ON_SubD& UniqueSubD();
|
|
|
|
/*
|
|
Description:
|
|
Remove this reference to the managed ON_SubD.
|
|
If this is the last reference, then the managed ON_SubD is deleted.
|
|
*/
|
|
void Clear();
|
|
|
|
public:
|
|
class ON_SubDVertexIterator VertexIterator() const;
|
|
class ON_SubDEdgeIterator EdgeIterator() const;
|
|
class ON_SubDFaceIterator FaceIterator() const;
|
|
|
|
/*
|
|
Description:
|
|
Expert user function to have this ON_SubDRef manage the lifetime of subd.
|
|
Parameters:
|
|
subd - [in/out]
|
|
subd must point to an ON_SubD that was constructed on the heap using
|
|
an operator new call with a public ON_SubD constructor.
|
|
Returns:
|
|
a pointer to the managed subd or nullptr subd in not valid.
|
|
Example:
|
|
ON_SubD* subd = new ON_SubD(...);
|
|
ON_SubDRef subr;
|
|
ON_SubD* managed_subd = subdr.SetSubD(subd);
|
|
// subd = nullptr
|
|
// managed_subd = pointer you can use
|
|
*/
|
|
class ON_SubD* SetSubDForExperts(
|
|
class ON_SubD*& subd
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user function to have this ON_SubDRef reference the
|
|
contents of an existing ON_SubD.
|
|
Do not use if user data on the referenced subd needs to be accessed.
|
|
Parameters:
|
|
subd - [in]
|
|
Any subd on the heap or the stack.
|
|
Returns:
|
|
true if successful.
|
|
*/
|
|
static ON_SubDRef CreateReferenceForExperts(
|
|
const ON_SubD& subd
|
|
);
|
|
|
|
private:
|
|
/*
|
|
Description:
|
|
Expert user function to have this ON_SubDRef reference the
|
|
contents of an existing ON_SubD.
|
|
Do not use if user data on the referenced subd needs to be accessed.
|
|
Parameters:
|
|
subd - [in]
|
|
Any subd on the heap or the stack.
|
|
*/
|
|
ON_SubDRef(
|
|
const class ON_SubD& subd
|
|
);
|
|
|
|
private:
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
|
|
// C4251: ... needs to have dll-interface to be used by clients of class ...
|
|
// m_subd_sp is private and all code that manages m_subd_sp is explicitly implemented in the DLL.
|
|
private:
|
|
std::shared_ptr<class ON_SubD> m_subd_sp;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
};
|
|
|
|
|
|
#if defined(ON_DLL_TEMPLATE)
|
|
ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_SubDComponentAndNumber>;
|
|
#endif
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentList
|
|
//
|
|
class ON_CLASS ON_SubDComponentList
|
|
{
|
|
public:
|
|
ON_SubDComponentList() = default;
|
|
~ON_SubDComponentList() = default;
|
|
ON_SubDComponentList(const ON_SubDComponentList&);
|
|
ON_SubDComponentList& operator=(const ON_SubDComponentList&);
|
|
|
|
public:
|
|
static const ON_SubDComponentList Empty;
|
|
|
|
public:
|
|
unsigned CreateFromMarkedComponents(const ON_SubD& subd, bool bComponentInListMark);
|
|
unsigned CreateFromMarkedVertices(const ON_SubD& subd, bool bVertexInListMark);
|
|
unsigned CreateFromMarkedEdges(const ON_SubD& subd, bool bEdgeInListMark);
|
|
unsigned CreateFromMarkedFaces(const ON_SubD& subd, bool bFaceInListMark);
|
|
|
|
unsigned CreateFromComponentList(const ON_SubD& subd, const ON_SimpleArray<ON_COMPONENT_INDEX>& component_list);
|
|
unsigned CreateFromComponentList(const ON_SubD& subd, const ON_SimpleArray<ON_SubDComponentPtr>& component_list);
|
|
|
|
unsigned CreateFromVertexIdList(const ON_SubD& subd, const ON_SimpleArray<unsigned>& free_vertex_ids);
|
|
unsigned CreateFromVertexList(const ON_SubD& subd, const ON_SimpleArray<ON_SubDVertexPtr>& free_vertices);
|
|
unsigned CreateFromVertexList(const ON_SubD& subd, const ON_SimpleArray<const ON_SubDVertex*>& free_vertices);
|
|
|
|
void Destroy();
|
|
|
|
/*
|
|
Returns:
|
|
Number of removed components.
|
|
*/
|
|
unsigned int RemoveAllComponents();
|
|
|
|
/*
|
|
Returns:
|
|
Number of removed components.
|
|
*/
|
|
unsigned int RemoveAllVertices();
|
|
|
|
/*
|
|
Returns:
|
|
Number of removed components.
|
|
*/
|
|
unsigned int RemoveAllEdges();
|
|
|
|
/*
|
|
Returns:
|
|
Number of removed components.
|
|
*/
|
|
unsigned int RemoveAllFaces();
|
|
|
|
/*
|
|
Returns:
|
|
SubD runtime serial number.
|
|
*/
|
|
ON__UINT64 SubDRuntimeSerialNumber() const;
|
|
|
|
/*
|
|
Returns:
|
|
SubD content serial number when this list was created or the last
|
|
time UpdateContentSerialNumbers() was run.
|
|
*/
|
|
ON__UINT64 SubDGeometryContentSerialNumber() const;
|
|
|
|
/*
|
|
Returns:
|
|
SubD content serial number when this list was created or the last
|
|
time UpdateContentSerialNumbers() was run.
|
|
*/
|
|
ON__UINT64 SubDRenderContentSerialNumber() const;
|
|
|
|
unsigned int Count() const;
|
|
|
|
/*
|
|
operator[] returns ON_SubDComponentPtr::Null when index is out of bounds.
|
|
*/
|
|
const ON_SubDComponentPtr operator[](int) const;
|
|
const ON_SubDComponentPtr operator[](unsigned int) const;
|
|
const ON_SubDComponentPtr operator[](ON__INT64) const;
|
|
const ON_SubDComponentPtr operator[](ON__UINT64) const;
|
|
#if defined(ON_RUNTIME_APPLE)
|
|
const ON_SubDComponentPtr operator[](size_t) const;
|
|
#endif
|
|
|
|
const ON_SimpleArray< ON_SubDComponentPtr >& ComponentList() const;
|
|
|
|
const ON_SubD& SubD() const;
|
|
|
|
/*
|
|
Description:
|
|
Update the saved subd geometry and render content serial number to the current values
|
|
of SubD().GeometryContentSerialNumber() and SubD().RenderContentSerialNumber().
|
|
*/
|
|
void UpdateContentSerialNumbers();
|
|
|
|
/*
|
|
Description:
|
|
Change the component list to reference components in a different subd.
|
|
Parameters:
|
|
new_subd - [in]
|
|
subd to replace current referenced subd
|
|
bUpdateDeletedComponents - [in]
|
|
false: current components that are deleted will be ignored.
|
|
true: if the corresponding component in new_sub is not deleted, it
|
|
will be added to the list.
|
|
Returns:
|
|
Number of components in list after updating.
|
|
*/
|
|
unsigned int UpdateSubDForExperts(const ON_SubD& subd, bool bUpdateDeletedComponents);
|
|
|
|
|
|
private:
|
|
unsigned Internal_Create(
|
|
const ON_SubD& subd,
|
|
bool bAddVertices,
|
|
bool bAddEdges,
|
|
bool bAddFaces,
|
|
bool bComponentInListMark,
|
|
unsigned marked_component_count
|
|
);
|
|
|
|
unsigned Internal_RemoveComponents(
|
|
bool bRemoveVertices,
|
|
bool bRemoveEdges,
|
|
bool bRemoveFaces
|
|
);
|
|
|
|
private:
|
|
ON__UINT64 m_subd_runtime_serial_number = 0;
|
|
ON__UINT64 m_subd_geometry_content_serial_number = 0;
|
|
ON__UINT64 m_subd_render_content_serial_number = 0;
|
|
|
|
unsigned m_subd_vertex_count = 0;
|
|
unsigned m_subd_edge_count = 0;
|
|
unsigned m_subd_face_count = 0;
|
|
unsigned m_reserved = 0;
|
|
|
|
private:
|
|
ON_SubD m_subd; // keeps subd dimple in scope while m_component_list[] is active
|
|
ON_SimpleArray< ON_SubDComponentPtr > m_component_list;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentMarksClearAndRestore
|
|
//
|
|
class ON_SubDComponentMarksClearAndRestore
|
|
{
|
|
public:
|
|
// Constructor saves current component RuntimeMark() settings and then clears them.
|
|
ON_SubDComponentMarksClearAndRestore(
|
|
const ON_SubD& subd
|
|
);
|
|
|
|
// Destructor restores saved marks.
|
|
~ON_SubDComponentMarksClearAndRestore();
|
|
|
|
/*
|
|
Description:
|
|
Restore marks saved by the constructor.
|
|
Parameters:
|
|
bDisableFutureRestores - [in]
|
|
If true, no additional restores, including by the destructor, will occur.
|
|
*/
|
|
bool Restore(
|
|
bool bDisableFutureRestores
|
|
);
|
|
|
|
// Call DisableRestore() to prevent the destructor from restoring saved marks.
|
|
void DisableRestore();
|
|
|
|
const ON_SimpleArray< const class ON_SubDComponentBase* >& ComponentList() const;
|
|
|
|
private:
|
|
ON_SubD m_subd;
|
|
|
|
ON_SimpleArray< const class ON_SubDComponentBase* > m_component_list;
|
|
|
|
bool m_bRestore = true;
|
|
unsigned char m_reserved1 = 0;
|
|
unsigned char m_reserved2 = 0;
|
|
unsigned char m_reserved3 = 0;
|
|
unsigned int m_reserved4 = 0;
|
|
|
|
private:
|
|
ON_SubDComponentMarksClearAndRestore(const ON_SubDComponentMarksClearAndRestore&) = delete;
|
|
ON_SubDComponentMarksClearAndRestore& operator=(const ON_SubDComponentMarksClearAndRestore&) = delete;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDSectorType
|
|
//
|
|
class ON_CLASS ON_SubDSectorType
|
|
{
|
|
public:
|
|
ON_SubDSectorType() = default;
|
|
ON_SubDSectorType(const ON_SubDSectorType&) = default;
|
|
ON_SubDSectorType& operator=(const ON_SubDSectorType&) = default;
|
|
|
|
static const ON_SubDSectorType Empty;
|
|
|
|
bool IsValid() const;
|
|
|
|
unsigned int SectorTypeHash() const;
|
|
|
|
static int Compare(const ON_SubDSectorType*, const ON_SubDSectorType*);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sector Coefficients
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// In the comment below,
|
|
// F = number of faces in the sector,
|
|
// E = number of edges in the sector.
|
|
//
|
|
// There are five valid sector configurations of edges and faces. In all
|
|
// configurations, the edges have one end at the center vertex and the
|
|
// faces have one corner at the center vertex.
|
|
//
|
|
// SMOOTH
|
|
// 1) The center vertex is smooth.
|
|
// 2) F >= 2
|
|
// 3) E = F
|
|
// 4) Every edge is smooth.
|
|
// 5) Every edge is an edge of two different faces in the sector.
|
|
//
|
|
// DART
|
|
// 1) The center vertex is a dart.
|
|
// 2) F >= 2
|
|
// 3) E = F
|
|
// 4) One edge is a crease.
|
|
// 5) The crease edge is an edge of two geometrically adjacent sector faces.
|
|
//
|
|
// DART* (The same as "DART", but the crease edge has been duplicated.)
|
|
// 1) The center vertex is a dart.
|
|
// 2) F >= 2
|
|
// 3) E = F+1
|
|
// 4) Two edges are creases that have the same end locations.
|
|
// 5) Each crease edge is an edge of a single face in the sector,
|
|
// these faces are different and are geometrically adjacent.
|
|
//
|
|
// BOUNDED
|
|
// 1) The center vertex is a crease or corner vertex.
|
|
// 2) F >= 2
|
|
// 3) E = F+1
|
|
// 4) Two edges are crease edges that have different vertices at their ends.
|
|
// 5) Each crease edge is an edge of a single face in the sector,
|
|
// these faces are different and not geometrically adjacent.
|
|
//
|
|
// BOUNDED*
|
|
// 1) The center vertex is a crease or corner vertex.
|
|
// 2) F = 1
|
|
// 3) E = 2
|
|
// 4) The edges are crease edges that have different vertices at their ends.
|
|
// 5) The edges a edges of the face.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The sector weight is used when subdividing smooth edges in sectors
|
|
// with a DART, DART* or BOUNDED configuration. In these cases the
|
|
// sector weight is a value strictly between 0.0 and 1.0 that depends on
|
|
// 1) the center vertex tag (crease, corner or dart),
|
|
// 2) the value of F,
|
|
// 3) and when the center vertex is a corner, the angle between
|
|
// the boundary edges.
|
|
//
|
|
// The sector weight is ignored when dividing smooth edges in SMOOTH sectors.
|
|
// The sector weight is ignored when subdividing crease edges.
|
|
//
|
|
// For a smooth edge in a sector with a DART, DART* or BOUNDED configuration,
|
|
// with w = sector weight, C = location of the center vertex
|
|
// and P = location of the smooth vertex at the other end
|
|
// of the smooth edge, the point
|
|
//
|
|
// Q = 3/4 * (w*C + (1-w)*P)
|
|
//
|
|
// is the contribution of C and P to the edge's subdivision point.
|
|
//
|
|
// When a smooth edge has smooth vertices at both ends located
|
|
// at A and B, the contribution of A and B to the edge's subdivision
|
|
// point is
|
|
//
|
|
// Q = 3/8 * (A + B) = 3/4 * (1/2*A + 1/2*B)
|
|
//
|
|
// A crease edge's subdivision point is always the edge's midpoint.
|
|
/*
|
|
Description:
|
|
Calculates sector weight value for the sector type
|
|
identified by this ON_SubDSectorType.
|
|
Returns:
|
|
w: 0.0 <= w < 1.0
|
|
w = sector theta value.
|
|
ON_SubDSectorType::ErrorSectorCoefficient
|
|
This ON_SubDSectorType is not valid and the calculation failed.
|
|
*/
|
|
double SectorCoefficient() const;
|
|
|
|
|
|
unsigned int FacetEdgeCount() const;
|
|
|
|
ON_SubDVertexTag VertexTag() const;
|
|
|
|
|
|
unsigned int EdgeCount() const;
|
|
|
|
unsigned int FaceCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of points in the point ring.
|
|
For quad subds, this is 1 + FaceCount() + EdgeCount().
|
|
For tri subds, this is 1 + EdgeCount().
|
|
*/
|
|
unsigned int PointRingCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
1 + FaceCount() + EdgeCount()
|
|
*/
|
|
unsigned int ComponentRingCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
If the sector vertex tag is ON_SubDVertexTag::Corner,
|
|
the angle between the corner crease boundary edges is
|
|
returned.
|
|
Otherwise, ON_SubDSectorType::ErrorCornerSectorAngle is returned.
|
|
*/
|
|
double CornerSectorAngleRadians() const;
|
|
|
|
/*
|
|
Returns:
|
|
a value >= 0 and <= ON_SubDSectorType::MaximumCornerAngleIndex
|
|
*/
|
|
unsigned int CornerSectorAngleIndex() const;
|
|
|
|
/*
|
|
Description:
|
|
An angle index value of ON_SubDSectorType::MaximumCornerAngleIndex indicates
|
|
the angle is 2pi radians.
|
|
*/
|
|
enum : unsigned int
|
|
{
|
|
MaximumCornerAngleIndex = 72
|
|
};
|
|
|
|
// ON_SubDSectorType::MinimumCornerAngleRadians = (2.0*ON_PI)/((double)(ON_SubDSectorType::MaximumCornerAngleIndex));
|
|
static const double MinimumCornerAngleRadians;
|
|
|
|
// ON_SubDSectorType::MaximumCornerAngleRadians = 2.0*ON_PI - ON_SubDSectorType::MinimumCornerAngleRadians;
|
|
static const double MaximumCornerAngleRadians;
|
|
|
|
/*
|
|
Parameters:
|
|
angle_radians - [in] (0.0 <= angle_radians <= 2*ON_PI)
|
|
The angle between the bounding crease edges
|
|
Returns:
|
|
If angle_radians is valid input, then the value angle_index is returned.
|
|
The value angle_index is selected so that
|
|
(0 < angle_index < ON_SubDSectorType::MaximumCornerSectorIndex) and
|
|
fabs(angle_index*angle_quantum - angle_radians) is as small as possible, where
|
|
angle_quantum = (2.0*ON_PI)/ON_SubDSectorType::MaximumCornerSectorIndex.
|
|
Otherwise ON_UNSET_UINT_INDEX is returned.
|
|
*/
|
|
static unsigned int CornerAngleIndexFromCornerAngleRadians(
|
|
double angle_radians
|
|
);
|
|
|
|
/*
|
|
Convert and angle index into radians
|
|
Parameters:
|
|
corner_angle_index - [in]
|
|
0 to ON_SubDSectorType::MaximumCornerAngleIndex.
|
|
Returns:
|
|
If angle_index is valid, the corresponding angle in radians is returned.
|
|
= (angle_index / ((double)ON_SubDSectorType::MaximumCornerAngleIndex)) * ON_2PI
|
|
Otherwise ON_UNSET_VALUE is returned.
|
|
*/
|
|
static double AngleRadiansFromCornerAngleIndex(
|
|
unsigned int corner_angle_index
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
True if this is a smooth interior vertex sector
|
|
*/
|
|
bool IsSmoothSector() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
True if this is a dart interior vertex sector
|
|
*/
|
|
bool IsDartSector() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
True if this is a crease vertex sector
|
|
*/
|
|
bool IsCreaseSector() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this is a corner vertex sector
|
|
*/
|
|
bool IsCornerSector() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this is a convex corner vertex sector (sector angle <= pi)
|
|
*/
|
|
bool IsConvexCornerSector() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this is a concave corner vertex sector (sector angle > pi)
|
|
*/
|
|
bool IsConcaveCornerSector() const;
|
|
|
|
/*
|
|
Parameters:
|
|
sector_boundary_edge0_ptr - [in]
|
|
sector_boundary_edge1_ptr - [in]
|
|
Crease edges that bound the sector containing the smooth edge.
|
|
The edge direction must identify the corner vertex.
|
|
corner vertex = sector_boundary_edge0_ptr.RelativeVertex(0) = sector_boundary_edge1_ptr.RelativeVertex(0)
|
|
Returns:
|
|
tagged end angle for a smooth edge that
|
|
1) ends at a vertex tagged on ON_SubDVertexTag::Corner
|
|
2) has two adjacent faces.
|
|
3) lies in a sector bounded by 2 distinct crease edges.
|
|
*/
|
|
static double CornerSectorAngleRadiansFromEdges(
|
|
ON_SubDEdgePtr sector_boundary_edge0_ptr,
|
|
ON_SubDEdgePtr sector_boundary_edge1_ptr
|
|
);
|
|
|
|
static bool IsValidCornerSectorAngleRadians(
|
|
double corner_sector_angle_radians
|
|
);
|
|
|
|
static double ClampCornerSectorAngleRadians(
|
|
double corner_sector_angle_radians
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of subdivision points in a sector ring
|
|
facet_type vertex_tag ring count
|
|
tri smooth N+1
|
|
tri crease N+2
|
|
quad smooth 2N+1
|
|
quad crease 2N+2
|
|
(2 * valence + 1) for quad subds
|
|
(valence + 1) for tri subds
|
|
*/
|
|
static unsigned int SectorPointRingCountFromEdgeCount(
|
|
ON_SubDVertexTag vertex_tag,
|
|
unsigned int sector_edge_count
|
|
);
|
|
|
|
static unsigned int SectorPointRingCountFromFaceCount(
|
|
ON_SubDVertexTag vertex_tag,
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
static unsigned int SectorFaceCountFromEdgeCount(
|
|
ON_SubDVertexTag vertex_tag,
|
|
unsigned int sector_edge_count
|
|
);
|
|
|
|
static unsigned int SectorEdgeCountFromFaceCount(
|
|
ON_SubDVertexTag vertex_tag,
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
static unsigned int MinimumSectorEdgeCount(
|
|
ON_SubDVertexTag vertex_tag
|
|
);
|
|
|
|
static unsigned int MinimumSectorFaceCount(
|
|
ON_SubDVertexTag vertex_tag
|
|
);
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
ON_SubDSectorType::IgnoredSectorCoefficient
|
|
*/
|
|
static double SmoothSectorCoefficient();
|
|
|
|
/*
|
|
Parameters:
|
|
face_type - [in]
|
|
sector_face_count - [in]
|
|
number of faces in the smooth sector.
|
|
Returns:
|
|
0:
|
|
failed to caclulate weight
|
|
ON_SubDSectorType::UnsetSectorCoefficient:
|
|
This typically happens when a SubD control net is being
|
|
created and a facet type is not specified.
|
|
The weights will be calculated at the first subdivision.
|
|
0 < w < 1:
|
|
1/2 + 1/3*cos(tagged end angle) for quadrangle facets
|
|
1/3 + 1/3*cos(tagged end angle) for triangle facets
|
|
Remarks:
|
|
This is a useful tool when calling AddEdge while a subdivision
|
|
level is being constructed.
|
|
*/
|
|
static double CreaseSectorCoefficient(
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
static double DartSectorCoefficient(
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
static double CornerSectorCoefficient(
|
|
unsigned int sector_face_count,
|
|
double corner_sector_angle_radians
|
|
);
|
|
|
|
// This value is is used to set sector angles when the
|
|
// actual value is not needed. This occurs at both ends
|
|
// of a creased edge and when the end of a smooth edge
|
|
// is a smooth vertex.
|
|
static const double IgnoredCornerSectorAngle; // = 0.0;
|
|
|
|
// This value is used to set sector weights that could not be
|
|
// correctly set because something in the calculation failed.
|
|
// It is typically used when an invalid component in SubD object
|
|
// was needed to calculate the weight.
|
|
static const double UnsetCornerSectorAngle; // = -8881.0;
|
|
|
|
// This value is indicate a corner sector angle calculation failed.
|
|
static const double ErrorCornerSectorAngle; // = -9991.0;
|
|
|
|
|
|
// This value is used for smooth sector thetas
|
|
static const double SmoothSectorTheta; // = 0.5*ON_PI
|
|
|
|
// This value is used to indicate a sector theta needs to be set
|
|
static const double UnsetSectorTheta; // = -8882.0;
|
|
|
|
// This value is used to indicate a sector theta calculation failed.
|
|
static const double ErrorSectorTheta; // = -9992.0;
|
|
|
|
|
|
// This value is is used to set edge sector coefficients when the
|
|
// actual value is not needed. This occurs at both ends
|
|
// of a creased edge and when the end of a smooth edge
|
|
// is a smooth vertex.
|
|
static const double IgnoredSectorCoefficient; // = 0.0;
|
|
|
|
// This value is used to mark edge sector coefficients that need to be
|
|
// set in the future when more information is available.
|
|
// It is typically used when creating a subD control net
|
|
// and the facet type is not known. Any value < 0.0 and not
|
|
// equal to ON_UNSET_VALUE would work. The fact that the actual
|
|
// value is -999.0 has no other significance.
|
|
static const double UnsetSectorCoefficient; // = -8883.0;
|
|
|
|
// This value indicates an edge sector coefficient calculation failed.
|
|
static const double ErrorSectorCoefficient; // = -9993.0;
|
|
|
|
static bool IsValidSectorCoefficientValue(
|
|
double weight_value,
|
|
bool bAllowUnsetTaggedEndCoefficient
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
ON_SubDSectorType::ErrorSectorCoefficient and calls debug breakpoint
|
|
*/
|
|
static double SectorCoefficientCalculationError();
|
|
|
|
|
|
/*
|
|
Description:
|
|
Create a ON_SubDSectorType from a ON_SubDSectorIterator.
|
|
Parameters:
|
|
subd_type - [in]
|
|
vertex_tag - [in]
|
|
sector_face_count - [in]
|
|
Number of faces in the sector.
|
|
corner_sector_angle_radians - [in]
|
|
If vertex_tag is ON_SubDVertexTag::Corner, this
|
|
parameter is the angle between the crease edges
|
|
that bound the corner.
|
|
If vertex_tag is not ON_SubDVertexTag::Corner,
|
|
this parameter is ignored.
|
|
Returns:
|
|
An ON_SubDSectorType for the case the input parameters
|
|
identify.
|
|
*/
|
|
static ON_SubDSectorType Create(
|
|
ON_SubDVertexTag vertex_tag,
|
|
unsigned int sector_face_count,
|
|
double corner_sector_angle_radians
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Create a ON_SubDSectorType from a ON_SubDSectorIterator.
|
|
Parameters:
|
|
subd_type - [in]
|
|
sit - [in]
|
|
Returns:
|
|
An ON_SubDSectorType for the sector identified by sit.
|
|
*/
|
|
static ON_SubDSectorType Create(
|
|
const ON_SubDSectorIterator& sit
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Create a ON_SubDSectorType for the sector containing the face.
|
|
Parameters:
|
|
subd_type - [in]
|
|
face - [in]
|
|
face_vertex_index - [in]
|
|
face->Vertex(face_vertex_index) will be the sector's
|
|
center vertex.
|
|
Returns:
|
|
An ON_SubDSectorType for the sector containing the face.
|
|
*/
|
|
static ON_SubDSectorType Create(
|
|
const class ON_SubDFace* face,
|
|
unsigned int face_vertex_index
|
|
);
|
|
|
|
static ON_SubDSectorType Create(
|
|
const class ON_SubDFace* face,
|
|
const class ON_SubDVertex* vertex
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Create a ON_SubDSectorType for the sector containing the edge.
|
|
Parameters:
|
|
subd_type - [in]
|
|
edge - [in]
|
|
edge_vertex_index - [in]
|
|
edge->Vertex(edge_vertex_index) will be the sector's
|
|
center vertex.
|
|
Returns:
|
|
An ON_SubDSectorType for the sector containing the edge.
|
|
*/
|
|
static ON_SubDSectorType Create(
|
|
const class ON_SubDEdge* edge,
|
|
unsigned int edge_vertex_index
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Create a smooth ON_SubDSectorType.
|
|
Parameters:
|
|
subd_type - [in]
|
|
sector_face_count - [in]
|
|
Number of faces in the sector.
|
|
Returns:
|
|
An ON_SubDSectorType for the smooth sector case specified
|
|
by the input parameters.
|
|
*/
|
|
static ON_SubDSectorType CreateSmoothSectorType(
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Create a crease ON_SubDSectorType.
|
|
Parameters:
|
|
subd_type - [in]
|
|
sector_face_count - [in]
|
|
Number of faces in the sector.
|
|
Returns:
|
|
An ON_SubDSectorType for the crease sector case specified
|
|
by the input parameters.
|
|
*/
|
|
static ON_SubDSectorType CreateCreaseSectorType(
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Create a dart ON_SubDSectorType.
|
|
Parameters:
|
|
subd_type - [in]
|
|
sector_face_count - [in]
|
|
Number of faces in the sector.
|
|
Returns:
|
|
An ON_SubDSectorType for the dart sector case specified
|
|
by the input parameters.
|
|
*/
|
|
static ON_SubDSectorType CreateDartSectorType(
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Create a corner ON_SubDSectorType.
|
|
Parameters:
|
|
subd_type - [in]
|
|
sector_face_count - [in]
|
|
Number of faces in the sector.
|
|
corner_sector_angle_radians - [in]
|
|
The angle between the crease edges that bound the corner.
|
|
Returns:
|
|
An ON_SubDSectorType for the corner sector case specified
|
|
by the input parameters.
|
|
*/
|
|
static ON_SubDSectorType CreateCornerSectorType(
|
|
unsigned int sector_face_count,
|
|
double sector_corner_angle_radians
|
|
);
|
|
|
|
static int Compare(
|
|
const ON_SubDSectorType& a,
|
|
const ON_SubDSectorType& b
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get the subdivision matrix for the default subdivison algorithms
|
|
used by ON_SubD.
|
|
|
|
The matrix coefficents are ordered so that the matrix acts on
|
|
the left of the points returned by ON_SubDSectorIterator::GetVertexRing().
|
|
|
|
For an interior vertex (smooth or dart), the coefficents are ordered
|
|
so that one iteration of subdivision is given by:
|
|
S*Transpose(V, E[0], F[0], E[1], F[1], ..., E[N-1], F[N-1]).
|
|
For a dart vertex, E[0] is the point at the end of the creased edge.
|
|
|
|
|
|
For a boundary vertex (crease or corner), the coefficents are ordered
|
|
so that one iteration of subdivision is given by:
|
|
S*Transpose(V, E[0], F[0], E[1], F[1], ..., F[N-2], E[N-1]).
|
|
|
|
N = edge valence = number of edges in the sector.
|
|
E[i] = end of i-th edge radiating from V.
|
|
F[i] = point on the quad that is opposite V.
|
|
The edges and faces are ordered radially so that the face for F[i]
|
|
lies between the edges for E[i] and E[(i+1)%N].
|
|
|
|
Parameters:
|
|
S - [out]
|
|
subdivision matrix
|
|
Matrix coefficent (i,j) = S[i][j]
|
|
0 <= i < R, 0 <= j < R, R = ON_SubDSectorType.PointRingCount()
|
|
matrix_capacity - [in]
|
|
S[] can store any RxR matrix with R <= matrix_capacity.
|
|
|
|
Returns:
|
|
R > 0:
|
|
R = PointRingCount() and S is the RxR subdivision matrix for the sector type.
|
|
0: Invalid input
|
|
*/
|
|
unsigned int GetSubdivisionMatrix(
|
|
double** S,
|
|
size_t matrix_capacity
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
S - [out]
|
|
subdivision matrix.
|
|
Matrix coefficent (i,j) = S[i*R + j],
|
|
0 <= i < R, 0 <= j < R, R = ON_SubDSectorType.PointRingCount()
|
|
S_capacity - [in]
|
|
Number of elements in S[] array
|
|
Returns:
|
|
0: Invalid input.
|
|
>0: Number of rows and columns in S.
|
|
This number is always ON_SubDSectorType.PointRingCount().
|
|
*/
|
|
unsigned int GetSubdivisionMatrix(
|
|
double* S,
|
|
size_t S_capacity
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
All the subdivision matrices for the ON_SubD built-in
|
|
subdivision algorithms have eigenvalues (1, lambda1, lambda2, e4, ..., eR),
|
|
where 1 > lambda1 >= lambda2 > |e4| >= ... >= |eR| > 0.
|
|
|
|
The subdominant eigenvalue is lambda1 and,
|
|
with one exception, lambda1 = lambda2.
|
|
The exception is described in the description of
|
|
ON_SubDSectorType::SubdominantEigenvalueMulitiplicity().
|
|
|
|
Returns:
|
|
> 0.0:
|
|
The subdominant eigenvalue for the subdivision matrix.
|
|
|
|
ON_UNSET_VALUE:
|
|
This ON_SubDSectorType is not valid.
|
|
*/
|
|
double SubdominantEigenvalue() const;
|
|
|
|
/*
|
|
Returns:
|
|
0:
|
|
The sector type is not set.
|
|
|
|
2:
|
|
The subdominant eigenvalue has algebraic and geometric multiplicty = 2.
|
|
This is the most common case.
|
|
|
|
1:
|
|
The subdominant eigenvalue has algebraic and geometric multiplicty = 1.
|
|
This occures in Catmull-Clark subdivision at a crease vertex with
|
|
two crease edges and a single face. The subdivision matrix for this
|
|
case is
|
|
S is a 4 x 4 matrix with rows =
|
|
(3/4, 1/8, 0, 1/8),
|
|
(1/2, 1/2, 0, 0),
|
|
(1/4, 1/4, 1/4, 1/4),
|
|
(1/2, 0, 0, 1/2).
|
|
S has 4 real eigenvalues = (1, 1/2, 1/4, 1/4), all wtih
|
|
geometric multiplicity = 1.
|
|
The three eigenvectors are
|
|
(1, 1, 1, 1), (0, -1, 0, 1), (0, 0, 1, 0).
|
|
*/
|
|
unsigned int SubdominantEigenvalueMulitiplicity() const;
|
|
|
|
/*
|
|
Description:
|
|
With one exception, which is described below,
|
|
all the subdivision matrices for the ON_SubD built-in
|
|
subdivision algorithms have eigenvalues (1, lambda, lambda, e4, ..., eR),
|
|
where lambda is real, 1 > lambda > |e4| >= ... >= |eR| > 0, and the
|
|
geometric dimension of the lambda eigenspace is 2 (there are two
|
|
linearly independent lambda eigenvectors).
|
|
|
|
The subdominant eigenvalue is lamda. This function returns an
|
|
orthogonal basis, (E1, E2), for the subdominant eigenspace.
|
|
|
|
An eigenvector for the dominant eigen value 1 has is (1,1,...,1).
|
|
The domainant eignevector is orthogonal to the subdominant eigenspace.
|
|
|
|
Put another way,
|
|
0 = E1[0] + ... + E1[R-1]
|
|
0 = E2[0] + ... + E2[R-1]
|
|
0 = E1[0]*E2[0] + ... + E1[R-1]*E2[R-1]
|
|
|
|
Exceptional case:
|
|
The Catmull-Clark subdivision matrix for a crease vertex with
|
|
two crease edges and a single face is a special case.
|
|
In this exceptional, this function returns
|
|
lambda = 1/2, E1 = {0,-1,0,-1} and E2 = {1, -2, -5, -2}.
|
|
For more information about the exceptional case, see the description of
|
|
ON_SubDSectorType::SubdominantEigenvalueMulitiplicity().
|
|
|
|
Parameters:
|
|
E1_capacity - [in]
|
|
Capacity of the E1[] array.
|
|
E1 - [out]
|
|
E2_capacity - [in]
|
|
Capacity of the E2[] array.
|
|
E2 - [out]
|
|
When E1_capacity > 0 and E2_capacity > 0, two orthoganal eigenvectors
|
|
spanning the subdivision matrix subdominant eigenspace are returned
|
|
in E1[] and E2[].
|
|
If one of E1_capacity or E2_capacity is > 0, then both must be > 0.
|
|
|
|
Returns:
|
|
ON_UNSET_VALUE: Invalid input.
|
|
e > 0.0 and e < 1.0:
|
|
subdominant eigenvalue.
|
|
*/
|
|
double GetSubdominantEigenvectors(
|
|
double* E1,
|
|
size_t E1_capacity,
|
|
double* E2,
|
|
size_t E2_capacity
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
LPev_capacity - [in]
|
|
Capacity of the LPev[] array.
|
|
LPev - [out]
|
|
When LPev_capacity > 0, then the limit surface point evaluation coefficients are
|
|
returned in LPev[]. Otherwise LPev is ignored.
|
|
LT0ev_capacity - [in]
|
|
Capacity of the LPev[] array.
|
|
LT0ev - [out]
|
|
LT1ev_capacity - [in]
|
|
Capacity of the LPev[] array.
|
|
LT1ev - [out]
|
|
When LT0ev_capacity > 0 and LT1ev_capacity > 0, then the limit surface
|
|
tangent coefficients are returned in LT0ev[] and LT1ev[]. Otherwise,
|
|
LT0ev[] and LT1ev[] are ignored.
|
|
If one of LT0ev_capacity or LT1ev_capacity is > 0, then both must be > 0.
|
|
Returns:
|
|
0: Invalid input.
|
|
>0: Number of evaluation coefficients in the L*ev[] arrays.
|
|
This number is always ON_SubDSectorType.PointRingCount().
|
|
*/
|
|
unsigned int GetSurfaceEvaluationCoefficients(
|
|
double* LPev,
|
|
size_t LPev_capacity,
|
|
double* LT0ev,
|
|
size_t LT0ev_capacity,
|
|
double* LT1ev,
|
|
size_t LT1ev_capacity
|
|
) const;
|
|
|
|
// SurfaceNormalSign() is a debugging tool - slow and not useful in general
|
|
double SurfaceNormalSign() const;
|
|
|
|
bool SurfaceEvaluationCoefficientsAvailable() const;
|
|
|
|
/*
|
|
Parameters:
|
|
eigenvalues_capacity - [in]
|
|
Capacity of the eigenvalues[] array.
|
|
Must be 0 or >= PointRingCount()
|
|
eigenvalues - [out]
|
|
If 0 = eigenvalues_capacity, eigenvalues must be nullptr.
|
|
If eigenvalues_capacity > 0, is specifies the capactiy
|
|
of the eigenvalues[] array.
|
|
Returns:
|
|
R > 0:
|
|
A complete set of eigenvalues is available for this sector type.
|
|
The eigenvalues are (1, lambda, lambda, e3, ..., eR), where
|
|
1 > lambda > e3 >= ... >= eR > 0.
|
|
0:
|
|
Invalid input or the eigenvalues for this sector typoe are not available.
|
|
*/
|
|
unsigned int GetAllEigenvalues(
|
|
double* eigenvalues,
|
|
size_t eigenvalues_capacity
|
|
);
|
|
|
|
/////*
|
|
////Description:
|
|
//// The subdivision matrix for all cases is known.
|
|
//// A complete set of eigenvalues are available for some cases.
|
|
////Parameters:
|
|
//// facet_type - [in]
|
|
//// vertex_tag - [in]
|
|
//// sector_edge_count - [in]
|
|
//// The input parameters identify the subdivision case.
|
|
////Returns:
|
|
//// R > 0: Eigenvalues are known. There subdivison matrix is R x R.
|
|
//// 0: Eigenvalues for this case are not known.
|
|
////*/
|
|
////static unsigned int AllEigenvaluesAvailableKnown(
|
|
//// ON_SubDVertexTag vertex_tag,
|
|
//// unsigned int sector_edge_count
|
|
//// );
|
|
|
|
/*
|
|
Description:
|
|
Create a partial subdivison sector around vertex.
|
|
The resulting ON_SubD has an outer ring with smooth edges and vertices,
|
|
which is not valid as a stand-alone subd. This is typically used for
|
|
testing.
|
|
Parameters:
|
|
radius - [in]
|
|
The center vertex is located at (0,0,0),
|
|
If radius > 0.0, then the end of the first edge is at (radius,0,0),
|
|
subsequent edges are in a radial array and quad face points, if any,
|
|
are 2*radius from the origin.
|
|
sector_angle_radians - [in]
|
|
If radius > 0,
|
|
this->VertexTag() is ON_SubDVertexTag::Crease,
|
|
crease_sector_angle_radians > 0.0 and
|
|
crease_sector_angle_radians < 2.0*ON_PI,
|
|
then this will be the angle between the crease boundary edges.
|
|
In all other cases, crease_sector_angle_radians is ignored.
|
|
subd - [in]
|
|
If subd is not null, the vertex ring is put in this
|
|
subd.
|
|
Returns:
|
|
a pointer to the vertex ring
|
|
nullptr is returned if the input is not valid.
|
|
*/
|
|
ON_SubD* SectorRingSubD(
|
|
double radius,
|
|
double sector_angle_radians,
|
|
ON_SubD* subd
|
|
) const;
|
|
|
|
private:
|
|
ON_SubDVertexTag m_vertex_tag = ON_SubDVertexTag::Unset;
|
|
unsigned char m_reserved1 = 0;
|
|
unsigned short m_reserved2 = 0;
|
|
unsigned int m_hash = 0; // SetHash() sets this field, SectorTypeHash() returns its value.
|
|
unsigned int m_corner_sector_angle_index = 0; // >= 0 and <= ON_SubDSectorType::MaximumCornerAngleIndex
|
|
unsigned int m_sector_face_count = 0;
|
|
double m_sector_coefficient = 0.0;
|
|
double m_sector_theta = 0.0;
|
|
double m_corner_sector_angle_radians = 0.0;
|
|
|
|
private:
|
|
void SetHash();
|
|
|
|
/*
|
|
Description:
|
|
Calculates sector theta value for the sector type
|
|
identified by this ON_SubDSectorType.
|
|
Returns:
|
|
theta: 0.0 <= theta <= ON_PI
|
|
The sector theta value.
|
|
ON_SubDSectorType::ErrorSectorTheta
|
|
This ON_SubDSectorType is not valid and the calculation failed.
|
|
*/
|
|
double SectorTheta() const;
|
|
|
|
/*
|
|
Parameters:
|
|
sector_face_count - [in] >= 1
|
|
Number of faces in the crease sector.
|
|
Returns:
|
|
theta: 0.0 < theta <= ON_PI
|
|
sector theta value for a crease sector with sector_face_count faces.
|
|
ON_SubDSectorType::ErrorSectorTheta
|
|
sector_face_count is not valid and the calculation failed.
|
|
*/
|
|
static double CreaseSectorTheta(
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
sector_face_count - [in] >= 2
|
|
Number of faces in the dart sector.
|
|
Returns:
|
|
theta: 0.0 < theta <= ON_PI
|
|
sector theta value for a dart sector with sector_face_count faces.
|
|
ON_SubDSectorType::ErrorSectorTheta
|
|
sector_face_count is not valid and the calculation failed.
|
|
*/
|
|
static double DartSectorTheta(
|
|
unsigned int sector_face_count
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
sector_face_count - [in] >= 2
|
|
Number of faces in the dart sector.
|
|
corner_sector_angle_radians - [in] (0.0 <= corner_sector_angle_radians <= 2*ON_PI
|
|
The angle between the bounding crease edges
|
|
Returns:
|
|
theta: 0.0 < theta <= ON_PI/2
|
|
sector theta value for the corner sector.
|
|
ON_SubDSectorType::ErrorSectorTheta
|
|
sector_face_count or corner_sector_angle_radians were not valid
|
|
and the calculation failed.
|
|
*/
|
|
static double CornerSectorThetaFromCornerAngle(
|
|
unsigned int sector_face_count,
|
|
double corner_sector_angle_radians
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
sector_theta - [in] 0 < sector_theta <= 2*ON_PI
|
|
value from one of the sector theta functions.
|
|
ON_SubDEdge::SectorTheta()
|
|
ON_SubDEdge::SmoothSectorTheta()
|
|
ON_SubDEdge::CreaseSectorTheta()
|
|
ON_SubDEdge::CornerSectorTheta()
|
|
ON_SubDEdge::DartSectorTheta()
|
|
Returns:
|
|
0:
|
|
failed to caclulate weight
|
|
ON_SubDSectorType::ErrorSectorCoefficient:
|
|
sector_theta is not valid.
|
|
0 < w < 1:
|
|
The returned value is
|
|
1/2 + 1/3*cos(sector_angle_radians). (1/6 <= w <= 5/6)
|
|
Remarks:
|
|
This is a useful tool when calling AddEdge while a subdivision
|
|
level is being constructed.
|
|
*/
|
|
static double SectorCoefficientFromTheta(
|
|
double sector_theta
|
|
);
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDMeshFragment
|
|
//
|
|
// Meshes of ON_SubD limit surface are calculated in fragments.
|
|
//
|
|
class ON_CLASS ON_SubDMeshFragmentGrid
|
|
{
|
|
public:
|
|
// No construction for performance reasons.
|
|
// use = ON_SubDMeshFragmentGrid::Empty
|
|
// QuadGridFromSideSegmentCount(...)
|
|
// or QuadGridFromDisplayDensity(...) to initialize.
|
|
//
|
|
//ON_SubDMeshFragmentGrid() = default;
|
|
//~ON_SubDMeshFragmentGrid() = default;
|
|
//ON_SubDMeshFragmentGrid(const ON_SubDMeshFragmentGrid&) = default;
|
|
//ON_SubDMeshFragmentGrid& operator=(const ON_SubDMeshFragmentGrid&) = default;
|
|
|
|
|
|
static const ON_SubDMeshFragmentGrid Empty;
|
|
|
|
static const ON_SubDMeshFragmentGrid OneQuadGrid;
|
|
|
|
/*
|
|
Description:
|
|
Get mesh facet quads that index into a grid of points.
|
|
Parameters:
|
|
side_segment_count - [in]
|
|
number quads in each row and column of the quad grid.
|
|
side_segment_count >= 1
|
|
side_segment_count <= ON_SubDMesh::MaximumSideSegmentCount
|
|
side_segment_count must be a power of 2
|
|
|
|
mesh_density_reduction - [in]
|
|
0: quad count = maximum quad count = (side_count x side_count)
|
|
1: quad count = 1/4 maximum quad count
|
|
1: quad count = 1/16 maximum quad count
|
|
...
|
|
If 4^mesh_density_reduction > maximum quad count, then a single quad is returned.
|
|
*/
|
|
static ON_SubDMeshFragmentGrid QuadGridFromSideSegmentCount(
|
|
unsigned int side_segment_count,
|
|
unsigned int mesh_density_reduction
|
|
);
|
|
|
|
static ON_SubDMeshFragmentGrid QuadGridFromDisplayDensity(
|
|
unsigned int display_density,
|
|
unsigned int mesh_density_reduction
|
|
);
|
|
|
|
private:
|
|
/*
|
|
Description:
|
|
Get mesh facet quads that index into a grid of points.
|
|
Parameters:
|
|
side_segment_count - [in]
|
|
number quads in each row and column of the quad grid
|
|
with the highest level of detail (level_of_detail = 0)
|
|
side_count must be a power of 2
|
|
level_of_detail - [in]
|
|
Desired level of detail of the returned grid
|
|
0: highest (side_count x side_count) quads
|
|
1: 1/4 density (side_count x side_count)/4 quads
|
|
2: 1/16 density (side_count x side_count)/16 quads
|
|
...
|
|
side_count-2: 4 quads
|
|
side_count-1: 1 quad
|
|
>= side_count: 1 quad
|
|
Returns:
|
|
Number of quads in the grid.
|
|
*/
|
|
static unsigned int SetQuads(
|
|
unsigned int side_segment_count,
|
|
unsigned int level_of_detail,
|
|
unsigned int* quads,
|
|
size_t quad_capacity,
|
|
size_t quad_stride,
|
|
unsigned int* sides,
|
|
size_t side_capacity,
|
|
size_t side_stride
|
|
);
|
|
|
|
public:
|
|
unsigned int SideSegmentCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
SideSegmentCount() + 1;
|
|
*/
|
|
unsigned int SidePointCount() const;
|
|
|
|
/*
|
|
Description:
|
|
The GridId() is persistent and unique based on the contents of the
|
|
grid. It is intended to be used in render applications that store
|
|
copies of ON_SubDMeshFragmentGrid settings in things like
|
|
vertex object buffers and want a reliable way to index into them.
|
|
The Empty grid has id = 0;
|
|
Returns:
|
|
0:
|
|
when the grid is empty
|
|
32*n + 2*lod + t:
|
|
t = 0 for quads and 1 for tris,
|
|
(0 <= n <= 8) m_F_count = 2^(2n),
|
|
(0 <= lod <= 8) m_F_level_of_detail = lod
|
|
Remarks:
|
|
m_F_count is always
|
|
*/
|
|
unsigned int GridId() const;
|
|
|
|
|
|
unsigned int GridFaceCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Total number of points in the grid = SidePointCount()*SidePointCount().
|
|
*/
|
|
unsigned int GridPointCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_point_index - [in]
|
|
0 <= grid_point_index < GridPointCount().
|
|
grid_parameters = [out]
|
|
g2dex = Grid2dexFromPointIndex(grid_point_index).
|
|
grid_parameters[] = {g2dex.i/SideSegmentCount(), g2dex.j/SideSegmentCount()}
|
|
Returns:
|
|
True if grid_point_index was valid and grid_parameters was returned.
|
|
Remarks:
|
|
On a SubD quad face,
|
|
face->Vertex(0), face->Vertex(1), face->Vertex(2), face->Vertex(3)
|
|
are the SubD quad corners in counter-clockwise order.
|
|
When a grid comes from a SubD quad face, the associated grid parameters are:
|
|
grid_parameters[] = (0,0) at face->Vertex(0),
|
|
grid_parameters[] = (1,0) at face->Vertex(1),
|
|
grid_parameters[] = (0,1) at face->Vertex(3),
|
|
grid_parameters[] = (1,1) at face->Vertex(2),
|
|
*/
|
|
bool GetGridParameters(
|
|
unsigned int grid_point_index,
|
|
double grid_parameters[2]
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_point_index - [in]
|
|
0 <= grid_point_index < GridPointCount().
|
|
Returns:
|
|
Grid (i,j) for that grid_point_index.
|
|
0 <= i < SidePointCount()
|
|
0 <= j < SidePointCount()
|
|
Remarks:
|
|
On a SubD quad face,
|
|
face->Vertex(0), face->Vertex(1), face->Vertex(2), face->Vertex(3)
|
|
are the SubD quad corners in counter-clockwise order.
|
|
|
|
Set
|
|
n = grid->GridPointCount()-1 and
|
|
k = grid->SideSegmentCount() = (grid->SidePointCount()-1).
|
|
Note that (k+1)*(k+1) = (n+1) = GridPointCount().
|
|
|
|
When a grid comes from a SubD quad face, the associated grid point indices are
|
|
|
|
vertex, grid point index, grid point 2dex
|
|
face->Vertex(0), 0, (0,0)
|
|
face->Vertex(1), k, (k,0)
|
|
face->Vertex(2), n-k, (k,k)
|
|
face->Vertex(3), n, (0,k)
|
|
*/
|
|
const ON_2udex Grid2dexFromPointIndex(
|
|
unsigned int grid_point_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
i - [in]
|
|
0 <= i < SidePointCount()
|
|
j - [in]
|
|
0 <= j < SidePointCount()
|
|
Returns:
|
|
0 <= grid_point_index < GridPointCount().
|
|
Remarks:
|
|
On a SubD quad face,
|
|
face->Vertex(0), face->Vertex(1), face->Vertex(2), face->Vertex(3)
|
|
are the SubD quad corners in counter-clockwise order.
|
|
|
|
Set
|
|
n = grid->GridPointCount()-1 and
|
|
k = grid->SideSegmentCount() = (grid->SidePointCount()-1).
|
|
Note that (k+1)*(k+1) = (n+1) = GridPointCount().
|
|
|
|
When a grid comes from a SubD quad face, the associated grid point indices are
|
|
|
|
vertex, grid point index, grid point 2dex
|
|
face->Vertex(0), 0, (0,0)
|
|
face->Vertex(1), k, (k,0)
|
|
face->Vertex(2), n-k, (k,k)
|
|
face->Vertex(3), n, (0,k)
|
|
*/
|
|
unsigned int PointIndexFromGrid2dex(
|
|
unsigned int i,
|
|
unsigned int j
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
A number between 0 and 8 or ON_UNSET_INT_INDEX.
|
|
SideSegmentCount() = 2^DisplayDensity().
|
|
*/
|
|
unsigned int DisplayDensity() const;
|
|
|
|
ON_DEPRECATED_MSG("Identical to DisplayDensityReduction(). Use DisplayDensityReduction() instead because its a better name.")
|
|
unsigned int LevelOfDetail() const;
|
|
|
|
/*
|
|
Description
|
|
Each grid set has grids of quads that index the identical set of points (normals, texture coordinates, ...).
|
|
The grid in the set with the maximum number of quads has DisplayDensityReduction() = 0.
|
|
Additional grids in the set reduce the number of quads by a factor of 4.
|
|
The intedger on the left is the DisplayDensityReduction value. The value of the right
|
|
is the number of quads where M = maximum quad count for that grid set.
|
|
All nonzero values of M are powers of 4 (4^n). The relationship between
|
|
P = number of points in the set and M (the maximum number of quads for the point set)
|
|
is P = (M/2+1)*(M/2+1).
|
|
|
|
DisplayDensityReduction(): number of quads
|
|
0: M
|
|
1: M/4
|
|
2: M/16
|
|
3: M/64
|
|
4: M/256
|
|
...
|
|
|
|
Returns:
|
|
The display density reduction from the maximum display density for this grid set.
|
|
*/
|
|
unsigned int DisplayDensityReduction() const;
|
|
|
|
private:
|
|
unsigned char m_reserved;
|
|
|
|
public:
|
|
unsigned char m_reserved1 = 0;
|
|
unsigned char m_side_segment_count; // = 2^n for non-empty grids (0 <= n <= 8)
|
|
|
|
// m_F_count = number of quads
|
|
// = m_side_segment_count*m_side_segment_count
|
|
// (0,1,4,16,256,1024,4096) Afer 0, each permitted value is 4x previous value
|
|
unsigned short m_F_count;
|
|
|
|
// m_F_level_of_detail is poorly named. It should be named m_F_mesh_density_reduction.
|
|
// 0 = no reduction (maximum level of detail)
|
|
// 1 = number of quads reduced by 1/4
|
|
// 2 = number of quads reduced by 1/16
|
|
// ...
|
|
unsigned short m_F_level_of_detail;
|
|
|
|
unsigned short m_F_stride;
|
|
const unsigned int* m_F;
|
|
const unsigned int* m_S; // [4*m_side_segment_count + 1] indices that form the polyline boundary.
|
|
const ON_SubDMeshFragmentGrid* m_prev_level_of_detail; // nullptr or the previous level with 4 times the number of quads.
|
|
const ON_SubDMeshFragmentGrid* m_next_level_of_detail; // nullptr or the next level with 1/4 times the number of quads.
|
|
};
|
|
|
|
class ON_CLASS ON_SubDMeshFragment
|
|
{
|
|
public:
|
|
// No construction for performance reasons.
|
|
// If you require initialization, use = ON_SubDMeshFragment::Empty
|
|
//
|
|
//ON_SubDMeshFragment() = default;
|
|
//~ON_SubDMeshFragment() = default;
|
|
//ON_SubDMeshFragment(const ON_SubDMeshFragment&) = default;
|
|
//ON_SubDMeshFragment& operator=(const ON_SubDMeshFragment&) = default;
|
|
|
|
bool CopyFrom( const ON_SubDMeshFragment& src_fragment );
|
|
|
|
/*
|
|
Parameters:
|
|
src_fragment - [in]
|
|
fragment to copy
|
|
display_density - [in]
|
|
The desired display density of the copy.
|
|
|
|
If display_density = ON_UNSET_UINT_INDEX, then this->m_P_capacity must
|
|
be at least srf_fragment.m_P_count, all points are copied, and
|
|
this->m_grid = srf_fragment.m_grid.
|
|
|
|
Otherwise, src_fragment must have enough points to provide
|
|
the specified denisity and this must have enough
|
|
point capacity to store the specified density.
|
|
|
|
this - [out]
|
|
This must have a point capacity large enough to accomodate the
|
|
requested display density.
|
|
|
|
*/
|
|
bool CopyFrom(
|
|
const ON_SubDMeshFragment& src_fragment,
|
|
unsigned int display_density
|
|
);
|
|
|
|
// Every field of ON_SubDMeshFragment::Empty is zero.
|
|
static const ON_SubDMeshFragment Empty;
|
|
|
|
enum : unsigned int
|
|
{
|
|
MaximumSideSegmentCount = (1U << ON_SubDDisplayParameters::MaximumDensity)
|
|
};
|
|
|
|
/*
|
|
Returns:
|
|
side_segment_count = 2^display_density
|
|
*/
|
|
static unsigned int SideSegmentCountFromDisplayDensity(
|
|
unsigned int display_density
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
base 2 log of side_segment_count.
|
|
Remarks:
|
|
side_segment_count = 2^display_density
|
|
*/
|
|
static unsigned int DisplayDensityFromSideSegmentCount(
|
|
unsigned int side_segment_count
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
display_density - [in]
|
|
>= 0
|
|
Returns:
|
|
total number of points in the limit mesh fragment.
|
|
Remarks:
|
|
The number of points is the same for quad or tri subdivision limit
|
|
mesh fragments, even though one is a rectanglular collection of
|
|
quads and the other is a trianglular collection of triangles.
|
|
*/
|
|
static unsigned int PointCountFromDisplayDensity(
|
|
unsigned int display_density
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
display_density - [in]
|
|
>= 0
|
|
Returns:
|
|
total number of faces in the limit mesh fragment.
|
|
*/
|
|
static unsigned int FaceCountFromDisplayDensity(
|
|
unsigned int display_density
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
true if side_segment_count is valid.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
static bool SideSegmentCountIsValid(
|
|
unsigned int side_segment_count
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
If side_segment_count is valide, then (side_segment_count+1) is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
static unsigned int SidePointCountFromSideCount(
|
|
unsigned int side_segment_count
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
If side_segment_count is valide, then (side_segment_count+1)^2 is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
static unsigned int QuadGridPointCountFromSideCount(
|
|
unsigned int side_segment_count
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
If side_segment_count is valide, then side_segment_count^2 is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
static unsigned int QuadGridQuadCountFromSideCount(
|
|
unsigned int side_segment_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Copies location and optionally normal information from a side of src_fragment
|
|
to a side of dst_fragment. This is often used for "sealing" adjacent fragments
|
|
where the same edge is evaluated from different faces. All evaluations are as accurate
|
|
as IEEE double precision arithmetic can produce. However there are often tiny differences
|
|
(last few bits of the coordinate values differ) in vertext locations because we are
|
|
using finite precision arithmetic with operations in different orders.
|
|
In general, rendering, mesho topology, and edge analysis calculations perform poorly
|
|
when tinity differences exist.
|
|
|
|
Parameters:
|
|
bTestNearEqual - [in]
|
|
If true, then the copy is performed only when the points or normals are nearly
|
|
identical. In this case if the discrepance between coordinates is too large,
|
|
then this function returns false.
|
|
bCopyNormals - [in]
|
|
If true, then normal information is copied along with point information.
|
|
src_fragment - [in]
|
|
source fragment
|
|
i0, i1 - [in]
|
|
indices for the src_fragment.m_S[] array.
|
|
dst_fragment - [in]
|
|
destination fragment
|
|
j0, j1 - [in]
|
|
indices for dst_fragment.m_S[] array.
|
|
abs(j0-j1) = abs(i0-i1);
|
|
Remarks:
|
|
It is required that max(i0,i1) - min(i0,i1) = max(j0,j1) - min(j0,j1) and
|
|
all indices are valid for the respective fragments.
|
|
The src_fragment point/normal identified by src_fragment.m_S[i]
|
|
is copied to he dst_fragment point/normal identified by dst_fragment.m_S[j],
|
|
where i0->j0, i1->j1.
|
|
*/
|
|
static bool SealAdjacentSides(
|
|
bool bTestNearEqual,
|
|
bool bCopyNormals,
|
|
const ON_SubDMeshFragment& src_fragment,
|
|
unsigned int i0,
|
|
unsigned int i1,
|
|
ON_SubDMeshFragment& dst_fragment,
|
|
unsigned int j0,
|
|
unsigned int j1
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
bTestNearEqual - [in]
|
|
If true, then the copy is performed only when the points or normals are nearly
|
|
identical. In this case if the discrepance between coordinates is too large,
|
|
then this function returns false.
|
|
src - [in]
|
|
dst - [in/out]
|
|
The 3d point (src[0],src[1],src2[2]) is copied to (dst[0],dst[1],dst[2]).
|
|
Returns:
|
|
True if a copy occured.
|
|
*/
|
|
static bool SealPoints(
|
|
bool bTestNearEqual,
|
|
const double* src,
|
|
double* dst
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
bTestNearEqual - [in]
|
|
If true, then the copy is performed only when the points or normals are nearly
|
|
identical. In this case if the discrepance between coordinates is too large,
|
|
then this function returns false.
|
|
src - [in]
|
|
dst - [in/out]
|
|
The 3d point (src[0],src[1],src2[2]) is copied to (dst[0],dst[1],dst[2]).
|
|
Returns:
|
|
True if a copy occured.
|
|
*/
|
|
static bool SealNormals(
|
|
bool bTestNearEqual,
|
|
const double* src,
|
|
double* dst
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of mesh quads in a full sized fragment with the specified mesh density.
|
|
*/
|
|
static unsigned int FullFragmentMeshQuadCountFromDensity(
|
|
unsigned int mesh_density
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of mesh quads in a half sized fragment with the specified mesh density.
|
|
*/
|
|
static unsigned int HalfFragmentMeshQuadCountFromDensity(
|
|
unsigned int mesh_density
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of mesh points in a full sized fragment with the specified mesh density.
|
|
*/
|
|
static unsigned int FullFragmentMeshPointCountFromDensity(
|
|
unsigned int mesh_density
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Number of mesh points in a half sized fragment with the specified mesh density.
|
|
*/
|
|
static unsigned int HalfFragmentMeshPointCountFromDensity(
|
|
unsigned int mesh_density
|
|
);
|
|
|
|
private:
|
|
// This field overlaps with ON_FixedSizePoolElement.m_next when a fixed size pool is managing the fragments.
|
|
// When m_reserved != 0, the framgment is uninitialized.
|
|
ON__UINT64 m_reserved;
|
|
|
|
public:
|
|
const class ON_SubDFace* m_face;
|
|
|
|
// m_face_vertex_index[] stores the information needed for the Vertex()
|
|
// and Edge() functions to work.
|
|
//
|
|
// If m_face is nullptr, then m_face_vertex_index[] has no meaning.
|
|
// If m_face is not nullptr and a corner of the grid is on a face
|
|
// vertex, then the corresponding m_face_vertex_index[] value
|
|
// will be <= ON_SubDFace::MaximumEdgeCount and m_face->Vertex(m_face_vertex_index[])
|
|
// is the vertex. Otherwise, the corresponding m_face_vertex_index[] value
|
|
// will be > ON_SubDFace::MaximumEdgeCount.
|
|
// Catmull-Clark limit meshes:
|
|
// When the original SubD face is a quad, a full fragment is created and
|
|
// m_face_vertex_index[4] = {0,1,2,3}.
|
|
// When the original SuD face is an N-gon with N != 4, a partial fragment
|
|
// is delivered and m_face_vertex_index[2] identifies the face vertex
|
|
// for that fragment. m_face_vertex_index[0,1,3] = a value > ON_SubDFace::MaximumEdgeCount
|
|
unsigned short m_face_vertex_index[4];
|
|
|
|
const class ON_SubDFace* SubDFace() const;
|
|
|
|
const bool HasValidPointAndNormalGrid() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the fragment covers the entire SubD face.
|
|
*/
|
|
bool IsFullFaceFragment() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the fragment covers a corner of the SubD face.
|
|
*/
|
|
bool IsFaceCornerFragment() const;
|
|
|
|
/*
|
|
Returns:
|
|
If IsFaceCornerFragment() is true, then the index of the face's vertex for the corner is returned.
|
|
Otherwise, ON_UNSET_UINT_INDEX is returned.
|
|
*/
|
|
unsigned int FaceCornerIndex() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of fragments that cover this face. 1 for quads and N>= 3 for faces with N sides when N != 4.
|
|
*/
|
|
unsigned int FaceFragmentCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
First fragment for this->m_face.
|
|
*/
|
|
const ON_SubDMeshFragment* FirstFaceFragment() const;
|
|
|
|
/*
|
|
Returns:
|
|
Last fragment for this->m_face.
|
|
*/
|
|
const ON_SubDMeshFragment* LastFaceFragment() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bReturnLastFromFirstFirst - in
|
|
If false and this is the first fragment, then nullptr is returned.
|
|
If true and this is the first fragment, then LastFaceFragment() is returned.
|
|
Returns:
|
|
Previous fragment for this->m_face.
|
|
*/
|
|
const ON_SubDMeshFragment* PreviousFaceFragment(
|
|
bool bReturnLastFromFirstFirst
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
bReturnFirstFromLast - in
|
|
If false and this is the last fragment, then nullptr is returned.
|
|
If true and this is the last fragment, then FirstFaceFragment() is returned.
|
|
Returns:
|
|
Next fragment for this->m_face.
|
|
*/
|
|
const ON_SubDMeshFragment* NextFaceFragment(
|
|
bool bReturnFirstFromLast
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
fragments_capacity - in
|
|
Capacity of the fragments[] array.
|
|
fragments[] - out
|
|
Fragments are returned here.
|
|
*/
|
|
unsigned int GetFaceFragments(
|
|
const ON_SubDMeshFragment** fragments,
|
|
size_t fragments_capacity
|
|
) const;
|
|
|
|
unsigned int GetFaceFragments(
|
|
ON_SimpleArray<const ON_SubDMeshFragment*>& fragments
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid2dex_i - [in]
|
|
0 <= grid2dex_i < m_grid.SidePointCount()
|
|
grid2dex_j - [in]
|
|
0 <= grid2dex_j < m_grid.SidePointCount()
|
|
Returns:
|
|
*/
|
|
const ON_3dPoint VertexPoint(
|
|
unsigned grid2dex_i,
|
|
unsigned grid2dex_j
|
|
) const;
|
|
const ON_3dPoint VertexPoint(
|
|
ON_2udex grid2dex
|
|
) const;
|
|
const ON_3dPoint VertexPoint(
|
|
unsigned grid_point_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid2dex_i - [in]
|
|
0 <= grid2dex_i < m_grid.SidePointCount()
|
|
grid2dex_j - [in]
|
|
0 <= grid2dex_j < m_grid.SidePointCount()
|
|
Returns:
|
|
*/
|
|
const ON_3dVector VertexNormal(
|
|
unsigned grid2dex_i,
|
|
unsigned grid2dex_j
|
|
) const;
|
|
const ON_3dVector VertexNormal(
|
|
ON_2udex grid2dex
|
|
) const;
|
|
const ON_3dVector VertexNormal(
|
|
unsigned grid_point_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid2dex_i - [in]
|
|
0 <= grid2dex_i < m_grid.SidePointCount()
|
|
grid2dex_j - [in]
|
|
0 <= grid2dex_j < m_grid.SidePointCount()
|
|
Returns:
|
|
The texture coordinates calculated by iterpolating the m_ctrlnetT[] values.
|
|
*/
|
|
const ON_3dPoint VertexTextureCoordinateFromCorners(
|
|
unsigned grid2dex_i,
|
|
unsigned grid2dex_j
|
|
) const;
|
|
const ON_3dPoint VertexTextureCoordinateFromCorners(
|
|
ON_2udex grid2dex
|
|
) const;
|
|
const ON_3dPoint VertexTextureCoordinateFromCorners(
|
|
unsigned grid_point_index
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the texture coordinate for the specified fragment grid point.
|
|
Parameters:
|
|
grid2dex_i - [in]
|
|
0 <= grid2dex_i < m_grid.SidePointCount()
|
|
grid2dex_j - [in]
|
|
0 <= grid2dex_j < m_grid.SidePointCount()
|
|
Returns:
|
|
The texture coordinate for the specified fragment grid point.
|
|
TextureCoordinateDimension() reports the number of coordinates to set.
|
|
When it is 2, the z coordinate of the returned point is 0.0.
|
|
*/
|
|
const ON_3dPoint VertexTextureCoordinate(
|
|
unsigned grid2dex_i,
|
|
unsigned grid2dex_j
|
|
) const;
|
|
const ON_3dPoint VertexTextureCoordinate(
|
|
ON_2udex grid2dex
|
|
) const;
|
|
const ON_3dPoint VertexTextureCoordinate(
|
|
unsigned grid_point_index
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Set the texture coordinate for the specified fragment grid point.
|
|
Parameters:
|
|
grid2dex_i - [in]
|
|
0 <= grid2dex_i < m_grid.SidePointCount()
|
|
grid2dex_j - [in]
|
|
0 <= grid2dex_j < m_grid.SidePointCount()
|
|
unsigned texture_coordinate_dimension - [in]
|
|
2 or 3
|
|
texture_coordinate - [in]
|
|
Texture coordinates are mutable and are often modified on an otherwise const fragment.
|
|
Returns:
|
|
True if input was valid and the texture coordinate was set.
|
|
*/
|
|
bool SetVertexTextureCoordinate(
|
|
unsigned grid2dex_i,
|
|
unsigned grid2dex_j,
|
|
ON_3dPoint texture_coordinate
|
|
) const;
|
|
bool SetVertexTextureCoordinate(
|
|
ON_2udex grid2dex,
|
|
ON_3dPoint texture_coordinate
|
|
) const;
|
|
bool SetVertexTextureCoordinate(
|
|
unsigned grid_point_index,
|
|
ON_3dPoint texture_coordinate
|
|
) const;
|
|
|
|
bool TextureCoordinatesExist() const;
|
|
void SetTextureCoordinatesExist(bool bTextureCoordinatesExist) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_side_index - [in]
|
|
0 to 3 for quad grids.
|
|
0 to 2 for tri grids
|
|
Returns:
|
|
The subd edge that is on the identified side of the grid.
|
|
*/
|
|
const class ON_SubDEdgePtr SubDEdgePtr(
|
|
unsigned int grid_side_index
|
|
) const;
|
|
const class ON_SubDEdge* SubDEdge(
|
|
unsigned int grid_side_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
0, 1, 2, or 3
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const class ON_SubDVertexPtr SubDVertexPtr(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
0, 1, 2, or 3
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const class ON_SubDVertex* SubDVertex(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
0, 1, 2, or 3
|
|
Returns:
|
|
Limit surface location at the grid corner or ON_3dPoint::NanPoint if the fragment is empty.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_3dPoint CornerPoint(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
0, 1, 2, or 3
|
|
Returns:
|
|
Limit surface normal at the grid corner or ON_3dPoint::NanPoint if the fragment is empty.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_3dVector CornerNormal(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
grid side N is between corner index N and corner index (N+1)%4.
|
|
Returns:
|
|
Limit surface frame at the grid corner or ON_3dPoint::NanPoint if the fragment is empty.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_Plane CornerFrame(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
0, 1, 2, or 3
|
|
Returns:
|
|
vertex color at the grid corner or ON_Color::UnsetColor if thre are not vertex colors.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_Color CornerColor(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
0, 1, 2, or 3
|
|
Returns:
|
|
vertex surface curvature at the grid corner or ON_SurfaceCurvature::Nan if there are not vertex curvatures.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_SurfaceCurvature CornerCurvature(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
grid_side_index - [in]
|
|
grid side N is between corner index N and corner index (N+1)%4.
|
|
Returns:
|
|
Limit surface location at the midde of the grid side or ON_3dPoint::NanPoint if the fragment is empty.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_3dPoint SidePoint(
|
|
unsigned int grid_side_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_side_index - [in]
|
|
grid side N is between corner index N and corner index (N+1)%4.
|
|
Returns:
|
|
Limit surface normal at the grid corner or ON_3dPoint::NanPoint if the fragment is empty.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_3dVector SideNormal(
|
|
unsigned int grid_side_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_side_index - [in]
|
|
grid side N is between corner index N and corner index (N+1)%4.
|
|
Returns:
|
|
Limit surface frame at the grid corner or ON_3dPoint::NanPoint if the fragment is empty.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_Plane SideFrame(
|
|
unsigned int grid_side_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
grid_side_index - [in]
|
|
grid side N is between corner index N and corner index (N+1)%4.
|
|
Returns:
|
|
Limit surface location at the center of the grid side or ON_3dPoint::NanPoint if the fragment is empty.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_3dPoint CenterPoint(
|
|
) const;
|
|
|
|
const ON_3dVector CenterNormal() const;
|
|
|
|
const ON_Plane CenterFrame() const;
|
|
|
|
const ON_3dPoint CenterTextureCoordinate() const;
|
|
|
|
private:
|
|
bool Internal_GetFrameHelper(
|
|
unsigned int P_dex,
|
|
unsigned int Q_dex,
|
|
ON_Plane& frame
|
|
) const;
|
|
|
|
public:
|
|
|
|
/*
|
|
Returns:
|
|
Status of the face.
|
|
*/
|
|
ON_ComponentStatus Status() const;
|
|
|
|
bool Transform(
|
|
const ON_Xform& xform
|
|
);
|
|
|
|
ON_SubDMeshFragment* m_next_fragment;
|
|
ON_SubDMeshFragment* m_prev_fragment;
|
|
|
|
unsigned short m_face_fragment_count; // Number of fragments that will be delivered for this face.
|
|
unsigned short m_face_fragment_index; // First fragment has index = 0. Last fragment has index = m_face_fragment_count-1.
|
|
|
|
// The mesh fragment is a grid of quads.
|
|
// There are m_side_count quad edges along each side of the tesselation,
|
|
// There are a total of m_side_count X m_side_count quads, and
|
|
// m_P_count = (m_side_count+1)*(m_side_count+1).
|
|
|
|
public:
|
|
enum : unsigned
|
|
{
|
|
/// <summary>
|
|
/// 64x64 grid of points
|
|
/// </summary>
|
|
MaximumVertexCount = 0x1000
|
|
};
|
|
|
|
/*
|
|
Returns:
|
|
Number of vertices in the mesh fragment grid.
|
|
VertexCount() should be identical to m_grid.GridPointCount().
|
|
VertexCapacity() should be >= VertexCount().
|
|
*/
|
|
unsigned VertexCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets number of fragment vertices being used (number of elements being used in the m_P[], m_N[], and m_T[] arrays).
|
|
Parameters:
|
|
vertex_count - [in]
|
|
A value no larger than ON_SubDMeshFragment::MaximumVertexCount.
|
|
*/
|
|
bool SetVertexCount(size_t vertex_count);
|
|
|
|
/*
|
|
Returns:
|
|
Capactity for vertices in the mesh fragment grid.
|
|
VertexCapacity() should be >= VertexCount().
|
|
VertexCount() should be identical to m_grid.PointCount().
|
|
*/
|
|
unsigned VertexCapacity() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets number of fragment vertices available (number of elements available in the m_P[], m_N[], and m_T[] arrays).
|
|
The memory for the arrays is managed by something besides this ON_SubDManagedMeshFragment instance.
|
|
Parameters:
|
|
vertex_capacity - [in]
|
|
A value no larger than ON_SubDMeshFragment::MaximumVertexCount.
|
|
Returns:
|
|
True if successful
|
|
*/
|
|
bool SetUnmanagedVertexCapacity(size_t vertex_capacity);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Sets number of fragment vertices available (number of elements available in the m_P[], m_N[], and m_T[] arrays).
|
|
The memory for the arrays is managed by something besides this ON_SubDManagedMeshFragment instance.
|
|
Parameters:
|
|
vertex_capacity - [in]
|
|
A value no larger than ON_SubDMeshFragment::MaximumVertexCount.
|
|
Returns:
|
|
True if successful
|
|
*/
|
|
bool ReserveManagedVertexCapacity(size_t vertex_capacity);
|
|
|
|
/*
|
|
Returns:
|
|
True if the memory in the m_P[], m_N[], and m_T[] is managed by this ON_SubDManagedMeshFragment instance.
|
|
*/
|
|
bool ManagedArrays() const;
|
|
|
|
bool DeleteManagedArrays();
|
|
|
|
/*
|
|
Returns:
|
|
True if the memory in the m_P[], m_N[], and m_T[] is managed by something besides this ON_SubDManagedMeshFragment instance.
|
|
*/
|
|
bool UnmanagedArrays() const;
|
|
|
|
private:
|
|
friend class ON_SubDManagedMeshFragment;
|
|
friend class ON_SubDMeshImpl;
|
|
friend class ON_SubDHeap;
|
|
|
|
// Number of grid vertices and capacity of arrays in certain conditions.
|
|
enum
|
|
{
|
|
/// <summary>
|
|
/// 3 double for the vertex point
|
|
/// 3 double for the vertex normal
|
|
/// 3 double for the vertex texture coordinate
|
|
/// 1 double (4 bytes used for vertex color and 4 bytes currently not used)
|
|
/// </summary>
|
|
ManagedDoublesPerVertex = 10,
|
|
|
|
/// <summary>
|
|
/// Number of doubles between successive 3d points in m_P[]/m_N[]/m_T[].
|
|
/// When managed arrays are not interlaced, this value must be 3.
|
|
/// When managed arraays are interlaced, this value must be ManagedDoublesPerPoint.
|
|
/// </summary>
|
|
Managed_3d_stride = 3,
|
|
|
|
/// <summary>
|
|
/// Number of ON_Color elements between successive colors in m_C[].
|
|
/// When managed arrays are not interlaced, this value must be 1.
|
|
/// When managed arraays are interlaced, this value must be ManagedDoublesPerPoint*sizeof(double)/sizeof(ON_Color).
|
|
/// </summary>
|
|
Managed_color_stride = 1,
|
|
};
|
|
|
|
static bool Internal_ManagedArraysAreInterlaced();
|
|
static size_t Internal_Managed3dArrayOffset(size_t vertex_capacity);
|
|
|
|
/*
|
|
Parameters:
|
|
PNTC_array[] - [in]
|
|
An array of ManagedDoublesPerVertex*vertex_capacity doubles.
|
|
*/
|
|
void Internal_LayoutArrays(
|
|
bool bManagedArray,
|
|
double* PNTC_array,
|
|
size_t vertex_capacity
|
|
);
|
|
|
|
enum : unsigned short
|
|
{
|
|
/// <summary>
|
|
/// Vertex count = (m_vertex_count_etc & EtcMask)
|
|
/// Vertex capacity = (m_vertex_capacity_etc & EtcMask)
|
|
/// These are the counts and capacities of the m_P[]/m_N[]/m_T[]/m_C[] arrays the pointer
|
|
/// is not nullpr and the corresponding m_P_stride/m_N_stride/m_T_stride/m_C_stride > 0.
|
|
/// </summary>
|
|
ValueMask = 0x1FFF, // maximum vertex count and capacity
|
|
|
|
/// <summary>
|
|
/// The use of the 3 bits in (m_vertex_count_etc & EtcMask) and 3 bits in (m_vertex_capacity_etc & EtcMask)
|
|
/// are described in the enum values below.
|
|
/// </summary>
|
|
EtcMask = 0xE000,
|
|
|
|
/// <summary>
|
|
/// This bit is on m_vertex_count_etc.
|
|
/// Set means 4 m_ctrlnetP[] points are set and the m_ctrlnetT[]/m_ctrlnetC[]
|
|
/// are set if m_T[]/m_C[] is set.
|
|
/// </summary>
|
|
EtcControlNetQuadBit = 0x8000,
|
|
|
|
/// <summary>
|
|
/// This bit is on m_vertex_count_etc.
|
|
/// Set means m_T[] contains set values.
|
|
/// </summary>
|
|
EtcTextureCoordinatesExistBit = 0x4000,
|
|
|
|
/// <summary>
|
|
/// This bit is on m_vertex_capacity_etc.
|
|
/// Set means m_C[] contains set values.
|
|
/// </summary>
|
|
EtcColorsExistBit = 0x2000,
|
|
|
|
/// <summary>
|
|
/// This bit is on m_vertex_capacity_etc.
|
|
/// Set means m_K[] contains set values.
|
|
/// </summary>
|
|
EtcCurvaturesExistBit = 0x4000,
|
|
|
|
/// <summary>
|
|
/// This bit is on m_vertex_capacity_etc.
|
|
/// Set means the memory for the m_P[], m_N[], m_T[], and m_C[] arrays is managed by this class as a single
|
|
/// allocation.
|
|
/// m_P = new(std::nothrow) double[10*(point capacity)] and m_N, m_T, and m_C point into this allocation.
|
|
/// </summary>
|
|
EtcManagedArraysBit = 0x8000,
|
|
};
|
|
mutable unsigned short m_vertex_count_etc; // count value and 3 et cetera status bits
|
|
mutable unsigned short m_vertex_capacity_etc; // capacity value and 3 et cetera status bits
|
|
|
|
static void Internal_Set3dPointArrayToNan(double* a, size_t a_count, size_t a_stride);
|
|
|
|
private:
|
|
// corners for control net display in grid order (counter-clockwise quad order must swap [2] and[3])
|
|
double m_ctrlnetP[4][3];
|
|
|
|
// Normal used for shading the control net display in grid order.
|
|
double m_ctrlnetN[3];
|
|
|
|
|
|
public:
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
grid side N is between corner index N and corner index (N+1)%4.
|
|
Returns:
|
|
Texture coordinate at that corner.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_3dPoint TextureCoordinateCorner(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
private:
|
|
// The fragment's current corner texture coordinates in grid order.
|
|
// These can be from ON_SubDFace pack rectangles, ON_SubDFace custom texture points,
|
|
// a texture mapping, or any other values rendering code deems desirable.
|
|
// When a texture mapping evaluatior is not involved, they are typically
|
|
// used to generate the fragment's texture coordinates by interpolation.
|
|
// m_ctrlnetT[0]
|
|
// m_ctrlnetT[1]
|
|
// m_ctrlnetT[2]
|
|
// m_ctrlnetT[3]
|
|
mutable double m_ctrlnetT[4][3];
|
|
|
|
// Corner principal curvatures in grid order.
|
|
mutable ON_SurfaceCurvature m_ctrlnetK[4];
|
|
|
|
// Corner vertex colors in grid order.
|
|
mutable ON_Color m_ctrlnetC[4];
|
|
|
|
private:
|
|
// When an ON_SubDFace is a quad, there is a single ON_SubDMeshFragment for the face
|
|
// and ON_SubDMeshFragment.m_pack_rect are the corners of the quad face's pack rect in
|
|
// ON_SubDMeshFragment gid order.
|
|
// When an ON_SubDFace is an N-gon with N !+ 4, there are N ON_SubDMeshFragments for the face
|
|
// and ON_SubDMeshFragment.m_pack_rect are corners of a subrect of the face's pack rect
|
|
// in ON_SubDMeshFragment gid order.
|
|
// The m_pack_rect[] points are in grid order. If the parent ON_SubDFace pack rect is rotated,
|
|
// then "lower/upper" and "left/right" are with the rotation applied and hence a lower/left coordinate
|
|
// may be greater than an upper/right coorinate value.
|
|
// m_pack_rect[0] "lower left"
|
|
// m_pack_rect[1] "lower right"
|
|
// m_pack_rect[2] "upper left"
|
|
// m_pack_rect[3] "upper right"
|
|
double m_pack_rect[4][2]; // NOT a mutable property
|
|
|
|
public:
|
|
/*
|
|
Parameters:
|
|
grid_corner_index - [in]
|
|
grid side N is between corner index N and corner index (N+1)%4.
|
|
Returns:
|
|
Pack rect corner point.
|
|
Remarks:
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_corner_index = 2 is the only
|
|
corner that corresponds to a SubD vertex.
|
|
For partial fragments (IsFaceCornerFragment() = true), grid_side_index = 1 and grid_side_index = 2
|
|
correspond to half of original SuD edges.
|
|
*/
|
|
const ON_2dPoint PackRectCorner(
|
|
unsigned int grid_corner_index
|
|
) const;
|
|
|
|
const ON_2dPoint PackRectCenter() const;
|
|
|
|
void SetPackRectCornersForExperts(
|
|
bool bGridOrder,
|
|
const ON_2dPoint fragment_pack_rect_corners[4]
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This functions sets the pack rect corners on fragments used to render
|
|
quad and 3-gon ON_SubDFaces.
|
|
When an ON_SubDFace is a quad, it is rendered with one ON_SubDMeshFragment.
|
|
When an ON_SubDFace is a 3-gon, it is rendered with three ON_SubDMeshFragments.
|
|
Remarks:
|
|
It is critcial that m_face_fragment_count and m_face_fragment_index be set
|
|
correctly before calling this function.
|
|
A ON_SubDMeshFragment used to render a quad ON_SubDFace has
|
|
m_face_fragment_count = 1 and m_face_fragment_index = 0.
|
|
A ON_SubDMeshFragment used to render a 3-gon ON_SubDFace has
|
|
m_face_fragment_count = 3 and m_face_fragment_index = 0, 1 or 2.
|
|
*/
|
|
void SetQuadOr3gonFaceFragmentPackRectCorners(
|
|
bool bGridOrder,
|
|
const ON_2dPoint face_pack_rect_corners[4]
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This functions sets the pack rect corners on fragments used to render
|
|
n-gon ON_SubDFaces when n >= 5.
|
|
When an ON_SubDFace is an n-gon, it is rendered with n ON_SubDMeshFragments.
|
|
Parameters:
|
|
bGridOrder = [in]
|
|
Order for face_pack_rect_corners[].
|
|
face_texture_coordinate_corners - [in]
|
|
The points returned by ON_SubDFace::PackRectCorner(bGridOrder, i)
|
|
face_pack_rect_size - [in]
|
|
The n-gon face's ON_SubDFace::PackRectSize() value.
|
|
ngon_grid_size - [in]
|
|
ngon_sub_pack_rect_size - [in]
|
|
ngon_sub_pack_rect_delta - [in]
|
|
These three parameters are values from ON_SubDFace::GetNgonSubPackRectSizeAndDelta().
|
|
ngon_grid_size, ngon_sub_pack_rect_size, and ngon_sub_pack_rect_delta are identical
|
|
for all the ON_SubDMeshFragments used to render the n-gon face. The value of
|
|
m_face_fragment_index detemines which sub pack rect is assigned to each of
|
|
the n ON_SubDMeshFragments use to render the n-gon face.
|
|
Remarks:
|
|
It is critcial that m_face_fragment_count and m_face_fragment_index be set
|
|
correctly before calling this function.
|
|
A ON_SubDMeshFragment used to render an n-gon ON_SubDFace has
|
|
m_face_fragment_count = n and m_face_fragment_index = 0, ..., n-1.
|
|
*/
|
|
void SetNgonFaceFragmentPackRectCorners(
|
|
bool bGridOrder,
|
|
const ON_2dPoint face_pack_rect_corners[4],
|
|
ON_2dVector face_pack_rect_size,
|
|
ON_2udex ngon_grid_size,
|
|
ON_2dVector ngon_sub_pack_rect_size,
|
|
ON_2dVector ngon_sub_pack_rect_delta
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This functions gets the pack rect corners on fragments used to render 3-gon ON_SubDFaces.
|
|
When an ON_SubDFace is an 3-gon, it is rendered with 3 ON_SubDMeshFragments.
|
|
Parameters:
|
|
bFacePackRectGridOrder - [in]
|
|
Order for face_pack_rect_corners[].
|
|
face_pack_rect_corners - [in]
|
|
The points returned by ON_SubDFace::PackRectCorner(bGridOrder, i)
|
|
fragment_index - [in]
|
|
0 <= ngon_fragment_index < 3
|
|
bFragmentPackRectGridOrder - [in]
|
|
Order for face_pack_rect_corners[].
|
|
fragment_pack_rect_corners - [out]
|
|
*/
|
|
static bool Get3gonFaceFragmentPackRectCorners(
|
|
bool bFaceGridOrder,
|
|
const ON_2dPoint face_pack_rect_corners[4],
|
|
unsigned int fragment_index,
|
|
bool bFragmentGridOrder,
|
|
ON_2dPoint fragment_pack_rect_corners[4]
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This functions gets the pack rect corners for fragments used to render
|
|
n-gon ON_SubDFaces when n >= 5.
|
|
When an ON_SubDFace is an n-gon, it is rendered with n ON_SubDMeshFragments.
|
|
Parameters:
|
|
ngon_fragment_index - [in]
|
|
0 <= ngon_fragment_index < ngon_edge_count
|
|
bGridOrder - [in]
|
|
Order for face_pack_rect_corners[].
|
|
face_pack_rect_corners - [in]
|
|
The points returned by ON_SubDFace::PackRectCorner(bGridOrder, i)
|
|
face_pack_rect_size - [in]
|
|
The n-gon face's ON_SubDFace::PackRectSize() value.
|
|
ngon_grid_size - [in]
|
|
ngon_sub_pack_rect_size - [in]
|
|
ngon_sub_pack_rect_delta - [in]
|
|
These three parameters are values from ON_SubDFace::GetNgonSubPackRectSizeAndDelta().
|
|
ngon_grid_size, ngon_sub_pack_rect_size, and ngon_sub_pack_rect_delta are identical
|
|
for all the ON_SubDMeshFragments used to render the n-gon face. The value of
|
|
m_face_fragment_index detemines which sub pack rect is assigned to each of
|
|
the n ON_SubDMeshFragments use to render the n-gon face.
|
|
fragment_pack_rect_corners - [out]
|
|
*/
|
|
static bool GetNgonFaceFragmentPackRectCorners(
|
|
unsigned int ngon_edge_count,
|
|
unsigned int ngon_fragment_index,
|
|
bool bGridOrder,
|
|
const ON_2dPoint face_pack_rect_corners[4],
|
|
ON_2dVector face_pack_rect_size,
|
|
ON_2udex ngon_grid_size,
|
|
ON_2dVector ngon_sub_pack_rect_size,
|
|
ON_2dVector ngon_sub_pack_rect_delta,
|
|
ON_2dPoint fragment_pack_rect_corners[4]
|
|
);
|
|
|
|
public:
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 3-dimensional grid vertex points
|
|
//
|
|
// Depending on the strides, m_P[], m_N[], and m_T[] can be separate or interlaced.
|
|
//
|
|
// The stride m_P_stride and memory m_P references is managed by some other class or function.
|
|
// Never modify m_P_stride, m_P, or the values in m_P.
|
|
// Use m_grid functions to get point indices and quad face indices.
|
|
double* m_P; // surface points
|
|
size_t m_P_stride; // stride between points for m_P[] as an array of 8 byte doubles (so 0 or >= 3)
|
|
const double* PointArray(ON_SubDComponentLocation subd_appearance)const;
|
|
size_t PointArrayStride(ON_SubDComponentLocation subd_appearance)const;
|
|
unsigned PointArrayCount(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
public:
|
|
|
|
/*
|
|
Description:
|
|
Create a one quad fragment with
|
|
m_P = this->m_ctrlnetP[], m_P_stride = 3
|
|
m_N = this->m_ctrlnetN, m_N_stride = 0
|
|
m_T = this->m_ctrlnetT, m_T_stride = 3
|
|
NOTE WELL:
|
|
1) "this" must remain in scope and unchanged while the returned value
|
|
is used because the returned value references memory in thism_ctrlnetX[] arrays.
|
|
2) The next/prev pointers on the returned fragment are copied from this,
|
|
but the returned value is not reciprocally referenced by next/prev in the linked list.
|
|
Returns:
|
|
A control net quad fragment that can be used locally when the SubDAppearance
|
|
is ON_SubDComponentLocation::ControlNet.
|
|
The points, normals, and texture_coordinates of the returned fragment
|
|
are the control net quad points, normals, and texture coordinates
|
|
of this fragment. m_grid is a single quad grid.
|
|
*/
|
|
const ON_SubDMeshFragment ControlNetQuadFragmentForExperts() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bGridOrder - [in]
|
|
If true, then points are returned in fragment grid order.
|
|
Otherwise, points are returned in counter-clockwise quad order.
|
|
quad_points - [out]
|
|
quad_normal - [out]
|
|
*/
|
|
bool GetControlNetQuad(
|
|
bool bGridOrder,
|
|
ON_3dPoint quad_points[4],
|
|
ON_3dVector& quad_normal
|
|
) const;
|
|
|
|
const ON_3dPoint ControlNetQuadPoint(
|
|
bool bGridOrder,
|
|
unsigned point_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
bGridOrder - [in]
|
|
If true, then points are returned in fragment grid order.
|
|
Otherwise, points are returned in counter-clockwise quad order.
|
|
quad_points - [in]
|
|
*/
|
|
void SetControlNetQuad(
|
|
bool bGridOrder,
|
|
const ON_3dPoint quad_points[4],
|
|
ON_3dVector quad_normal
|
|
);
|
|
|
|
void UnsetControlNetQuad();
|
|
|
|
const ON_BoundingBox SurfaceBoundingBox() const;
|
|
const ON_BoundingBox ControlNetQuadBoundingBox() const;
|
|
const ON_BoundingBox BoundingBox(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
If grid vertex points are available, then VertexCount() is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
unsigned int PointCount() const;
|
|
unsigned int PointCapacity() const;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 3-dimensional grid vertex surface normals
|
|
//
|
|
// The m_N[] and m_P[] arrays are parallel.
|
|
// Depending on the strides, m_P[], m_N[], and m_T[] can be separate or interlaced.
|
|
//
|
|
// If m_N is not nullptr and m_N_stride>0, then m_N[] can accomodate up to m_P_capacity normals.
|
|
// If m_N is not nullptr and m_N_stride=0, then m_N[] can accomodate a single normal (flat shaded polygon face).
|
|
// The stride m_N_stride and memory m_N references is managed by some other class or function.
|
|
// Never modify m_N_stride, m_N, or the values in m_N.
|
|
// Use m_grid functions to get normal indices and quad face indices.
|
|
// Note well: m_N_stride can be 0 when the normal is constant (control net face normal for example).
|
|
double* m_N; // surface normals
|
|
size_t m_N_stride; // stride between normals for m_N[] as an array of 8 byte doubles (so 0 or >= 3)
|
|
const double* NormalArray(ON_SubDComponentLocation subd_appearance)const;
|
|
size_t NormalArrayStride(ON_SubDComponentLocation subd_appearance)const;
|
|
unsigned NormalArrayCount(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
If grid vertex surface normals are available, then VertexCount() is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
unsigned int NormalCount() const;
|
|
unsigned int NormalCapacity() const;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 3d vertex texture coordinates.
|
|
//
|
|
// Depending on the strides, m_P[], m_N[], and m_T[] can be separate or interlaced.
|
|
//
|
|
// If m_T is not nullptr and m_T_stride>0, then m_T[] can accomodate up to m_P_capacity textures coordinates.
|
|
// Otherwise there are no texture coordinates.
|
|
// Never modify m_T_stride, m_T.
|
|
// Use m_grid functions to get texture indices and quad face indices.
|
|
// Note well: m_T_stride can be 0 when the texture coordinate is constant (one color per face for example)
|
|
mutable double* m_T;
|
|
mutable size_t m_T_stride; // stride between texture points for m_T[] as an array of 8 byte doubles (so 0 or >= 3)
|
|
|
|
const double* TextureCoordinateArray(ON_SubDComponentLocation subd_appearance)const;
|
|
size_t TextureCoordinateArrayStride(ON_SubDComponentLocation subd_appearance)const;
|
|
unsigned TextureCoordinateArrayCount(ON_SubDComponentLocation subd_appearance) const;
|
|
public:
|
|
/*
|
|
Returns:
|
|
If grid texture coordinates are available, then VertexCount() is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
unsigned int TextureCoordinateCount() const;
|
|
unsigned int TextureCoordinateCapacity() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Sets the values of each fragment's m_ctrlnetT[] member.
|
|
Parameters:
|
|
bSetTextureCoordinates
|
|
If true, the texture coordinate corners are used ti set the fragment's m_T[]
|
|
values after m_ctrlnetT[] is set.
|
|
*/
|
|
void SetTextureCoordinateCornersForExperts(
|
|
bool bGridOrder,
|
|
const ON_3dPoint fragment_texture_coordinate_corners[4],
|
|
bool bSetTextureCoordinates
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
This functions sets the texture coordinates on fragments used to render
|
|
quad and 3-gon ON_SubDFaces.
|
|
A quad ON_SubDFace is rendered with one ON_SubDMeshFragment.
|
|
A 3-gon ON_SubDFace is rendered with three ON_SubDMeshFragments.
|
|
Remarks:
|
|
It is critcial that m_face_fragment_count and m_face_fragment_index be set
|
|
correctly before calling this function.
|
|
A ON_SubDMeshFragment used to render a quad ON_SubDFace has
|
|
m_face_fragment_count = 1 and m_face_fragment_index = 0.
|
|
A ON_SubDMeshFragment used to render a 3-gon ON_SubDFace has
|
|
m_face_fragment_count = 3 and m_face_fragment_index = 0, 1 or 2.
|
|
*/
|
|
void SetQuadOr3gonFaceFragmentTextureCoordinateCorners(
|
|
bool bGridOrder,
|
|
const ON_3dPoint face_texture_coordinate_corners[4],
|
|
bool bSetTextureCoordinates
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
When an ON_SubDFace is an n-gon with n >= 5, it is rendered with n ON_SubDMeshFragments.
|
|
This functions sets the texture coordinates on those fragments.
|
|
Parameters:
|
|
bGridOrder = [in]
|
|
Order for face_pack_rect_corners[].
|
|
face_texture_coordinate_corners - [in]
|
|
The points returned by ON_SubDFace::TextureCoordinateCorner(bGridOrder, i, false)
|
|
face_pack_rect_size - [in]
|
|
The n-gon face's ON_SubDFace::PackRectSize() value.
|
|
ngon_grid_size - [in]
|
|
ngon_sub_pack_rect_size - [in]
|
|
ngon_sub_pack_rect_delta - [in]
|
|
These three parameters are values from ON_SubDFace::GetNgonSubPackRectSizeAndDelta().
|
|
ngon_grid_size, ngon_sub_pack_rect_size, and ngon_sub_pack_rect_delta are identical
|
|
for all the ON_SubDMeshFragments used to render the n-gon face. The value of
|
|
m_face_fragment_index detemines which sub pack rect is assigned to each of
|
|
the n ON_SubDMeshFragments use to render the n-gon face.
|
|
Remarks:
|
|
It is critcial that m_face_fragment_count and m_face_fragment_index be set
|
|
correctly before calling this function.
|
|
A ON_SubDMeshFragment used to render an n-gon ON_SubDFace has
|
|
m_face_fragment_count = n and m_face_fragment_index = 0, ..., n-1.
|
|
*/
|
|
void SetNgonFaceFragmentTextureCoordinateCorners(
|
|
bool bGridOrder,
|
|
const ON_3dPoint face_texture_coordinate_corners[4],
|
|
ON_2dVector face_pack_rect_size,
|
|
ON_2udex ngon_grid_size,
|
|
ON_2dVector ngon_sub_pack_rect_size,
|
|
ON_2dVector ngon_sub_pack_rect_delta,
|
|
bool bSetTextureCoordinates
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the texture coordinate corners.
|
|
Parameters:
|
|
bGridOrder - [in]
|
|
If true, then points are returned in fragment grid order.
|
|
Otherwise, points are returned in counter-clockwise quad order.
|
|
texture_coordinate_corners - [out]
|
|
*/
|
|
bool GetTextureCoordinteCorners(
|
|
bool bGridOrder,
|
|
ON_3dPoint texture_coordinate_corners[4]
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Set the texture coordinates in m_T[] from the values in m_ctrlnetT[].
|
|
*/
|
|
void SetTextureCoordinatesFromCorners() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the texture coordinates in m_T[] from the values in m_pack_rect[].
|
|
*/
|
|
void SetPackedTextureCoordinates() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the this fragments texture coordinates in m_T[] to cover (0,1)x(0,1)
|
|
*/
|
|
void SetUnpackedTextureCoordinates() const;
|
|
|
|
private:
|
|
void Internal_SetTextureCoordinatesFromCorners(
|
|
const double* corner0,
|
|
const double* corner1,
|
|
const double* corner2,
|
|
const double* corner3,
|
|
double default_coordinate_value,
|
|
int corner_dim
|
|
) const;
|
|
|
|
private:
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Per vertex colors
|
|
//
|
|
// Depending on the strides, m_P[], m_N[], m_T[] and m_C[] can be separate or interlaced.
|
|
//
|
|
// If m_C is not nullptr and m_C_stride>0, then m_C[] can accomodate up to m_P_capacity
|
|
// elements.
|
|
// Otherwise there is no per vertex false color.
|
|
// Never modify m_C_stride, m_C.
|
|
// Use m_grid functions to get color indices and quad face indices.
|
|
//
|
|
// m_C[] is rarely used and typically managed with ReserveManagedColorCapacity() / DeleteManagedColorCapacity().
|
|
// NOTE WELL:
|
|
// When m_C is interlaced with something containing doubles, m_C_stride must be
|
|
// a multiple of 2 to keep the doubles 8 bytes aligned.
|
|
// When m_C is not interlaced, m_C_stride is typically 1. If this is confusing,
|
|
// please learn more about algnment and interlacing before working on this code.
|
|
mutable ON_Color* m_C;
|
|
mutable size_t m_C_stride; // stride for m_C[] as an array of 4 bytes ON_Color elements (so 0 or >= 1).
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
If grid vertex colors are available, then VertexCount() is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
unsigned int ColorCount() const;
|
|
unsigned int ColorCapacity() const;
|
|
|
|
const ON_Color* ColorArray(ON_SubDComponentLocation subd_appearance)const;
|
|
size_t ColorArrayStride(ON_SubDComponentLocation subd_appearance)const;
|
|
unsigned ColorArrayCount(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if vertex color values are set on this fragment.
|
|
*/
|
|
bool ColorsExist() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bSetColorsExist - [in]
|
|
True if vertex colors exist.
|
|
False vertex colors do not exist or are no longer valid.
|
|
*/
|
|
void SetColorsExist(bool bSetColorsExist) const;
|
|
|
|
/*
|
|
Description:
|
|
Set the vertex colors in m_C[] to color.
|
|
Parameters:
|
|
color - [in]
|
|
*/
|
|
bool SetColors(
|
|
ON_Color color
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Set the vertex colors in m_C[] from a callback function.
|
|
Parameters:
|
|
*/
|
|
bool SetColorsFromCallback(
|
|
const ON_MappingTag& fragment_colors_mapping_tag,
|
|
const ON_SubD& subd,
|
|
ON__UINT_PTR callback_context,
|
|
const ON_Color(*color_callback)(
|
|
ON__UINT_PTR callback_context,
|
|
const ON_MappingTag& mapping_tag,
|
|
const ON_SubD& subd,
|
|
ON_SubDComponentPtr cptr,
|
|
const ON_3dPoint& P,
|
|
const ON_3dVector& N,
|
|
const ON_3dPoint& T,
|
|
const ON_SurfaceCurvature& K
|
|
)
|
|
)const;
|
|
|
|
private:
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Principal curvatures
|
|
//
|
|
// If m_K is not nullptr and m_K_stride>0, then m_K[] can accomodate up to m_P_capacity
|
|
// principal curvatures and sectional curvatures (four doubles, k1,k2,sx,sy).
|
|
// Otherwise there are no principal curvatures or sectional curvatures.
|
|
// (sx = sectional curvature in grid "x" direction, sy = sectional curvature in grid "y" direction.)
|
|
// At exceptional points, the curvature values may be nan.
|
|
// Never modify m_K_stride, m_K.
|
|
// Use m_grid functions to get principal curvature indices and quad face indices.
|
|
//
|
|
// m_K[] is rarely used and typically managed with ReserveManagedCurvatureCapacity() / DeleteManagedCurvatureCapacity().
|
|
// NOTE WELL:
|
|
// If m_K[] is interlacesd, the number of bytes between successive elements of m_K[] must be a multiple of 16
|
|
// because sizeof(m_K) = 16 AND m_K_stride is the stride between elements of m_K[]
|
|
// This is different than m_P_stride, m_N_stride, and m_T_stride, which count the number of doubles between successive
|
|
// points/normals/texture points in m_P[]/m_N[]/m_T[].
|
|
mutable ON_SurfaceCurvature* m_K;
|
|
size_t m_K_stride; // stride for m_K[] as an array of 16 byte ON_SurfaceCurvature elements (so 0 or >= 1).
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
If grid vertex principal curvatures and sectional curvatures are available, then VertexCount() is returned.
|
|
Otherwise 0 is returned.
|
|
*/
|
|
unsigned int CurvatureCount() const;
|
|
unsigned int CurvatureCapacity() const;
|
|
|
|
const ON_SurfaceCurvature* CurvatureArray(ON_SubDComponentLocation subd_appearance)const;
|
|
unsigned CurvatureArrayCount(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
/*
|
|
Description:
|
|
Adds managed curvature capacity to store vertex curvatures.
|
|
*/
|
|
bool ReserveManagedCurvatureCapacity() const;
|
|
|
|
/*
|
|
Description:
|
|
Deletes capacity added by ReserveManagedCurvatureCapacity().
|
|
*/
|
|
void DeleteManagedCurvatureCapacity() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
True if vertex color values are set on this fragment.
|
|
*/
|
|
bool CurvaturesExist() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bSetCurvaturesExist - [in]
|
|
True if vertex curvatures exist.
|
|
False vertex curvatures do not exist or are no longer valid.
|
|
*/
|
|
void SetCurvaturesExist(bool bSetCurvaturesExist) const;
|
|
|
|
public:
|
|
|
|
// Normalized grid parameters useful for appling a texture to the grid are available
|
|
// from m_grid functions.
|
|
|
|
// Information to resolve m_P[], m_N[], and m_T[] into a grid of NxN quads.
|
|
ON_SubDMeshFragmentGrid m_grid;
|
|
|
|
const ON_SubDMeshFragmentGrid& Grid(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
// 3d bounding box of grid vertex points.
|
|
ON_BoundingBox m_surface_bbox;
|
|
public:
|
|
/*
|
|
Parameters:
|
|
display_density - [in]
|
|
Determines grid size
|
|
bCurvatureArray - [in]
|
|
true to include room for the m_K[] array.
|
|
Returns:
|
|
Amount of memory needed for the fragment, the m_P[], m_N[], m_T[], m_C[],
|
|
and optionally the m_K[] arrays.
|
|
*/
|
|
static size_t SizeofFragment(
|
|
unsigned int display_density,
|
|
bool bCurvatureArray
|
|
);
|
|
|
|
public:
|
|
void Dump(ON_TextLog& text_log) const;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDManagedMeshFragment : public ON_SubDMeshFragment
|
|
{
|
|
public:
|
|
ON_SubDManagedMeshFragment() ON_NOEXCEPT;
|
|
~ON_SubDManagedMeshFragment() ON_NOEXCEPT;
|
|
ON_SubDManagedMeshFragment(const ON_SubDManagedMeshFragment&) ON_NOEXCEPT;
|
|
ON_SubDManagedMeshFragment& operator=(const ON_SubDManagedMeshFragment&) ON_NOEXCEPT;
|
|
|
|
static ON_SubDManagedMeshFragment Create(const ON_SubDMeshFragment& src) ON_NOEXCEPT;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDManagedMeshFragment( ON_SubDManagedMeshFragment&& ) ON_NOEXCEPT;
|
|
|
|
// rvalue assignment operator
|
|
ON_SubDManagedMeshFragment& operator=( ON_SubDManagedMeshFragment&& ) ON_NOEXCEPT;
|
|
#endif
|
|
|
|
void Clear() ON_NOEXCEPT;
|
|
|
|
void Destroy() ON_NOEXCEPT;
|
|
|
|
bool ReserveCapacity(
|
|
unsigned int mesh_density
|
|
) ON_NOEXCEPT;
|
|
|
|
private:
|
|
void CopyHelper(const ON_SubDMeshFragment& src);
|
|
size_t m_storage_capacity = 0;
|
|
double* m_storage = nullptr;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDMesh
|
|
//
|
|
|
|
/// <summary>
|
|
/// ON_SubDMesh is used to store a high density traditional quad mesh
|
|
/// of a SubD surface or a mesh of a SubD control net.
|
|
/// In general, is is better to use an ON_SubDMeshFragmentIterator(subd)
|
|
/// that iterates the ON_MeshFragments cached on the ON_SubD.
|
|
/// </summary>
|
|
class ON_CLASS ON_SubDMesh
|
|
{
|
|
#if defined(ON_SUBD_CENSUS)
|
|
private:
|
|
ON_SubDMeshCensusCounter m_census_counter;
|
|
#endif
|
|
|
|
public:
|
|
static const ON_SubDMesh Empty;
|
|
|
|
/*
|
|
Returns:
|
|
A runtime number that changes if the limit mesh content changes.
|
|
0: Empty limit mesh
|
|
Remarks:
|
|
This is a runtime number. It is not saved in archives and begins
|
|
at 1 with each new runtime instance of the opennurbs library.
|
|
*/
|
|
ON__UINT64 ContentSerialNumber() const;
|
|
|
|
|
|
|
|
/*
|
|
Description:
|
|
Parameters:
|
|
destination_mesh - [in]
|
|
If destination_mesh is not nullptr, then the returned mesh
|
|
will be store here. Otherwise the returned mesh will be
|
|
allocated with a call to new ON_Mesh().
|
|
Returns:
|
|
If this limit mesh is not empty, an ON_Mesh representation of this limit mesh.
|
|
Othewise, nullptr.
|
|
*/
|
|
ON_Mesh* ToMesh(
|
|
ON_Mesh* destination_mesh
|
|
) const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Parameters:
|
|
mesh_density - [in]
|
|
Larger numbers return denser meshes.
|
|
destination_mesh - [in]
|
|
If destination_mesh is not nullptr, then the returned mesh
|
|
will be store here. Otherwise the returned mesh will be
|
|
allocated with a call to new ON_Mesh().
|
|
Returns:
|
|
If this limit mesh is not empty, an ON_Mesh representation of this limit mesh.
|
|
Othewise, nullptr.
|
|
*/
|
|
ON_Mesh* ToMesh(
|
|
unsigned int mesh_density,
|
|
ON_Mesh* destination_mesh
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Parameters:
|
|
frit - [in]
|
|
A fragment iterator from an ON_SubDMesh or ON_SubD.
|
|
mesh_density - [in]
|
|
Larger numbers return denser meshes.
|
|
MinimumMeshDensity() <= mesh_density <= MaximumMeshDensity()
|
|
destination_mesh - [in]
|
|
If destination_mesh is not nullptr, then the returned mesh
|
|
will be store here. Otherwise the returned mesh will be
|
|
allocated with a call to new ON_Mesh().
|
|
Returns:
|
|
If this limit mesh is not empty, an ON_Mesh representation of this limit mesh.
|
|
Othewise, nullptr.
|
|
*/
|
|
static ON_Mesh* ToMesh(
|
|
class ON_SubDMeshFragmentIterator& frit,
|
|
unsigned int mesh_density,
|
|
ON_Mesh* destination_mesh
|
|
);
|
|
|
|
ON_SubDMesh() = default;
|
|
~ON_SubDMesh() = default;
|
|
ON_SubDMesh(const ON_SubDMesh&) = default;
|
|
ON_SubDMesh& operator=(const ON_SubDMesh&) = default;
|
|
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDMesh( ON_SubDMesh&& ) ON_NOEXCEPT;
|
|
// rvalue assignment operator
|
|
ON_SubDMesh& operator=( ON_SubDMesh&& );
|
|
#endif
|
|
|
|
ON_SubDMesh Copy() const;
|
|
|
|
ON_SubDMesh& CopyFrom(
|
|
const ON_SubDMesh& src
|
|
);
|
|
|
|
static void Swap(
|
|
ON_SubDMesh& a,
|
|
ON_SubDMesh& b
|
|
);
|
|
|
|
bool Transform(
|
|
const ON_Xform& xform
|
|
);
|
|
|
|
ON_DEPRECATED_MSG("AbsoluteSubDDisplayDensity")
|
|
unsigned int DisplayDensity() const;
|
|
|
|
/*
|
|
Returns:
|
|
The absolute subd display density used to create this display mesh.
|
|
*/
|
|
unsigned int AbsoluteSubDDisplayDensity() const;
|
|
|
|
ON_SubDDisplayParameters DisplayParameters() const;
|
|
|
|
unsigned int FragmentCount() const;
|
|
const ON_SubDMeshFragment* FirstFragment() const; // linked list of mesh fragments
|
|
|
|
/*
|
|
Parameters:
|
|
face - [in]
|
|
Returns:
|
|
The first fragment for this face or nullptr if none is found.
|
|
If the face is not a quad, then there will be multiple partial
|
|
fragments for the face and this is the first on. The others
|
|
follow using m_next_fragment.
|
|
*/
|
|
const ON_SubDMeshFragment* FaceFragment(
|
|
const class ON_SubDFace* face
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the limit surface point location and normal for
|
|
the face's center from the limit mesh grid.
|
|
Parameters:
|
|
face - [in]
|
|
P - [out]
|
|
P = limit surface location or ON_3dPoint::NanPoint if not available.
|
|
N - [out]
|
|
N = limit surface unit normal or ON_3dVector::NanVector if not available.
|
|
Returns:
|
|
True if the point and normal were set from the limit mesh frament.
|
|
False if the limit mesh fragment was not found and nan values were returned.
|
|
*/
|
|
bool GetFaceCenterPointAndNormal(
|
|
const class ON_SubDFace* face,
|
|
double* P,
|
|
double* N
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the limit surface point location and normal for
|
|
the edge's midpoint from the limit mesh grid.
|
|
Parameters:
|
|
edge - [in]
|
|
edge_face_index - [in]
|
|
Index of the face to use for the normal. If the edge is a crease, then
|
|
each attached face may have a different normal. Pass 0 when in doubt.
|
|
P - [out]
|
|
P = limit surface location or ON_3dPoint::NanPoint if not available.
|
|
N - [out]
|
|
N = limit surface unit normal or ON_3dVector::NanVector if not available.
|
|
Returns:
|
|
True if the point and normal were set from the limit mesh frament.
|
|
False if the limit mesh fragment was not found and nan values were returned.
|
|
*/
|
|
bool GetEdgeCenterPointAndNormal(
|
|
const class ON_SubDEdge* edge,
|
|
unsigned int edge_face_index,
|
|
double* P,
|
|
double* N
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
If the subd referenced by m_subd_ref changes, then call
|
|
Update to update the limit mesh.
|
|
*/
|
|
bool Update(
|
|
bool bShareUpdate
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
The ON__INT_PTRs in the tree are const ON_SubDMeshFragment* pointers.
|
|
*/
|
|
const ON_RTree& FragmentTree() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears everything.
|
|
*/
|
|
void Clear();
|
|
|
|
/*
|
|
Description:
|
|
If the tree is not needed and memory resources are tight, then call ClearTree()
|
|
to remove the RTree.
|
|
*/
|
|
void ClearTree();
|
|
|
|
bool IsEmpty() const;
|
|
|
|
ON_BoundingBox BoundingBox() const;
|
|
|
|
bool GetTightBoundingBox(
|
|
ON_BoundingBox& bbox,
|
|
bool bGrowBox,
|
|
const ON_Xform* xform
|
|
) const;
|
|
|
|
ON_SubDRef SubDRef() const;
|
|
ON_SubD SubD() const;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Pretend this function and ON_SubDMeshImpl do not exist.
|
|
Returns:
|
|
Something that you are pretending does not exist.
|
|
Remarks:
|
|
It is intentional that the definition of ON_SubDMeshImpl class is not
|
|
available in the opennurbs library interface (not in a header file).
|
|
The size and design of ON_SubDMeshImpl will change constantly.
|
|
If you choose to hack and whack so you can dereference an
|
|
ON_SubDMeshImpl* pointer, then your code will crash unpredictably.
|
|
*/
|
|
class ON_SubDMeshImpl* SubLimple() const;
|
|
unsigned int SubLimpleUseCount() const;
|
|
|
|
private:
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
|
|
friend class ON_SubDMeshImpl;
|
|
// C4251: ... needs to have dll-interface to be used by clients of class ...
|
|
// m_impl_sp is private and all code that manages m_impl_sp is explicitly implemented in the DLL.
|
|
private:
|
|
std::shared_ptr< class ON_SubDMeshImpl > m_impl_sp;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
|
|
};
|
|
|
|
|
|
class ON_CLASS ON_SubDSectorSurfacePoint
|
|
{
|
|
public:
|
|
// For performance reasons, the default the data members are
|
|
// not initialized by the default constructor
|
|
// Use = ON_SubDSectorSurfacePoint::Unset when initialization is required
|
|
static const ON_SubDSectorSurfacePoint Unset; // all doubles are ON_UNSET_VALUE, all pointer are nullptr
|
|
static const ON_SubDSectorSurfacePoint Nan; // all doubles are ON_DBL_QNAN, all pointer are nullptr
|
|
static const ON_SubDSectorSurfacePoint Zero; // all doubles are 0.0, all pointer are nullptr
|
|
|
|
/*
|
|
Returns:
|
|
true if m_limitP[0] is ON_UNSET_VALUE.
|
|
false otherwise.
|
|
*/
|
|
bool IsUnset() const;
|
|
|
|
/*
|
|
Returns:
|
|
true if m_limitP[0] is a nan (like ON_DBL_QNAN).
|
|
false otherwise.
|
|
*/
|
|
bool IsNan() const;
|
|
|
|
/*
|
|
Returns:
|
|
true if all coordinates are zero.
|
|
false otherwise.
|
|
*/
|
|
bool IsZero() const;
|
|
|
|
/*
|
|
Returns:
|
|
true if all coordinates are valid doubles and the tangents and normal have at least
|
|
one nonzero coordinate.
|
|
false otherwise.
|
|
*/
|
|
bool IsSet(
|
|
bool bUndefinedNormalIsPossible
|
|
) const;
|
|
|
|
bool Transform(
|
|
const ON_Xform& xform
|
|
);
|
|
|
|
// limit surface point, tangents and normal
|
|
double m_limitP[3]; // point
|
|
double m_limitT1[3]; // first unit tangent
|
|
double m_limitT2[3]; // second unit tangent
|
|
double m_limitN[3]; // unit normal (same direction as m_limitT1 x m_limitT2)
|
|
|
|
// When an ON_SubDVertex has a single sector, (ON_SubDVertex.IsSingleSectorVertex() is true),
|
|
// these pointers are both null.
|
|
// When an ON_SubDVertex has a multiple sectors,
|
|
// m_sector_face is the "first" face in the sector and
|
|
// m_next_sector_limit_point is used to create a linked list.
|
|
// (The "first" face in a sector is the one ON_SubDSectorIterator.IncrementToCrease(-1) returns.)
|
|
const class ON_SubDSectorSurfacePoint* m_next_sector_limit_point; // nullptr for vertices with one sector
|
|
const class ON_SubDFace* m_sector_face; // nullptr for vertices with one sector
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentBase
|
|
//
|
|
class ON_CLASS ON_SubDComponentBase
|
|
{
|
|
public:
|
|
static const ON_SubDComponentBase Unset;
|
|
|
|
/*
|
|
Returns:
|
|
True if this component is active in its parent subd or other
|
|
relevent context.
|
|
Remarks:
|
|
When a component is in use, IsActive() = true.
|
|
If was used and then deleted, IsActive() is false.
|
|
*/
|
|
bool IsActive() const;
|
|
|
|
public:
|
|
ON_SubDComponentBase() = default;
|
|
~ON_SubDComponentBase() = default;
|
|
ON_SubDComponentBase(const ON_SubDComponentBase&) = default;
|
|
ON_SubDComponentBase& operator=(const ON_SubDComponentBase&) = default;
|
|
|
|
public:
|
|
static int CompareId(
|
|
const ON_SubDComponentBase* lhs,
|
|
const ON_SubDComponentBase* rhs
|
|
);
|
|
|
|
|
|
public:
|
|
// The audience for this comment is anybody who wants to change the data
|
|
// fields in ON_SubDComponentBase. Everyone else should ignore this comment.
|
|
// ON_SubD components come from ON_FixedSizePool and ON_SubD code
|
|
// uses ON_FixedSizePool.ReturnElement. The first sizeof(void*) bytes
|
|
// must be a data field that is not referenced in returned elements.
|
|
// Since a returned element cannot have a "next level vertex",
|
|
// m_subd_point1 is a good data member to put first.
|
|
|
|
// m_subd_point1 points to the next level's vertex when this component
|
|
// has been subdivided using an algorithm like Catmull-Clark or Loop-Warren.
|
|
const class ON_SubDVertex* m_subd_point1 = nullptr;
|
|
|
|
public:
|
|
// The audience for this comment is anybody who wants to change the data
|
|
// fields in ON_SubDComponentBase. Everyone else should ignore this comment.
|
|
// It is critical that the offset of m_id in ON_SubDComponentBase be >= sizeof(void*).
|
|
// ON_SubD components come from ON_FixedSizePool and ON_SubD code
|
|
// use ON_FixedSizePool.ElementFromId and ON_FixedSizePool.ReturnElement.
|
|
// Once assigned, m_id is never changed and that allows ON_SubD component
|
|
// indices to work.
|
|
|
|
// Id assigned to this component. NEVER MODIFY THE m_id VALUE.
|
|
// It is assigned by allocators and used to find the component
|
|
// from an ON_COMPONENT_INDEX.
|
|
unsigned int m_id = 0;
|
|
|
|
private:
|
|
// The m_archive_id must be immediately after the m_id field.
|
|
// A value of ON_UNSET_UINT_INDEX indicate the component was
|
|
// in use and then deleted. See ON_SubDHeap Return...() functions
|
|
// for more details.
|
|
mutable unsigned int m_archive_id = 0;
|
|
|
|
public:
|
|
|
|
/*
|
|
Returns:
|
|
Subdivision level (0 to 255)
|
|
*/
|
|
unsigned const SubdivisionLevel() const;
|
|
|
|
/*
|
|
Parameters:
|
|
level - [in]
|
|
Subdivision level (0 to 255)
|
|
*/
|
|
void SetSubdivisionLevel(unsigned level);
|
|
|
|
|
|
public:
|
|
const ON_ComponentStatus Status() const;
|
|
|
|
|
|
public:
|
|
mutable ON_ComponentStatus m_status = ON_ComponentStatus::NoneSet;
|
|
|
|
/*
|
|
Returns:
|
|
The current value of the component mark ( m_status->RuntimeMark() ).
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
Any code can use Mark() at any time. You cannot assume that
|
|
other functions including const will not change its value.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
*/
|
|
bool Mark() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears (sets to false) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
Any code can use Mark() at any time. You cannot assume that
|
|
other functions including const will not change its value.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool ClearMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets (sets to true) the value of the component mark.
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
Any code can use Mark() at any time. You cannot assume that
|
|
other functions including const will not change its value.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark() const;
|
|
|
|
/*
|
|
Description:
|
|
Sets the value of the component mark to bMark.
|
|
Parameter:
|
|
bMark - [in]
|
|
Remarks:
|
|
SubD components have a mutable runtime mark that can be used
|
|
in any context where a single thread cares about the marks.
|
|
Any code can use Mark() at any time. You cannot assume that
|
|
other functions including const will not change its value.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
Returns:
|
|
Input value of Mark().
|
|
*/
|
|
bool SetMark(
|
|
bool bMark
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
The current value of the component mark bits ( m_status->MarkBits() ).
|
|
Remarks:
|
|
Mark() and MarkBits() are independent.
|
|
|
|
SubD components have a mutable runtime mark bits that can be used
|
|
in any context where a single thread cares about the mark bits value.
|
|
Any code can use MarkBits() at any time. You cannot assume that
|
|
other functions including const will not change their value.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
|
|
MarkBits() is used in more complex calculations where the single true/false
|
|
provided by Mark() is not sufficient. Typically MarkBits() is used when
|
|
a collecection of components needs to be partitioned into more than two
|
|
sets or when the value of Mark() cannot be changed.
|
|
*/
|
|
ON__UINT8 MarkBits() const;
|
|
|
|
/*
|
|
Returns:
|
|
Set the component mark bits ( m_status->SetMarkBits( mark_bits ) ).
|
|
Remarks:
|
|
Mark() and MarkBits() are independent.
|
|
|
|
SubD components have a mutable runtime mark bits that can be used
|
|
in any context where a single thread cares about the mark bits value.
|
|
Any code can use MarkBits() at any time. You cannot assume that
|
|
other functions including const will not change their value.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
|
|
MarkBits() is used in more complex calculations where the single true/false
|
|
provided by Mark() is not sufficient. Typically MarkBits() is used when
|
|
a collecection of components needs to be partitioned into more than two
|
|
sets or when the value of Mark() cannot be changed.
|
|
Returns:
|
|
Input value of MarkBits().
|
|
*/
|
|
ON__UINT8 SetMarkBits(
|
|
ON__UINT8 mark_bits
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
Set the component mark bits to 0 ( m_status->SetMarkBits( 0 ) ).
|
|
Remarks:
|
|
Mark() and MarkBits() are independent.
|
|
|
|
SubD components have a mutable runtime mark bits that can be used
|
|
in any context where a single thread cares about the mark bits value.
|
|
Any code can use MarkBits() at any time. You cannot assume that
|
|
other functions including const will not change their value.
|
|
It is widely used in many calculations to keep track of sets of
|
|
components that are in a certain context specfic state.
|
|
|
|
MarkBits() is used in more complex calculations where the single true/false
|
|
provided by Mark() is not sufficient. Typically MarkBits() is used when
|
|
a collecection of components needs to be partitioned into more than two
|
|
sets or when the value of Mark() cannot be changed.
|
|
Returns:
|
|
Input value of MarkBits().
|
|
*/
|
|
ON__UINT8 ClearMarkBits() const;
|
|
|
|
|
|
public:
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Saved subdivision point
|
|
//
|
|
/*
|
|
Description:
|
|
Set the saved subdivision point.
|
|
Parameters:
|
|
subdivision_point - [in]
|
|
includes displacement if it exists
|
|
Returns:
|
|
true if successful
|
|
*/
|
|
bool SetSavedSubdivisionPoint(
|
|
const double subdivision_point[3]
|
|
) const;
|
|
|
|
bool GetSavedSubdivisionPoint(
|
|
double subdivision_point[3]
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this component.
|
|
Attached components are not modifed.
|
|
*/
|
|
void ClearSavedSubdivisionPoint() const;
|
|
|
|
/*
|
|
Returns:
|
|
Saved subdivision point. If a point has not been saved,
|
|
ON_3dPoint::NanPoint is returned.
|
|
*/
|
|
const ON_3dPoint SavedSubdivisionPoint() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the subdivision point is cached.
|
|
*/
|
|
bool SavedSubdivisionPointIsSet() const;
|
|
|
|
ON_DEPRECATED_MSG("Does nothing. Returns false.")
|
|
bool SetSubdivisionDisplacement(const double*);
|
|
|
|
ON_DEPRECATED_MSG("Does nothing. Returns false.")
|
|
bool GetSubdivisionDisplacement(double*) const;
|
|
|
|
ON_DEPRECATED_MSG("Does nothing. Returns nans.")
|
|
const ON_3dVector SubdivisionDisplacement() const;
|
|
|
|
ON_DEPRECATED_MSG("Does nothing. Returns false.")
|
|
bool SubdivisionDisplacementIsNonzero() const;
|
|
|
|
ON_DEPRECATED_MSG("Does nothing.")
|
|
void ClearSubdivisionDisplacement() const;
|
|
|
|
protected:
|
|
friend class ON_Internal_SubDFaceMeshFragmentAccumulator;
|
|
friend class ON_SubDHeap;
|
|
enum SavedPointsFlags : unsigned char
|
|
{
|
|
// if ( 0 != (m_saved_points_flags & SubdivisionPointBit), then m_cache_subd_P is set.
|
|
SubdivisionPointBit = 0x40,
|
|
|
|
// if ( 0 != (m_saved_points_flags & SurfacePointBit), then ON_SubDVertex.m_limit* values are set.
|
|
// ON_SubDVertex: Set means one or more sector limit surface points are saved in ON_SubDVertex.m_limit_point.
|
|
// ON_SubDEdge: Set means the limit surface NURBS curve control points are cached.
|
|
// ON_SubDFace: Set means limit surface mesh fragments are saved in ON_SubDFace.m_surface_mesh_fragments.
|
|
// Unset means any information in the fields identified above is invalid and must be recalculated.
|
|
SurfacePointBit = 0x80,
|
|
|
|
// SubdivisionPointBit | SurfacePointBit
|
|
CachedPointMask = 0xC0
|
|
};
|
|
|
|
enum ModifiedFlags : unsigned char
|
|
{
|
|
// if ( 0 != (m_saved_points_flags & Modified1Bit), then the component has been modified and
|
|
// cached subdivision information needs to be recalculated.
|
|
Modified1Bit = 0x01,
|
|
|
|
// if ( 0 != (m_saved_points_flags & Modified2Bit), then the component is adjacent to
|
|
// a modified component and cached subdivision information needs to be recalculated.
|
|
Modified2Bit = 0x02,
|
|
|
|
// ModifiedFlagsMask = Modified1Bit | Modified2Bit
|
|
// if ( 0 != (m_saved_points_flags & ModifiedFlagsMask), then any cached subdivision information
|
|
// on that component needs to be recalculated.
|
|
ModifiedFlagsMask = 0x03
|
|
};
|
|
|
|
// m_saved_points_flags is a bit field based on ON_SubDComponentBase::SavePointsFlags values.
|
|
// GetSurfacePoint( bUseSavedSurfacePoint=true ) can change the value of m_saved_points_flags
|
|
void Internal_SetSavedSurfacePointFlag(bool bSavedSurfacePointFlag) const;
|
|
void Internal_SetModified1Flag() const;
|
|
void Internal_SetModified2Flag() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if Modified1Bit or Modified2Bit is set.
|
|
*/
|
|
bool Internal_Modified1IsSet() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if Modified1Bit or Modified2Bit is set.
|
|
*/
|
|
bool Internal_Modified1or2IsSet() const;
|
|
|
|
void Internal_ClearModifiedFlags() const;
|
|
mutable unsigned char m_saved_points_flags = 0U;
|
|
|
|
unsigned char m_level = 0U;
|
|
public:
|
|
|
|
// All the faces with the same nonzero value of m_group_id are in the same "group".
|
|
// SDK interface on ON_SubD will be added after we get a better idea of how this
|
|
// feature will be used.
|
|
mutable unsigned int m_group_id = 0U;
|
|
|
|
protected:
|
|
/*
|
|
Description:
|
|
Clears the flags indicating the saved subdivision point and surface point information
|
|
is current.
|
|
*/
|
|
void Internal_ClearSubdivisionPointAndSurfacePointFlags() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears the flag indicating the saved subdivision point is current.
|
|
*/
|
|
void Internal_ClearSubdivisionPointFlag() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears the flag indicating the saved surface point information is current.
|
|
*/
|
|
void Internal_ClearSurfacePointFlag() const;
|
|
|
|
bool Internal_SubdivisionPointFlag() const;
|
|
|
|
bool Internal_SurfacePointFlag() const;
|
|
|
|
void Internal_TransformComponentBase(bool bTransformationSavedSubdivisionPoint, const class ON_Xform& xform);
|
|
// GetSubdivisionPoint( bUseSavedSubdivisionPoint=true ) can change the value of m_cache_subd_P
|
|
mutable double m_saved_subd_point1[3]; // saved subdivision point
|
|
|
|
private:
|
|
// Reserved for future use for attributes that apply to allSubD components (ON_SubDVertex, ON_SubDEdge, and ON_SubDFace).
|
|
ON__UINT64 m_reserved8bytes1;
|
|
ON__UINT64 m_reserved8bytes2;
|
|
ON__UINT64 m_reserved8bytes3;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Pretend ArchiveId() and SetArchiveId() do not exist.
|
|
Returns:
|
|
The ArchiveId is a value set and used by ON_BinaryArchive Read() and Write()
|
|
functions and copy constructors and operator=().
|
|
A public interface is supplied because it is not practical to use friends.
|
|
Remarks:
|
|
A value of ON_UNSET_UINT_INDEX indicates the component is not in use.
|
|
*/
|
|
unsigned int ArchiveId() const
|
|
{
|
|
return m_archive_id;
|
|
}
|
|
|
|
void SetArchiveId(
|
|
unsigned int archive_id
|
|
) const
|
|
{
|
|
// m_archive_id is mutable
|
|
if ( ON_UNSET_UINT_INDEX != archive_id )
|
|
m_archive_id = archive_id;
|
|
}
|
|
|
|
protected:
|
|
void CopyBaseFrom(
|
|
const ON_SubDComponentBase* src,
|
|
bool bCopySymmetrySetNext
|
|
);
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
True if this component is marked as a primary motif component.
|
|
Remarks:
|
|
You must use ON_SubD SymmetrySet memeber functions to get symmetry set contents.
|
|
*/
|
|
bool IsSymmetrySetPrimaryMotif() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if this component is marked being in a symmetry set.
|
|
Remarks:
|
|
You must use ON_SubD SymmetrySet memeber functions to get symmetry set contents.
|
|
*/
|
|
bool InSymmetrySet() const;
|
|
|
|
private:
|
|
// Symmetry sets are a linked loops of components order so that symmetry(component) = next component.
|
|
// There is exactly one motif in each symmetry set.
|
|
// The motif component is marked with 1 == m_symmetry_set_next.ComponentDirection().
|
|
// The next component in the symmetry set loop is m_symmetry_set_next.Vertex()/Edge()/Face().
|
|
// When a symmetry set is a singleton (fixed component in the symmetry), this = m_symmetry_set_next
|
|
// and m_symmetry_set_next.ComponentDirection()= 1.
|
|
// The only safe way query, set, and clear symmetry set information is to use
|
|
// ON_SubD.*SymmetrySet*() functions. Any other technique is not supported and will cause crashes.
|
|
friend class ON_SubDArchiveIdMap;
|
|
ON_SubDComponentPtr m_symmetry_set_next;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDVertexEdgeProperties
|
|
//
|
|
class ON_CLASS ON_SubDVertexEdgeProperties
|
|
{
|
|
public:
|
|
ON_SubDVertexEdgeProperties() = default;
|
|
~ON_SubDVertexEdgeProperties() = default;
|
|
ON_SubDVertexEdgeProperties(const ON_SubDVertexEdgeProperties&) = default;
|
|
ON_SubDVertexEdgeProperties& operator=(const ON_SubDVertexEdgeProperties&) = default;
|
|
|
|
public:
|
|
static const ON_SubDVertexEdgeProperties Zero; // all member values are zero.
|
|
|
|
/*
|
|
Returns:
|
|
True if there are no null edges and there are two edges with a single face and all remaining edges have two faces.
|
|
Remarks:
|
|
Tags are ignored.
|
|
*/
|
|
bool HasInteriorVertexTopology() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if there are no null edges, exactly two boundary edges, and any other edges have two faces.
|
|
Remarks:
|
|
Tags are ignored.
|
|
*/
|
|
bool HasBoundaryVertexTopology() const;
|
|
|
|
/*
|
|
Returns:
|
|
HasInteriorVertexTopology() || HasBoundaryVertexTopology().
|
|
*/
|
|
bool HasManifoldVertexTopology() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if there are no null edges and there is an edge with zero faces or an edge with three or more faces.
|
|
Remarks:
|
|
Tags are ignored.
|
|
*/
|
|
bool HasNonmanifoldVertexTopology() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of edges.
|
|
*/
|
|
unsigned EdgeCount() const;
|
|
|
|
public:
|
|
// Number of null edges
|
|
unsigned short m_null_edge_count = 0;
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// Vertex attached component counts
|
|
//
|
|
|
|
// vertex->m_edge_count
|
|
unsigned short m_edge_count = 0;
|
|
|
|
// vertex->m_face_count
|
|
unsigned short m_face_count = 0;
|
|
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// Edge tag counts
|
|
//
|
|
|
|
// Number of edges tags ON_SubDEdgeTag::Unset
|
|
unsigned short m_unset_edge_count = 0;
|
|
|
|
// Number of edges tags ON_SubDEdgeTag::Smooth or ON_SubDEdgeTag::SmoothX
|
|
unsigned short m_smooth_edge_count = 0;
|
|
|
|
// Number of edges tags ON_SubDEdgeTag::Crease
|
|
unsigned short m_crease_edge_count = 0;
|
|
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// Edge topology counts
|
|
//
|
|
|
|
// Number of wire edges (0 attached faces)
|
|
unsigned short m_wire_edge_count = 0;
|
|
|
|
// Number of boundary edges (1 attached face)
|
|
unsigned short m_boundary_edge_count = 0;
|
|
|
|
// Number of interior edges (2 attached faces)
|
|
unsigned short m_interior_edge_count = 0;
|
|
|
|
// Number of nonmanifold edges (3 or more attached faces)
|
|
unsigned short m_nonmanifold_edge_count = 0;
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// Edge face counts
|
|
//
|
|
|
|
// Minimum value of attached edges's m_face_count.
|
|
unsigned short m_min_edge_face_count = 0;
|
|
|
|
// Maximum value of attached edges's m_face_count.
|
|
unsigned short m_max_edge_face_count = 0;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDVertex
|
|
//
|
|
class ON_CLASS ON_SubDVertex : public ON_SubDComponentBase
|
|
{
|
|
private:
|
|
friend class ON_SubDArchiveIdMap;
|
|
friend class ON_SubDEdge;
|
|
friend class ON_SubDFace;
|
|
|
|
public:
|
|
ON_SubDVertex() = default;
|
|
~ON_SubDVertex() = default;
|
|
ON_SubDVertex(const ON_SubDVertex&) = default;
|
|
ON_SubDVertex& operator=(const ON_SubDVertex&) = default;
|
|
|
|
public:
|
|
unsigned int VertexId() const;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this vertex.
|
|
Attached edges and faces are not modifed.
|
|
*/
|
|
void ClearSavedSubdivisionPoints() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this vertex.
|
|
Parameters:
|
|
bClearNeighborhood - [in]
|
|
If true, all edges and faces attached to this vertex are also cleared.
|
|
*/
|
|
void ClearSavedSubdivisionPoints(
|
|
bool bClearNeighborhood
|
|
) const;
|
|
|
|
public:
|
|
static const ON_SubDVertex Empty;
|
|
|
|
bool Write (
|
|
class ON_BinaryArchive& archive
|
|
) const;
|
|
|
|
static bool Read (
|
|
class ON_BinaryArchive& archive,
|
|
class ON_SubD& subd,
|
|
class ON_SubDVertex*& vertex
|
|
);
|
|
|
|
const ON_wString ToString(
|
|
bool bIncludeControlNetPoint,
|
|
bool bIncludeTopology
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
bIncludeEdges - [in]
|
|
If true, then attached edges are included.
|
|
bIncludeFaces - [in]
|
|
If true, then attached faces are included.
|
|
Returns:
|
|
A ON_ComponentStatusLogicalOr() of this vertex's status and the
|
|
specified attached components.
|
|
See Also:
|
|
ON_SubDComponentBase::Status()
|
|
*/
|
|
const ON_ComponentStatus NeighborhoodStatusLogicalOr(
|
|
bool bIncludeEdges,
|
|
bool bIncludeFaces
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Apply a tranxfomration matrix to vertex geometry information.
|
|
Parameters:
|
|
bTransformationSavedSubdivisionPoint - [in]
|
|
If the transformation is being applied to every vertex, edge and
|
|
face in every level of a subdivision object, and the transformation
|
|
is an isometry (rotation, translation, ...), a uniform scale, or a
|
|
composition of these types, then set
|
|
bTransformationSavedSubdivisionPoint = true to apply the
|
|
transformation to saved subdivision and saved limit point information.
|
|
In all other cases, set bTransformationSavedSubdivisionPoint = false
|
|
and any saved subdivision points or saved limit points will be
|
|
deleted. When in doubt, pass false.
|
|
|
|
xform - [in]
|
|
*/
|
|
bool Transform(
|
|
bool bTransformationSavedSubdivisionPoint,
|
|
const class ON_Xform& xform
|
|
);
|
|
|
|
bool SetControlNetPoint(
|
|
ON_3dPoint control_net_point,
|
|
bool bClearNeighborhoodCache
|
|
);
|
|
|
|
|
|
ON_BoundingBox ControlNetBoundingBox() const;
|
|
|
|
|
|
public:
|
|
const ON_COMPONENT_INDEX ComponentIndex() const;
|
|
const ON_SubDComponentPtr ComponentPtr() const;
|
|
|
|
public:
|
|
// m_prev_vertex, m_next_vertex must be the first data members of ON_SubDVertex
|
|
const class ON_SubDVertex* m_prev_vertex = nullptr; // linked list of vertices on this level
|
|
const class ON_SubDVertex* m_next_vertex = nullptr; // linked list of vertices on this level
|
|
|
|
public:
|
|
ON_SubDVertexTag m_vertex_tag = ON_SubDVertexTag::Unset;
|
|
|
|
|
|
private:
|
|
//ON_SubD::VertexEdgeOrder m_vertex_edge_order = ON_SubD::VertexEdgeOrder::unset;
|
|
unsigned char m_reserved1 = 0;
|
|
unsigned short m_reserved2 = 0;
|
|
unsigned int m_reserved3 = 0;
|
|
|
|
public:
|
|
unsigned short m_edge_count = 0;
|
|
unsigned short m_face_count = 0;
|
|
|
|
unsigned short m_edge_capacity = 0;
|
|
unsigned short m_face_capacity = 0;
|
|
|
|
public:
|
|
// Array of m_edge_count edges.
|
|
// m_edge[i].EdgeDirection() indicates which edge end is located at this vertex
|
|
// If m_edge_capacity > 0, m_edge_capacity is the number of elements that
|
|
// may be used in m_edges[].
|
|
class ON_SubDEdgePtr* m_edges = nullptr;
|
|
|
|
// Array of m_face_count faces.
|
|
// If m_face_capacity > 0, m_face_capacity is the number of elements that
|
|
// may be used in m_faces[].
|
|
const class ON_SubDFace** m_faces = nullptr;
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove an edge from the vertex's m_edges[] array.
|
|
Remarks:
|
|
Does not modify the edge. If the vertex is referenced by the edge,
|
|
then the vertex must be removed from edge's m_vertex[] array.
|
|
*/
|
|
bool RemoveEdgeFromArray(
|
|
const class ON_SubDEdge* f
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove a face from the vertex's m_faces[] array.
|
|
Remarks:
|
|
Does not modify the face or any edges. The faces edges must be updated accordingly.
|
|
*/
|
|
bool RemoveFaceFromArray(
|
|
const class ON_SubDFace* f
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
bApplyInputTagBias - [in]
|
|
If bApplyInputTagBias is true, the current tag value is used
|
|
to choose between possible output results. When in doubt, pass false.
|
|
bReturnBestGuessWhenInvalid
|
|
If bReturnBestGuessWhenInvalid is true and the topology and current edges
|
|
tags do not meet the conditions for a valid vertex, then a best guess for
|
|
a vertex tag is returned. Otherwise ON_SubDVertexTag::Unset is returned.
|
|
When in doubt pass false and check for unset before using.
|
|
Returns:
|
|
The suggested value for this vertices tag based on its current tag value and
|
|
its current edges. Assumes the vertex and edge topology are correct and the
|
|
edge tags are correctly set.
|
|
*/
|
|
ON_SubDVertexTag SuggestedVertexTag(
|
|
bool bApplyInputTagBias,
|
|
bool bReturnBestGuessWhenInvalid
|
|
) const;
|
|
|
|
public:
|
|
double m_P[3]; // vertex control net location
|
|
|
|
///<summary>
|
|
/// The SubD vertex control net point.
|
|
///</summary>
|
|
const ON_3dPoint ControlNetPoint() const;
|
|
|
|
private:
|
|
// Cached limit point and limit normal
|
|
// GetSurfacePoint( bUseSavedSurfacePoint=true ) can change the value of m_limit_point.
|
|
// If the limit point is set and vertex has a single sector, then
|
|
// m_limit_point.m_sector_face = nullptr and m_limit_point.m_next_sector_limit_point = nullptr.
|
|
// If the limit point is set and vertex has a multiple sectors, then
|
|
// m_limit_point.m_sector_face = first face in the sector.
|
|
// If multiple limit points are set, then they are in a linked list
|
|
// traversed using the ON_SubDSectorSurfacePoint.m_next_sector_limit_point.
|
|
// The second and any additional limit points are managed by a fixed size pool.
|
|
// Calling ClearSurfacePoint() will return these to the pool.
|
|
mutable ON_SubDSectorSurfacePoint m_limit_point = ON_SubDSectorSurfacePoint::Unset;
|
|
|
|
public:
|
|
enum : unsigned int
|
|
{
|
|
MaximumEdgeCount = 0xFFF0U,
|
|
MaximumFaceCount = 0xFFF0U
|
|
};
|
|
|
|
static int CompareUnorderedEdges(
|
|
const ON_SubDVertex* a,
|
|
const ON_SubDVertex* b
|
|
);
|
|
|
|
static int CompareUnorderedFaces(
|
|
const ON_SubDVertex* a,
|
|
const ON_SubDVertex* b
|
|
);
|
|
|
|
static int CompareUnorderedEdgesAndFaces(
|
|
const ON_SubDVertex* a,
|
|
const ON_SubDVertex* b
|
|
);
|
|
|
|
///*
|
|
//Description:
|
|
// Sort the m_edges[] and m_faces[] arrays so radial groups are together.
|
|
// After the sorting is completed, m_vertex_edge_order is set to recored
|
|
// the current sorting state and its value is returned.
|
|
// The sorting is done unconditionally.
|
|
//*/
|
|
//ON_SubD::VertexEdgeOrder SortEdges();
|
|
|
|
unsigned int EdgeCount(
|
|
ON_SubDEdgeTag edge_tag
|
|
) const;
|
|
|
|
unsigned int EdgeCount() const;
|
|
|
|
const class ON_SubDEdge* Edge(
|
|
unsigned int i
|
|
) const;
|
|
|
|
const ON_SubDEdgePtr EdgePtr(
|
|
unsigned int i
|
|
) const;
|
|
|
|
ON__UINT_PTR EdgeDirection(
|
|
unsigned int i
|
|
) const;
|
|
|
|
unsigned int EdgeArrayIndex(
|
|
const ON_SubDEdge* edge
|
|
) const;
|
|
|
|
unsigned int FaceCount() const;
|
|
|
|
const class ON_SubDFace* Face(
|
|
unsigned int i
|
|
) const;
|
|
|
|
unsigned int FaceArrayIndex(
|
|
const ON_SubDFace* face
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to replace reference to old_face with a reference to new_face.
|
|
Parameters:
|
|
old_face = [in]
|
|
Cannot be nullptr.
|
|
new_face = [in]
|
|
If new_face is nullptr, old_face is simply removed.
|
|
Returns:
|
|
If the replacement was successful, then the m_faces[] array index where old_face/new_face replacement occured is returned.
|
|
Otherwise ON_UNSET_UINT_INDEX is returned.
|
|
Remarks:
|
|
No modifications are made to old_face or new_face.
|
|
*/
|
|
unsigned int ReplaceFaceInArray(
|
|
const ON_SubDFace* old_face,
|
|
const ON_SubDFace* new_face
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Smooth.
|
|
*/
|
|
bool IsSmooth() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Crease.
|
|
*/
|
|
bool IsCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Corner.
|
|
*/
|
|
bool IsCorner() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Dart.
|
|
*/
|
|
bool IsDart() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Smooth or ON_SubDVertexTag::Crease.
|
|
*/
|
|
bool IsSmoothOrCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Crease or ON_SubDVertexTag::Corner.
|
|
*/
|
|
bool IsCreaseOrCorner() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Dart, ON_SubDVertexTag::Crease or ON_SubDVertexTag::Corner.
|
|
*/
|
|
bool IsDartOrCreaseOrCorner() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Dart or ON_SubDVertexTag::Crease
|
|
*/
|
|
bool IsDartOrCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_vertex_tag is ON_SubDVertexTag::Smooth or ON_SubDVertexTag::Dart.
|
|
*/
|
|
bool IsSmoothOrDart() const;
|
|
|
|
const ON_SubDVertexEdgeProperties EdgeProperties() const;
|
|
|
|
/*
|
|
Parameters:
|
|
eptr0 - [out]
|
|
eptr1 - [out]
|
|
If a vertex has exactly two attached edges, each of which has a single attached face,
|
|
then these edges are returned in the order the appear in the vertex's edge list.
|
|
(RelativeVertex(0) = this vertex). Othwerise the parameters are set to null.
|
|
Returns:
|
|
True if the vertex has exactly two attached edges, each of which has a single attached face.
|
|
False otherwise.
|
|
*/
|
|
bool GetBoundaryVertexEdges(
|
|
ON_SubDEdgePtr* eptr0,
|
|
ON_SubDEdgePtr* eptr1
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
vei0 - [out]
|
|
vei1 - [out]
|
|
If a vertex has exactly two attached edges, each of which has a single attached face,
|
|
then the indices of those edges in the vertex's edge list are returned.
|
|
Othewise ON_UNSET_UINT_INDEX is returned.
|
|
Returns:
|
|
True if the vertex has exactly two attached edges, each of which has a single attached face.
|
|
False otherwise.
|
|
*/
|
|
bool GetBoundaryVertexEdgeIndices(
|
|
unsigned* vei0,
|
|
unsigned* vei1
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
A "standard" vertex is one where the standard subdivsion matrix for that vertex
|
|
can be used to calculate the subdivision point.
|
|
This function is desinged to be useful for testing and debugging code when
|
|
a certain situation is expected to exist. It is not used for evaluation
|
|
because it is too slow.
|
|
|
|
Returns:
|
|
True if the subdivison point of the vertex can be calulated using the standard
|
|
subdivion matrix for the vertex type and face count.
|
|
|
|
Remarks:
|
|
If the vertex is tagged and has multiple sectors, like an interior
|
|
crease or corner vertex, then this function will return false.
|
|
In this situation, it is possible that the vertex, as the center of a
|
|
sector, is standard.
|
|
*/
|
|
bool IsStandard() const;
|
|
|
|
/*
|
|
Description:
|
|
A single sector vertex is a smooth vertex, a dart vertex, or a manifold boundary
|
|
vertex.
|
|
Returns:
|
|
True if the vertex has a single sector and, consequently, a single
|
|
limit surface normal.
|
|
|
|
*/
|
|
bool IsSingleSectorVertex() const;
|
|
|
|
/*
|
|
Description:
|
|
A manifold boundary vertex is a crease or corner vertex with 2 creased edges,
|
|
each attached to a single face, and all other edges are smooth edges attached
|
|
to two faces. There is a single sector at a manifold boundary vertex.
|
|
Returns:
|
|
True if the vertex has a single sector and, consequently, a single
|
|
limit surface normal.
|
|
|
|
*/
|
|
bool IsManifoldBoundaryVertex() const;
|
|
|
|
/*
|
|
Description:
|
|
A vertex has interior vertex topology if
|
|
EdgeCount() >= 2,
|
|
EdgeCount() == FaceCount(),
|
|
and every attached edge has two attached faces.
|
|
Returns:
|
|
True if the vertex has interior vertex toplology.
|
|
Remarks:
|
|
Tags are ignored. This property is often used during construction
|
|
and modification when tags are not set.
|
|
*/
|
|
bool HasInteriorVertexTopology() const;
|
|
|
|
/*
|
|
Description:
|
|
A vertex has boundary vertex topology if
|
|
EdgeCount() >= 2,
|
|
EdgeCount() == 1+FaceCount(),
|
|
two attached edges are attached to one face,
|
|
the remaining edges are attached to two faces.
|
|
Returns:
|
|
True if the vertex has interior vertex toplology.
|
|
Remarks:
|
|
Tags are ignored. This property is often used during construction
|
|
and modification when tags are not set.
|
|
*/
|
|
bool HasBoundaryVertexTopology() const;
|
|
|
|
/*
|
|
Returns:
|
|
If this vertex has two boundary edges, they are returned in the pair with
|
|
BoundaryEdgePair().First().EdgePtr().RelativeVetex(0) and
|
|
BoundaryEdgePair().Second().EdgePtr().RelativeVetex(0)
|
|
equal to this vertex.
|
|
Otherwise ON_SubDComponentPtrPair::Null is returned.
|
|
*/
|
|
const ON_SubDComponentPtrPair BoundaryEdgePair() const;
|
|
|
|
/*
|
|
Returns:
|
|
If this vertex has two creased edges, they are returned in the pair.
|
|
Otherwise ON_SubDComponentPtrPair::Null is returned.
|
|
*/
|
|
const ON_SubDComponentPtrPair CreasedEdgePair(
|
|
bool bInteriorEdgesOnly
|
|
) const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
If this vertex has one creased edge, it is returned.
|
|
Otherwise ON_SubDEdgePtr::Null is returned.
|
|
*/
|
|
const ON_SubDEdgePtr CreasedEdge(
|
|
bool bInteriorEdgesOnly
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Count creases with specified topology.
|
|
Parameters:
|
|
bCountInteriorCreases - [in]
|
|
Count includes crease edges with 2 faces.
|
|
bCountBoundaryCreases - [in]
|
|
Count includes crease edges with 1 face.
|
|
bCountNonmanifoldCreases - [in]
|
|
Count includes crease edges with 3 or more faces.
|
|
bCountWireCreases - [in]
|
|
Count includes crease edges with 0 faces.
|
|
Returns:
|
|
Number of creased edges with the specified topology.
|
|
*/
|
|
const unsigned int CreasedEdgeCount(
|
|
bool bCountInteriorCreases,
|
|
bool bCountBoundaryCreases,
|
|
bool bCountNonmanifoldCreases,
|
|
bool bCountWireCreases
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of creased edges.
|
|
*/
|
|
const unsigned int CreasedEdgeCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bUseSavedSubdivisionPoint - [in]
|
|
If there is a saved subdivision point and bUseSavedSubdivisionPoint
|
|
is true, then the saved value is returned.
|
|
subdivision_point - [out]
|
|
The SubD vertex Catmull-Clark subdivision point is returned here.
|
|
Returns:
|
|
true if successful
|
|
*/
|
|
bool GetSubdivisionPoint(
|
|
double subdivision_point[3]
|
|
) const;
|
|
|
|
///<summary>
|
|
/// The SubD vertex Catmull-Clark subdivision point.
|
|
///</summary>
|
|
const ON_3dPoint SubdivisionPoint() const;
|
|
|
|
/*
|
|
Description:
|
|
Evaluates the Catmull-Clark subdivision point ignoring all cached information.
|
|
This function is typically used in testing and debugging code and
|
|
in ordinary cases, it is faster and better to call SubdivisionPoint()
|
|
or GetSubdivisionPoint().
|
|
Parameters:
|
|
subdivision_point - [out]
|
|
The vertex Catmull-Clark subdivision point is returned here.
|
|
*/
|
|
bool EvaluateCatmullClarkSubdivisionPoint(
|
|
double subdivision_point[3]
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
sector_face - [in]
|
|
A face in the sector of interest
|
|
limit_point - [out]
|
|
Returns:
|
|
true if successful
|
|
*/
|
|
bool GetSurfacePoint(
|
|
const ON_SubDFace* sector_face,
|
|
class ON_SubDSectorSurfacePoint& limit_point
|
|
) const;
|
|
|
|
bool GetSurfacePoint(
|
|
const ON_SubDFace* sector_face,
|
|
bool bUndefinedNormalIsPossible,
|
|
class ON_SubDSectorSurfacePoint& limit_point
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
If there is a saved limit surface point, then its location is returned in surface_point[].
|
|
Parameters:
|
|
surface_point - [out]
|
|
Returns:
|
|
True if a saved limit surface point is returned.
|
|
False if there is no saved limit surface point. The input value of surface_point[] is not changed.
|
|
*/
|
|
bool GetSavedSurfacePoint(
|
|
double surface_point[3]
|
|
) const;
|
|
|
|
bool GetSurfacePoint(
|
|
double surface_point[3]
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
The SubD surface point.
|
|
*/
|
|
const ON_3dPoint SurfacePoint() const;
|
|
|
|
/*
|
|
Parameters:
|
|
sector_face - [in]
|
|
When the vertex is a crease or corner vertex, different sectors typically
|
|
have different normals and you must specify a face to determine the sector.
|
|
bUndefinedNormalPossible - [in]
|
|
If the SubD control net is degenerate around the vertex, the normal may
|
|
be zero. Pass true if you will accept a zero normal vector. Otherwise
|
|
ON_3dVector::NanVector is returned when a non-zero normal cannot be calculated.
|
|
Returns:
|
|
The SubD surface normal.
|
|
*/
|
|
const ON_3dVector SurfaceNormal(
|
|
const ON_SubDFace* sector_face,
|
|
bool bUndefinedNormalPossible
|
|
) const;
|
|
|
|
const ON_SubDSectorSurfacePoint& SectorSurfacePointForExperts() const;
|
|
|
|
/*
|
|
Parameters:
|
|
subd_appearance - [in]
|
|
If ON_SubDComponentLocation::ControlNet, then this->ControlNetPoint() is returned.
|
|
If ON_SubDComponentLocation::Surface, then this->SurfacePoint() is returned.
|
|
Otherwise ON_3dPoint::NanPoint is returned.
|
|
*/
|
|
const ON_3dPoint Point(ON_SubDComponentLocation subd_appearance) const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Save limit surface point and limit normal for future use.
|
|
Parameters:
|
|
bUndefinedNormalIsPossible - [in]
|
|
true if an undefined normal might occur
|
|
surface_point - [in]
|
|
Returns:
|
|
true if successful
|
|
Remarks:
|
|
ClearSavedSubdivisionPoints() clears any saved limit points.
|
|
*/
|
|
bool SetSavedSurfacePoint(
|
|
bool bUndefinedNormalIsPossible,
|
|
const ON_SubDSectorSurfacePoint surface_point
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
In general, after you modify a vertex you should call VertexModifiedNotification().
|
|
|
|
This is an expert user function that clears any saved limit point evaluations for this vertex.
|
|
No saved subdivision points are cleared.
|
|
No modifications are made to attached edges or faces.
|
|
Remarks:
|
|
In general, you should call VertexModifiedNotification() after you modify a vertex.
|
|
Compare with ClearSavedSubdivisionPoints() which clears any subdivision point
|
|
limit point evaluations saved on this vertex.
|
|
*/
|
|
void ClearSavedSurfacePoints() const;
|
|
|
|
/*
|
|
Returns:
|
|
true
|
|
The vertex limit point and at least one sector normal are saved for Catmull-Clark quad subdivision.
|
|
*/
|
|
bool SurfacePointIsSet() const;
|
|
|
|
|
|
const ON_Plane VertexFrame(
|
|
ON_SubDComponentLocation subd_appearance
|
|
) const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Call this function if the vertex is modified.
|
|
It will clear saved subdivision information on the vertex and neighboring faces and edges that needs to be recalculated.
|
|
*/
|
|
void VertexModifiedNofification() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of edges attached to this vertex with Edge().m_status.RuntimeMark() = true;
|
|
*/
|
|
unsigned int MarkedEdgeCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears all marks on edges.
|
|
Returns:
|
|
true if all edges are not null.
|
|
false if any edges are null.
|
|
*/
|
|
bool ClearEdgeMarks() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of faces attached to this vertex with Face().m_status.RuntimeMark() = true;
|
|
*/
|
|
unsigned int MarkedFaceCount() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Clears all marks on faces.
|
|
Returns:
|
|
true if all faces are not null.
|
|
false if any faces are null.
|
|
*/
|
|
bool ClearFaceMarks() const;
|
|
|
|
/*
|
|
Returns:
|
|
Minimum number of edges for any face attached to this vertex.
|
|
*/
|
|
unsigned int MinimumFaceEdgeCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Maximum number of edges for any face attached to this vertex.
|
|
*/
|
|
unsigned int MaximumFaceEdgeCount() const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
Minimum number of faces for any edge attached to this vertex.
|
|
*/
|
|
unsigned int MinimumEdgeFaceCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Maximum number of faces for any edge attached to this vertex.
|
|
*/
|
|
unsigned int MaximumEdgeFaceCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to unset ON_SubEdge.m_sector_coefficent[] values for
|
|
edges attached to this vertex.
|
|
Parameters:
|
|
relative_edge_end_dex - [in]
|
|
0: unset vertex edge sector coefficient at the end where the edges
|
|
attaches to this vertex.
|
|
1: unset vertex edge sector coefficient at the end where the edges
|
|
attaches to the other vertex.
|
|
2: unset vertex edge sector coefficients at both ends of the edge.
|
|
*/
|
|
void UnsetSectorCoefficientsForExperts(
|
|
unsigned int relative_edge_end_dex
|
|
) const;
|
|
|
|
private:
|
|
static bool Internal_GetCatmullClarkSubdivisionPoint(
|
|
const class ON_SubDVertex* vertex, // smooth or dart
|
|
double vertex_point[3]
|
|
);
|
|
|
|
static unsigned int Internal_GetFacePointSum(
|
|
const ON_SubDFace* face,
|
|
const ON_SubDVertex* vertex,
|
|
double* facePsum // sum of points that are not immediately adjacent to vertex
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Used for smooth and dart vertices when there are faces
|
|
that use the vertex have different numbers of sides.
|
|
This typically happen when a quad subd control net is
|
|
being subdivided for the first time.
|
|
Parameters:
|
|
vertex - [in]
|
|
vertex_point - [out]
|
|
Returns:
|
|
true if successful
|
|
*/
|
|
static bool Internal_GetGeneralQuadSubdivisionPoint(
|
|
const class ON_SubDVertex* vertex,
|
|
double vertex_point[3]
|
|
);
|
|
|
|
private:
|
|
void CopyFrom(
|
|
const ON_SubDVertex* src,
|
|
bool bCopyEdgeArray,
|
|
bool bCopyFaceArray,
|
|
bool bCopySurfacePointList,
|
|
bool bCopySymmetrySetNext
|
|
);
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDEdge
|
|
//
|
|
class ON_CLASS ON_SubDEdge : public ON_SubDComponentBase
|
|
{
|
|
private:
|
|
friend class ON_Internal_SubDFaceMeshFragmentAccumulator;
|
|
friend class ON_SubDHeap;
|
|
friend class ON_SubDArchiveIdMap;
|
|
friend class ON_SubDVertex;
|
|
friend class ON_SubDFace;
|
|
|
|
public:
|
|
ON_SubDEdge() = default;
|
|
~ON_SubDEdge() = default;
|
|
ON_SubDEdge(const ON_SubDEdge&) = default;
|
|
ON_SubDEdge& operator=(const ON_SubDEdge&) = default;
|
|
|
|
public:
|
|
unsigned int EdgeId() const;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this edge.
|
|
Attached vertices and faces are not modifed.
|
|
*/
|
|
void ClearSavedSubdivisionPoints() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this edge.
|
|
Parameters:
|
|
bClearNeighborhood - [in]
|
|
If true, all vertices and faces attached to this edge are also cleared.
|
|
*/
|
|
void ClearSavedSubdivisionPoints(
|
|
bool bClearNeighborhood
|
|
) const;
|
|
|
|
public:
|
|
static const ON_SubDEdge Empty;
|
|
|
|
bool Write (
|
|
class ON_BinaryArchive& archive
|
|
) const;
|
|
|
|
static bool Read (
|
|
class ON_BinaryArchive& archive,
|
|
class ON_SubD& subd,
|
|
class ON_SubDEdge*& edge
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
bIncludeVertices - [in]
|
|
If true, then attached vertices are included.
|
|
bIncludeFaces - [in]
|
|
If true, then attached faces are included.
|
|
Returns:
|
|
A ON_ComponentStatusLogicalOr() of this vertex's status and the
|
|
specified attached components.
|
|
See Also:
|
|
ON_SubDComponentBase::Status()
|
|
*/
|
|
const ON_ComponentStatus NeighborhoodStatusLogicalOr(
|
|
bool bIncludeVertices,
|
|
bool bIncludeFaces
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Apply a tranxfomration matrix to vertex geometry information.
|
|
|
|
Parameters:
|
|
bTransformationSavedSubdivisionPoint - [in]
|
|
If the transformation is being applied to every vertex, edge and
|
|
face in every level of a subdivision object, and the transformation
|
|
is an isometry (rotation, translation, ...), a uniform scale, or a
|
|
composition of these types, then set
|
|
bTransformationSavedSubdivisionPoint = true to apply the
|
|
transformation to saved subdivision and saved limit point information.
|
|
In all other cases, set bTransformationSavedSubdivisionPoint = false
|
|
and any saved subdivision points or saved limit points will be
|
|
deleted. When in doubt, pass false.
|
|
|
|
xform - [in]
|
|
*/
|
|
bool Transform(
|
|
bool bTransformationSavedSubdivisionPoint,
|
|
const class ON_Xform& xform
|
|
);
|
|
|
|
const ON_BoundingBox ControlNetBoundingBox() const;
|
|
|
|
const ON_Plane CenterFrame(
|
|
ON_SubDComponentLocation subd_appearance
|
|
) const;
|
|
|
|
|
|
|
|
/*
|
|
Description:
|
|
Call this function if the edge is modified and it will clear any
|
|
cached subdivision information that needs to be recalculated.
|
|
*/
|
|
void EdgeModifiedNofification() const;
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to unset sector coefficients.
|
|
*/
|
|
void UnsetSectorCoefficientsForExperts() const;
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to set mutable sector coefficients.
|
|
Returns:
|
|
True if values were modified.
|
|
*/
|
|
bool UpdateEdgeSectorCoefficientsForExperts(
|
|
bool bUnsetEdgeSectorCoefficientsOnly
|
|
) const;
|
|
|
|
public:
|
|
const ON_COMPONENT_INDEX ComponentIndex() const;
|
|
const ON_SubDComponentPtr ComponentPtr() const;
|
|
|
|
public:
|
|
// m_prev_edge, m_next_edge must be the first data members of ON_SubDEdge
|
|
const class ON_SubDEdge* m_prev_edge = nullptr; // linked list of edges on this level
|
|
const class ON_SubDEdge* m_next_edge = nullptr; // linked list of edges on this level
|
|
|
|
public:
|
|
// When checking the edge tag, it is important to consider what
|
|
// should happen in the ON_SubDEdgeTag::SmoothX case. It is strongly
|
|
// suggested that you use the member functions ON_SubDEdge::IsSmooth()
|
|
// and ON_SubDEdge::IsCrease() instead of comparing m_edge_tag to
|
|
// ON_SubDEdgeTag values.
|
|
ON_SubDEdgeTag m_edge_tag = ON_SubDEdgeTag::Unset;
|
|
|
|
private:
|
|
unsigned char m_reserved1 = 0;
|
|
unsigned short m_reserved2 = 0;
|
|
|
|
public:
|
|
// Array of m_face_count faces.
|
|
//
|
|
// The first two are in m_face2[0] and m_face2[1].
|
|
// When m_face_count > 3, the third and additional faces
|
|
// are in m_facex[0], ..., m_facex[m_face_count-3];
|
|
//
|
|
// The value of ON_SubDFacePtr.FaceDirection() is 0 if the
|
|
// edge's natural orientation from m_vertex[0] to m_vertex[1]
|
|
// agrees with the face's boundary orientation.
|
|
//
|
|
// The value of ON_SubDFacePtr.FaceDirection() is 1 if the
|
|
// edge's natural orientation from m_vertex[0] to m_vertex[1]
|
|
// is opposited the face's boundary orientation.
|
|
enum : unsigned int
|
|
{
|
|
MaximumFaceCount = 0xFFF0U
|
|
};
|
|
unsigned short m_face_count = 0;
|
|
unsigned short m_facex_capacity = 0;
|
|
ON_SubDFacePtr m_face2[2] = {};
|
|
ON_SubDFacePtr* m_facex = nullptr;
|
|
|
|
// m_vertex[0] = vertex at the start of the edge.
|
|
// m_vertex[1] = vertex at the end of the edge.
|
|
const class ON_SubDVertex* m_vertex[2] = {};
|
|
|
|
// If the value of vertex->m_vertex_tag is not ON_SubDVertexTag::Smooth,
|
|
// then that vertex is "tagged".
|
|
//
|
|
// If the value of m_edge_tag is ON_SubDEdgeTag::Crease,
|
|
// then m_sector_coefficient[] should be {0,0}.
|
|
// In any case m_sector_coefficient[] values are ignored and the
|
|
// midpoint of the edge is the location of the edge.s subdivision point.
|
|
// The edge's subdivision vertex will be tagged as ON_SubDVertexTag::Crease
|
|
// and both subdivision edges will be tagged as ON_SubDEdgeTag::Crease.
|
|
//
|
|
// If the value of m_edge_tag is ON_SubDEdgeTag::Smooth
|
|
// and neither end vertex is tagged, then m_sector_coefficient[] should be {0,0}.
|
|
// In any case m_sector_coefficient[] values are ignored on smooth edges
|
|
// with smooth vertices at both ends.
|
|
// The edge's subdivision vertex will be tagged as ON_SubDVertexTag::Smooth
|
|
// and both subdivision edges will be tagged as ON_SubDEdgeTag::Smooth.
|
|
//
|
|
// If the value of m_edge_tag is ON_SubDEdgeTag::Smooth and
|
|
// exactly one end vertex is tagged, then the m_sector_coefficient[]
|
|
// value for the tagged end is calculated by ON_SubDSectorType::SectorCoefficient().
|
|
// tagged_weight*tagged_vertex + (1.0 - tagged_weight)*untagged_vertex
|
|
// is used when combining the edge ends.
|
|
// The edge's subdivision vertex will be tagged as ON_SubDVertexTag::Smooth
|
|
// and both subdivision edges will be tagged as ON_SubDEdgeTag::Smooth.
|
|
//
|
|
// If the value of m_edge_tag is ON_SubDEdgeTag::SmoothX, then the edge
|
|
// must have exactly two neighboring faces,
|
|
// both vertices must be tagged and the m_sector_coefficient[]
|
|
// values are calculated by ON_SubDSectorType::SectorCoefficient().
|
|
// When the edge is subdivided, the midpoint of the edge is the
|
|
// location of the edge.s subdivision point.
|
|
// The edge's subdivision vertex will be tagged as ON_SubDVertexTag::Smooth
|
|
// and both subdivision edges will be tagged as ON_SubDEdgeTag::Smooth.
|
|
//
|
|
// If the value of m_edge_tag is ON_SubDEdgeTag::Smooth
|
|
// and both end vertices are tagged, that is a severe error
|
|
// condition and the edge is subdivided at its midpoint.
|
|
//
|
|
// If the value of m_edge_tag is ON_SubDEdgeTag::SmoothX
|
|
// and both end vertices are not tagged, that is a severe error
|
|
// condition and the edge is subdivided at its midpoint.
|
|
//
|
|
// m_sector_coefficient[tagged_end] = 1/2 + 1/3*cos(theta)
|
|
// where "theta" = tagged end "theta" (which depends on vertex tag (dart/crease/corner),
|
|
// the number of faces in the sector, and the control net crease angle when the tagged end is a corner.
|
|
//
|
|
// The name "sector coefficient" is used because the value is a property of the
|
|
// vertex's sector (every smooth edge inside a vertex sector has the same value at the tagged vertex).
|
|
// The sector coefficient does not change which a subdivision is applied.
|
|
mutable double m_sector_coefficient[2] = {};
|
|
|
|
// If m_edge_tag is not ON_SubDEdgeTag::Sharp, then m_sharpness is ignored.
|
|
// If m_edge_tag is ON_SubDEdgeTag::Sharp, then m_sharpness controls how hard/soft
|
|
// the edge appears.
|
|
// The behavior of a "sharp" edge with m_sharpness = 1 is identical to a crease edge.
|
|
// A "sharp" edge with m_sharpness = 0 is identical to a smooth edge.
|
|
// For this reason, m_sharpness must be > 0 and < 1.
|
|
double m_sharpness = 0.0;
|
|
|
|
private:
|
|
// Cached limit curve
|
|
// GetEdgeSurfaceCurveControlPoints( bUseSavedSurfacePoint=true ) can change the value of m_limit_curve.
|
|
// If 0 != ON_SUBD_CACHE_LIMIT_FLAG(m_saved_points_flags), then
|
|
// m_limit_curve is the edge's limit surface curve.
|
|
// The memory is managed by the parent ON_SubD.
|
|
// If 0 == ON_SUBD_CACHE_LIMIT_FLAG(m_saved_points_flags),
|
|
// then any information in m_limit_mesh_fragments is dirty
|
|
// and should not be used.
|
|
// ClearSavedSubdivisionPoints() zeros
|
|
// the appropriate bit of m_saved_points_flags.
|
|
|
|
mutable class ON_SubDEdgeSurfaceCurve* m_limit_curve = nullptr;
|
|
|
|
public:
|
|
|
|
/*
|
|
Returns:
|
|
Number of distinct non-nullptr vertices.
|
|
If the edge is valid, this will be 2.
|
|
*/
|
|
unsigned int VertexCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
evi - [in]
|
|
0 or 1
|
|
Returns:
|
|
If evi is 0 or 1 and m_vertex[evi] is not nullptr, then m_vertex[evi]->m_id is returned. Otherwise 0 i returned.
|
|
*/
|
|
unsigned int VertexId(
|
|
unsigned evi
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
evi - [in]
|
|
0 or 1
|
|
Returns:
|
|
If evi is 0 or 1, then m_vertex[evi] is returned. Otherwise nullptr is returned.
|
|
*/
|
|
const class ON_SubDVertex* Vertex(
|
|
unsigned evi
|
|
) const;
|
|
|
|
unsigned int VertexArrayIndex(
|
|
const class ON_SubDVertex* v
|
|
) const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Return the vertex at the other end of the edge.
|
|
Parameters:
|
|
vertex - [in]
|
|
A vertex referenced in the edge's m_vertex[] array.
|
|
Returns:
|
|
If vertex is not nullptr and exactly one of m_vertex[] is equal to vertex,
|
|
then the other m_vertex[] pointer is returned.
|
|
In any other case, nullptr is returned.
|
|
See Also:
|
|
ON_SubDEdge.NeighborFace()
|
|
*/
|
|
const class ON_SubDVertex* OtherEndVertex(
|
|
const class ON_SubDVertex* vertex
|
|
) const;
|
|
|
|
|
|
unsigned int FaceCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bRequireSameFaceOrientation - [in]
|
|
If true, the attached faces must use the edge with opposite directions (oriented manifold).
|
|
Returns:
|
|
True if the edge has two distinct faces.
|
|
*/
|
|
bool HasInteriorEdgeTopology(
|
|
bool bRequireOppositeFaceDirections
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
bRequireSameFaceOrientation - [in]
|
|
If true, the attached faces must use the edge with opposite directions (oriented manifold).
|
|
Returns:
|
|
True if the edge has two distinct faces.
|
|
*/
|
|
bool HasBoundaryEdgeTopology() const;
|
|
|
|
const ON_SubDFacePtr FacePtr(
|
|
unsigned int i
|
|
) const;
|
|
|
|
const ON_SubDFacePtr FacePtrFromFace(
|
|
const class ON_SubDFace* f
|
|
) const;
|
|
|
|
const class ON_SubDFace* Face(
|
|
unsigned int i
|
|
) const;
|
|
|
|
ON__UINT_PTR FaceDirection(
|
|
unsigned int i
|
|
) const;
|
|
|
|
unsigned int FaceArrayIndex(
|
|
const class ON_SubDFace* f
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove a face from the edges's face array.
|
|
Remarks:
|
|
Does not modify the face. If the edge is referenced in the face's edge array,
|
|
then the edge must be removed from the face's edge array.
|
|
*/
|
|
bool RemoveFaceFromArray(
|
|
const ON_SubDFace* f
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove a face from the edges's face array.
|
|
Remarks:
|
|
Does not modify the face. If the edge is referenced in the face's edge array,
|
|
then the edge must be removed from the face's edge array.
|
|
*/
|
|
bool RemoveFaceFromArray(
|
|
unsigned int i,
|
|
ON_SubDFacePtr& removed_face
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to add a face from the edges's face array.
|
|
Remarks:
|
|
Does not modify the face. If the edge is not referenced in the face's edge array,
|
|
then the edge must be inserted in the correct location in the faces array.
|
|
If you are creating a non-manifold SubD, you must first reserve m_facex[]
|
|
capacity by calling ON_SubD::GrowEdgeFaceArray().
|
|
*/
|
|
bool AddFaceToArray(
|
|
ON_SubDFacePtr face_ptr
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to replace reference to old_face with a reference to new_face.
|
|
Existing orientation is copied. No changes are made to old_face and new_face and
|
|
their edge references must be updated accordingly.
|
|
Parameters:
|
|
old_face = [in]
|
|
Cannot be nullptr.
|
|
new_face = [in]
|
|
If new_face is nullptr, old_face is simply removed.
|
|
Returns:
|
|
If the replacement was successful, then the m_faces[] array index where old_face/new_face replacement occured is returned.
|
|
Otherwise ON_UNSET_UINT_INDEX is returned.
|
|
Remarks:
|
|
No modifications are made to old_face or new_face.
|
|
*/
|
|
unsigned int ReplaceFaceInArray(
|
|
const ON_SubDFace* old_face,
|
|
const ON_SubDFace* new_face
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
vertex0 - [in]
|
|
vertex1 - [in]
|
|
bIgnoreOrientation - [in]
|
|
If false, then the returned edge must have vertices (vertex0, vertex1).
|
|
If true, then the returned edge may have vertices (vertex0, vertex1) or (vertex1, vertex0).
|
|
Returns:
|
|
If an edge connects the input vertices, it is returned. Otherwise nullptr is returned.
|
|
*/
|
|
static const ON_SubDEdge* FromVertices(
|
|
const ON_SubDVertex* vertex0,
|
|
const ON_SubDVertex* vertex1,
|
|
bool bIgnoreOrientation
|
|
);
|
|
|
|
static const ON_SubDEdgePtr FromVertices(
|
|
const ON_SubDVertex* vertex0,
|
|
const ON_SubDVertex* vertex1
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
i - [in]
|
|
0 or 1.
|
|
Returns:
|
|
If i is 0 or 1 and vertex[i] is set, then vertex[i]->ControlNetPoint() is returned.
|
|
Otherwise ON_3dPoint::NanPoint is returned.
|
|
*/
|
|
const ON_3dPoint ControlNetPoint( unsigned int i ) const;
|
|
|
|
const ON_Line ControlNetLine() const;
|
|
|
|
/*
|
|
Returns:
|
|
If vertices are set, then the vector from m_vertex[0]->ControlNetPoint()
|
|
to m_vertex[1]->ControlNetPoint() is returned.
|
|
Otherwise ON_3dVector::NanVector is returned.
|
|
*/
|
|
const ON_3dVector ControlNetDirection() const;
|
|
|
|
/*
|
|
Returns:
|
|
If vertices are set and v is an end of the edge,
|
|
then the vector from v to OtherEndVertex(v) is returned.
|
|
Otherwise ON_3dVector::NanVector is returned.
|
|
*/
|
|
const ON_3dVector ControlNetDirectionFrom(
|
|
const ON_SubDVertex* v
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Return the neighboring face.
|
|
Parameters:
|
|
face - [in]
|
|
A face referenced in the edge's m_face2[] array.
|
|
bStopAtCrease - [in]
|
|
If true and if m_edge_tag = ON_SubDEdgeTag::Crease,
|
|
then nullptr is returned.
|
|
Returns:
|
|
If the m_face_count = 2,
|
|
m_edge_tag is smooth or x or passes the crease tag test,
|
|
one of m_face2[0,1] points a face, then
|
|
the neighboring face is returned.
|
|
In any other case, nullptr is returned.
|
|
*/
|
|
const ON_SubDFace* NeighborFace(
|
|
const ON_SubDFace* face,
|
|
bool bStopAtCrease
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Return the neighboring face.
|
|
Parameters:
|
|
face - [in]
|
|
A face referenced in the edge's m_face2[] array.
|
|
bStopAtCrease - [in]
|
|
If true and if m_edge_tag = ON_SubDEdgeTag::Crease,
|
|
then nullptr is returned.
|
|
Returns:
|
|
If the m_face_count = 2,
|
|
m_edge_tag is smooth or x or passes the crease tag test,
|
|
one of m_face2[0,1] points a face, then
|
|
the neighboring face is returned.
|
|
In any other case, ON_SubDFacePtr::Null is returned.
|
|
*/
|
|
const ON_SubDFacePtr NeighborFacePtr(
|
|
const ON_SubDFace* face,
|
|
bool bStopAtCrease
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
edge_vertex_index - [in]
|
|
0 or 1 identifying which end of this edge to check.
|
|
i - [in]
|
|
Index of the face in this edge's face array.
|
|
Returns:
|
|
The edge adjacent to this edge in this->Face(i).
|
|
The orientation is with respect to this->Face(i).
|
|
*/
|
|
const ON_SubDEdgePtr AdjacentEdgePtr(
|
|
unsigned int edge_vertex_index,
|
|
unsigned int i
|
|
) const;
|
|
|
|
const ON_SubDEdge* AdjacentEdge(
|
|
unsigned int edge_vertex_index,
|
|
unsigned int i
|
|
) const;
|
|
/*
|
|
Returns:
|
|
True if m_edge_tag is ON_SubDEdgeTag::Smooth or ON_SubDEdgeTag::SmoothX.
|
|
False in all other cases.
|
|
*/
|
|
bool IsSmooth() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_edge_tag is ON_SubDEdgeTag::Smooth.
|
|
Remarks:
|
|
Expert user function.
|
|
This is used in rare cases when level 0 edges tagged as ON_SubDEdgeTag::SmoothX
|
|
need special handling in low level evaluation code. Typical SDK level functions
|
|
and anything related to runtime user interface should call IsSmooth().
|
|
*/
|
|
bool IsSmoothNotX() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_edge_tag is ON_SubDEdgeTag::SmoothX.
|
|
Remarks:
|
|
Expert user function.
|
|
This is used in rare cases when level 0 edges tagged as ON_SubDEdgeTag::SmoothX
|
|
need special handling in low level evaluation code. Typical SDK level functions
|
|
and anything related to runtime user interface should call IsSmooth().
|
|
An edge tagged as "X" can occur at level 0. It is subdivided as a smooth
|
|
vertex and both of its end vertices are tagged as ON_SubDVertexTag::Crease,
|
|
ON_SubDVertexTag::Corner, or ON_SubDVertexTag::Dart.
|
|
This tag cannot appear at level N with N >= 1.
|
|
*/
|
|
bool IsSmoothX() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_edge_tag is ON_SubDEdgeTag::Crease.
|
|
*/
|
|
bool IsCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_edge_tag is ON_SubDEdgeTag::Crease and both of its end vertices
|
|
are tagged as ON_SubDVertexTag::Crease, or ON_SubDVertexTag::Corner.
|
|
*/
|
|
bool IsHardCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
True if m_edge_tag is ON_SubDEdgeTag::Crease and at least one of its end vertices
|
|
are tagged as ON_SubDVertexTag::Dart.
|
|
*/
|
|
bool IsDartCrease() const;
|
|
|
|
/*
|
|
Returns:
|
|
0: end vertices are not tagged as darts
|
|
1: one end vertex is tagged as a dart.
|
|
2: both end vertices are tagged as a darts.
|
|
*/
|
|
unsigned int DartCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
bitwise or of applicable ON_ComponentAttributes::EdgeAttributes values.
|
|
Remarks:
|
|
ON_ComponentAttributes::EdgeAttributes has subsets of mutually exclusive
|
|
edge attributes. If the edge is valid, then exactly one bit from each
|
|
mutually exclusive set of properties will be set.
|
|
If an edge is not valie, then all bits for a set may be clear.
|
|
For example, if the edge has nullptr values in m_vertex[]
|
|
or the vertex control point locations are unset or nan,
|
|
then neither the ON_ComponentAttributes::EdgeAttributes::Open bit
|
|
nor ON_ComponentAttributes::EdgeAttributes::Closed bit will be set.
|
|
*/
|
|
unsigned int EdgeAttributes() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bUseSavedSubdivisionPoint - [in]
|
|
If there is a saved subdivision point and bUseSavedSubdivisionPoint
|
|
is true, then the saved value is returned.
|
|
subdivision_point - [out]
|
|
Returns:
|
|
true if successful
|
|
*/
|
|
bool GetSubdivisionPoint(
|
|
double subdivision_point[3]
|
|
) const;
|
|
|
|
///<summary>
|
|
/// The SubD edge Catmull-Clark subdivision point.
|
|
///</summary>
|
|
const ON_3dPoint SubdivisionPoint() const;
|
|
|
|
/*
|
|
Description:
|
|
Evaluates the Catmull-Clark subdivision point ignoring all cached information.
|
|
This function is typically used in testing and debugging code and
|
|
in ordinary cases, it is faster and better to call SubdivisionPoint()
|
|
or GetSubdivisionPoint().
|
|
Parameters:
|
|
subdivision_point - [out]
|
|
The edge Catmull-Clark subdivision point is returned here.
|
|
*/
|
|
bool EvaluateCatmullClarkSubdivisionPoint(
|
|
double subdivision_point[3]
|
|
) const;
|
|
|
|
const ON_3dPoint ControlNetCenterPoint() const;
|
|
const ON_3dVector ControlNetCenterNormal(
|
|
unsigned int edge_face_index
|
|
) const;
|
|
|
|
bool EdgeSurfaceCurveIsSet() const;
|
|
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
edge_vertex_index - [in]
|
|
0 or 1
|
|
edge_ptr0 - [out]
|
|
edge_ptr1 - [out]
|
|
Crease edges that bound the sector containing this edge.
|
|
The direction value of the edge pointer identifies the end
|
|
of the sector boundary edge this->at m_vertex[edge_vertex_index].
|
|
Returns:
|
|
Number of faces in the sector.
|
|
*/
|
|
unsigned int GetSectorBoundaryEdges(
|
|
unsigned int edge_vertex_index,
|
|
ON_SubDEdgePtr* edge_ptr0,
|
|
ON_SubDEdgePtr* edge_ptr1
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
Set bTagged[i] = m_vertex[0]->IsDartOrCreaseOrCorner().
|
|
0: bTagged[0] is true and bTagged[1] is false.
|
|
1: bTagged[0] is false and bTagged[1] is true.
|
|
2: bTagged[0] and Tagged[1] are both true.
|
|
3: bTagged[0] and Tagged[1] are both false.
|
|
*/
|
|
unsigned int TaggedEndIndex() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of end vertices with Vertex().m_status.RuntimeMark() = true;
|
|
*/
|
|
unsigned int MarkedVertexCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of faces attached to this edge with Face().m_status.RuntimeMark() = true;
|
|
*/
|
|
unsigned int MarkedFaceCount() const;
|
|
|
|
private:
|
|
static unsigned int GetFacePointSum(
|
|
const ON_SubDFace* face,
|
|
const ON_SubDEdge* edge,
|
|
double* facePsum // sum of face vertex points not on the edge
|
|
);
|
|
|
|
private:
|
|
void CopyFrom(
|
|
const ON_SubDEdge* src,
|
|
bool bReverseEdge,
|
|
bool bCopyVertexArray,
|
|
bool bCopyFaceArray,
|
|
bool bCopySymmetrySetNext
|
|
);
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDFace
|
|
//
|
|
class ON_CLASS ON_SubDFace : public ON_SubDComponentBase
|
|
{
|
|
private:
|
|
friend class ON_Internal_SubDFaceMeshFragmentAccumulator;
|
|
friend class ON_SubDHeap;
|
|
friend class ON_SubDArchiveIdMap;
|
|
friend class ON_SubDVertex;
|
|
friend class ON_SubDEdge;
|
|
|
|
public:
|
|
ON_SubDFace() = default;
|
|
~ON_SubDFace() = default;
|
|
ON_SubDFace(const ON_SubDFace&) = default;
|
|
ON_SubDFace& operator=(const ON_SubDFace&) = default;
|
|
|
|
public:
|
|
unsigned int FaceId() const;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this face.
|
|
Attached edges and vertices are not modifed.
|
|
*/
|
|
void ClearSavedSubdivisionPoints() const;
|
|
|
|
/*
|
|
Description:
|
|
Clears saved subdivision and limit surface information for this face.
|
|
Parameters:
|
|
bClearNeighborhood - [in]
|
|
If true, all vertices, edges and face attached to this face are also cleared.
|
|
*/
|
|
void ClearSavedSubdivisionPoints(
|
|
bool bClearNeighborhood
|
|
) const;
|
|
|
|
public:
|
|
static const ON_SubDFace Empty;
|
|
|
|
bool Write(
|
|
class ON_BinaryArchive& archive
|
|
) const;
|
|
|
|
static bool Read(
|
|
class ON_BinaryArchive& archive,
|
|
class ON_SubD& subd,
|
|
class ON_SubDFace*& face
|
|
);
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
bIncludeVertices - [in]
|
|
If true, then attached vertices are included.
|
|
bIncludeEdges - [in]
|
|
If true, then attached edges are included.
|
|
Returns:
|
|
A ON_ComponentStatusLogicalOr() of this vertex's status and the
|
|
specified attached components.
|
|
See Also:
|
|
ON_SubDComponentBase::Status()
|
|
*/
|
|
const ON_ComponentStatus NeighborhoodStatusLogicalOr(
|
|
bool bIncludeVertices,
|
|
bool bIncludeEdges
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Apply a tranxfomration matrix to vertex geometry information.
|
|
|
|
Parameters:
|
|
bTransformationSavedSubdivisionPoint - [in]
|
|
If the transformation is being applied to every vertex, edge and
|
|
face in every level of a subdivision object, and the transformation
|
|
is an isometry (rotation, translation, ...), a uniform scale, or a
|
|
composition of these types, then set
|
|
bTransformationSavedSubdivisionPoint = true to apply the
|
|
transformation to saved subdivision and saved limit point information.
|
|
In all other cases, set bTransformationSavedSubdivisionPoint = false
|
|
and any saved subdivision points or saved limit points will be
|
|
deleted. When in doubt, pass false.
|
|
|
|
xform - [in]
|
|
*/
|
|
bool Transform(
|
|
bool bTransformationSavedSubdivisionPoint,
|
|
const class ON_Xform& xform
|
|
);
|
|
|
|
const ON_BoundingBox ControlNetBoundingBox() const;
|
|
|
|
/*
|
|
Parameters:
|
|
vertex_list - [in]
|
|
vertices in face boundary.
|
|
vertex_list[0] can be any vertex in the face boundary and vertex_list[] can traverse the
|
|
boundary in order or reversed.
|
|
Return:
|
|
If there is a face whose boundary vertex list is face_vertices[], then that face is returned and
|
|
ON_SubDFacePtr.FaceDirection() indicates the orientation of face_vertices[].
|
|
Otherwise ON_SubDFacePtr::Null is returned.
|
|
*/
|
|
static const ON_SubDFacePtr FromVertices(
|
|
const ON_SimpleArray< const ON_SubDVertex* >& vertex_list
|
|
);
|
|
static const ON_SubDFacePtr FromVertices(
|
|
const ON_SubDVertex*const* vertex_list,
|
|
size_t face_vertices_count
|
|
);
|
|
|
|
|
|
const ON_COMPONENT_INDEX ComponentIndex() const;
|
|
const ON_SubDComponentPtr ComponentPtr() const;
|
|
|
|
/*
|
|
Description:
|
|
Call this function if the face is modified and it will clear any
|
|
cached subdivision information that needs to be recalculated.
|
|
*/
|
|
void FaceModifiedNofification() const;
|
|
|
|
public:
|
|
// m_prev_face, m_next_face must be the first data members of ON_SubDFace
|
|
const class ON_SubDFace* m_prev_face = nullptr; // linked list of faces on this level
|
|
const class ON_SubDFace* m_next_face = nullptr; // linked list of faces on this level
|
|
|
|
private:
|
|
unsigned int m_reserved = 0;
|
|
|
|
private:
|
|
// If non zero, m_pack_id identifies the packed group of faces this faces belongs to.
|
|
// Faces that are not quads are never in grouped with other faces.
|
|
// When possible, quads are packed into groups that form larger rectangular regions.
|
|
// ON_SubD::Packfaces() creates the packing information.
|
|
// Packing information is saved in 3dm files.
|
|
unsigned int m_pack_id = 0;
|
|
|
|
// Location of this face's pack rectin normaized coordinates
|
|
// Each face is assigned a unique rectangle in the unit square (0,1)x(0,1).
|
|
// Groups of quad faces packed together.
|
|
// If faces are added to an existing subd, the pack rects for the entire subd must be recalculated.
|
|
// If faces in a quad group are removed from a subd, the pack rects for the entire subd must be recalculated.
|
|
double m_pack_rect_origin[2] = {ON_DBL_QNAN};
|
|
double m_pack_rect_size[2] = {ON_DBL_QNAN};
|
|
unsigned int m_packed_rect_u = 0;
|
|
unsigned int m_packed_rect_v = 0;
|
|
|
|
enum PackStatusBits : unsigned char
|
|
{
|
|
ZeroPackStatusBits = 0,
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Pack rectangle status
|
|
//
|
|
|
|
// 4 ways the pack rectangle can be rotated for a face when packed texture coordinates are
|
|
// calculated from the packing rectangle.
|
|
// These enum values must be 0,1,2,3 because these values are used in arithmetic formulae.
|
|
// Rotation is used to keep pac rect coordinates continuous in quad packs containing faces
|
|
// with inconsistent topological orientations, which is the most common situation.
|
|
PackingRotate0 = 0,
|
|
PackingRotate90 = 1,
|
|
PackingRotate180 = 2,
|
|
PackingRotate270 = 3,
|
|
|
|
// mask for the bits used to encode the packing rotation
|
|
PackingRotateMask = 3,
|
|
|
|
// bit used to determine if the values in m_packed_coordinate_origin[] and m_packed_coordinate_delta[]
|
|
// are set to valid values.
|
|
PackRectSet = 0x04U,
|
|
|
|
PackingBitsMask = 0x07U,
|
|
NotPackingBitsMask = 0xF8U,
|
|
|
|
// add other non-mutable bits here
|
|
};
|
|
|
|
// NOT mutable on purpose
|
|
unsigned char m_pack_status_bits = 0;
|
|
|
|
private:
|
|
enum TextureStatusBits : unsigned char
|
|
{
|
|
ZeroTextureStatusBits = 0,
|
|
|
|
// TexturePoints bits
|
|
TexturePointsSet = 0x01U, // set when face has set custom texture coordinates
|
|
TexturePointsBitsMask = 0x01U,
|
|
NotTexturePointsBitsMask = 0xFEU,
|
|
|
|
// add other mutable bits here
|
|
};
|
|
// mutable because rendering code frequently modifis const objects in the Rhino.
|
|
mutable unsigned char m_texture_status_bits = 0;
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
0: unset pack id.
|
|
> 0: set pack id.
|
|
Remarks:
|
|
Faces that share the same PackId() must be neighboring quad faces that form a larger
|
|
rectangular grid of quads. Single faces that are not quads and isolated quads cannot
|
|
share a pack id with other faces.
|
|
*/
|
|
unsigned int PackId() const;
|
|
|
|
/*
|
|
Returns:
|
|
true if the pack rect is set.
|
|
Remarks:
|
|
Faces that share the same PackId() must be neighboring quad faces that form a larger
|
|
rectangular grid of quads. Single faces that are not quads and isolated quads cannot
|
|
share a pack id with other faces.
|
|
*/
|
|
bool PackRectIsSet() const;
|
|
|
|
/*
|
|
Returns
|
|
Lower left coordinate of this face's pack rect in normalized pack rect coordinates.
|
|
*/
|
|
const ON_2dPoint PackRectOrigin() const;
|
|
|
|
/*
|
|
Returns
|
|
Size of this face's pack rect in normalized pack rect coordinates.
|
|
*/
|
|
const ON_2dVector PackRectSize() const;
|
|
|
|
/*
|
|
Returns:
|
|
0, 90, 180, or 270
|
|
Remarks:
|
|
This rotation is used to keep pack rect coordinates continuous in quad packs
|
|
containing faces with inconsistent topological orientations, which is the most
|
|
common situation.
|
|
*/
|
|
unsigned PackRectRotationDegrees() const;
|
|
|
|
/*
|
|
Returns:
|
|
0, 0.5*ON_PI, ON_PI, or 1.5*ON_PI
|
|
Remarks:
|
|
This rotation is used to keep pack rect coordinates continuous in quad packs
|
|
containing faces with inconsistent topological orientations, which is the most
|
|
common situation.
|
|
*/
|
|
double PackRectRotationRadians() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bGridOrder - [in]
|
|
false: counter clockwise quad order.
|
|
true: fragment grid order
|
|
corner_index - [in]
|
|
0, 1, 2, or 3
|
|
Returns:
|
|
Specified pack rectangle corner coordinates.
|
|
The pack rect is the (x0,x0+dx) x (y0,y0+dy) rectangle inside the unit square (0,1)x(0,1)
|
|
where (x0,y0) = PackRectOrigin() and (dx,dy) = PackRectSize().
|
|
*/
|
|
const ON_2dPoint PackRectCorner(
|
|
bool bGridOrder,
|
|
int corner_index
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
bGridOrder - [in]
|
|
false: counter clockwise quad order.
|
|
true: fragment grid order
|
|
mesh_fragment_pack_rect_corners - [out]
|
|
Pack rectangle corners for the specified mesh fragment are returned here.
|
|
face_pack_rect_corners[i] = this->PackRectCorner(bGridOrder,i);
|
|
Returns:
|
|
True if the input is valid and the face's pack rectangle corner coordinates were returned.
|
|
False otherwise.
|
|
Remarks:
|
|
Compare with ON_SubDFace.GetMeshFragmentPackRectCorners().
|
|
*/
|
|
bool GetFacePackRectCorners(
|
|
bool bGridOrder,
|
|
ON_2dPoint face_pack_rect_corners[4]
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
bGridOrder - [in]
|
|
false: counter clockwise quad order.
|
|
true: fragment grid order
|
|
fragment_index - [in]
|
|
If the face is a quad (EdgeCount() = 4), then fragment_index must be zero.
|
|
If the face is a n-gon (EdgeCount() = n and n != 4),
|
|
then 0 <= fragment_index < EdgeCount().
|
|
mesh_fragment_pack_rect_corners - [out]
|
|
Pack rectangle corners for the specified mesh fragment are returned here.
|
|
If the face is a quad, mesh_fragment_pack_rect_corners[] are the pack rect texture points for
|
|
the quad corners in the order specified by bGridOrder and standard linear interpolation
|
|
between the 4 corners will produce reasonable texture mapping coordinates.
|
|
If the face is an n-gon, mesh_fragment_pack_rect_corners[0] is the pack rect texture point
|
|
at face->Vertex(fragment_index). For n-gons, the n fragments are assigned non-overlapping rectangular
|
|
subsetsof the face's pack rect. Interpolating between corner values will not produce good texture
|
|
mapping coordinates. Pack rects are create useful and optimal texture mapping results when the SubD
|
|
is renderered from its mesh fragmantes.
|
|
Returns:
|
|
True if the input is valid and the pack rectangle corner coordinates for the specified mesh fragment were returned.
|
|
False otherwise.
|
|
Remarks:
|
|
A quad face (EdgeCount()=4) is rendered using 1 ON_SubDMeshFragment.
|
|
An n-gon face (EdgeCount()=n and n != 4) is rendered using n ON_SubDMeshFragments. These n fragments correspond
|
|
the SubD quads the n-gon face would generate with one level of Catmull-Clark subdivision.
|
|
*/
|
|
bool GetMeshFragmentPackRectCorners(
|
|
bool bGridOrder,
|
|
unsigned int fragment_index,
|
|
ON_2dPoint mesh_fragment_pack_rect_corners[4]
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Sets PackId() to zero.
|
|
Remarks:
|
|
Does not change the values of ON_SubDFace::PackRectOrigin(), ON_SubDFace::PackRectSize(),
|
|
ON_SubDFace::PackRectRotationDegrees(), or ON_SubDFace::TextureCoordinateType()
|
|
Use ON_SubDFace::ClearPackRect() to clear the pack rectangle.
|
|
*/
|
|
void ClearPackId();
|
|
|
|
/*
|
|
Description:
|
|
Clears the pack rectangle.
|
|
Remarks:
|
|
Does not change the value of ON_SubDFace::PackId() or ON_SubDFace::TextureCoordinateType()
|
|
Use ON_SubDFace::ClearPackId() to clear the pack id.
|
|
*/
|
|
void ClearPackRect();
|
|
|
|
/*
|
|
Parameters:
|
|
pack_rect_origin - [in]
|
|
Lower left corner.
|
|
Valid origins have (0 <= origin.x < 1) and (0 <= origin.y < 1)
|
|
pack_rect_size - [in]
|
|
vector from lower left corner to upper right corner.
|
|
Valid deltas have (0 < delta.x, 0 < delta.y, (origin.x+delta.x) <= 1) and (origin.y+delta.y) <= 1.
|
|
packing_rotation_degrees - [in]
|
|
Valid packing_rotation_degrees are a mulitple of 90.
|
|
Returns:
|
|
True if the input parameters define a valid pack rectangle.
|
|
*/
|
|
static bool IsValidPackRect(
|
|
ON_2dPoint pack_rect_origin,
|
|
ON_2dVector pack_rect_size,
|
|
int packing_rotation_degrees
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
The ON_SubD::PackFaces() function uses this function to set the value of ON_SubDFace::PackId().
|
|
Unless you are an expert and doing something very carefully and very fancy, to not call this function.
|
|
You must also set the pack rectangle correctly.
|
|
Remarks:
|
|
Faces that share the same PackId() must be neighboring quad faces that form a larger
|
|
rectangular grid of quads. Single faces that are not quads and isolated quads cannot
|
|
share a pack id with other faces.
|
|
*/
|
|
void SetPackIdForExperts(
|
|
unsigned int pack_id
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
The ON_SubD::PackFaces() function uses this function to set the face's pack rectangle
|
|
(ON_SubDFace::PackRectOrigin(), ON_SubDFace::PackRectSize(), ON_SubDFace::PackRectRotationDegrees()).
|
|
Unless you are an expert and doing something very carefully and very fancy, to not call this function.
|
|
The lower left corner will be origin, the upper right corner will be delta.
|
|
You must also set the pack id correctly.
|
|
Parameters:
|
|
pack_rect_origin - [in]
|
|
Lower left corner.
|
|
Valid origins have (0 <= origin.x < 1) and (0 <= origin.y < 1)
|
|
pack_rect_size - [in]
|
|
vector from lower left corner to upper right corner.
|
|
Valid deltas have (0 < delta.x, 0 < delta.y, (origin.x+delta.x) <= 1) and (origin.y+delta.y) <= 1.
|
|
packing_rotation_degrees - [in]
|
|
Valid packing_rotation_degrees are a mulitple of 90.
|
|
Return:
|
|
True if input is valid and the pack rectangle was set.
|
|
False if the input was not vaie and the pack rectangle coordinates were set to nan.
|
|
*/
|
|
bool SetPackRectForExperts(
|
|
ON_2dPoint pack_rect_origin,
|
|
ON_2dVector pack_rect_size,
|
|
int packing_rotation_degrees
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Calculate how a packing rectangle assigned to an ON_SubDFace will
|
|
be subdivided into n sub packing rectanges for an ngon when n >= 5.
|
|
Parameters:
|
|
ngon_edge_count - [in]
|
|
>= 5.
|
|
ngon_face_pack_rect_size - [in]
|
|
ngon_face_pack_rect_size.x > 0 and ngon_face_pack_rect_size.y > 0
|
|
The width and height of the sizeof the ngon's entire packing rectangle.
|
|
This is typically ON_SubD_Face::PackRectSize() once that property is
|
|
coorectly set.
|
|
ngon_sub_pack_rect_size - [out]
|
|
The size of sub pack rects.
|
|
If input is not valid, then ON_2dVector::ZeroVector is returned.
|
|
ngon_sub_pack_rect_delta - [out]
|
|
The delta from one sub pack rect to the next.
|
|
If input is not valid, then ON_2dVector::ZeroVector is returned.
|
|
Returns:
|
|
When the input is valid, ON_2udex(i,j) is returned and specifies the face's packing
|
|
rectangle should be divided into i X j sub packing rectangles.
|
|
Otherwise, ON_2udex(0,0) is returned and
|
|
*/
|
|
static const ON_2udex GetNgonSubPackRectSizeAndDelta(
|
|
unsigned int ngon_edge_count,
|
|
ON_2dVector ngon_face_pack_rect_size,
|
|
ON_2dVector& ngon_sub_pack_rect_size,
|
|
ON_2dVector& ngon_sub_pack_rect_delta
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
pack_rect_distance_in_pixels - [in]
|
|
A (normalized pack rect distance) * ON_SubD::TextureImageSuggestedMinimumSize
|
|
Returns:
|
|
Suggested gap between adjacent pack rects for a texture images
|
|
with width and height >= ON_SubD::TextureImageSuggestedMinimumSize.
|
|
This value will be 0.0 when pack_rect_distance_in_pixels is too
|
|
small to permit a gap of 1 or more pixels without visibly
|
|
adverse effects in a texture map clarity.
|
|
*/
|
|
static double PackRectGapInPixels(
|
|
double pack_rect_distance_in_pixels
|
|
);
|
|
|
|
|
|
private:
|
|
// The application specifies a base ON_Material used to render the subd this face belongs to.
|
|
// If m_material_channel_index > 0 AND face_material_id = base.MaterialChannelIdFromIndex(m_material_channel_index)
|
|
// is not nil, then face_material_id identifies an override rendering material for this face.
|
|
// Othewise base will be used to render this face.
|
|
mutable unsigned short m_material_channel_index = 0;
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Set the per face rendering material channel index.
|
|
|
|
Parameters:
|
|
material_channel_index - [in]
|
|
A value between 0 and ON_Material::MaximumMaterialChannelIndex, inclusive.
|
|
This value is typically 0 or the value returned from ON_Material::MaterialChannelIndexFromId().
|
|
|
|
Remarks:
|
|
If base_material is the ON_Material assigned to render this subd and
|
|
ON_UUID face_material_id = base_material.MaterialChannelIdFromIndex( material_channel_index )
|
|
is not nil, then face_material_id identifies an override rendering material for this face.
|
|
Otherwise base_material is used to reneder this face.
|
|
*/
|
|
void SetMaterialChannelIndex(int material_channel_index) const;
|
|
|
|
/*
|
|
Description:
|
|
Remove the per face rendering material channel index.
|
|
The face will use the material assigned to the subd object.
|
|
*/
|
|
void ClearMaterialChannelIndex() const;
|
|
|
|
/*
|
|
Returns:
|
|
This face's rendering material channel index.
|
|
|
|
Remarks:
|
|
If base_material is the ON_Material assigned to render this subd, MaterialChannelIndex() > 0,
|
|
and ON_UUID face_material_id = base_material.MaterialChannelIdFromIndex( face.MaterialChannelIndex() )
|
|
is not nil, then face_material_id identifies an override rendering material for this face.
|
|
Otherwise base_material is used to reneder this face.
|
|
*/
|
|
int MaterialChannelIndex() const;
|
|
|
|
private:
|
|
// The application specifies a base ON_Material used to render the subd this face belongs to.
|
|
// If m_material_channel_index > 0 AND face_material_id = base.MaterialChannelIdFromIndex(m_material_channel_index)
|
|
// is not nil, then face_material_id identifies an override rendering material for this face.
|
|
// Othewise base will be used to render this face.
|
|
mutable ON_Color m_per_face_color = ON_Color::UnsetColor;
|
|
|
|
public:
|
|
|
|
/*
|
|
Description:
|
|
Set per face color.
|
|
|
|
Parameters:
|
|
color - [in]
|
|
*/
|
|
void SetPerFaceColor(
|
|
ON_Color color
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Remove per face color setting. The face will use the color assigned to the subd object.
|
|
*/
|
|
void ClearPerFaceColor() const;
|
|
|
|
/*
|
|
Returns:
|
|
Per face color. A value of ON_Color::UnsetColor indicates the face uses the color assigned to the subd object.
|
|
*/
|
|
const ON_Color PerFaceColor() const;
|
|
|
|
public:
|
|
unsigned int m_level_zero_face_id = 0; // id of level zero face
|
|
|
|
public:
|
|
// Array of m_edge_count edges that form the boundary of the face.
|
|
// The edges are in ordered to form a continuous loop.
|
|
//
|
|
// The first four are in m_edge4[0], ..., m_edge4[3].
|
|
// When m_edge_count > 4, the fifth and additional edges
|
|
// are in m_edgex[0], ..., m_edgex[m_edge_count-5];
|
|
//
|
|
// The value of ON_SubDEdgePtr.EdgeDirection() is 0 if the
|
|
// edge's natural orientation from m_vertex[0] to m_vertex[1]
|
|
// agrees with the face's boundary orientation.
|
|
//
|
|
// The value of ON_SubDEdgePtr.EdgeDirection() is 1 if the
|
|
// edge's natural orientation from m_vertex[0] to m_vertex[1]
|
|
// is opposited the face's boundary orientation.
|
|
enum : unsigned int
|
|
{
|
|
MaximumEdgeCount = 0xFFF0U
|
|
};
|
|
unsigned short m_edge_count = 0;
|
|
unsigned short m_edgex_capacity = 0;
|
|
|
|
ON_SubDEdgePtr m_edge4[4];
|
|
ON_SubDEdgePtr* m_edgex = nullptr;
|
|
|
|
/*
|
|
Returns:
|
|
A linked list of limit mesh fragments that cover this face.
|
|
Nullptr if none are currently available.
|
|
|
|
If the face is a quad, there is a single fragment. If the
|
|
face is an n-gon with 4 != n, then the list has n fragments.
|
|
The i-th fragment covers the subdivision quad with its
|
|
corner at Vertex(i).
|
|
|
|
Remarks:
|
|
Use the returned fragments immediately or make a
|
|
copies you manage for later use.
|
|
|
|
Use ON_SubD.UpdateSurfaceMeshCache(false) or ON_SubD.UpdateSurfaceMeshCache(true)
|
|
to create the face fragments.
|
|
|
|
ON_SubDFace.ClearSavedSubdivisionPoints() removes any saved
|
|
fragments and is called when the face or nearby components
|
|
are modified.
|
|
*/
|
|
const class ON_SubDMeshFragment* MeshFragments() const;
|
|
|
|
|
|
const ON_3dPoint ControlNetCenterPoint() const;
|
|
|
|
const ON_3dVector ControlNetCenterNormal() const;
|
|
|
|
const ON_Plane ControlNetCenterFrame() const;
|
|
|
|
bool IsConvex() const;
|
|
|
|
bool IsNotConvex() const;
|
|
|
|
bool IsPlanar(double planar_tolerance = ON_ZERO_TOLERANCE) const;
|
|
|
|
bool IsNotPlanar(double planar_tolerance = ON_ZERO_TOLERANCE) const;
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
Number of texture points that can be set on this face.
|
|
Remarks:
|
|
To allocate texture point storage, call ON_SubD.AddFaceTexturePointCapacity(this).
|
|
*/
|
|
unsigned int TexturePointsCapacity() const;
|
|
|
|
/*
|
|
Returns:
|
|
If texture points are set, then true is returned.
|
|
Otherwise, false is returned.
|
|
*/
|
|
bool TexturePointsAreSet() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the texture point at the specified face vertex.
|
|
Parameters:
|
|
i - [in]
|
|
0 <= 0 < this->EdgeCount()
|
|
Parameters:
|
|
texture_point - [in]
|
|
Returns:
|
|
If this->TexturePointsCanBeSet() is true and i is a valid index,
|
|
then the texture point is set and true is returned.
|
|
Otherwise, false is returned.
|
|
Remarks:
|
|
To allocate texture point storage, call ON_SubD.AddFaceTexturePointStorage(this).
|
|
Texture points are a mutable property on ON_SubDFace.
|
|
*/
|
|
bool SetTexturePoint(
|
|
unsigned i,
|
|
ON_3dPoint texture_point
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Remove all texture points.
|
|
Remarks:
|
|
Texture points are a mutable property on ON_SubDFace.
|
|
*/
|
|
void ClearTexturePoints() const;
|
|
|
|
/*
|
|
Description:
|
|
Get the texture point at the specified face vertex.
|
|
Parameters:
|
|
i - [in]
|
|
0 <= 0 < this->EdgeCount()
|
|
Returns:
|
|
If texture
|
|
*/
|
|
const ON_3dPoint TexturePoint(
|
|
unsigned int i
|
|
) const;
|
|
|
|
const ON_3dPoint TextureCenterPoint() const;
|
|
|
|
private:
|
|
// If m_texture_points is not nullptr, it has capacity 4 + m_edgex_capacity.
|
|
// Custom texture coordinates are stored in m_texture_points.
|
|
// When texture coodinates are packed or come from a mapping,
|
|
// m_texture_points is not used. Typically m_texture_points
|
|
// is used when an ON_SubD is created from an ON_Mesh and the mesh
|
|
// has custom texture coordinates. Here "custom" means
|
|
// not from a mapping.
|
|
// https://mcneel.myjetbrains.com/youtrack/issue/RH-59465
|
|
mutable ON_3dPoint* m_texture_points = nullptr;
|
|
|
|
private:
|
|
// If 0 != ON_SUBD_CACHE_LIMIT_FLAG(m_saved_points_flags), then
|
|
// m_mesh_fragments is a linked list of (4==m_edge_count?1:m_edge_count)
|
|
// fragments available from MeshFragments() and managed by the parent ON_SubD.
|
|
// If 0 == ON_SUBD_CACHE_LIMIT_FLAG(m_saved_points_flags), then any information
|
|
// in m_limit_mesh_fragments is dirty and should not be used.
|
|
// ClearSavedSubdivisionPoints() zeros the appropriate bit of m_saved_points_flags.
|
|
|
|
// Mesh fragment(s) for this face
|
|
mutable class ON_SubDMeshFragment* m_mesh_fragments = nullptr;
|
|
|
|
private:
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
Returns the number of edges and (number of vertices) in the face's boundary.
|
|
Remarks:
|
|
Boundaries that vist the same vertex or same edge multiple times are not permitted.
|
|
So the number of vertices and number of edges is always the same.
|
|
*/
|
|
unsigned int EdgeCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Rapidly verifies that:
|
|
1. EdgeCount() >= 3
|
|
2. Every edge is not null and has 2 non-null vertices.
|
|
3. The end vertex of and edge is identical to the start vertex of the next edge.
|
|
4. Every edge has FaceCount() >= 1.
|
|
5. Every vertex has EdgeCount() >= 2 and FaceCount() >= 1.
|
|
6. The first 4 edges are unique.
|
|
6. The first 4 vertices are unique.
|
|
Returns:
|
|
True if the 5 conditions above are true.
|
|
Remarks:
|
|
The face can still be invalid, but if HasValidEdges() returns true,
|
|
it is save to deference pointers returned by the face's Edge() and Vertex() functions.
|
|
*/
|
|
bool HasEdges() const;
|
|
|
|
const ON_SubDEdgePtr EdgePtr(
|
|
unsigned int i
|
|
) const;
|
|
|
|
const ON_SubDEdgePtr EdgePtrFromEdge(
|
|
const class ON_SubDEdge* e
|
|
) const;
|
|
|
|
bool EdgeMark(
|
|
unsigned int i,
|
|
bool bMissingEgeReturnValue
|
|
) const;
|
|
|
|
ON__UINT8 EdgeMarkBits(
|
|
unsigned int i,
|
|
ON__UINT8 missing_edge_return_value
|
|
) const;
|
|
|
|
|
|
const class ON_SubDVertex* Vertex(
|
|
unsigned int i
|
|
) const;
|
|
|
|
const ON_3dPoint ControlNetPoint(
|
|
unsigned int i
|
|
) const;
|
|
|
|
unsigned int VertexIndex(
|
|
const ON_SubDVertex* vertex
|
|
) const;
|
|
|
|
bool VertexMark(
|
|
unsigned int i,
|
|
bool bMissingVertexReturnValue
|
|
) const;
|
|
|
|
ON__UINT8 VertexMarkBits(
|
|
unsigned int i,
|
|
ON__UINT8 missing_vertex_return_value
|
|
) const;
|
|
|
|
/*
|
|
Returns;
|
|
If the vertex is in this face's boundary, pair of face boundary edges at the vertex is returned
|
|
with face boundary orientations, that is vertex = pair.First().EdgePtr().RelativeVertex(1)
|
|
and vertex = pair.Second().EdgePtr().RelativeVertex(0). Otherwise, ON_SubDComponentPtrPair::Null
|
|
is returned.
|
|
*/
|
|
const ON_SubDComponentPtrPair VertexEdgePair(
|
|
const ON_SubDVertex* vertex
|
|
) const;
|
|
|
|
/*
|
|
Returns;
|
|
If the vertex is in this face's boundary, pair of face boundary edges at the vertex is returned
|
|
with face boundary orientations, that is vertex = pair.First().EdgePtr().RelativeVertex(1)
|
|
and vertex = pair.Second().EdgePtr().RelativeVertex(0). Otherwise, ON_SubDComponentPtrPair::Null
|
|
is returned.
|
|
*/
|
|
const ON_SubDComponentPtrPair VertexEdgePair(
|
|
unsigned vertex_index
|
|
) const;
|
|
|
|
const class ON_SubDEdge* Edge(
|
|
unsigned int i
|
|
) const;
|
|
|
|
ON__UINT_PTR EdgeDirection(
|
|
unsigned int i
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
If e is part of the face's boundary, then the index of the edge is returned.
|
|
Otherwise, ON_UNSET_UINT_INDEX is returned.
|
|
*/
|
|
unsigned int EdgeArrayIndex(
|
|
const ON_SubDEdge* e
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove an edge from the face's edge array.
|
|
Remarks:
|
|
Does not modify the edge. If the face is referenced in the edge's face array,
|
|
then the face must be removed from the edge's face array.
|
|
*/
|
|
bool RemoveEdgeFromArray(
|
|
const ON_SubDEdge* e
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to remove an edge from the face's edge array.
|
|
Remarks:
|
|
Does not modify the edge. If the face is referenced in the edge's face array,
|
|
then the face must be removed from the edge's face array.
|
|
*/
|
|
bool RemoveEdgeFromArray(
|
|
unsigned int i,
|
|
ON_SubDEdgePtr& removed_edge
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Expert user tool to replace one edge with another in the face's edge array.
|
|
Parameters:
|
|
edge_to_remove - [in]
|
|
edge_to_insert - [in]
|
|
The inserted edge is assigned the same boundary orientation as the
|
|
removed edge.
|
|
Remarks:
|
|
Does not modify the edge. The corresponding reference to this face must
|
|
be removed from the first edge and added to the second edge.
|
|
*/
|
|
bool ReplaceEdgeInArray(
|
|
unsigned int fei0,
|
|
ON_SubDEdge* edge_to_remove,
|
|
ON_SubDEdge* edge_to_insert
|
|
);
|
|
|
|
/////*
|
|
////Description:
|
|
//// Expert user tool to replace one edge with another in the face's edge array.
|
|
////Parameters:
|
|
//// edge_to_remove - [in]
|
|
//// edge_to_insert - [in]
|
|
//// The inserted edge is assigned the same boundary orientation specified
|
|
//// in edgeptr_to_insert.
|
|
////Remarks:
|
|
//// Does not modify the edge. The corresponding reference to this face must
|
|
//// be removed from the first edge and added to the second edge.
|
|
////*/
|
|
////bool ReplaceEdgeInArray(
|
|
//// unsigned int fei0,
|
|
//// ON_SubDEdge* edge_to_remove,
|
|
//// ON_SubDEdgePtr edgeptr_to_insert
|
|
////);
|
|
|
|
/*
|
|
Description:
|
|
Rotates the edge array so that Edge(fei0) becomes the first edge in the edge array.
|
|
*/
|
|
bool RotateEdgeArray(
|
|
unsigned int fei0
|
|
);
|
|
|
|
const ON_SubDEdge* PrevEdge(
|
|
const ON_SubDEdge* edge
|
|
) const;
|
|
|
|
const ON_SubDEdge* NextEdge(
|
|
const ON_SubDEdge* edge
|
|
) const;
|
|
|
|
unsigned int PrevEdgeArrayIndex(
|
|
unsigned int edge_array_index
|
|
) const;
|
|
|
|
unsigned int NextEdgeArrayIndex(
|
|
unsigned int edge_array_index
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
If the face is a quad, get the opposite corner vertex.
|
|
Parameters:
|
|
vertex - [in]
|
|
a vertex on this face.
|
|
Returns:
|
|
If the face is a quad and vertex is a vertex of the face, then
|
|
the vertex on the opposite corner is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const ON_SubDVertex* QuadOppositeVertex(
|
|
const ON_SubDVertex* vertex
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
If the face is a quad, get the opposite side edge.
|
|
Parameters:
|
|
edge - [in]
|
|
an edge on this face.
|
|
Returns:
|
|
If the face is a quad and edge is an edge of the face, then
|
|
the edge on the opposite side is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const ON_SubDEdge* QuadOppositeEdge(
|
|
const ON_SubDEdge* edge
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
subdivision_point - [out]
|
|
The average of the face vertex locations.
|
|
Returns:
|
|
true if successful
|
|
*/
|
|
bool GetSubdivisionPoint(
|
|
double subdivision_point[3]
|
|
) const;
|
|
|
|
///<summary>
|
|
/// The SubD face Catmull-Clark subdivision point.
|
|
///</summary>
|
|
const ON_3dPoint SubdivisionPoint() const;
|
|
|
|
/*
|
|
Description:
|
|
Evaluates the Catmull-Clark subdivision point ignoring all cached information.
|
|
This function is typically used in testing and debugging code and
|
|
in ordinary cases, it is faster and better to call SubdivisionPoint()
|
|
or GetSubdivisionPoint().
|
|
Parameters:
|
|
subdivision_point - [out]
|
|
The Catmull-Clark face subdivision point is returned here.
|
|
*/
|
|
bool EvaluateCatmullClarkSubdivisionPoint(
|
|
double subdivision_point[3]
|
|
) const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
Reverse the order and orientation of the edges that form
|
|
the boundary of this face.
|
|
*/
|
|
bool ReverseEdgeList();
|
|
|
|
/*
|
|
Description:
|
|
Get the bicubic b-spline control points for the limit surface.
|
|
The corresponding knots are uniform.
|
|
Parameters:
|
|
vertex - [in]
|
|
limit_surface_cv_stride0 - [int]
|
|
limit_surface_cv_stride1 - [out]
|
|
limit_surface_cv - [out]
|
|
control points for a cubic spline surface
|
|
CV[i][j][k] = limit_surface_cv[i*limit_bspline_cv_stride0 + j*limit_bspline_cv_stride1 + k]
|
|
0 <= i < 4, 0 <= j < 4, 0 <= k < 3
|
|
Returns:
|
|
true if successful
|
|
false if the limit surface for this face is not a cubic surface
|
|
Remarks:
|
|
The knots for the bicubic b-spline surface are uniform.
|
|
*/
|
|
bool GetQuadSurface(
|
|
double* limit_surface_cv,
|
|
size_t limit_surface_cv_stride0,
|
|
size_t limit_surface_cv_stride1
|
|
) const;
|
|
|
|
bool GetQuadSurface(
|
|
class ON_NurbsSurface& limit_surface
|
|
) const;
|
|
|
|
bool GetQuadSurface(
|
|
class ON_BezierSurface& limit_surface
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of edges in the face's boundary with Edge().m_status.RuntimeMark() = true;
|
|
*/
|
|
unsigned int MarkedEdgeCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of vertices in the face's boundary with Vertex().m_status.RuntimeMark() = true;
|
|
*/
|
|
unsigned int MarkedVertexCount() const;
|
|
|
|
/*
|
|
Description:
|
|
Set the mark of every vertex attached to this face.
|
|
Returns:
|
|
Number of marks changed.
|
|
*/
|
|
unsigned int SetVertexMarks(
|
|
bool bMark
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Set the mark of every boundary edge attached to this face.
|
|
Returns:
|
|
Number of marks changed.
|
|
*/
|
|
unsigned int SetEdgeMarks(
|
|
bool bMark
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the face's boundary.
|
|
Parameters:
|
|
face_edge_array - [out]
|
|
The boundary of the face is returned in canonical counter-clockwise order.
|
|
Returns:
|
|
Number of edges in the face's boundary.
|
|
*/
|
|
unsigned int GetEdgeArray(
|
|
ON_SimpleArray< ON_SubDEdgePtr >& face_edge_array
|
|
) const;
|
|
|
|
private:
|
|
void CopyFrom(
|
|
const ON_SubDFace* src,
|
|
bool bCopyEdgeArray,
|
|
bool bCopySymmetrySetNext
|
|
);
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDVertexArray
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
Avoid using ON_SubDVertexArray. ON_SubDVertexIterator is more efficient and a better choice.
|
|
*/
|
|
class ON_CLASS ON_SubDVertexArray
|
|
{
|
|
public:
|
|
ON_SubDVertexArray(
|
|
const ON_SubD& subd
|
|
);
|
|
ON_SubDVertexArray() = default;
|
|
ON_SubDVertexArray(const ON_SubDVertexArray&) = default;
|
|
ON_SubDVertexArray& operator=(const ON_SubDVertexArray&) = default;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDVertexArray(ON_SubDVertexArray&&) ON_NOEXCEPT;
|
|
|
|
// rvalue copy operator-=
|
|
ON_SubDVertexArray& operator=(ON_SubDVertexArray&&);
|
|
#endif
|
|
|
|
const ON_SubD& SubD() const
|
|
{
|
|
return m_subd;
|
|
}
|
|
|
|
unsigned int VertexCount() const
|
|
{
|
|
return m_vertex_count;
|
|
}
|
|
|
|
const class ON_SubDVertex* operator[](unsigned int i) const
|
|
{
|
|
return (i < m_vertex_count) ? m_a[i] : nullptr;
|
|
}
|
|
|
|
private:
|
|
ON_SubD m_subd;
|
|
const class ON_SubDVertex*const* m_a = nullptr;
|
|
unsigned int m_vertex_count = 0;
|
|
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
|
|
// C4251: ... needs to have dll-interface to be used by clients of class ...
|
|
// m_sp is private and all code that manages m_sp is explicitly implemented in the DLL.
|
|
private:
|
|
std::shared_ptr< const class ON_SubDVertex* > m_sp;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDEdgeArray
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
Avoid using ON_SubDEdgeArray. ON_SubDEdgeIterator is more efficient and a better choice.
|
|
*/
|
|
class ON_CLASS ON_SubDEdgeArray
|
|
{
|
|
public:
|
|
ON_SubDEdgeArray(
|
|
const ON_SubD& subd
|
|
);
|
|
ON_SubDEdgeArray() = default;
|
|
ON_SubDEdgeArray(const ON_SubDEdgeArray&) = default;
|
|
ON_SubDEdgeArray& operator=(const ON_SubDEdgeArray&) = default;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDEdgeArray(ON_SubDEdgeArray&&) ON_NOEXCEPT;
|
|
|
|
// rvalue copy operator-=
|
|
ON_SubDEdgeArray& operator=(ON_SubDEdgeArray&&);
|
|
#endif
|
|
|
|
const ON_SubD& SubD() const
|
|
{
|
|
return m_subd;
|
|
}
|
|
|
|
unsigned int EdgeCount() const
|
|
{
|
|
return m_edge_count;
|
|
}
|
|
|
|
const class ON_SubDEdge* operator[](unsigned int i) const
|
|
{
|
|
return (i < m_edge_count) ? m_a[i] : nullptr;
|
|
}
|
|
|
|
private:
|
|
ON_SubD m_subd;
|
|
const class ON_SubDEdge*const* m_a = nullptr;
|
|
unsigned int m_edge_count = 0;
|
|
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
|
|
// C4251: ... needs to have dll-interface to be used by clients of class ...
|
|
// m_sp is private and all code that manages m_sp is explicitly implemented in the DLL.
|
|
private:
|
|
std::shared_ptr< const class ON_SubDEdge* > m_sp;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDFaceArray
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
Avoid using ON_SubDFaceArray. ON_SubDFaceIterator is more efficient and a better choice.
|
|
*/
|
|
class ON_CLASS ON_SubDFaceArray
|
|
{
|
|
public:
|
|
ON_SubDFaceArray(
|
|
const ON_SubD& subd
|
|
);
|
|
ON_SubDFaceArray() = default;
|
|
ON_SubDFaceArray(const ON_SubDFaceArray&) = default;
|
|
ON_SubDFaceArray& operator=(const ON_SubDFaceArray&) = default;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDFaceArray(ON_SubDFaceArray&&) ON_NOEXCEPT;
|
|
|
|
// rvalue copy operator-=
|
|
ON_SubDFaceArray& operator=(ON_SubDFaceArray&&);
|
|
#endif
|
|
|
|
const ON_SubD& SubD() const
|
|
{
|
|
return m_subd;
|
|
}
|
|
|
|
unsigned int FaceCount() const
|
|
{
|
|
return m_face_count;
|
|
}
|
|
|
|
const class ON_SubDFace* operator[](unsigned int i) const
|
|
{
|
|
return (i < m_face_count) ? m_a[i] : nullptr;
|
|
}
|
|
|
|
private:
|
|
ON_SubD m_subd;
|
|
const class ON_SubDFace*const* m_a = nullptr;
|
|
unsigned int m_face_count = 0;
|
|
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
|
|
// C4251: ... needs to have dll-interface to be used by clients of class ...
|
|
// m_sp is private and all code that manages m_sp is explicitly implemented in the DLL.
|
|
private:
|
|
std::shared_ptr< const class ON_SubDFace* > m_sp;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDVertexIterator
|
|
//
|
|
class ON_CLASS ON_SubDVertexIterator
|
|
{
|
|
public:
|
|
// The best way to get an ON_SubDVertexIterator is so use the ON_SubD member function
|
|
// ON_SubDVertexIterator vit = subd.VertexIterator();
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubD& subd
|
|
);
|
|
|
|
// The best way to get an ON_SubDVertexIterator is so use the ON_SubD member function
|
|
// ON_SubDVertexIterator vit = subd.VertexIterator();
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubDRef& subd_ref
|
|
);
|
|
|
|
// Construct and interator that iterates over a single vertex.
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDVertex& vertex
|
|
);
|
|
|
|
// Construct and interator that iterates over a single vertex.
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDVertex& vertex
|
|
);
|
|
|
|
// Construct and interator that iterates over the vertices of an edge.
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDEdge& edge
|
|
);
|
|
|
|
// Construct and interator that iterates over the vertices of an edge.
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDEdge& edge
|
|
);
|
|
|
|
// Construct and interator that iterates over the vertices of a face.
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDFace& face
|
|
);
|
|
|
|
// Construct and interator that iterates over the vertices of a face.
|
|
ON_SubDVertexIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDFace& face
|
|
);
|
|
|
|
ON_SubDVertexIterator() = default;
|
|
ON_SubDVertexIterator(const ON_SubDVertexIterator&) = default;
|
|
ON_SubDVertexIterator& operator=(const ON_SubDVertexIterator&) = default;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDVertexIterator( ON_SubDVertexIterator&& ) ON_NOEXCEPT;
|
|
// rvalue assignment operator
|
|
ON_SubDVertexIterator& operator=( ON_SubDVertexIterator&& );
|
|
#endif
|
|
|
|
/*
|
|
Returns:
|
|
The subD object for this iterator.
|
|
*/
|
|
const class ON_SubD& SubD() const
|
|
{
|
|
return m_subd_ref.SubD();
|
|
}
|
|
|
|
const class ON_SubDRef& SubDRef() const
|
|
{
|
|
return m_subd_ref;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Increment the iterator.
|
|
Returns:
|
|
Current vertex.
|
|
Remarks:
|
|
operator++ and NextVertex() behave differently.
|
|
*/
|
|
const class ON_SubDVertex* operator++()
|
|
{
|
|
const class ON_SubDVertex* v = m_v_current;
|
|
NextVertex();
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
Return:
|
|
Number of vertices this iterator will iterate through.
|
|
*/
|
|
unsigned int VertexCount() const
|
|
{
|
|
return m_vertex_count;
|
|
}
|
|
|
|
/*
|
|
Return:
|
|
Interator index of the current vertex.
|
|
*/
|
|
unsigned int CurrentVertexIndex() const
|
|
{
|
|
return m_vertex_index;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the beginning of the vertex list.
|
|
Returns:
|
|
First vertex in the list.
|
|
*/
|
|
const class ON_SubDVertex* FirstVertex()
|
|
{
|
|
m_vertex_index = 0;
|
|
return (m_v_current = m_v_first);
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Increment the iterator.
|
|
Returns:
|
|
Next vertex.
|
|
Remarks:
|
|
operator++ and NextVertex() behave differently.
|
|
*/
|
|
const class ON_SubDVertex* NextVertex()
|
|
{
|
|
m_vertex_index++;
|
|
if (m_vertex_index < m_vertex_count)
|
|
{
|
|
if (0 == m_component_ptr.m_ptr)
|
|
{
|
|
if (nullptr != m_v_current)
|
|
m_v_current = m_v_current->m_next_vertex;
|
|
}
|
|
else
|
|
{
|
|
const ON_SubDEdge* edge = m_component_ptr.Edge();
|
|
if (nullptr != edge)
|
|
{
|
|
m_v_current = edge->Vertex(m_vertex_index);
|
|
}
|
|
else
|
|
{
|
|
const ON_SubDFace* face = m_component_ptr.Face();
|
|
if (nullptr != face)
|
|
m_v_current = face->Vertex(m_vertex_index);
|
|
else
|
|
m_v_current = nullptr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_vertex_index = m_vertex_count;
|
|
m_v_current = nullptr;
|
|
}
|
|
return m_v_current;
|
|
}
|
|
|
|
/*
|
|
Returns:
|
|
Current vertex;
|
|
*/
|
|
const class ON_SubDVertex* CurrentVertex() const
|
|
{
|
|
return m_v_current;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the end of the vertex list.
|
|
Returns:
|
|
Last vertex in the list.
|
|
*/
|
|
const class ON_SubDVertex* LastVertex()
|
|
{
|
|
m_vertex_index = (m_vertex_count > 0) ? (m_vertex_count - 1) : 0;
|
|
return (m_v_current = m_v_last);
|
|
}
|
|
|
|
private:
|
|
void Internal_Init(
|
|
const ON_SubDRef& subd_ref,
|
|
unsigned int vertex_count,
|
|
const ON_SubDVertex* first,
|
|
const ON_SubDVertex* last,
|
|
ON_SubDComponentPtr component_ptr
|
|
);
|
|
ON_SubDRef m_subd_ref;
|
|
const ON_SubDVertex* m_v_first = nullptr;
|
|
const ON_SubDVertex* m_v_last = nullptr;
|
|
const ON_SubDVertex* m_v_current = nullptr;
|
|
unsigned int m_vertex_index = 0;
|
|
unsigned int m_vertex_count = 0;
|
|
ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDVertexIdIterator
|
|
//
|
|
|
|
class ON_CLASS ON_SubDVertexIdIterator : private ON_FixedSizePoolIterator
|
|
{
|
|
public:
|
|
ON_SubDVertexIdIterator() = default;
|
|
~ON_SubDVertexIdIterator() = default;
|
|
ON_SubDVertexIdIterator(const ON_SubDVertexIdIterator&) = default;
|
|
ON_SubDVertexIdIterator& operator=(const ON_SubDVertexIdIterator&) = default;
|
|
|
|
public:
|
|
ON_SubDVertexIdIterator(const ON_SubDRef& subd_ref);
|
|
ON_SubDVertexIdIterator(const ON_SubD& subd);
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
In general, you want to use a ON_SubDVertexIterator to loop through SubD vertices.
|
|
This is a special tool for unusual sitiations wheh it is necessary to
|
|
iteratate through every vertex on every level of a SubD in order
|
|
of increasing m_id value.
|
|
Returns:
|
|
The vertex with the smallest id.
|
|
*/
|
|
const ON_SubDVertex* FirstVertex();
|
|
|
|
const ON_SubDVertex* FirstVertexOnLevel(unsigned int level_index);
|
|
|
|
|
|
/*
|
|
Description:
|
|
In general, you want to use a ON_SubDVertexIterator to loop through SubD vertices.
|
|
This is a special tool for unusual sitiations wheh it is necessary to
|
|
iteratate through every vertex on every level of a SubD in order
|
|
of increasing m_id value.
|
|
Returns:
|
|
The vertex in order of increasing id.
|
|
*/
|
|
const ON_SubDVertex* NextVertex();
|
|
|
|
const ON_SubDVertex* NextVertexOnLevel(unsigned int level_index);
|
|
|
|
/*
|
|
Returns:
|
|
The most recently returned vertex from a call to FirstVertex() or NextVertex().
|
|
*/
|
|
const ON_SubDVertex* CurrentVertex() const;
|
|
|
|
private:
|
|
friend class ON_SubDHeap;
|
|
ON_SubDRef m_subd_ref;
|
|
void Internal_Init();
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDEdgeIterator
|
|
//
|
|
class ON_CLASS ON_SubDEdgeIterator
|
|
{
|
|
public:
|
|
// The best way to get an ON_SubDEdgeIterator is so use the ON_SubD member function
|
|
// ON_SubDEdgeIterator eit = subd.EdgeIterator();
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubD& subd
|
|
);
|
|
|
|
// The best way to get an ON_SubDEdgeIterator is so use the ON_SubD member function
|
|
// ON_SubDEdgeIterator eit = subd.EdgeIterator();
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubDRef& subd_ref
|
|
);
|
|
|
|
// Construct and interator that iterates over a single edge.
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDEdge& edge
|
|
);
|
|
|
|
// Construct and interator that iterates over a single edge.
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDEdge& edge
|
|
);
|
|
|
|
// Construct and interator that iterates over the edges of a vertex.
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDVertex& vertex
|
|
);
|
|
|
|
// Construct and interator that iterates over the edges of a vertex.
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDVertex& vertex
|
|
);
|
|
|
|
// Construct and interator that iterates over the edges of a face.
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDFace& face
|
|
);
|
|
|
|
// Construct and interator that iterates over the edges of a face.
|
|
ON_SubDEdgeIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDFace& face
|
|
);
|
|
|
|
ON_SubDEdgeIterator() = default;
|
|
ON_SubDEdgeIterator(const ON_SubDEdgeIterator&) = default;
|
|
ON_SubDEdgeIterator& operator=(const ON_SubDEdgeIterator&) = default;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDEdgeIterator( ON_SubDEdgeIterator&& ) ON_NOEXCEPT;
|
|
// rvalue assignment operator
|
|
ON_SubDEdgeIterator& operator=( ON_SubDEdgeIterator&& );
|
|
#endif
|
|
|
|
/*
|
|
Returns:
|
|
The subD object for this iterator.
|
|
*/
|
|
const class ON_SubD& SubD() const
|
|
{
|
|
return m_subd_ref.SubD();
|
|
}
|
|
|
|
const class ON_SubDRef& SubDRef() const
|
|
{
|
|
return m_subd_ref;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Increment the iterator.
|
|
Returns:
|
|
Current edge.
|
|
Remarks:
|
|
operator++ and NextEdge() behave differently.
|
|
*/
|
|
const class ON_SubDEdge* operator++()
|
|
{
|
|
const class ON_SubDEdge* e = m_e_current;
|
|
NextEdge();
|
|
return e;
|
|
}
|
|
|
|
/*
|
|
Return:
|
|
Number of edges this iterator will iterate through.
|
|
*/
|
|
unsigned int EdgeCount() const
|
|
{
|
|
return m_edge_count;
|
|
}
|
|
|
|
/*
|
|
Return:
|
|
Interator index of the current edge.
|
|
*/
|
|
unsigned int CurrentEdgeIndex() const
|
|
{
|
|
return m_edge_index;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the beginning of the edge list.
|
|
Returns:
|
|
First edge in the list.
|
|
*/
|
|
const class ON_SubDEdge* FirstEdge()
|
|
{
|
|
m_edge_index = 0;
|
|
return m_e_current = m_e_first;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Increment the iterator.
|
|
Returns:
|
|
Next edge.
|
|
Remarks:
|
|
operator++ and NextEdge() behave differently.
|
|
*/
|
|
const class ON_SubDEdge* NextEdge()
|
|
{
|
|
m_edge_index++;
|
|
if (m_edge_index < m_edge_count)
|
|
{
|
|
if (0 == m_component_ptr.m_ptr)
|
|
{
|
|
if (nullptr != m_e_current)
|
|
m_e_current = m_e_current->m_next_edge;
|
|
}
|
|
else
|
|
{
|
|
const ON_SubDVertex* vertex = m_component_ptr.Vertex();
|
|
if (nullptr != vertex)
|
|
{
|
|
m_e_current = vertex->Edge(m_edge_index);
|
|
}
|
|
else
|
|
{
|
|
const ON_SubDFace* face = m_component_ptr.Face();
|
|
if (nullptr != face)
|
|
m_e_current = face->Edge(m_edge_index);
|
|
else
|
|
m_e_current = nullptr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_edge_index = m_edge_count;
|
|
m_e_current = nullptr;
|
|
}
|
|
return m_e_current;
|
|
}
|
|
|
|
/*
|
|
Returns:
|
|
Current edge;
|
|
*/
|
|
const class ON_SubDEdge* CurrentEdge() const
|
|
{
|
|
return m_e_current;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the end of the edge list.
|
|
Returns:
|
|
Last edge in the list.
|
|
*/
|
|
const class ON_SubDEdge* LastEdge()
|
|
{
|
|
m_edge_index = (m_edge_count > 0) ? (m_edge_count - 1) : 0;
|
|
return m_e_current = m_e_last;
|
|
}
|
|
|
|
private:
|
|
void Internal_Init(
|
|
const ON_SubDRef& subd_ref,
|
|
unsigned int edge_count,
|
|
const ON_SubDEdge* first,
|
|
const ON_SubDEdge* last,
|
|
ON_SubDComponentPtr component_ptr
|
|
);
|
|
ON_SubDRef m_subd_ref;
|
|
const ON_SubDEdge* m_e_first = nullptr;
|
|
const ON_SubDEdge* m_e_last = nullptr;
|
|
const ON_SubDEdge* m_e_current = nullptr;
|
|
unsigned int m_edge_index = 0;
|
|
unsigned int m_edge_count = 0;
|
|
ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDEdgeIdIterator
|
|
//
|
|
|
|
class ON_CLASS ON_SubDEdgeIdIterator : private ON_FixedSizePoolIterator
|
|
{
|
|
public:
|
|
ON_SubDEdgeIdIterator() = default;
|
|
~ON_SubDEdgeIdIterator() = default;
|
|
ON_SubDEdgeIdIterator(const ON_SubDEdgeIdIterator&) = default;
|
|
ON_SubDEdgeIdIterator& operator=(const ON_SubDEdgeIdIterator&) = default;
|
|
|
|
public:
|
|
ON_SubDEdgeIdIterator(const ON_SubDRef& subd_ref);
|
|
ON_SubDEdgeIdIterator(const ON_SubD& subd);
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
In general, you want to use a ON_SubDEdgeIterator to loop through SubD edges.
|
|
This is a special tool for unusual sitiations wheh it is necessary to
|
|
iteratate through every edge on every level of a SubD in order
|
|
of increasing m_id value.
|
|
Returns:
|
|
The edge with the smallest id.
|
|
*/
|
|
const ON_SubDEdge* FirstEdge();
|
|
|
|
const ON_SubDEdge* FirstEdgeOnLevel(unsigned int level_index);
|
|
|
|
|
|
/*
|
|
Description:
|
|
In general, you want to use a ON_SubDEdgeIterator to loop through SubD edges.
|
|
This is a special tool for unusual sitiations wheh it is necessary to
|
|
iteratate through every edge on every level of a SubD in order
|
|
of increasing m_id value.
|
|
Returns:
|
|
The edge in order of increasing id.
|
|
*/
|
|
const ON_SubDEdge* NextEdge();
|
|
|
|
const ON_SubDEdge* NextEdgeOnLevel(unsigned int level_index);
|
|
|
|
/*
|
|
Returns:
|
|
The most recently returned edge from a call to FirstEdge() or NextEdge().
|
|
*/
|
|
const ON_SubDEdge* CurrentEdge() const;
|
|
|
|
private:
|
|
friend class ON_SubDHeap;
|
|
ON_SubDRef m_subd_ref;
|
|
void Internal_Init();
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDFaceIterator
|
|
//
|
|
class ON_CLASS ON_SubDFaceIterator
|
|
{
|
|
public:
|
|
// The best way to get an ON_SubDFaceIterator is so use the ON_SubD member function
|
|
// ON_SubDFaceIterator fit = subd.FaceIterator();
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubD& subd
|
|
);
|
|
|
|
// The best way to get an ON_SubDFaceIterator is so use the ON_SubD member function
|
|
// ON_SubDFaceIterator fit = subd.FaceIterator();
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubDRef& subd_ref
|
|
);
|
|
|
|
// Construct and interator that iterates over the single face.
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDFace& face
|
|
);
|
|
|
|
// Construct and interator that iterates over the single face.
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDFace& face
|
|
);
|
|
|
|
// Construct and interator that iterates over the faces of a vertex.
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDVertex& vertex
|
|
);
|
|
|
|
// Construct and interator that iterates over the faces of a vertex.
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDVertex& vertex
|
|
);
|
|
|
|
// Construct and interator that iterates over the faces of an edge.
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubD& subd,
|
|
const class ON_SubDEdge& edge
|
|
);
|
|
|
|
// Construct and interator that iterates over the faces of an edge.
|
|
ON_SubDFaceIterator(
|
|
const class ON_SubDRef& subd_ref,
|
|
const class ON_SubDEdge& edge
|
|
);
|
|
|
|
ON_SubDFaceIterator() = default;
|
|
ON_SubDFaceIterator(const ON_SubDFaceIterator&) = default;
|
|
ON_SubDFaceIterator& operator=(const ON_SubDFaceIterator&) = default;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDFaceIterator( ON_SubDFaceIterator&& ) ON_NOEXCEPT;
|
|
// rvalue assignment operator
|
|
ON_SubDFaceIterator& operator=( ON_SubDFaceIterator&& );
|
|
#endif
|
|
|
|
/*
|
|
Returns:
|
|
The subD object for this iterator.
|
|
*/
|
|
const class ON_SubD& SubD() const
|
|
{
|
|
return m_subd_ref.SubD();
|
|
}
|
|
|
|
const class ON_SubDRef& SubDRef() const
|
|
{
|
|
return m_subd_ref;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Returns the current face and increment the iterator.
|
|
Returns:
|
|
Current face.
|
|
Remarks:
|
|
operator++ and NextFace() behave differently.
|
|
*/
|
|
const class ON_SubDFace* operator++()
|
|
{
|
|
const class ON_SubDFace* f = m_face_current;
|
|
NextFace();
|
|
return f;
|
|
}
|
|
|
|
/*
|
|
Return:
|
|
Number of faces this iterator will iterate through.
|
|
*/
|
|
unsigned int FaceCount() const
|
|
{
|
|
return m_face_count;
|
|
}
|
|
|
|
/*
|
|
Return:
|
|
Interator index of the current face.
|
|
*/
|
|
unsigned int CurrentFaceIndex() const
|
|
{
|
|
return m_face_index;
|
|
}
|
|
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the beginning of the face list.
|
|
Returns:
|
|
First face in the list.
|
|
*/
|
|
const class ON_SubDFace* FirstFace()
|
|
{
|
|
m_face_index = 0;
|
|
return (m_face_current = m_face_first);
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Returns the next face and incrments the iterator.
|
|
Returns:
|
|
Next face.
|
|
Remarks:
|
|
operator++ and NextFace() behave differently.
|
|
*/
|
|
const class ON_SubDFace* NextFace()
|
|
{
|
|
m_face_index++;
|
|
if (m_face_index < m_face_count)
|
|
{
|
|
if (0 == m_component_ptr.m_ptr)
|
|
{
|
|
if (nullptr != m_face_current)
|
|
m_face_current = m_face_current->m_next_face;
|
|
}
|
|
else
|
|
{
|
|
const ON_SubDVertex* vertex = m_component_ptr.Vertex();
|
|
if (nullptr != vertex)
|
|
{
|
|
m_face_current = vertex->Face(m_face_index);
|
|
}
|
|
else
|
|
{
|
|
const ON_SubDEdge* edge = m_component_ptr.Edge();
|
|
if (nullptr != edge)
|
|
m_face_current = edge->Face(m_face_index);
|
|
else
|
|
m_face_current = nullptr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_face_index = m_face_count;
|
|
m_face_current = nullptr;
|
|
}
|
|
return m_face_current;
|
|
}
|
|
|
|
/*
|
|
Returns:
|
|
Current face;
|
|
*/
|
|
const class ON_SubDFace* CurrentFace() const
|
|
{
|
|
return m_face_current;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the end of the face list.
|
|
Returns:
|
|
Last face in the list.
|
|
*/
|
|
const class ON_SubDFace* LastFace()
|
|
{
|
|
m_face_index = (m_face_count > 0) ? (m_face_count - 1) : 0;
|
|
return (m_face_current = m_face_last);
|
|
}
|
|
|
|
|
|
private:
|
|
void Internal_Init(
|
|
const ON_SubDRef& subd_ref,
|
|
unsigned int face_count,
|
|
const ON_SubDFace* first,
|
|
const ON_SubDFace* last,
|
|
ON_SubDComponentPtr component_ptr
|
|
);
|
|
ON_SubDRef m_subd_ref;
|
|
const ON_SubDFace* m_face_first = nullptr;
|
|
const ON_SubDFace* m_face_last = nullptr;
|
|
const ON_SubDFace* m_face_current = nullptr;
|
|
unsigned int m_face_index = 0;
|
|
unsigned int m_face_count = 0;
|
|
ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDFaceIdIterator
|
|
//
|
|
|
|
class ON_CLASS ON_SubDFaceIdIterator : private ON_FixedSizePoolIterator
|
|
{
|
|
public:
|
|
ON_SubDFaceIdIterator() = default;
|
|
~ON_SubDFaceIdIterator() = default;
|
|
ON_SubDFaceIdIterator(const ON_SubDFaceIdIterator&) = default;
|
|
ON_SubDFaceIdIterator& operator=(const ON_SubDFaceIdIterator&) = default;
|
|
|
|
public:
|
|
ON_SubDFaceIdIterator(const ON_SubDRef& subd_ref);
|
|
ON_SubDFaceIdIterator(const ON_SubD& subd);
|
|
|
|
public:
|
|
/*
|
|
Description:
|
|
In general, you want to use a ON_SubDFaceIterator to loop through SubD faces.
|
|
This is a special tool for unusual sitiations wheh it is necessary to
|
|
iteratate through every face on every level of a SubD in order
|
|
of increasing m_id value.
|
|
Returns:
|
|
The face with the smallest id.
|
|
*/
|
|
const ON_SubDFace* FirstFace();
|
|
|
|
const ON_SubDFace* FirstFaceOnLevel(unsigned int level_index);
|
|
|
|
/*
|
|
Description:
|
|
In general, you want to use a ON_SubDFaceIterator to loop through SubD faces.
|
|
This is a special tool for unusual sitiations wheh it is necessary to
|
|
iteratate through every face on every level of a SubD in order
|
|
of increasing m_id value.
|
|
Returns:
|
|
The face in order of increasing id.
|
|
*/
|
|
const ON_SubDFace* NextFace();
|
|
|
|
const ON_SubDFace* NextFaceOnLevel(unsigned int level_index);
|
|
|
|
/*
|
|
Returns:
|
|
The most recently returned face from a call to FirstFace() or NextFace().
|
|
*/
|
|
const ON_SubDFace* CurrentFace() const;
|
|
|
|
private:
|
|
friend class ON_SubDHeap;
|
|
ON_SubDRef m_subd_ref;
|
|
void Internal_Init();
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentIterator
|
|
//
|
|
class ON_CLASS ON_SubDComponentIterator
|
|
{
|
|
public:
|
|
static const ON_SubDComponentIterator Empty;
|
|
|
|
// The ON_SubD member function
|
|
// ON_SubDComponentIterator ON_SubD::ComponentIterator(subd_level_index)
|
|
// is the best way to get a component iterator for a subd level.
|
|
ON_SubDComponentIterator(
|
|
const class ON_SubD& subd
|
|
);
|
|
ON_SubDComponentIterator(
|
|
const class ON_SubDRef& subd_ref
|
|
);
|
|
|
|
ON_SubDComponentIterator() = default;
|
|
ON_SubDComponentIterator(const ON_SubDComponentIterator&) = default;
|
|
ON_SubDComponentIterator& operator=(const ON_SubDComponentIterator&) = default;
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDComponentIterator( ON_SubDComponentIterator&& ) ON_NOEXCEPT;
|
|
// rvalue assignment operator
|
|
ON_SubDComponentIterator& operator=( ON_SubDComponentIterator&& );
|
|
#endif
|
|
|
|
/*
|
|
Returns:
|
|
The subD object for this iterator.
|
|
*/
|
|
const class ON_SubD& SubD() const
|
|
{
|
|
return m_subd_ref.SubD();
|
|
}
|
|
|
|
const class ON_SubDRef& SubDRef() const
|
|
{
|
|
return m_subd_ref;
|
|
}
|
|
|
|
/*
|
|
Returns:
|
|
The subD level for this iterator.
|
|
*/
|
|
unsigned int SubDLevel() const
|
|
{
|
|
return m_subd_level;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Returns the current component and increment the iterator.
|
|
Returns:
|
|
Current component.
|
|
Remarks:
|
|
operator++ and NextComponent() behave differently.
|
|
*/
|
|
const class ON_SubDComponentPtr operator++()
|
|
{
|
|
const class ON_SubDComponentPtr cptr = m_cptr_current;
|
|
NextComponent();
|
|
return cptr;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the beginning of the component list.
|
|
Returns:
|
|
First component in the list.
|
|
*/
|
|
const class ON_SubDComponentPtr FirstComponent();
|
|
|
|
/*
|
|
Description:
|
|
Returns the next component and incrments the iterator.
|
|
Returns:
|
|
Next component.
|
|
Remarks:
|
|
operator++ and NextComponent() behave differently.
|
|
*/
|
|
const class ON_SubDComponentPtr NextComponent();
|
|
|
|
/*
|
|
Returns:
|
|
Current component;
|
|
*/
|
|
const class ON_SubDComponentPtr CurrentComponent() const
|
|
{
|
|
return m_cptr_current;
|
|
}
|
|
|
|
/*
|
|
Description:
|
|
Set the iterator to the end of the component list.
|
|
Returns:
|
|
Last component in the list.
|
|
*/
|
|
const class ON_SubDComponentPtr LastComponent();
|
|
|
|
private:
|
|
ON_SubDRef m_subd_ref;
|
|
unsigned int m_subd_level = 0;
|
|
const ON_SubDVertex* m_vertex_first = nullptr;
|
|
const ON_SubDVertex* m_vertex_last = nullptr;
|
|
const ON_SubDEdge* m_edge_first = nullptr;
|
|
const ON_SubDEdge* m_edge_last = nullptr;
|
|
const ON_SubDFace* m_face_first = nullptr;
|
|
const ON_SubDFace* m_face_last = nullptr;
|
|
ON_SubDComponentPtr m_cptr_current = ON_SubDComponentPtr::Null;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDMeshFragmentIterator
|
|
//
|
|
|
|
class ON_CLASS ON_SubDMeshFragmentIterator
|
|
{
|
|
public:
|
|
ON_SubDMeshFragmentIterator() = default;
|
|
~ON_SubDMeshFragmentIterator() = default;
|
|
ON_SubDMeshFragmentIterator(const ON_SubDMeshFragmentIterator&);
|
|
ON_SubDMeshFragmentIterator& operator=(const ON_SubDMeshFragmentIterator&);
|
|
|
|
public:
|
|
ON_SubDMeshFragmentIterator(const class ON_SubDMesh limit_mesh);
|
|
ON_SubDMeshFragmentIterator(ON_SubDRef& subd_ref);
|
|
ON_SubDMeshFragmentIterator(const ON_SubD& subd);
|
|
ON_SubDMeshFragmentIterator(const ON_SubDFaceIterator& fit);
|
|
|
|
public:
|
|
const ON_SubDMeshFragment* FirstFragment();
|
|
const ON_SubDMeshFragment* NextFragment();
|
|
const ON_SubDMeshFragment* CurrentFragment();
|
|
|
|
bool IsEmpty() const;
|
|
|
|
const ON_SubD& SubD() const;
|
|
|
|
/*
|
|
Returns
|
|
ON_SubDComponentLocation::Surface or ON_SubDComponentLocation::ControlNet
|
|
*/
|
|
ON_SubDComponentLocation SubDAppearance() const;
|
|
|
|
/*
|
|
Parameters:
|
|
subd_appearance_override - [in]
|
|
ON_SubDComponentLocation::Unset - appearance controlled by SubD().SubDAppearance().
|
|
ON_SubDComponentLocation::Surface
|
|
ON_SubDComponentLocation::ControlNet
|
|
Returns
|
|
ON_SubDComponentLocation::Surface or ON_SubDComponentLocation::ControlNet
|
|
*/
|
|
void SetSubDAppearanceOverride(ON_SubDComponentLocation subd_appearance_override);
|
|
|
|
|
|
/*
|
|
Returns:
|
|
Density setting used to create the fragments and the maximum mesh density
|
|
these fragments can deliver.
|
|
Remarks:
|
|
0: a single mesh quad per SubD quad
|
|
1: 4 mesh quads per SubD quad (n mesh quads per SubD n-gon when n != 4)
|
|
d: 4^d mesh quads per SubD quad (n*(4^(d-1)) mesh quads per SubD n-gon when n != 4)
|
|
*/
|
|
unsigned int MaximumMeshDensity() const;
|
|
|
|
/*
|
|
Returns:
|
|
Minimum mesh density that can be extracted from these fragments.
|
|
Remarks:
|
|
0 = all fragments are full sized.
|
|
1 = there are half sixed fragments because the SubD has n-gons with n != 4.
|
|
*/
|
|
unsigned int MinimumMeshDensity() const;
|
|
|
|
enum : unsigned int
|
|
{
|
|
/// <summary>
|
|
/// Rhino uses this value in MeshDensityFromMaxMeshQuadCount() to se the default level of detail.
|
|
/// The enum will always exist but the value can change without breaking the SDK.
|
|
/// You code must assume this value will change with each service release of Rhino.
|
|
/// </summary>
|
|
DefaultMaximumMeshQuadCount = 262144
|
|
};
|
|
|
|
/*
|
|
Parameters:
|
|
candidate_mesh_density - [in]
|
|
Returns:
|
|
If candidate_mesh_density > MeshDensity(), then MeshDensity() is returned.
|
|
If candidate_mesh_density < MinimumMeshDensity(), then MinimumMeshDensity() is returned.
|
|
Otherwise, candidate_mesh_density is returned.
|
|
*/
|
|
unsigned int ClampMeshDensity(
|
|
unsigned int candidate_mesh_density
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
Total number of fragments.
|
|
*/
|
|
unsigned int FragmentCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Total number of full sized fragments.
|
|
Remarks:
|
|
A full sized fragment covers an entire quad face.
|
|
*/
|
|
unsigned int FullSizeFragmentCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Total number of half sized fragments.
|
|
Remarks:
|
|
A half sized fragment covers the corner of an N-gon and are used when N != 4.
|
|
*/
|
|
unsigned int HalfSizeFragmentCount() const;
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
full_size_fragment_count - [out]
|
|
Number of full sized fragments. These cover an entire quad face.
|
|
half_size_fragment_count - [out]
|
|
Number of half sized fragments. These cover a corner of an N-gon
|
|
and are used when N != 4.
|
|
Returns:
|
|
Total number of fragments.
|
|
*/
|
|
unsigned int GetFragmentCounts(
|
|
unsigned int& full_size_fragment_count,
|
|
unsigned int& half_size_fragment_count
|
|
) const;
|
|
|
|
/*
|
|
Parameters:
|
|
mesh_density - [in]
|
|
MinimumMeshDensity() <= mesh_density <= MeshDensity()
|
|
Returns:
|
|
Total number of mesh quads in at the specified mesh density.
|
|
*/
|
|
unsigned int TotalQuadCount(unsigned int mesh_density) const;
|
|
|
|
/*
|
|
Parameters:
|
|
mesh_density - [in]
|
|
MinimumMeshDensity() <= mesh_density <= MeshDensity()
|
|
Returns:
|
|
Total number of mesh points delivered at the specified mesh density.
|
|
*/
|
|
unsigned int TotalPointCount(unsigned int mesh_density) const;
|
|
|
|
/*
|
|
Returns:
|
|
Total number of mesh quads delivered at MaximumMeshDensity().
|
|
*/
|
|
unsigned int MaximumDensityQuadCount() const;
|
|
|
|
/*
|
|
Parameters:
|
|
mesh_density - [in]
|
|
MinimumMeshDensity() <= mesh_density <= MeshDensity()
|
|
Returns:
|
|
Total number of mesh points delivered at MaximumMeshDensity().
|
|
*/
|
|
unsigned int MaximumDensityPointCount() const;
|
|
|
|
const ON_BoundingBox SurfaceBoundingBox() const;
|
|
const ON_BoundingBox ControlNetQuadBoundingBox() const;
|
|
/*
|
|
Returns:
|
|
If this->SubDAppearance() is ON_SubDComponentLocation::ControlNet, then this->ControlNetQuadBoundingBox() is returned.
|
|
Otherwise this->SurfaceBoundingBox() returned.
|
|
*/
|
|
const ON_BoundingBox BoundingBox() const;
|
|
|
|
private:
|
|
void Internal_CopyFrom(const ON_SubDMeshFragmentIterator& src);
|
|
|
|
ON_SubDMesh m_limit_mesh;
|
|
ON_SubD m_subd;
|
|
ON_SubDFaceIterator m_fit;
|
|
const ON_SubDMeshFragment* m_current_fragment = nullptr;
|
|
bool m_bFromFaceFragments = false;
|
|
mutable bool m_bHaveCounts = false;
|
|
|
|
// used to override the appearance of SubD().SubDApperance().
|
|
ON_SubDComponentLocation m_subd_appearance_override = ON_SubDComponentLocation::Unset;
|
|
|
|
private:
|
|
// Rendering density = MaximumMeshDensity() - m_density_reduction.
|
|
unsigned char m_reserved_density_reduction = 0; // 0 = none
|
|
|
|
private:
|
|
mutable unsigned int m_maximum_mesh_density = 0; // See MaximumMeshDensity() comment
|
|
|
|
// full sized fragment count (for quads)
|
|
mutable unsigned int m_full_size_fragment_count = 0;
|
|
|
|
// half sized fragment count (for n-gons with n != 4)
|
|
mutable unsigned int m_half_size_fragment_count = 0;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDSectorIterator
|
|
//
|
|
|
|
class ON_CLASS ON_SubDSectorIterator
|
|
{
|
|
public:
|
|
static const ON_SubDSectorIterator Empty;
|
|
|
|
ON_SubDSectorIterator() = default;
|
|
~ON_SubDSectorIterator() = default;
|
|
ON_SubDSectorIterator(const ON_SubDSectorIterator&) = default;
|
|
ON_SubDSectorIterator& operator=(const ON_SubDSectorIterator&) = default;
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
center_vertex - [in]
|
|
The vertex on initial_face that will be iterated around.
|
|
center_vertex->Face(0) is used to select the sector.
|
|
Returns:
|
|
If input is valid, a pointer to the center vertex is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const ON_SubDVertex* Initialize(
|
|
const ON_SubDVertex* center_vertex
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
initial_face - [in]
|
|
iterator_orientation - [in]
|
|
0: (more common)
|
|
"next" means counter-clockwise with respect to the orientation of initial_face
|
|
1: (less common)
|
|
"next" means clockwise with respect to the orientation of initial_face
|
|
center_vertex - [in]
|
|
The vertex on initial_face that will be iterated around.
|
|
Returns:
|
|
If input is valid, a pointer to the center vertex is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const ON_SubDVertex* Initialize(
|
|
const ON_SubDFace* initial_face,
|
|
ON__UINT_PTR iterator_orientation,
|
|
const ON_SubDVertex* center_vertex
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
initial_face - [in]
|
|
iterator_orientation - [in]
|
|
0: (more common)
|
|
"next" means counter-clockwise with respect to the orientation of initial_face
|
|
1: (less common)
|
|
"next" means clockwise with respect to the orientation of initial_face
|
|
face_vertex_index - [in]
|
|
initial_face->Vertex(face_vertex_index) is the center vertex
|
|
that will be iterated around.
|
|
Returns:
|
|
If input is valid, a pointer to the center vertex is returned.
|
|
Otherwise, nullptr is returned.
|
|
*/
|
|
const ON_SubDVertex* Initialize(
|
|
const ON_SubDFace* initial_face,
|
|
ON__UINT_PTR iterator_orientation,
|
|
unsigned int face_vertex_index
|
|
);
|
|
|
|
bool InitializeToCurrentFace();
|
|
|
|
void Initialize();
|
|
|
|
/*
|
|
Description:
|
|
The current ring index reports the total increment from the
|
|
start to the current state. It can be positive or negative.
|
|
*/
|
|
int CurrentRingIndex() const;
|
|
|
|
const ON_SubDVertex* CenterVertex() const;
|
|
|
|
const ON_SubDFace* InitialFace() const;
|
|
|
|
unsigned int InitialFaceCenterVertexIndex() const;
|
|
|
|
const ON_SubDFace* CurrentFace() const;
|
|
|
|
unsigned int CurrentFaceDirection() const;
|
|
|
|
ON_SubDFacePtr CurrentFacePtr() const;
|
|
|
|
unsigned int CurrentFaceCenterVertexIndex() const;
|
|
|
|
|
|
/*
|
|
Description:
|
|
|
|
CurrentEdge(1)
|
|
|
|
|
|
|
|
NextFace() | CurrentFace()
|
|
|
|
|
|
|
|
*------------- CurrentEdge(0)
|
|
PrevFace()
|
|
|
|
The asterisk (*) marks the center vertex.
|
|
The diagram is With respect to the initial iterator orientation.
|
|
|
|
Parameters:
|
|
face_side_index - [in]
|
|
CurrentEdge(0) = edge on the clockwise (PrevFace) side of the current face
|
|
CurrentEdge(1) = edge on the counterclockwise (NextFace) side of the current face
|
|
The directions "counterclockwise" and "clockwise" are with respect to the
|
|
initial iterator orientation.
|
|
|
|
Returns:
|
|
The requested edge. The edge pointer is oriented such that
|
|
RelativeVertex(0) is the center vertex.
|
|
*/
|
|
ON_SubDEdgePtr CurrentEdgePtr(
|
|
unsigned int face_side_index
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
|
|
CurrentEdge(1)
|
|
|
|
|
|
|
|
NextFace() | CurrentFace()
|
|
|
|
|
|
|
|
*------------- CurrentEdge(0)
|
|
PrevFace()
|
|
|
|
The asterisk (*) marks the center vertex.
|
|
The diagram is With respect to the initial iterator orientation.
|
|
|
|
Parameters:
|
|
face_side_index - [in]
|
|
CurrentEdge(0) = edge on the clockwise (PrevFace) side of the current face
|
|
CurrentEdge(1) = edge on the counterclockwise (NextFace) side of the current face
|
|
The directions "counterclockwise" and "clockwise" are with respect to the
|
|
initial iterator orientation.
|
|
Returns:
|
|
The requested edge or nullptr if the iterator is not initialized,
|
|
has terminated, or is not valid.
|
|
When the sector iterator is initialized and valid, sit.CenterVertex() = CurrentEdge(*).RelativeVertex(0).
|
|
*/
|
|
const ON_SubDEdge* CurrentEdge(
|
|
unsigned int face_side_index
|
|
) const;
|
|
|
|
ON__UINT_PTR CurrentEdgeDirection(
|
|
unsigned int face_side_index
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
The vertex on CurrentEdge(face_side_index) that is opposite
|
|
the central vertex.
|
|
*/
|
|
const ON_SubDVertex* CurrentEdgeRingVertex(
|
|
unsigned int face_side_index
|
|
) const;
|
|
|
|
enum class StopAt : unsigned char
|
|
{
|
|
///<summary>
|
|
/// Sector iteration will terminate when the edge being crossed does not have two faces.
|
|
///</summary>
|
|
Boundary = 0,
|
|
|
|
///<summary>
|
|
/// Sector iteration will terminate when the edge being crossed does not have two faces
|
|
/// or that edge is tagged as ON_SubDEdgeTag::Crease.
|
|
///</summary>
|
|
AnyCrease = 1,
|
|
|
|
///<summary>
|
|
/// Sector iteration will terminate when the edge being crossed does not have two faces
|
|
/// or that edge is tagged as ON_SubDEdgeTag::Crease and has no dart vertices.
|
|
///</summary>
|
|
HardCrease = 2,
|
|
};
|
|
|
|
/*
|
|
Description:
|
|
Advance the "current" face to the "next" face in the ring
|
|
by crossing CurrentEdge(1).
|
|
|
|
If the current face is not reversed (1 == CurrentFaceDirection),
|
|
then this rotation is counter-clockwise with respect to
|
|
the current face's orientation.
|
|
|
|
If the current face is reversed (1 == CurrentFaceDirection),
|
|
then this rotation is clockwise with respect to
|
|
the current face's orientation.
|
|
Parameters:
|
|
stop_at - [in]
|
|
Determines that type of CurrentEdge(1) will terminate iteration.
|
|
Returns:
|
|
When the input CurrentEdge(1) has exactly two faces and
|
|
is not tagged as a crease or bStopAtCrease is false, the
|
|
face on the other side of CurrentEdge(1) becomes the new
|
|
current face and a pointer to this face is returned.
|
|
Remarks:
|
|
Identical to calling IncrementFace(+1,bStopAtCrease);
|
|
*/
|
|
const ON_SubDFace* NextFace(
|
|
ON_SubDSectorIterator::StopAt stop_at
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Advance the "current" face to the "previous" face in the ring
|
|
by crossing CurrentEdge(0).
|
|
|
|
If the current face is not reversed (0 == CurrentFaceDirection),
|
|
then this rotation is clockwise with respect to
|
|
the current face's orientation.
|
|
|
|
If the current face is reversed (1 == CurrentFaceDirection),
|
|
then this rotation is counter-clockwise with respect to
|
|
the current face's orientation.
|
|
Parameters:
|
|
stop_at - [in]
|
|
Determines that type of CurrentEdge(0) will terminate iteration.
|
|
Returns:
|
|
When the input CurrentEdge(0) has exactly two faces and
|
|
is not tagged as a crease or bStopAtCrease is false, the
|
|
face on the other side of CurrentEdge(0) becomes the new
|
|
current face and a pointer to this face is returned.
|
|
In all other cases, nullptr is returned
|
|
Remarks:
|
|
Identical to calling IncrementFace(-1,bStopAtCrease);
|
|
*/
|
|
const ON_SubDFace* PrevFace(
|
|
ON_SubDSectorIterator::StopAt stop_at
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Advance the "current" face by "hopping across" the edge
|
|
CurrentEdge((increment_direction>0) ? 1 : 0).
|
|
|
|
If the current face is not reversed (0 == CurrentFaceDirection),
|
|
then increment_direction>0 rotates counter-clockwise with respect to
|
|
the current face's orientation.
|
|
|
|
If the current face is reversed (1 == CurrentFaceDirection),
|
|
then increment_direction>0 rotates clockwise with respect to
|
|
the current face's orientation.
|
|
Parameters:
|
|
increment_direction - [in]
|
|
> 0 advance the "current" face to next face
|
|
<= 0 advance the "current" face to previous face
|
|
stop_at - [in]
|
|
Determines that type of CurrentEdge((increment_direction>0) ? 1 : 0) will terminate iteration.
|
|
If true and the input value of CurrentEdge((increment_direction>0) ? 1 : 0)
|
|
When iteration terminates at a crease,
|
|
CurrentFace() becomes nullptr
|
|
CurrentEdge((increment_direction>0) ? 1 : 0) becomes nullptr
|
|
CurrentEdge((increment_direction>0) ? 0 : 1) points at the crease
|
|
and nullptr returned.
|
|
Returns:
|
|
nullptr if iteration terminates.
|
|
*/
|
|
const ON_SubDFace* IncrementFace(
|
|
int increment_direction,
|
|
ON_SubDSectorIterator::StopAt stop_at
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Increment the iterator until it reaches a face with
|
|
a crease
|
|
Parameters:
|
|
increment_direction - [in]
|
|
> 0 advance next until CurrentEdge(1) is a crease.
|
|
<= 0 advance previous until CurrentEdge(0) is a crease.
|
|
Returns:
|
|
nullptr - the sector has no creases.
|
|
not nullptr - incremented to a crease
|
|
*/
|
|
const ON_SubDFace* IncrementToCrease(
|
|
int increment_direction
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Reset iterator to initial face.
|
|
*/
|
|
const ON_SubDFace* FirstFace();
|
|
|
|
bool IsValid() const;
|
|
|
|
private:
|
|
const ON_SubDVertex* m_center_vertex = nullptr;
|
|
const ON_SubDFace* m_initial_face = nullptr;
|
|
const ON_SubDFace* m_current_face = nullptr;
|
|
|
|
// m_current_eptr[0].Edge() = "prev" side edge
|
|
// m_current_eptr[1].Edge() = "next" side edge
|
|
// center vertex = m_current_eptr[i].RelativeVertex(0)
|
|
ON_SubDEdgePtr m_current_eptr[2] = {}; // default = { ON_SubDEdgePtr::Null, ON_SubDEdgePtr::Null };
|
|
|
|
unsigned int m_initial_fvi = 0;
|
|
unsigned int m_current_fvi = 0;
|
|
unsigned int m_current_fei[2] = {}; // default = { 0, 0 }; // "prev" and "next"
|
|
|
|
// m_initial_face_dir
|
|
// 0: "next" means clockwise with respect to the initial face's orientation.
|
|
// 1: "next" means counter-clockwise with respect to the initial face's orientation.
|
|
unsigned int m_initial_face_dir = 0;
|
|
|
|
// m_current_face_dir
|
|
// 0: "next" means clockwise with respect to the initial face's orientation.
|
|
// 1: "next" means counter-clockwise with respect to the initial face's orientation.
|
|
// When the subd faces around the center vertex are consistently oriented,
|
|
// m_current_face_dir is always equal to m_initial_face_dir.
|
|
unsigned int m_current_face_dir = 0;
|
|
|
|
int m_current_ring_index = 0;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDFaceEdgeIterator
|
|
//
|
|
class ON_CLASS ON_SubDFaceEdgeIterator
|
|
{
|
|
public:
|
|
ON_SubDFaceEdgeIterator();
|
|
|
|
/*
|
|
Description:
|
|
Construct an iterator for going around the edges on a face.
|
|
Parameters:
|
|
face - [in]
|
|
first_edge - [in]
|
|
starting edge for the iterator or nullptr to start at face->Edge(0).
|
|
*/
|
|
ON_SubDFaceEdgeIterator(
|
|
const ON_SubDFace* face
|
|
);
|
|
|
|
ON_SubDFaceEdgeIterator(
|
|
const ON_SubDFace* face,
|
|
const ON_SubDEdge* first_edge
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Initialize an iterator for going around the edges on a face.
|
|
Parameters:
|
|
face - [in]
|
|
first_edge - [in]
|
|
starting edge for the iterator or nullptr to start at face->Edge(0).
|
|
*/
|
|
unsigned int Initialize(
|
|
const ON_SubDFace* face
|
|
);
|
|
|
|
unsigned int Initialize(
|
|
const ON_SubDFace* face,
|
|
const ON_SubDEdge* first_edge
|
|
);
|
|
|
|
unsigned int EdgeCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Resets the iterator and returns the first edge.
|
|
*/
|
|
const ON_SubDEdge* FirstEdge();
|
|
|
|
/*
|
|
Description:
|
|
Increments the iterator and returns the edge.
|
|
*/
|
|
const ON_SubDEdge* NextEdge();
|
|
|
|
/*
|
|
Description:
|
|
Decrements the iterator and returns the edge.
|
|
*/
|
|
const ON_SubDEdge* PrevEdge();
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
bReturnNullAtFirstEdge = [in]
|
|
If true and the next edge would be FirstEdge(), the nullptr is returned
|
|
and CurrentEdge() is not changed.
|
|
Description:
|
|
Increments the iterator and returns the edge.
|
|
*/
|
|
const ON_SubDEdge* NextEdge(
|
|
bool bReturnNullAtFirstEdge
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
bReturnNullAtLastEdge = [in]
|
|
If true and the previous edge would be FirstEdge(), the nullptr is returned
|
|
and CurrentEdge() is not changed.
|
|
Description:
|
|
Decrements the iterator and returns the edge.
|
|
*/
|
|
const ON_SubDEdge* PrevEdge(
|
|
bool bReturnNullAtFirstEdge
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Current edge.
|
|
*/
|
|
const ON_SubDEdge* CurrentEdge() const;
|
|
|
|
unsigned int FirstEdgeIndex() const;
|
|
|
|
unsigned int CurrentEdgeIndex() const;
|
|
|
|
private:
|
|
const ON_SubDFace* m_face;
|
|
unsigned int m_edge_count;
|
|
unsigned int m_edge_index0;
|
|
unsigned int m_edge_index;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDFromMeshParameters
|
|
//
|
|
class ON_CLASS ON_SubDFromMeshParameters
|
|
{
|
|
public:
|
|
|
|
// Default construction is identical to ON_SubDFromMeshParameters::Smooth.
|
|
ON_SubDFromMeshParameters() = default;
|
|
~ON_SubDFromMeshParameters() = default;
|
|
ON_SubDFromMeshParameters(const ON_SubDFromMeshParameters&) = default;
|
|
ON_SubDFromMeshParameters& operator=(const ON_SubDFromMeshParameters&) = default;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crease options
|
|
//
|
|
|
|
// No interior creases and no corners.
|
|
static const ON_SubDFromMeshParameters Smooth;
|
|
|
|
|
|
// Create an interior sub-D crease along all input mesh double edges.
|
|
static const ON_SubDFromMeshParameters InteriorCreases;
|
|
|
|
// Look for convex corners at sub-D vertices with 2 edges
|
|
// that have an included angle <= 90 degrees.
|
|
static const ON_SubDFromMeshParameters ConvexCornersAndInteriorCreases;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Custom interior crease options
|
|
//
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDFromMeshParameters::InteriorCreaseOption] [Rhino.Geometry.SubDCreationOptions.InteriorCreaseOption] [nested:byte]
|
|
/// <summary>
|
|
/// Specifies the test used to determine when an interior mesh edge generates an interior SubD creased edge.
|
|
/// </summary>
|
|
enum class InteriorCreaseOption : unsigned char
|
|
{
|
|
///<summary>The interior crease test is not defined.</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>No interior creases.</summary>
|
|
None = 1,
|
|
|
|
///<summary>An interior mesh double edge will create an interior SubD creased edge.
|
|
/// An interior mesh double edge occurs when the sides of two mesh faces have
|
|
/// have distinct vertex indices and identical vertex locations.
|
|
///</summary>
|
|
AtMeshDoubleEdge = 2,
|
|
};
|
|
#pragma endregion
|
|
|
|
static ON_SubDFromMeshParameters::InteriorCreaseOption InteriorCreaseOptionFromUnsigned(
|
|
unsigned int interior_crease_option_as_unsigned
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
interior_crease_option - [in]
|
|
*/
|
|
void SetInteriorCreaseOption(
|
|
ON_SubDFromMeshParameters::InteriorCreaseOption interior_crease_option
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The interior crease option.
|
|
*/
|
|
ON_SubDFromMeshParameters::InteriorCreaseOption GetInteriorCreaseOption() const;
|
|
|
|
/*
|
|
Description:
|
|
Copy all settings that control how interior crease edges are created.
|
|
Parameters:
|
|
source_options - [in]
|
|
Returns:
|
|
The currently selected interior crease option.
|
|
*/
|
|
ON_SubDFromMeshParameters::InteriorCreaseOption CopyInteriorCreaseTest(
|
|
ON_SubDFromMeshParameters source_options
|
|
);
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Convex corner options
|
|
//
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDFromMeshParameters::ConvexCornerOption] [Rhino.Geometry.SubDCreationOptions.ConvexCornerOption] [nested:byte]
|
|
/// <summary>
|
|
/// Defines how convex corners are treated.
|
|
/// </summary>
|
|
enum class ConvexCornerOption : unsigned char
|
|
{
|
|
///<summary>The option is not set.</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>No convex coners.</summary>
|
|
None = 1,
|
|
|
|
///<summary>A convex subd corner will appear at input mesh boundary vertices
|
|
/// where the corner angle <= MaximumConvexCornerAngleRadians() and
|
|
/// the number of edges the end at the vertex is <= MaximumConvexCornerEdgeCount().
|
|
///</summary>
|
|
AtMeshCorner = 2
|
|
};
|
|
#pragma endregion
|
|
|
|
static ON_SubDFromMeshParameters::ConvexCornerOption ConvexCornerOptionFromUnsigned(
|
|
unsigned int convex_corner_option_as_unsigned
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
convex_corner_option - [in]
|
|
*/
|
|
void SetConvexCornerOption(
|
|
ON_SubDFromMeshParameters::ConvexCornerOption convex_corner_option
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The currently selected convex corner option.
|
|
*/
|
|
ON_SubDFromMeshParameters::ConvexCornerOption GetConvexCornerOption() const;
|
|
|
|
/*
|
|
Description:
|
|
If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
|
|
and the corner angle is <= MaximumConvexCornerAngleRadians().
|
|
Parameters:
|
|
maximum_convex_corner_edge_count - [in]
|
|
*/
|
|
void SetMaximumConvexCornerEdgeCount(
|
|
unsigned int maximum_convex_corner_edge_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
|
|
and the corner angle is <= MaximumConvexCornerAngleRadians().
|
|
Returns:
|
|
The maximum number of edges at a convex corner vertex.
|
|
*/
|
|
unsigned int MaximumConvexCornerEdgeCount() const;
|
|
|
|
/*
|
|
Description:
|
|
If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
|
|
and the corner angle is <= MaximumConvexCornerAngleRadians().
|
|
Parameters:
|
|
maximum_convex_corner_angle_radians - [in]
|
|
> 0.0 and < ON_PI
|
|
*/
|
|
void SetMaximumConvexCornerAngleRadians(
|
|
double maximum_convex_corner_angle_radians
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
If ConvexCornerTest() ConvexCornerOption::at_mesh_corner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is <= MaximumConvexCornerEdgeCount() edges
|
|
and the corner angle is <= MaximumConvexCornerAngleRadians().
|
|
Returns:
|
|
The maximum corner angle.
|
|
*/
|
|
double MaximumConvexCornerAngleRadians() const;
|
|
|
|
/*
|
|
Description:
|
|
Copy all settings that control how convex corner vertices are created.
|
|
Parameters:
|
|
source_options - [in]
|
|
Returns:
|
|
The currently selected convex corner option.
|
|
*/
|
|
ON_SubDFromMeshParameters::ConvexCornerOption CopyConvexCornerTest(
|
|
ON_SubDFromMeshParameters source_parameters
|
|
);
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Concave corner options
|
|
//
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDFromMeshParameters::ConcaveCornerOption] [Rhino.Geometry.SubDCreationOptions.ConcaveCornerOption] [nested:byte]
|
|
/// <summary>
|
|
/// Defines how concave corners are treated.
|
|
/// </summary>
|
|
enum class ConcaveCornerOption : unsigned char
|
|
{
|
|
///<summary>The option is not set.</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>No concave coners. In general, this is the best choice.</summary>
|
|
None = 1,
|
|
|
|
///<summary>A concave subd corner will appear at input mesh boundary vertices
|
|
/// where the corner angle >= MinimumConcaveCornerAngleRadians() and
|
|
/// the number of edges the end at the vertex is >= MinimumConcaveCornerEdgeCount().
|
|
///</summary>
|
|
AtMeshCorner = 2
|
|
};
|
|
#pragma endregion
|
|
|
|
static ON_SubDFromMeshParameters::ConcaveCornerOption ConcaveCornerOptionFromUnsigned(
|
|
unsigned int concave_corner_option_as_unsigned
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
concave_corner_option - [in]
|
|
*/
|
|
void SetConcaveCornerOption(
|
|
ON_SubDFromMeshParameters::ConcaveCornerOption concave_corner_option
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The currently selected concave corner option.
|
|
*/
|
|
ON_SubDFromMeshParameters::ConcaveCornerOption GetConcaveCornerOption() const;
|
|
|
|
/*
|
|
Description:
|
|
If ConcaveCornerTest() = ConcaveCornerOption::AtMeshConcaveCorner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is >= MinimumConcaveCornerEdgeCount() edges
|
|
and the corner angle is >= MinimumConcaveCornerAngleRadians().
|
|
Parameters:
|
|
minimum_concave_corner_edge_count - [in]
|
|
*/
|
|
void SetMinimumConcaveCornerEdgeCount(
|
|
unsigned int minimum_concave_corner_edge_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
If ConcaveCornerTest() ConcaveCornerOption::AtMeshConcaveCorner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is >= MinimumConcaveCornerEdgeCount() edges
|
|
and the corner angle is >= MinimumConcaveCornerAngleRadians().
|
|
Returns:
|
|
The minimum number of edges at a concave corner vertex.
|
|
*/
|
|
unsigned int MinimumConcaveCornerEdgeCount() const;
|
|
|
|
/*
|
|
Description:
|
|
If ConcaveCornerTest() ConcaveCornerOption::AtMeshConcaveCorner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is >= MinimumConcaveCornerEdgeCount() edges
|
|
and the corner angle is >= MinimumConcaveCornerAngleRadians().
|
|
Parameters:
|
|
minimum_concave_corner_angle_radians - [in]
|
|
> ON_PI and <= ON_2PI
|
|
*/
|
|
void SetMinimumConcaveCornerAngleRadians(
|
|
double minimum_concave_corner_angle_radians
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
If ConcaveCornerTest() ConcaveCornerOption::AtMeshConcaveCorner, then an
|
|
input mesh boundary vertex becomes a sub-D corner when the number of
|
|
edges that end at the vertex is >= MinimumConcaveCornerEdgeCount() edges
|
|
and the corner angle is >= MinimumConcaveCornerAngleRadians().
|
|
Returns:
|
|
The minimum corner angle.
|
|
*/
|
|
double MinimumConcaveCornerAngleRadians() const;
|
|
|
|
/*
|
|
Description:
|
|
Copy all settings that control concave corner vertices are created.
|
|
Parameters:
|
|
source_options - [in]
|
|
Returns:
|
|
The currently selected concave corner option.
|
|
*/
|
|
ON_SubDFromMeshParameters::ConcaveCornerOption CopyConcaveCornerTest(
|
|
ON_SubDFromMeshParameters source_parameters
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
false - In ON_SubD::CreateFromMesh(), input mesh vertex locations will be used to set subd vertex control net locations.
|
|
true - In ON_SubD::CreateFromMesh(), input mesh vertex locations will be used to set subd vertex limit surface locations.
|
|
Remark:
|
|
Interpolation computation is available in Rhino, Rhino compute, Rhino Inside,
|
|
Grasshopper. Interpolation computation is not available in the opennurbs IO toolkit.
|
|
*/
|
|
bool InterpolateMeshVertices() const;
|
|
|
|
/*
|
|
Parameters:
|
|
false
|
|
In ON_SubD::CreateFromMesh(), input mesh vertex locations will be used to set subd vertex control net locations.
|
|
This is the fastest and most robust way to create a subd from a mesh.
|
|
true
|
|
In ON_SubD::CreateFromMesh(), input mesh vertex locations will be used to set subd vertex limit surface locations.
|
|
If there are a large number of vertices, this option can require lots of computation.
|
|
Remark:
|
|
Interpolation computation is available in Rhino, Rhino compute, Rhino Inside,
|
|
Grasshopper. Interpolation computation is not available in the opennurbs IO toolkit.
|
|
*/
|
|
void SetInterpolateMeshVertices(
|
|
bool bInterpolateMeshVertices
|
|
);
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Texture coordinates
|
|
//
|
|
#pragma region RH_C_SHARED_ENUM [ON_SubDFromMeshParameters::TextureCoordinatesOption] [Rhino.Geometry.SubDCreationOptions.TextureCoordinateOption] [nested:byte]
|
|
/// <summary>
|
|
/// Specifies how texture coordinate information is transfered from the mesh to the SubD.
|
|
/// </summary>
|
|
enum class TextureCoordinatesOption : unsigned char
|
|
{
|
|
///<summary>The option is not set.</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>No texture coordianate information is transfered from the mesh.</summary>
|
|
None = 1,
|
|
|
|
///<summary>
|
|
/// If the mesh has a mapping, then TextureCoordinatesOption::CopyMapping is used.
|
|
/// Otherwise if the mesh has texture coordinates, then TextureCoordinatesOption::CopyCoordinates is used.
|
|
/// Otherwise TextureCoordinatesOption::Packed is used.
|
|
///</summary>
|
|
Automatic = 2,
|
|
|
|
///<summary>
|
|
/// No texture coordianate information is transfered from the mesh.
|
|
/// The SubD faces are packed.
|
|
///</summary>
|
|
Packed = 3,
|
|
|
|
///<summary>Texture coordinates mapping information is copied from the mesh.
|
|
/// Generally this is the best choice because common mappings, like planar,
|
|
/// will appear as most people expect on the SubD.
|
|
///</summary>
|
|
CopyMapping = 4,
|
|
|
|
///<summary>
|
|
/// If a mesh has custom texture coordinates, the custom texture coordinates
|
|
/// are transfered to the SubD. This requires more memory resources,
|
|
/// slows subdivision evaluation, often produces unattractive
|
|
/// results on n-gons, and distorts the texture when comes from a common mapping
|
|
/// technique, like planar. This option may be useful when the mesh contains only
|
|
/// triangles and quads and the custom texture coordinates are of high quality.
|
|
///</summary>
|
|
CopyCoordinates = 5,
|
|
};
|
|
#pragma endregion
|
|
|
|
|
|
/*
|
|
Description:
|
|
Set the texture coordinates option.
|
|
Parameters:
|
|
texture_coordinates_opton - [in]
|
|
*/
|
|
void SetTextureCoordinatesOption(
|
|
ON_SubDFromMeshParameters::TextureCoordinatesOption texture_coordinates_opton
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
The texture coorindates option.
|
|
*/
|
|
ON_SubDFromMeshParameters::TextureCoordinatesOption GetTextureCoordinatesOption() const;
|
|
|
|
static ON_SubDFromMeshParameters::TextureCoordinatesOption TextureCoordinatesOptionFromUnsigned(
|
|
unsigned int texture_coordinates_opton_as_unsigned
|
|
);
|
|
|
|
|
|
/*
|
|
Returns:
|
|
true - In ON_SubD::CreateFromMesh(), colinear boundary edges belonging to the same face are merged into a single edge.
|
|
false - In ON_SubD::CreateFromMesh(), each mesh boundary edge becomes a SubD boundary edge.
|
|
*/
|
|
bool MergeColinearBoundaryEdges() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bMergeColinearBoundaryEdges - [in]
|
|
true
|
|
In ON_SubD::CreateFromMesh(), colinear boundary edges belonging to the same face are merged into a single edge.
|
|
In general, this is the best choice and leads to the highest quality of SubD object.
|
|
false
|
|
In ON_SubD::CreateFromMesh(), each mesh boundary edge becomes a SubD boundary edge.
|
|
Use this when the boundary topology of the mesh and SubD should be identical.
|
|
*/
|
|
void SetMergeColinearBoundaryEdges(
|
|
bool bMergeColinearBoundaryEdges
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
true - In ON_SubD::CreateFromMesh(), colinear interior edges between two faces are merged into a single edge.
|
|
false - In ON_SubD::CreateFromMesh(), each mesh interior edge becomes a SubD interior edge.
|
|
*/
|
|
bool MergeColinearInteriorEdges() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bMergeColinearInteriorEdges - [in]
|
|
true
|
|
In ON_SubD::CreateFromMesh(), colinear interior edges between two faces are merged into a single edge.
|
|
In general, this is the best choice and leads to the highest quality of SubD object.
|
|
false
|
|
In ON_SubD::CreateFromMesh(), each mesh interior edge becomes a SubD interior edge.
|
|
Use this when the interior topology of the mesh and SubD should be identical.
|
|
*/
|
|
void SetMergeColinearInteriorEdges(
|
|
bool bMergeColinearInteriorEdges
|
|
);
|
|
|
|
|
|
private:
|
|
enum : unsigned char
|
|
{
|
|
MergeColinearBoundaryEdgesMask = 1,
|
|
MergeColinearInteriorEdgesMask = 2
|
|
};
|
|
unsigned char m_merge_edges_bits = 0; // clear bit (0) = "true, set bit (1) = "false"
|
|
|
|
bool m_bInterpolateMeshVertices = false;
|
|
|
|
ON_SubDFromMeshParameters::InteriorCreaseOption m_interior_crease_option = ON_SubDFromMeshParameters::InteriorCreaseOption::None;
|
|
ON_SubDFromMeshParameters::ConvexCornerOption m_convex_corner_option = ON_SubDFromMeshParameters::ConvexCornerOption::None;
|
|
ON_SubDFromMeshParameters::ConcaveCornerOption m_concave_corner_option = ON_SubDFromMeshParameters::ConcaveCornerOption::None;
|
|
ON_SubDFromMeshParameters::TextureCoordinatesOption m_texture_coordinates_option = ON_SubDFromMeshParameters::TextureCoordinatesOption::None;
|
|
|
|
unsigned short m_maximum_convex_corner_edge_count = 2U;
|
|
|
|
unsigned short m_minimum_concave_corner_edge_count = 4U;
|
|
|
|
unsigned short m_reserved2 = 0;
|
|
unsigned int m_reserved3 = 0;
|
|
|
|
double m_reserved4 = 0.0;
|
|
|
|
double m_maximum_convex_corner_angle_radians = 120.0 * ON_DEGREES_TO_RADIANS; // 120 degrees
|
|
double m_minimum_concave_corner_angle_radians = 240.0 * ON_DEGREES_TO_RADIANS; // 240 degrees
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentRef
|
|
//
|
|
// Used when an ON_SubD vertex, edge or face needs to be sent around as
|
|
// a piece of ON_Geometry.
|
|
//
|
|
class ON_CLASS ON_SubDComponentRef : public ON_Geometry
|
|
{
|
|
ON_OBJECT_DECLARE(ON_SubDComponentRef);
|
|
public:
|
|
static const ON_SubDComponentRef Empty;
|
|
|
|
ON_SubDComponentRef() = default;
|
|
~ON_SubDComponentRef() = default;
|
|
ON_SubDComponentRef(const ON_SubDComponentRef&) ON_NOEXCEPT;
|
|
ON_SubDComponentRef& operator=(const ON_SubDComponentRef&);
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_SubDComponentRef( ON_SubDComponentRef&& ) ON_NOEXCEPT;
|
|
|
|
// The rvalue assignment operator calls ON_Object::operator=(ON_Object&&)
|
|
// which could throw exceptions. See the implementation of
|
|
// ON_Object::operator=(ON_Object&&) for details.
|
|
ON_SubDComponentRef& operator=( ON_SubDComponentRef&& );
|
|
#endif
|
|
|
|
/*
|
|
Parameters:
|
|
subd_ref - [in]
|
|
component_index - [in]
|
|
component_location - [in]
|
|
*/
|
|
static const ON_SubDComponentRef Create(
|
|
const ON_SubDRef& subd_ref,
|
|
ON_COMPONENT_INDEX component_index,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
static const ON_SubDComponentRef Create(
|
|
const ON_SubDRef& subd_ref,
|
|
ON_SubDComponentPtr component_ptr,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
static const ON_SubDComponentRef Create(
|
|
const ON_SubDRef& subd_ref,
|
|
const class ON_SubDVertex* vertex,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
static const ON_SubDComponentRef Create(
|
|
const ON_SubDRef& subd_ref,
|
|
const class ON_SubDEdge* edge,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
static const ON_SubDComponentRef Create(
|
|
const ON_SubDRef& subd_ref,
|
|
const class ON_SubDFace* face,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
void Clear();
|
|
|
|
ON_SubDRef SubDRef() const;
|
|
|
|
const class ON_SubD& SubD() const;
|
|
|
|
ON_COMPONENT_INDEX ComponentIndex() const override;
|
|
|
|
ON_SubDComponentPtr ComponentPtr() const;
|
|
|
|
ON_SubDComponentLocation ComponentLocation() const;
|
|
|
|
/*
|
|
Description:
|
|
The interpretation of this value depends on the context.
|
|
When the context is an ON_SubDComponentRef created by
|
|
CRhinoGetObject, ReferenceId() is the parent CRhinoSubDObject's
|
|
runtime serial number.
|
|
*/
|
|
ON__UINT_PTR ReferenceId() const;
|
|
|
|
void SetReferenceId(
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
const class ON_SubDVertex* Vertex() const;
|
|
|
|
const class ON_SubDEdge* Edge() const;
|
|
|
|
const class ON_SubDFace* Face() const;
|
|
|
|
static int Compare(const ON_SubDComponentRef* lhs, const ON_SubDComponentRef* rhs);
|
|
static int Compare2(const ON_SubDComponentRef* const* lhs, const ON_SubDComponentRef* const* rhs);
|
|
|
|
private:
|
|
ON_SubDRef m_subd_ref;
|
|
ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
|
|
ON_COMPONENT_INDEX m_component_index = ON_COMPONENT_INDEX::UnsetComponentIndex;
|
|
ON_SubDComponentLocation m_component_location = ON_SubDComponentLocation::Unset;
|
|
ON__UINT_PTR m_reference_id = 0;
|
|
|
|
public:
|
|
// overrides of virtual ON_Object functions
|
|
bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
|
|
void Dump( ON_TextLog& ) const override;
|
|
unsigned int SizeOf() const override;
|
|
ON::object_type ObjectType() const override;
|
|
|
|
// overrides of virtual ON_Geometry functions
|
|
int Dimension() const override;
|
|
|
|
// virtual ON_Geometry GetBBox override
|
|
bool GetBBox( double* boxmin, double* boxmax, bool bGrowBox = false ) const override;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDComponentRefList
|
|
{
|
|
public:
|
|
ON_SubDComponentRefList() = default;
|
|
~ON_SubDComponentRefList();
|
|
ON_SubDComponentRefList(const ON_SubDComponentRefList& src);
|
|
ON_SubDComponentRefList& operator=(const ON_SubDComponentRefList& src);
|
|
|
|
/*
|
|
Description:
|
|
Append a ON_SubDComponentRef to the identified component.
|
|
Returns;
|
|
A pointer to the ON_SubDComponentRef managed by this class or
|
|
nullptr if the input is not valid.
|
|
*/
|
|
const ON_SubDComponentRef& Append(
|
|
const ON_SubDRef& subd_ref,
|
|
ON_COMPONENT_INDEX ci,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
const ON_SubDComponentRef& Append(
|
|
const ON_SubDRef& subd_ref,
|
|
ON_SubDComponentPtr component_ptr,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Appends a copy of src_ref and returns a pointer to the ON_SubDComponentRef
|
|
managed by this class.
|
|
*/
|
|
const ON_SubDComponentRef& Append(const ON_SubDComponentRef& src_ref);
|
|
const ON_SubDComponentRef& Append(const ON_SubDComponentRef* src_ref);
|
|
|
|
/*
|
|
Description:
|
|
Expert user function to transfer managment of an ON_SubDComponentRef on the heap
|
|
to this class.
|
|
*/
|
|
const ON_SubDComponentRef& AppendForExperts(ON_SubDComponentRef*& ref);
|
|
|
|
/*
|
|
Description:
|
|
Expert user function to append a ON_SubDComponentRef to the identified component.
|
|
The expert user is responsible for insuring subd exists fot the lifetime of this
|
|
class.
|
|
*/
|
|
const ON_SubDComponentRef& AppendForExperts(
|
|
const ON_SubD& subd,
|
|
ON_COMPONENT_INDEX ci,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
const ON_SubDComponentRef& AppendForExperts(
|
|
const ON_SubD& subd,
|
|
ON_SubDComponentPtr component_ptr,
|
|
ON_SubDComponentLocation component_location,
|
|
ON__UINT_PTR reference_id
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Sort by ON_SubDComponentRef::Compare2() and remove duplicates and empty elements.
|
|
Returns:
|
|
Length of clean list.
|
|
*/
|
|
int Clean();
|
|
|
|
|
|
/*
|
|
Returns:
|
|
Number of refs in the list.
|
|
*/
|
|
int Count() const;
|
|
|
|
void Remove(int i);
|
|
|
|
/*
|
|
Description:
|
|
Transfers the ref to an expert user who is responsible for properly managing it.
|
|
*/
|
|
ON_SubDComponentRef* TransferForExperts(int i);
|
|
|
|
const ON_SubDComponentRef& operator[](int) const;
|
|
|
|
/*
|
|
Returns:
|
|
If the list is clean, the number of subd objects in the list. Mutiple components can belong to the same SubD.
|
|
If the list is not clean, 0.
|
|
Remarks:
|
|
Use Clean() to get a clean list.
|
|
*/
|
|
int SubDCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of vertices.
|
|
*/
|
|
int VertexCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of vertices with the specified tag.
|
|
*/
|
|
int VertexCount(ON_SubDVertexTag vertex_tag) const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of edges.
|
|
*/
|
|
int EdgeCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of edges with the specified tag.
|
|
*/
|
|
int EdgeCount(ON_SubDEdgeTag edge_tag) const;
|
|
|
|
|
|
/*
|
|
Returns:
|
|
Number of faces.
|
|
*/
|
|
int FaceCount() const;
|
|
|
|
/*
|
|
Returns:
|
|
Number of components.
|
|
*/
|
|
int ComponentCount() const;
|
|
|
|
private:
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4251 )
|
|
// C4251: ... needs to have dll-interface to be used by clients of class ...
|
|
// m_subdimple_sp is private and all code that manages m_subdimple_sp is explicitly implemented in the DLL.
|
|
ON_SimpleArray< class ON_SubDComponentRef* > m_list;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
|
|
int m_subd_count = 0;
|
|
int m_subd_vertex_smooth_count = 0;
|
|
int m_subd_vertex_dart_count = 0;
|
|
int m_subd_vertex_crease_count = 0;
|
|
int m_subd_vertex_corner_count = 0;
|
|
int m_subd_edge_smooth_count = 0;
|
|
int m_subd_edge_crease_count = 0;
|
|
int m_subd_face_count = 0;
|
|
|
|
bool m_bIsClean = false; // true if m_list is clean.
|
|
|
|
unsigned char m_reserved1 = 0;
|
|
unsigned short m_reserved2 = 0;
|
|
unsigned int m_reserved3 = 0;
|
|
ON__UINT_PTR m_reserved4 = 0;
|
|
|
|
private:
|
|
bool Internal_UpdateCount(const ON_SubDComponentRef& r, int delta);
|
|
void Internal_Destroy();
|
|
void Internal_CopyFrom(const ON_SubDComponentRefList& src);
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDComponentPoint
|
|
//
|
|
// Used in selection tests to return a point and parameters on a component.
|
|
//
|
|
class ON_CLASS ON_SubDComponentPoint
|
|
{
|
|
public:
|
|
static const ON_SubDComponentPoint Unset;
|
|
|
|
ON_SubDComponentPoint() = default;
|
|
~ON_SubDComponentPoint() = default;
|
|
ON_SubDComponentPoint(const ON_SubDComponentPoint&) = default;
|
|
ON_SubDComponentPoint& operator=(const ON_SubDComponentPoint&) = default;
|
|
|
|
/*
|
|
Description:
|
|
Dictionary compare of component type, component pointer, and component direction (partial).
|
|
This function is useful for sorting arrays of ON_SubDComponentPoint values remove duplicates.
|
|
*/
|
|
static int CompareComponentAndDirection(
|
|
const ON_SubDComponentPoint* a,
|
|
const ON_SubDComponentPoint* b
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Compare the pick events to determine the component the user was most likely aiming at.
|
|
|
|
Parameters:
|
|
pick_type - [in]
|
|
When pick_type is ON_PickType::PointPick, several biases may be applied to favor vertices and edges.
|
|
|
|
vertex_depth_bias - [in]
|
|
When in doubt pass 0.0.
|
|
A positive value increases vertex bias in some situations; otherwise vertex_depth_bias is ignored.
|
|
When pick_type is ON_PickType::PointPick and either
|
|
an edge and a vertex of that edge or a face and a vertex of that face are being compared,
|
|
then then vertex_depth_bias is added to the vertex hit depth before comparing depths.
|
|
When the pick is happening in a perspective view, it is important to choose a vertex_depth_bias
|
|
appropriate for the depth in the view frustum.
|
|
|
|
edge_depth_bias - [in]
|
|
When in doubt pass 0.0.
|
|
A positive value increases edge bias in some situations; otherwise vertex_depth_bias is ignored.
|
|
When pick_type is ON_PickType::PointPick and a face and an edge of that face are being compared,
|
|
then then edge_depth_bias is added to the edge hit depth before comparing depths.
|
|
When the pick is happening in a perspective view, it is important to choose an edge_depth_bias
|
|
appropriate for the depth in the view frustum.
|
|
|
|
A - [in]
|
|
B - [in]
|
|
Returns:
|
|
A pick point for the component the user was most likely aiming at
|
|
with distance and depth settings that will lead to conistent improvment
|
|
if more than two points are being compared.
|
|
*/
|
|
static const ON_SubDComponentPoint BestPickPoint(
|
|
ON_PickType pick_type,
|
|
double vertex_depth_bias,
|
|
double edge_depth_bias,
|
|
const ON_SubDComponentPoint& A,
|
|
const ON_SubDComponentPoint& B
|
|
);
|
|
|
|
// m_component_ptr will be face, edge or vertex
|
|
ON_SubDComponentPtr m_component_ptr = ON_SubDComponentPtr::Null;
|
|
|
|
//// If the point is on a a face that does not have the ordinary number of
|
|
//// edges for the subdivision type, then m_face_corner_index identifies the
|
|
//// subfragment corner.
|
|
//unsigned int m_face_corner_index = ON_UNSET_UINT_INDEX;
|
|
|
|
//// If m_level_index is ON_UNSET_UINT_INDEX, the point is on the limit surface.
|
|
//// Otherwise the point is on the control net at the specified level.
|
|
//unsigned int m_level_index = ON_UNSET_UINT_INDEX;
|
|
|
|
ON_PickPoint m_pick_point = ON_PickPoint::Unset;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubDMatrix
|
|
//
|
|
class ON_CLASS ON_SubDMatrix
|
|
{
|
|
public:
|
|
ON_SubDMatrix() = default;
|
|
|
|
static const ON_SubDMatrix Empty;
|
|
|
|
/*
|
|
Description:
|
|
Precise evaluation of cos(a) and cos(a) where a = i/n pi.
|
|
These values are required for high qualitiy limit surface evaluation.
|
|
Parameters:
|
|
j - [in]
|
|
n - [in]
|
|
cos_theta - [out]
|
|
cos(j/n pi)
|
|
sin_theta - [out]
|
|
sin(j/n pi)
|
|
*/
|
|
static bool EvaluateCosAndSin(
|
|
unsigned int j,
|
|
unsigned int n,
|
|
double* cos_theta,
|
|
double* sin_theta
|
|
);
|
|
|
|
bool IsValid() const;
|
|
|
|
bool IsValidPointRing(
|
|
const double* point_ring,
|
|
size_t point_ring_count,
|
|
size_t point_ring_stride
|
|
) const;
|
|
|
|
bool EvaluateSubdivisionPoint(
|
|
unsigned int component_index,
|
|
const double* point_ring,
|
|
size_t point_ring_count,
|
|
size_t point_ring_stride,
|
|
double subd_point[3]
|
|
) const;
|
|
|
|
bool EvaluateSurfacePoint(
|
|
const double* point_ring,
|
|
size_t point_ring_count,
|
|
size_t point_ring_stride,
|
|
bool bUndefinedNormalIsPossible,
|
|
double limit_point[3],
|
|
double limit_tangent1[3],
|
|
double limit_tangent2[3],
|
|
double limit_normal[3]
|
|
) const;
|
|
|
|
bool EvaluateSurfacePoint(
|
|
const double* point_ring,
|
|
size_t point_ring_count,
|
|
size_t point_ring_stride,
|
|
bool bUndefinedNormalIsPossible,
|
|
class ON_SubDSectorSurfacePoint& limit_point
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Get the subdivision matrix information for the case specified
|
|
by the input parameters. This information is retrieved from
|
|
a cache. In some cases, it will be calculated the first time
|
|
it is needed.
|
|
Parameters:
|
|
facet_type - [in]
|
|
vertex_tag - [in]
|
|
valence - [in]
|
|
The input parameters identify the subdivision case.
|
|
Remarks:
|
|
Every member function of ON_SubDMatrix, including this one
|
|
is thread safe.
|
|
*/
|
|
static const ON_SubDMatrix& FromCache(
|
|
ON_SubDSectorType sector_type
|
|
);
|
|
|
|
ON_SubDSectorType m_sector_type;
|
|
|
|
unsigned int m_R = 0; // the matrix m_S is m_R x m_R (m_R = m_sector_type.PointRingCount())
|
|
|
|
// The term "standard vertex ring points" is used below.
|
|
//
|
|
// If "C" is an interior vertex (m_vertex_tag is smooth or dart),
|
|
// (E[0], ...., E[N-1]) is a radially sorted list of its edges,
|
|
// (F[0], ..., F[N-1]) is a radially sorted list of its faces,
|
|
// and (P[0], ..., P[N-1]) is a list of the edge vertices opposite C,
|
|
// E0type = smooth for a smooth vertex and crease for a dart vertex,
|
|
// then C is "standard" if E[0] has type E0type, every other
|
|
// edge E[i] is smooth, every outer vertex/ P[i] is smooth, and every
|
|
// face F[i] has the stadard facet type (tri or quad) for the subdivision
|
|
// algorithm.
|
|
//
|
|
// If If "C" is a boundary vertex (m_vertex_tag is crease or corner), the conditions
|
|
// listed above are satisified except
|
|
// E[0] and E[N-1] are tagged as crease edges,
|
|
// P[0] and P[N-1] are tagged as crease vertices (NOT corners),
|
|
// and there are N-2 faces,
|
|
// then "C" is a standard boundary vertex.
|
|
//
|
|
// If the facet type is triangle and C is a standard interior or boundary vertex,
|
|
// then the "standard vertex ring" is the list of N+1 points
|
|
// (C, P[0], ...., P[N-1]).
|
|
//
|
|
// If the facet type is quad, and C is a standard interior vertex,
|
|
// then the "standard vertex ring" is the list of 2*N+1 points
|
|
// (C, P[0], Q[0], ...., P[N-1], Q[N-1]), where Q[I] is the vertex of quad F[i] diagonally across from C.
|
|
//
|
|
// If the facet type is quad, and C is a standard boundary vertex,
|
|
// then the "standard vertex ring" is the list of 2*N points
|
|
// (C, P[0], Q[0], ...., P[N-1]).
|
|
|
|
// m_S = R x R subdivision matrix
|
|
// If (vertexR[0], ..., vertexR[R-1]) is a list of standard vertex ring points,
|
|
// then then the location of the subdivided ring points
|
|
// (vertexR1[0], ..., vertexR1[R-1]) can be calculated from m_S.
|
|
// vertexR1[i] = m_S[i][0]*vertexR[0] + ... + m_S[i][R-1]*vertexR[R-1]
|
|
const double* const* m_S = nullptr;
|
|
|
|
// m_LP[] = limit point evaluation vector.
|
|
// The array m_LP[] has m_R elements.
|
|
// If (vertexR[0], ..., vertexR[R-1]) is a list of standard vertex ring points,
|
|
// then Limit point = m_LP[0]*vertexR[0] + ... + m_LP[R-1]*vertexR[R-1].
|
|
// m_LP is the eigenvector of Transpose(m_S) with eigenvalue = 1.
|
|
// Length(m_LP) = 1.
|
|
const double* m_LP = nullptr;
|
|
|
|
// m_L1 and m_L2 = tangent space evaluation vectors.
|
|
// The arrays m_L1[] and m_L2[] have m_R elements.
|
|
// If (vertexR[0], ..., vertexR[R-1]) is a list of standard vertex ring points,
|
|
// then the two vectors
|
|
// V1 = m_L1[0]*vertexR[0] + ... + m_L1[R-1]*vertexR[R-1].
|
|
// V2 = m_L2[0]*vertexR[0] + ... + m_L2[R-1]*vertexR[R-1].
|
|
// span the tangent plane and
|
|
// N = V1 x V2 is perpindicular to the limit tangent plane.
|
|
// In general and almost always in practice, V1 and V2 are not unit vectors
|
|
// and it is best to noramalize V1 and V2 before taking the cross product.
|
|
// m_L1 and m_L2 are subdominant eigenvectors of Transpose(m_S).
|
|
// When the subdominant eigenvalue has geometric multiplicity 2,
|
|
// m_L1 and m_L2 span the same space as m_E1 and m_E2.
|
|
// The values stored in m_L1 and m_L2 are chosen to provide accurate
|
|
// evaluation. In come common cases m_L1 and m_L2 are equal to m_E1 and m_E2,
|
|
// but not in all cases.
|
|
const double* m_L1 = nullptr;
|
|
const double* m_L2 = nullptr;
|
|
|
|
/*
|
|
Description:
|
|
Set the values in this ON_SubDMatrix so the information
|
|
can be used to evaluate the case identified by the input
|
|
parameters.
|
|
Parameters:
|
|
facet_type - [in]
|
|
vertex_tag - [in]
|
|
sector_edge_count - [in]
|
|
The input parameters identify the subdivision case.
|
|
Returns:
|
|
R > 0: Success. The matrix is R x R.
|
|
0: Failure.
|
|
*/
|
|
unsigned int SetFromSectorType(
|
|
ON_SubDSectorType sector_type
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
ON_UNSET_VALUE - serious error
|
|
>= 0:
|
|
Maximum value of numbers that should be zero in and ideal world.
|
|
When the matrices, eigenvalues and eigenvectors are correctly calculated,
|
|
this returned value is in the range from 1e-16 to 5e-13 as valence goes
|
|
from 3 to 100.
|
|
For valences < 100, if a value larger than 1.0e-12 occurs, there is a bug in the code.
|
|
*/
|
|
double TestMatrix() const;
|
|
|
|
/*
|
|
Description:
|
|
Run evaluation tests on this subdivision case.
|
|
Returns:
|
|
>= 0.0: Test passed. Maximum deviation found in any test is returned.
|
|
ON_UNSET_VALUE: Test failed.
|
|
*/
|
|
double TestEvaluation() const;
|
|
|
|
/*
|
|
Description:
|
|
Run evaluation tests on a range of subdivision cases.
|
|
Parameters:
|
|
sector_type - [in]
|
|
If ON_SubDSectorType::Empty, then all supported sector types types are tested.
|
|
minimum_sector_face_count - [in]
|
|
If 0, then testing begins at ON_SubDSectorType::MinimumSectorFaceCount(vertex_tag)
|
|
when testing vertex_tag types
|
|
maximum_sector_face_count - [in]
|
|
If 0, then testing stops at ON_SubD::maximum_evaluation_valence.
|
|
text_log - [out]
|
|
If not nullptr, then a brief written report is printed for each test case.
|
|
Returns:
|
|
>= 0.0: Test passed. Maximum deviation found in any test is returned.
|
|
ON_UNSET_VALUE: Test failed.
|
|
*/
|
|
static double TestEvaluation(
|
|
ON_SubDSectorType sector_type,
|
|
unsigned int minimum_sector_face_count,
|
|
unsigned int maximum_sector_face_count,
|
|
ON_TextLog* text_log
|
|
);
|
|
|
|
double TestComponentRing(
|
|
const ON_SubDComponentPtr* component_ring,
|
|
size_t component_ring_count
|
|
) const;
|
|
|
|
/*
|
|
Description:
|
|
Test cached subdivision matrix on sector identified by sit.
|
|
Parameters:
|
|
subd_type - [in]
|
|
subd_recursion_count - [in]
|
|
number of times to subdivide
|
|
sit - [in]
|
|
vertex to subdivide
|
|
component_ring - [out]
|
|
subd_points - [out]
|
|
limit_point - [out]
|
|
limit_tangent0 - [out]
|
|
limit_tangent1 - [out]
|
|
limit_normal - [out]
|
|
*/
|
|
static double TestEvaluation(
|
|
const unsigned int subd_recursion_count,
|
|
ON_SubDSectorIterator sit,
|
|
ON_SimpleArray<ON_SubDComponentPtr>& component_ring,
|
|
ON_SimpleArray< ON_3dPoint >& subd_points,
|
|
class ON_SubDSectorSurfacePoint& limit_point
|
|
);
|
|
|
|
private:
|
|
unsigned int m__max_R = 0;
|
|
ON_Matrix m__S; // m_S matrix memory
|
|
ON_SimpleArray<double> m__buffer; // m_LP, m_L1, m_L2, m_E1, m_E2 memory
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ON_SubD_FixedSizeHeap
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
A ON_SubD_FixedSizeHeap is used to manage heap used for a local subdivision.
|
|
*/
|
|
class ON_CLASS ON_SubD_FixedSizeHeap
|
|
{
|
|
private:
|
|
static unsigned int m__sn_factory;
|
|
|
|
public:
|
|
// The serial number is used for debugging purposes.
|
|
const unsigned int m_sn = ++m__sn_factory;
|
|
|
|
public:
|
|
ON_SubD_FixedSizeHeap() = default;
|
|
~ON_SubD_FixedSizeHeap();
|
|
|
|
/*
|
|
Description:
|
|
Reserve enough room to for a subdivision of a vertex sector.
|
|
Parameters:
|
|
sector_edge_count - [in]
|
|
Number of edges in the sector.
|
|
*/
|
|
bool ReserveSubDWorkspace(
|
|
unsigned int sector_edge_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Reserve enough room for a local subdivide the neighborhood of center_face.
|
|
Parameters:
|
|
center_face0 - [in]
|
|
*/
|
|
bool ReserveSubDWorkspace(
|
|
const ON_SubDFace* center_face0
|
|
);
|
|
|
|
private:
|
|
bool Internal_ReserveSubDWorkspace(
|
|
size_t vertex_capacity,
|
|
size_t face_capacity,
|
|
size_t array_capacity,
|
|
bool bEnableHashTable
|
|
);
|
|
|
|
bool Internal_ReserveSubDWorkspace_HashTable();
|
|
|
|
public:
|
|
|
|
/*
|
|
Description:
|
|
Reset this ON_SubD_FixedSizeHeap so it can be used again.
|
|
*/
|
|
void Reset();
|
|
|
|
/*
|
|
Description:
|
|
Deallocate all reserved heap.
|
|
*/
|
|
void Destroy();
|
|
|
|
bool InUse() const;
|
|
|
|
ON_SubDVertex* AllocateVertex(
|
|
const double vertexP[3],
|
|
unsigned int edge_capacity
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Allocate a vertex located at the vertex0 subdivision point.
|
|
|
|
Parameters:
|
|
vertex0 - [in]
|
|
edge_capacity - [in]
|
|
If the returned vertex will be interior in a local subdivision,
|
|
then pass vertex0->EdgeCount().
|
|
If the returned vertex will be an outer ring vertex in a local subdivision,
|
|
then pass 3.
|
|
*/
|
|
ON_SubDVertex* AllocateVertex(
|
|
const ON_SubDVertex* vertex0,
|
|
unsigned int edge_capacity
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Allocate a vertex located at the edge0 subdivision point.
|
|
The vertex will have an edge and face capacity of 4.
|
|
Parameters:
|
|
edge0 - [in]
|
|
*/
|
|
ON_SubDVertex* AllocateVertex(
|
|
const ON_SubDEdge* edge0
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Find or allocate a vertex located at the edge0 subdivision point.
|
|
The vertex will have an edge and face capacity of 4.
|
|
Parameters:
|
|
edge0 - [in]
|
|
Remarks:
|
|
In order for FindOrAllocateVertex() to find a vertex, that vertex must
|
|
have been created by an earlier call to FindOrAllocateVertex().
|
|
Typically, AllocateVertex(edge0) is used for center face boundary edges
|
|
and FindOrAllocateVertex(edge0) is used for ring edges.
|
|
*/
|
|
ON_SubDVertex* FindOrAllocateVertex(
|
|
const ON_SubDEdge* edge0
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Allocate a vertex located at the edge0 subdivision point.
|
|
The vertex will have an edge and face capacity of 4.
|
|
Parameters:
|
|
edge0 - [in]
|
|
*/
|
|
ON_SubDVertex* AllocateEdgeSubdivisionVertex(
|
|
bool bUseFindOrAllocate,
|
|
const ON_SubDEdge * edge0
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Find or allocate a vertex and the face subdivision point. The vertex will have an
|
|
edge and face capacity of face0->EdgeCount().
|
|
Parameters:
|
|
face0 - [in]
|
|
outer face in a local subdivision situation
|
|
Remarks:
|
|
In order for FindOrAllocateVertex() to find a vertex, that vertex must
|
|
have been created by an earlier call to FindOrAllocateVertex().
|
|
Typically, AllocateVertex(edge0) is used for the center face and
|
|
and FindOrAllocateVertex(edge0) is used for ring faces.
|
|
*/
|
|
ON_SubDVertex* FindOrAllocateVertex(
|
|
const ON_SubDFace* face0
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Allocate a vertex located at the sector_face0 subdivision point.
|
|
The vertex will have an edge and face capacity of 3.
|
|
Parameters:
|
|
sector_face0 - [in]
|
|
A face in a vertex sector.
|
|
*/
|
|
ON_SubDVertex* AllocateSectorFaceVertex(
|
|
const ON_SubDFace* sector_face0
|
|
);
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
v0 - [in]
|
|
v0_sector_weight - [in]
|
|
If v0 null or ON_SubDVertexTag::Smooth == v0->m_vertex_tag, and v1 is null or tagged,
|
|
then m_sector_weight[0] is set to v0_sector_weight.
|
|
In all other cases the value of v0_sector_weight is ignored and m_sector_weight[0]
|
|
is set to ON_SubDSectorType::IgnoredSectorCoefficient.
|
|
v1 - [in]
|
|
v1_sector_weight - [in]
|
|
If v1 null or ON_SubDVertexTag::Smooth == v1->m_vertex_tag, and v0 is null or tagged,
|
|
then m_sector_weight[1] is set to v1_sector_weight.
|
|
In all other cases the value of v1_sector_weight is ignored and m_sector_weight[1]
|
|
is set to ON_SubDSectorType::IgnoredSectorCoefficient.
|
|
Returns:
|
|
An edge.
|
|
The vertex parameter information is used to set the ON_SubDEdge.m_vertex[]
|
|
and ON_SubDEdge.m_sector_weight[] values.
|
|
If v0 and v1 are not null and both are tagged, then ON_SubDEdge.m_edge_tag is
|
|
set to ON_SubDEdgeTag::Crease.
|
|
In all other cases, ON_SubDEdge.m_edge_tag is set to ON_SubDEdgeTag::Smooth.
|
|
If v0 or v1 is not null, then ON_SubDEdge.m_level is set to the
|
|
maximum of v0->m_level or v1->m_level.
|
|
*/
|
|
const ON_SubDEdgePtr AllocateEdge(
|
|
ON_SubDVertex* v0,
|
|
double v0_sector_weight,
|
|
ON_SubDVertex* v1,
|
|
double v1_sector_weight
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
NOTE WELL:
|
|
In order for FindOrAllocateEdge() to find an edge, that edge must have been created
|
|
by an earlier call to FindOrAllocateEdge().
|
|
*/
|
|
const ON_SubDEdgePtr FindOrAllocateEdge(
|
|
ON_SubDVertex* v0,
|
|
double v0_sector_weight,
|
|
ON_SubDVertex* v1,
|
|
double v1_sector_weight
|
|
);
|
|
|
|
const ON_SubDEdgePtr AllocateEdge(
|
|
bool bUseFindOrAllocatEdge,
|
|
ON_SubDVertex* v0,
|
|
double v0_sector_weight,
|
|
ON_SubDVertex* v1,
|
|
double v1_sector_weight
|
|
);
|
|
|
|
|
|
|
|
private:
|
|
/*
|
|
Returns:
|
|
A face with all field values zero (same values as ON_SubDEdge::Face), except ON_SubDFace.m_id.
|
|
*/
|
|
ON_SubDFace* Internal_AllocateFace(
|
|
unsigned int zero_face_id,
|
|
unsigned int parent_face_id
|
|
);
|
|
public:
|
|
|
|
ON_SubDFace* AllocateQuad(
|
|
unsigned int zero_face_id,
|
|
unsigned int parent_face_id,
|
|
const ON_SubDEdgePtr eptrs[4]
|
|
);
|
|
|
|
ON_SubDFace* AllocateQuad(
|
|
unsigned int zero_face_id,
|
|
unsigned int parent_face_id,
|
|
ON_SubDEdgePtr e0,
|
|
ON_SubDEdgePtr e1,
|
|
ON_SubDEdgePtr e2,
|
|
ON_SubDEdgePtr e3
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
capacity - [in]
|
|
desired array size
|
|
bZeroMemory - [in]
|
|
If true, all array element values are zero.
|
|
If false, array element values are undefined.
|
|
Returns:
|
|
An array of capacity ON__UINT_PTR pointers.
|
|
*/
|
|
ON__UINT_PTR* AllocatePtrArray(
|
|
unsigned int capacity,
|
|
bool bZeroMemory
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Return the most recent array obtained from AllocatePtrArray().
|
|
so it can be reused.
|
|
Returns:
|
|
True:
|
|
Success.
|
|
False:
|
|
Failure. The array was not the most recent array obtained
|
|
from AllocatePtrArray().
|
|
*/
|
|
bool ReturnPtrArray(
|
|
void* p,
|
|
unsigned int capacity
|
|
);
|
|
|
|
private:
|
|
ON_SubDVertex* m_v = nullptr;
|
|
unsigned int m_v_capacity = 0;
|
|
unsigned int m_v_index = 0;
|
|
|
|
ON_SubDEdge* m_e = nullptr;
|
|
unsigned int m_e_capacity = 0;
|
|
unsigned int m_e_index = 0;
|
|
|
|
ON_SubDFace* m_f = nullptr;
|
|
unsigned int m_f_capacity = 0;
|
|
unsigned int m_f_index = 0;
|
|
|
|
ON__UINT_PTR* m_p = nullptr;
|
|
unsigned int m_p_capacity = 0;
|
|
unsigned int m_p_index = 0;
|
|
|
|
private:
|
|
// Used to find level 1 subdivision vertex from level 0 component
|
|
class ON_SubD_FixedSizeHeap_ComponentPairHashElement** m_hash_table = nullptr;
|
|
class ON_SubD_FixedSizeHeap_ComponentPairHashElement* m_hash_elements = nullptr;
|
|
unsigned int m_h_capacity = 0; // m_hash_table[] capacity.
|
|
unsigned int m_h_count = 0; // 0xFFFFFFFFU means hash is disabled
|
|
enum : unsigned int
|
|
{
|
|
DisabledHashCount = 0xFFFFFFFFU
|
|
};
|
|
|
|
bool Internal_HashEnabled() const;
|
|
unsigned int Internal_Hash(ON_SubDComponentPtr component0);
|
|
class ON_SubDVertex* Internal_HashFindVertex1(unsigned int hash, ON_SubDComponentPtr component0);
|
|
void Internal_HashAddPair(unsigned int hash, ON_SubDComponentPtr component0, class ON_SubDVertex* vertex1);
|
|
|
|
private:
|
|
// copies not supported
|
|
ON_SubD_FixedSizeHeap(const ON_SubD_FixedSizeHeap&) = delete;
|
|
ON_SubD_FixedSizeHeap& operator=(const ON_SubD_FixedSizeHeap&) = delete;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDEdgeChain
|
|
{
|
|
public:
|
|
ON_SubDEdgeChain() = default;
|
|
~ON_SubDEdgeChain() = default;
|
|
ON_SubDEdgeChain(const ON_SubDEdgeChain&) = default;
|
|
ON_SubDEdgeChain& operator=(const ON_SubDEdgeChain&) = default;
|
|
|
|
public:
|
|
static const ON_SubDEdgeChain Empty;
|
|
|
|
public:
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Edge chain tools
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
Unconditionally sort edges into chains.
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
no edge chain will pass through that vertex.
|
|
To sort an array in place, pass the same array as both parameters.
|
|
|
|
sorted_edges - [out]
|
|
The sorted_edges[] has the edges grouped into edge chains.
|
|
A value of ON_SubDEdgePtr::Null is at the end of every chain
|
|
including the last chain.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
sorted_edges[i].RelativeVertex(1) == sorted_edges[i+1].RelativeVertex(0).
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
Remarks:
|
|
This version of SortEdgesIntoEdgeChains() uses MarkBits() on the edges
|
|
and vertices in unsorted_edges[]. The output values of MarkBits()
|
|
on these components are zero.
|
|
Multiple threads may not simultaneously use any SubD tools on that rely
|
|
on markbits on the same ON_SubD.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< ON_SubDEdgePtr >& unsorted_edges,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& sorted_edges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Unconditionally sort edges into chains.
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
no edge chain will pass through that vertex.
|
|
|
|
sorted_edges - [out]
|
|
The sorted_edges[] has the edges grouped into edge chains.
|
|
A value of ON_SubDEdgePtr::Null is at the end of every chain
|
|
including the last chain.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
sorted_edges[i].RelativeVertex(1) == sorted_edges[i+1].RelativeVertex(0).
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
Remarks:
|
|
This version of SortEdgesIntoEdgeChains() uses MarkBits() on the edges
|
|
and vertices in unsorted_edges[]. The output values of MarkBits()
|
|
on these components are zero.
|
|
Multiple threads may not simultaneously use any SubD tools on that rely
|
|
on markbits on the same ON_SubD.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< const ON_SubDEdge* >& unsorted_edges,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& sorted_edges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Unconditionally sort edges into chains.
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
no edge chain will pass through that vertex.
|
|
|
|
sorted_edges - [out]
|
|
The sorted_edges[] has the edges grouped into edge chains.
|
|
A value of ON_SubDEdgePtr::Null is at the end of every chain
|
|
including the last chain.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
sorted_edges[i].RelativeVertex(1) == sorted_edges[i+1].RelativeVertex(0).
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
Remarks:
|
|
This version of SortEdgesIntoEdgeChains() uses MarkBits() on the edges
|
|
and vertices in unsorted_edges[]. The output value of MarkBits()
|
|
on these components is zero.
|
|
Multiple threads may not simultaneously use any SubD tools on that rely
|
|
on markbits on the same ON_SubD.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< ON_SubDComponentPtr >& unsorted_edges,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& sorted_edges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Unconditionally sort edges into chains.
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
no edge chain will pass through that vertex.
|
|
|
|
sorted_edges - [out]
|
|
The sorted_edges[] has the edges grouped into edge chains.
|
|
A value of ON_SubDEdgePtr::Null is at the end of every chain
|
|
including the last chain.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
sorted_edges[i].RelativeVertex(1) == sorted_edges[i+1].RelativeVertex(0).
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
Remarks:
|
|
This version of SortEdgesIntoEdgeChains() uses MarkBits() on the edges
|
|
and vertices in unsorted_edges[]. The output value of MarkBits()
|
|
on these components is zero.
|
|
Multiple threads may not simultaneously use any SubD tools on that rely
|
|
on markbits on the same ON_SubD.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SubD& subd,
|
|
const ON_SimpleArray< ON_COMPONENT_INDEX >& unsorted_edges,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& sorted_edges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Determin if the array of ON_SubDEdgePtrs in edges[] can be sorted
|
|
into a single edge chain.
|
|
Parameters:
|
|
edges - [in]
|
|
Set of edges to test.
|
|
bIsClosed - [out]
|
|
If true is returned and edges[] sorts into a closed edge chain,
|
|
then bIsClosed is true. Otherwise bIsClosed is false.
|
|
bIsSorted - [out]
|
|
If true is returned and edges[] is currently sorted into an edge chain,
|
|
then bIsSorted is true. Otherwise bIsSorted is false.
|
|
Returns:
|
|
If the array of edges[] can be sorted into a single edge chain
|
|
with no self intersections, then true is returned. Otherwise false
|
|
is returned.
|
|
Remarks:
|
|
This test usesthe MarkBits() values on the edges and vertices and
|
|
restores the values to the input state.
|
|
Multiple threads may not simultaneously use any SubD tools on that rely
|
|
on markbits on the same ON_SubD.
|
|
*/
|
|
static bool IsSingleEdgeChain(
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& edges,
|
|
bool& bIsClosed,
|
|
bool& bIsSorted
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Determin if the array of ON_SubDEdgePtrs in edges[] can be sorted
|
|
into a single edge chain.
|
|
Parameters:
|
|
edges - [in]
|
|
Set of edges to test.
|
|
Returns:
|
|
If the array of edges[] can be sorted into a single edge chain
|
|
with no self intersections, then true is returned. Otherwise false
|
|
is returned.
|
|
Remarks:
|
|
This test usesthe MarkBits() values on the edges and vertices and
|
|
restores the values to the input state.
|
|
Multiple threads may not simultaneously use any SubD tools on that rely
|
|
on markbits on the same ON_SubD.
|
|
*/
|
|
static bool IsSingleEdgeChain(
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& edges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Sort edges into a chains
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
To sort an array in place, pass the same array as both parameters.
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
then all of the edges that share that vertex are ignored.
|
|
The edges can be from one or more SubDs.
|
|
|
|
unsigned int minimum_chain_length - [in]
|
|
minimum number of edges to consider for a chain.
|
|
|
|
edge_chains - [out]
|
|
The edge_chains[] has the edges grouped into edge chains.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
edge_chains[i].RelativeVertex(1) == edge_chains[i+1].RelativeVertex(0).
|
|
|
|
When edge_chains[i].RelativeVertex(1) != edge_chains[i+1].RelativeVertex(0),
|
|
a chain ends at edge_chains[i] and another begins at edge_chains[i+1].
|
|
|
|
Reasonnable effort is made to keep the first edge in every chain with the
|
|
same orientation as the input edge from edge_chains[]. However, this is not
|
|
possible in every case, for example if the input is two edges sharing the
|
|
same starting vertex.
|
|
|
|
NB: Reasonnable effort is made to keep the corner vertices on the exterior
|
|
of the chains, however some chains will have corners in their interior,
|
|
especially closed chains.
|
|
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
|
|
Remarks:
|
|
When the orientation of the input edges is not intentionally set,
|
|
the versions of SortEdgesIntoEdgeChains() above without a minimum_chain_length
|
|
variable are a better choice.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< ON_SubDEdgePtr >& unsorted_edges,
|
|
unsigned int minimum_chain_length,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& edge_chains
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Sort edges into a chains
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
To sort an array in place, pass the same array as both parameters.
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
then all of the edges that share that vertex are ignored.
|
|
The edges can be from one or more SubDs.
|
|
|
|
unsigned int minimum_chain_length - [in]
|
|
minimum number of edges to consider for a chain.
|
|
|
|
edge_chains - [out]
|
|
The edge_chains[] has the edges grouped into edge chains.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
edge_chains[i].RelativeVertex(1) == edge_chains[i+1].RelativeVertex(0).
|
|
|
|
When edge_chains[i].RelativeVertex(1) != edge_chains[i+1].RelativeVertex(0),
|
|
a chain ends at edge_chains[i] and another begins at edge_chains[i+1].
|
|
|
|
The first edge in every chain has the same orientation as the input edge
|
|
from edge_chains[].
|
|
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
|
|
Remarks:
|
|
When the orientation of the input edges is not intentionally set,
|
|
the versions of SortEdgesIntoEdgeChains() above without a minimum_chain_length
|
|
variable are a better choice.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< const ON_SubDEdge* >& unsorted_edges,
|
|
unsigned int minimum_chain_length,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& edge_chains
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Sort edges into a chains
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
To sort an array in place, pass the same array as both parameters.
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
then all of the edges that share that vertex are ignored.
|
|
The edges can be from one or more SubDs.
|
|
|
|
unsigned int minimum_chain_length - [in]
|
|
minimum number of edges to consider for a chain.
|
|
|
|
edge_chains - [out]
|
|
The edge_chains[] has the edges grouped into edge chains.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
edge_chains[i].RelativeVertex(1) == edge_chains[i+1].RelativeVertex(0).
|
|
|
|
When edge_chains[i].RelativeVertex(1) != edge_chains[i+1].RelativeVertex(0),
|
|
a chain ends at edge_chains[i] and another begins at edge_chains[i+1].
|
|
|
|
The first edge in every chain has the same orientation as the input edge
|
|
from edge_chains[].
|
|
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
|
|
Remarks:
|
|
When the orientation of the input edges is not intentionally set,
|
|
the versions of SortEdgesIntoEdgeChains() above without a minimum_chain_length
|
|
variable are a better choice.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< ON_SubDComponentPtr >& unsorted_edges,
|
|
unsigned int minimum_chain_length,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& sorted_edges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Sort edges into a chains
|
|
|
|
Parameters:
|
|
unsorted_edges - [in]
|
|
To sort an array in place, pass the same array as both parameters.
|
|
If unsorted_edges[] contains three or more edges that share a common vertex,
|
|
then all of the edges that share that vertex are ignored.
|
|
The edges can be from one or more SubDs.
|
|
|
|
unsigned int minimum_chain_length - [in]
|
|
minimum number of edges to consider for a chain.
|
|
|
|
edge_chains - [out]
|
|
The edge_chains[] has the edges grouped into edge chains.
|
|
|
|
In an edge chain subsequent edges share a common vertex; i.e.
|
|
edge_chains[i].RelativeVertex(1) == edge_chains[i+1].RelativeVertex(0).
|
|
|
|
When edge_chains[i].RelativeVertex(1) != edge_chains[i+1].RelativeVertex(0),
|
|
a chain ends at edge_chains[i] and another begins at edge_chains[i+1].
|
|
|
|
The first edge in every chain has the same orientation as the input edge
|
|
from edge_chains[].
|
|
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
|
|
Remarks:
|
|
When the orientation of the input edges is not intentionally set,
|
|
the versions of SortEdgesIntoEdgeChains() above without a minimum_chain_length
|
|
variable are a better choice.
|
|
*/
|
|
static unsigned int SortEdgesIntoEdgeChains(
|
|
const ON_SubD& subd,
|
|
const ON_SimpleArray< ON_COMPONENT_INDEX >& unsorted_edges,
|
|
unsigned int minimum_chain_length,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& edge_chains
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Orient edges[] into edge chains preserving the order of edges[].
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
*/
|
|
static unsigned int OrientEdgesIntoEdgeChains(
|
|
const ON_SubD& subd,
|
|
const ON_SimpleArray< ON_COMPONENT_INDEX >& edges,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& edge_chains
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Orient edges[] into edge chains preserving the order of edges[].
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
*/
|
|
static unsigned int OrientEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< const ON_SubDEdge* >& edges,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& edge_chains
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Orient edges[] into edge chains preserving the order of edges[].
|
|
Returns:
|
|
Number of chains in edge_chains[].
|
|
*/
|
|
static unsigned int OrientEdgesIntoEdgeChains(
|
|
const ON_SimpleArray< ON_SubDComponentPtr >& edges,
|
|
ON_SimpleArray< ON_SubDEdgePtr >& edge_chains
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
A SHA1 hash of the edge and vertex ids.
|
|
Useful for determining when two edge chains from different
|
|
subds (one generally a modified copy) involve the same
|
|
edges and vertices.
|
|
*/
|
|
const ON_SHA1_Hash Hash() const;
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Edge chain tools
|
|
//
|
|
|
|
/*
|
|
Description:
|
|
Get the neighboring link in an edge chain.
|
|
Parameters:
|
|
starting_edge - [in]
|
|
search_direction - [in]
|
|
ON_ChainDirection::Previous or ON_ChainDirection::Next.
|
|
The search direction is relative to this->EdgeDirection().
|
|
chain_type - [in]
|
|
Determines what edge/vertex tag conditions must be satisified by the neighbor.
|
|
Returns:
|
|
The next or previous edge in the chain if it exists.
|
|
Otherwise, nullptr is returned.
|
|
Remarks:
|
|
When multiple edges are candidates, there is a bias to preserve smooth/crease and a bias to
|
|
preserve face count. If the biases don't reduce the list of candidates to one or bStopAtBreak is true
|
|
and a creaase/smooth break is encountered, then ON_SubDEdgePtr::Null is returned.
|
|
*/
|
|
static const ON_SubDEdgePtr EdgeChainNeighbor(
|
|
ON_SubDEdgePtr starting_edge,
|
|
ON_ChainDirection search_direction,
|
|
ON_SubD::ChainType chain_type
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Get the neighboring link in an edge chain.
|
|
Parameters:
|
|
starting_edge - [in]
|
|
search_direction - [in]
|
|
ON_ChainDirection::Previous or ON_ChainDirection::Next.
|
|
The search direction is relative to this->EdgeDirection().
|
|
chain_type - [in]
|
|
Determines what edge/vertex tag conditions must be satisified by the neighbor.
|
|
bEnableStatusCheck - [in]
|
|
status_pass - [in]
|
|
status_fail - [in]
|
|
If bEnableStatusFilter is false, then no status checks are performed.
|
|
If bEnableStatusFilter is true, ON_ComponentStatus::StatusCheck(candidate_edge->m_status,status_pass,status_fail)
|
|
must be true for candidate_edge to be returned.
|
|
Returns:
|
|
The next or previous edge in the chain if it exists.
|
|
Otherwise, nullptr is returned.
|
|
Remarks:
|
|
When multiple edges are candidates, there is a bias to preserve smooth/crease and a bias to
|
|
preserve face count. If the biases don't reduce the list of candidates to one or bStopAtBreak is true
|
|
and a creaase/smooth break is encountered, then ON_SubDEdgePtr::Null is returned.
|
|
*/
|
|
static const ON_SubDEdgePtr EdgeChainNeighbor(
|
|
ON_SubDEdgePtr starting_edge,
|
|
ON_ChainDirection search_direction,
|
|
ON_SubD::ChainType chain_type,
|
|
bool bEnableStatusCheck,
|
|
ON_ComponentStatus status_pass,
|
|
ON_ComponentStatus status_fail
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Reverse the orientation of the elements and the order
|
|
of the elements in the edge_chain[] array.
|
|
Parameters:
|
|
edge_chain - [in/out]
|
|
*/
|
|
static void ReverseEdgeChain(
|
|
ON_SimpleArray< ON_SubDEdgePtr >& edge_chain
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Reverse the orientation of the elements and the order
|
|
of the elements in the edge_chain[] array.
|
|
Parameters:
|
|
edge_count - [in]
|
|
Number of elements in edge_chain[]
|
|
edge_chain - [in/out]
|
|
*/
|
|
static void ReverseEdgeChain(
|
|
ON_SubDEdgePtr* edge_chain,
|
|
size_t edge_count
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Checks that all edge and vertex pointers are not nullptr
|
|
and that adjacent edges in the list share the same vertex.
|
|
Parameters:
|
|
edge_chain - [in]
|
|
Edge chain to test
|
|
bCheckForDuplicateEdges - [in]
|
|
If bCheckForDuplicateEdges true, then false is returned if
|
|
there are duplicate edges or duplicate interior vertices.
|
|
Returns:
|
|
True if edge_chain[] is valid.
|
|
*/
|
|
static bool IsValidEdgeChain(
|
|
const ON_SimpleArray< ON_SubDEdgePtr >& edge_chain,
|
|
bool bCheckForDuplicateEdges
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Checks that all edge and vertex pointers are not nullptr
|
|
and that adjacent edges in the list share the same vertex.
|
|
Parameters:
|
|
edge_count - [in]
|
|
Number of elements in edge_chain[] to test.
|
|
edge_chain - [in]
|
|
Edge chain to test
|
|
bCheckForDuplicateEdges - [in]
|
|
If bCheckForDuplicateEdges true, then false is returned if
|
|
there are duplicate edges or duplicate interior vertices.
|
|
Returns:
|
|
True if edge_chain[] is valid.
|
|
*/
|
|
static bool IsValidEdgeChain(
|
|
const ON_SubDEdgePtr* edge_chain,
|
|
size_t edge_count,
|
|
bool bCheckForDuplicateEdges
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Get the edges and faces on a specified side of the edge chain.
|
|
Parameters:
|
|
relative_side - [in]
|
|
0: Get edges and faces on the ON_SubDEdgePtr::RelativeFace(0) side (left).
|
|
1: Get edges and faces on the ON_SubDEdgePtr::RelativeFace(1) side (right).
|
|
|
|
side_components - [out]
|
|
side_components[] is a sequence of made of vertices, edges, and faces that
|
|
record the edges and faces that are on the specified side of the edge chain.
|
|
|
|
When a vertex is in side_components[], ON_SubDComponentPtr.Vertex() is not nullptr
|
|
and the vertex is between two conscutive edges in the edge chain.
|
|
|
|
When an edge is in side_components[], ON_SubDComponentPtr.EdgePtr() is not nullptr,
|
|
the edge is on the specified side of the edge chain (not in the edge chain),
|
|
and ON_SubDComponentPtr.EdgePtr().RelativeVertex(0) is a vertex on the edge chain.
|
|
|
|
When a face is in side_components[], ON_SubDComponentPtr.Face() is not nullptr,
|
|
then at least one vertex of f is part of the edge chain and f is on the specified
|
|
side of the edge chain.
|
|
|
|
If a vertex v is side_components[], then it is preceded and followed by the same
|
|
face (...f,v,f,...), there are consecutive edges in the edge chain (...e0,e1,...),
|
|
and e0 and e1 are consecutive edges in f's boundary.
|
|
|
|
If ...eptr0,f,eptr1,... is in side_components[],
|
|
v0 = eptr0.RelativeVertex(0),
|
|
v1 = eptr0.RelativeVertex(0),
|
|
and v0 == v1,
|
|
then eptr0 and eptr1 are conecutive edges in the boundary of f
|
|
and v0==v1 is a vertex in the edge chain.
|
|
|
|
If ...eptr0,f,eptr1,... is in side_components[],
|
|
v0 = eptr0.RelativeVertex(0),
|
|
v1 = eptr0.RelativeVertex(0),
|
|
and v0 != v1,
|
|
then there is an edge c from v0 to v1 that is in the edge chain and
|
|
eptr0,c,eptr1 are conecutive edges in the boundary of f.
|
|
|
|
If ...eptr0,f,v,... is in side_components[] and v0 = eptr0.RelativeVertex(0),
|
|
and then v0 != v, then there is an edge c from v0 to v that is in the edge chain,
|
|
and eptr0,c are conecutive edges in the boundary of f.
|
|
|
|
If ...v,f,eptr1,... is in side_components[] and v1 = eptr1.RelativeVertex(0),
|
|
and then v != v1, then there is an edge c from v to v1 that is in the edge chain,
|
|
and c,eptr1 conecutive edges in the boundary of f.
|
|
|
|
Remarks:
|
|
If the SubD is not an oriented manifold along the entire side of the chain,
|
|
then there may be gaps in chain_side[]. When there are face fans at a chain
|
|
vertex, there will be faces that do not have an edge on the chain.
|
|
*/
|
|
bool GetSideComponents(
|
|
unsigned relative_side,
|
|
ON_SimpleArray<ON_SubDComponentPtr>& side_components
|
|
) const;
|
|
|
|
/*
|
|
See above.
|
|
*/
|
|
static bool GetSideComponents(
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& edge_chain,
|
|
unsigned relative_side,
|
|
ON_SimpleArray<ON_SubDComponentPtr>& side_components
|
|
);
|
|
|
|
public:
|
|
/*
|
|
Returns:
|
|
Current EdgeChain
|
|
*/
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& EdgeChain() const;
|
|
|
|
|
|
const ON_SubD& SubD() const;
|
|
const ON_SubDRef SubDRef() const;
|
|
|
|
bool InChain(
|
|
const ON_SubDEdgePtr edge_ptr
|
|
) const;
|
|
|
|
bool InChain(
|
|
const ON_SubDEdge* edge
|
|
) const;
|
|
|
|
bool InChain(
|
|
const ON_SubDVertex* vertex
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the edge chain has 3 or more edges that form a closed loop.
|
|
*/
|
|
bool IsClosedLoop() const;
|
|
|
|
/*
|
|
Parameters:
|
|
bStrictlyConvex - [in]
|
|
If true, then a colinear pair of edges is not considered convex.
|
|
Returns:
|
|
True if the edge chain has 3 or more edges that forma a convex loop.
|
|
*/
|
|
bool IsConvexLoop(
|
|
bool bStrictlyConvex
|
|
) const;
|
|
|
|
|
|
/*
|
|
Parameters:
|
|
persistent_subd_id - [in]
|
|
If this edge chain needs to persist in a 3dm archive, then persistent_subd_id
|
|
should identify the subd in its current context.
|
|
If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
If the edge chain is being used in a runtime context and will not be saved in a 3dm archive
|
|
or otherwise serialized, then persistent_subd_id can be ON_nil_uuid.
|
|
|
|
*/
|
|
unsigned int BeginEdgeChain(
|
|
ON_UUID persistent_subd_id,
|
|
ON_SubDRef subd_ref,
|
|
const ON_SubDEdge* initial_edge
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
persistent_subd_id - [in]
|
|
If this edge chain needs to persist in a 3dm archive, then persistent_subd_id
|
|
should identify the subd in its current context.
|
|
If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
If the edge chain is being used in a runtime context and will not be saved in a 3dm archive
|
|
or otherwise serialized, then persistent_subd_id can be ON_nil_uuid.
|
|
|
|
*/
|
|
unsigned int BeginEdgeChain(
|
|
ON_UUID persistent_subd_id,
|
|
ON_SubDRef subd_ref,
|
|
const ON_SimpleArray<const ON_SubDEdge* >& initial_edge_chain
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
persistent_subd_id - [in]
|
|
If this edge chain needs to persist in a 3dm archive, then persistent_subd_id
|
|
should identify the subd in its current context.
|
|
If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
If the edge chain is being used in a runtime context and will not be saved in a 3dm archive
|
|
or otherwise serialized, then persistent_subd_id can be ON_nil_uuid.
|
|
|
|
*/
|
|
unsigned int BeginEdgeChain(
|
|
ON_UUID persistent_subd_id,
|
|
ON_SubDRef subd_ref,
|
|
const ON_SubDEdge*const* initial_edge_chain,
|
|
size_t edge_count
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
persistent_subd_id - [in]
|
|
If this edge chain needs to persist in a 3dm archive, then persistent_subd_id
|
|
should identify the subd in its current context.
|
|
If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
If the edge chain is being used in a runtime context and will not be saved in a 3dm archive
|
|
or otherwise serialized, then persistent_subd_id can be ON_nil_uuid.
|
|
|
|
*/
|
|
unsigned int BeginEdgeChain(
|
|
ON_UUID persistent_subd_id,
|
|
ON_SubDRef subd_ref,
|
|
ON_SubDEdgePtr initial_edge
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
persistent_subd_id - [in]
|
|
If this edge chain needs to persist in a 3dm archive, then persistent_subd_id
|
|
should identify the subd in its current context.
|
|
If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
If the edge chain is being used in a runtime context and will not be saved in a 3dm archive
|
|
or otherwise serialized, then persistent_subd_id can be ON_nil_uuid.
|
|
|
|
*/
|
|
unsigned int BeginEdgeChain(
|
|
ON_UUID persistent_subd_id,
|
|
ON_SubDRef subd_ref,
|
|
const ON_SimpleArray<ON_SubDEdgePtr>& initial_edge_chain
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
persistent_subd_id - [in]
|
|
If this edge chain needs to persist in a 3dm archive, then persistent_subd_id
|
|
should identify the subd in its current context.
|
|
If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
If the edge chain is being used in a runtime context and will not be saved in a 3dm archive
|
|
or otherwise serialized, then persistent_subd_id can be ON_nil_uuid.
|
|
|
|
*/
|
|
unsigned int BeginEdgeChain(
|
|
ON_UUID persistent_subd_id,
|
|
ON_SubDRef subd_ref,
|
|
const ON_SubDEdgePtr* initial_edge_chain,
|
|
size_t edge_count
|
|
);
|
|
|
|
unsigned int EdgeCount() const;
|
|
|
|
void SetStatusCheck(
|
|
bool bEnableStatusCheck,
|
|
ON_ComponentStatus status_check_pass,
|
|
ON_ComponentStatus status_check_fail
|
|
);
|
|
|
|
bool StatusCheckEnabled() const;
|
|
|
|
const ON_ComponentStatus StatusCheckPass() const;
|
|
|
|
const ON_ComponentStatus StatusCheckFail() const;
|
|
|
|
bool StatusCheck(
|
|
const ON_SubDEdge* edge
|
|
) const;
|
|
|
|
void Reverse();
|
|
|
|
const ON_SubDEdgePtr FirstEdgePtr() const;
|
|
const ON_SubDEdgePtr LastEdgePtr() const;
|
|
const ON_SubDEdgePtr EdgePtr(int edge_index) const;
|
|
|
|
const ON_3dPoint FirstControlNetPoint() const;
|
|
const ON_3dPoint LastControlNetPoint() const;
|
|
const ON_3dPoint ControlNetPoint(int vertex_index) const;
|
|
|
|
const ON_SubDEdge* FirstEdge() const;
|
|
const ON_SubDEdge* LastEdge() const;
|
|
const ON_SubDEdge* Edge(int edge_index) const;
|
|
|
|
const ON_SubDVertex* FirstVertex() const;
|
|
const ON_SubDVertex* LastVertex() const;
|
|
const ON_SubDVertex* Vertex(int vertex_index) const;
|
|
|
|
unsigned int AddOneNeighbor(
|
|
ON_ChainDirection direction,
|
|
ON_SubD::ChainType chain_type
|
|
);
|
|
|
|
unsigned int AddAllNeighbors(
|
|
ON_ChainDirection direction,
|
|
ON_SubD::ChainType chain_type
|
|
);
|
|
|
|
unsigned int AddEdge(
|
|
const ON_SubDEdge* edge
|
|
);
|
|
|
|
unsigned int RemoveEdges(
|
|
const ON_SubDEdge* first_edge,
|
|
const ON_SubDEdge* last_edge
|
|
);
|
|
|
|
void ClearEdgeChain();
|
|
|
|
/*
|
|
Returns:
|
|
The persistent id of the parent subd object.
|
|
If the context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If the context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
*/
|
|
const ON_UUID PersistentSubDId() const;
|
|
|
|
bool HasPersistentEdgeIds() const;
|
|
|
|
bool HasRuntimeEdgePtrs() const;
|
|
|
|
bool SetPersistentEdgeIdsFromRuntimeEdgePtrs() const;
|
|
|
|
/*
|
|
Description:
|
|
In situations where this edge chain is being read from a 3dm archive,
|
|
or a similar serialization context, this function uses the saved edge
|
|
id information to initialize the runtime ON_SubDEdgePtr information.
|
|
Parameters:
|
|
persistent_subd_id - [in]
|
|
This id is passed to insure it matches the saved persistent_subd_id.
|
|
The source of the id depends on the context of the model managing the subd.
|
|
If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id().
|
|
If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId().
|
|
Returns:
|
|
True if successful.
|
|
False if not successful.
|
|
*/
|
|
bool SetRuntimeEdgePtrsFromPersistentSubD(
|
|
ON_UUID persistent_subd_id,
|
|
ON_SubDRef persistent_subd_ref
|
|
);
|
|
|
|
bool Write(class ON_BinaryArchive& archive) const;
|
|
bool Read(class ON_BinaryArchive& archive);
|
|
void Dump(class ON_TextLog& text_log) const;
|
|
|
|
private:
|
|
ON_SubDRef m_subd_ref;
|
|
ON_SimpleArray<ON_SubDEdgePtr> m_edge_chain;
|
|
|
|
|
|
// If m_persistent_subd_id, then the id identifies the parent subd in the model.
|
|
// In an ONX_Model, this is the ON_ModelGeometryComponent.Id() value
|
|
// of the corresponding ON_SubD in the ONX_Model.
|
|
// In Rhino, this is the CRhinoObject.ModelObjectId() value
|
|
// of the corresponding CRhinoSubDObject in the CRhinoDoc.
|
|
ON_UUID m_persistent_subd_id = ON_nil_uuid;
|
|
|
|
// If m_persistent_subd_id is set and m_persistent_edge_id[] is not empty,
|
|
// m_persistent_edge_id[] is a list of edge ids and orientations.
|
|
// unsigned id = m_persistent_edge_id[] & 0xFFFFFFFF.
|
|
// reversed orientation = (0 != (m_persistent_edge_id[] & 0x8000000000000000)).
|
|
// The persistent id information is saved in 3dm archives. When that archive is read,
|
|
// the SetRuntimeEdgePtrsFromPersistentSubD() can be used to set the runtime edge chain values.
|
|
// These mutable fields are set by Write and used by Read.
|
|
mutable ON_SimpleArray<unsigned int> m_persistent_edge_id;
|
|
mutable ON_SimpleArray<ON__UINT8> m_persistent_edge_orientation; // 0 = not reversed, 1 = reversed.
|
|
|
|
ON_UniqueTester m_unique_tester;
|
|
ON_ComponentStatus m_status_check_pass = ON_ComponentStatus::NoneSet;
|
|
ON_ComponentStatus m_status_check_fail = ON_ComponentStatus::Selected;
|
|
bool m_bEnableStatusCheck = false;
|
|
};
|
|
|
|
class ON_CLASS ON_SubDComponentFilter
|
|
{
|
|
public:
|
|
ON_SubDComponentFilter() = default;
|
|
~ON_SubDComponentFilter() = default;
|
|
ON_SubDComponentFilter(const ON_SubDComponentFilter&) = default;
|
|
ON_SubDComponentFilter& operator=(const ON_SubDComponentFilter&) = default;
|
|
|
|
public:
|
|
|
|
///<summary>
|
|
/// No filters are set and all components are accepted.
|
|
///</summary>
|
|
static const ON_SubDComponentFilter Unset;
|
|
|
|
///<summary>
|
|
/// Only vertices are accepted.
|
|
///</summary>
|
|
static const ON_SubDComponentFilter OnlyVertices;
|
|
|
|
///<summary>
|
|
/// Only edges are accepted.
|
|
///</summary>
|
|
static const ON_SubDComponentFilter OnlyEdges;
|
|
|
|
///<summary>
|
|
/// Only faces are accepted.
|
|
///</summary>
|
|
static const ON_SubDComponentFilter OnlyFaces;
|
|
|
|
/*
|
|
Parameters:
|
|
bAcceptVertices - [in]
|
|
If true, all vertices are accepted. Otherwise, all vertices are rejected.
|
|
bAcceptEdges - [in]
|
|
If true, all edges are accepted. Otherwise all edges are rejected.
|
|
bAcceptFaces - [in]
|
|
If true, all faces are accepted. Otherwise all faces are rejected.
|
|
*/
|
|
static const ON_SubDComponentFilter Create(
|
|
bool bAcceptVertices,
|
|
bool bAcceptEdges,
|
|
bool bAcceptFaces
|
|
);
|
|
|
|
public:
|
|
///<summary>
|
|
/// Topology filters.
|
|
///</summary>
|
|
enum class Topology : unsigned char
|
|
{
|
|
///<summary>
|
|
/// No topology filter.
|
|
///</summary>
|
|
Unset = 0,
|
|
|
|
///<summary>
|
|
/// A boundary vertex has a single sector bounded by two boundary edges.
|
|
/// A boundary edge has a single face.
|
|
/// A boundary face has at least one boundary edge.
|
|
///</summary>
|
|
Boundary = 1,
|
|
|
|
///<summary>
|
|
/// An interior vertex has the same number of edges and faces and all edges are interior.
|
|
/// An interior edge has two faces.
|
|
/// An interior face has all interior edges.
|
|
///</summary>
|
|
Interior = 2,
|
|
|
|
///<summary>
|
|
/// A nonmanifold vertex is a vertex that is neither boundary nor interior.
|
|
/// A nonmanifold edge is an edge that is neither boundary nor interior.
|
|
/// A nonmanifold face is a face that is neither boundary nor interior.
|
|
///</summary>
|
|
Nonmanifold = 4,
|
|
|
|
///<summary>
|
|
/// A component that is either boundary or interior.
|
|
///</summary>
|
|
BoundaryOrInterior = 3,
|
|
|
|
///<summary>
|
|
/// A component that is either boundary or nonmanifold.
|
|
///</summary>
|
|
BoundaryOrNonmanifold = 5,
|
|
|
|
///<summary>
|
|
/// A component that is either interior or nonmanifold
|
|
///</summary>
|
|
InteriorOrNonmanifold = 6
|
|
};
|
|
|
|
bool AcceptComponent(
|
|
const class ON_Geometry* geometry
|
|
) const;
|
|
|
|
bool AcceptComponent(
|
|
ON_COMPONENT_INDEX component_index,
|
|
const class ON_Geometry* geometry
|
|
) const;
|
|
|
|
bool AcceptComponent(
|
|
const class ON_SubDComponentRef* cref
|
|
) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the filter accepts the component. False otherwise.
|
|
*/
|
|
bool AcceptComponent(ON_SubDComponentPtr cptr) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the filter accepts the vertex. False otherwise.
|
|
*/
|
|
bool AcceptVertex(ON_SubDVertexPtr vptr) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the filter accepts the edge. False otherwise.
|
|
*/
|
|
bool AcceptEdge(ON_SubDEdgePtr eptr) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the filter accepts the face. False otherwise.
|
|
*/
|
|
bool AcceptFace(ON_SubDFacePtr fptr) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the filter accepts the vertex. False otherwise.
|
|
*/
|
|
bool AcceptVertex(const ON_SubDVertex* v) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the filter accepts the edge. False otherwise.
|
|
*/
|
|
bool AcceptEdge(const ON_SubDEdge* e) const;
|
|
|
|
/*
|
|
Returns:
|
|
True if the filter accepts the face. False otherwise.
|
|
*/
|
|
bool AcceptFace(const ON_SubDFace* f) const;
|
|
|
|
void SetAcceptVertices(bool bAcceptVertices);
|
|
|
|
bool AcceptVertices() const;
|
|
|
|
void SetAcceptEdges(bool bAcceptEdges);
|
|
|
|
bool AcceptEdges() const;
|
|
|
|
void SetAcceptFaces(bool bAcceptFaces);
|
|
|
|
bool AcceptFaces() const;
|
|
|
|
void SetVertexTopologyFilter(ON_SubDComponentFilter::Topology vertex_topology_filter);
|
|
|
|
void ClearVertexTopologyFilter();
|
|
|
|
ON_SubDComponentFilter::Topology VertexTopologyFilter() const;
|
|
|
|
void SetEdgeTopologyFilter(ON_SubDComponentFilter::Topology edge_topology_filter);
|
|
|
|
ON_SubDComponentFilter::Topology EdgeTopologyFilter() const;
|
|
|
|
void ClearEdgeTopologyFilter();
|
|
|
|
void SetFaceTopologyFilter(ON_SubDComponentFilter::Topology face_topology_filter);
|
|
|
|
ON_SubDComponentFilter::Topology FaceTopologyFilter() const;
|
|
|
|
void ClearFaceTopologyFilter();
|
|
|
|
bool AcceptVertexTag(ON_SubDVertexTag vertex_tag) const;
|
|
|
|
void AddAcceptedVertexTag(ON_SubDVertexTag vertex_tag);
|
|
|
|
void ClearVertexTagFilter();
|
|
|
|
bool AcceptEdgeTag(ON_SubDEdgeTag edge_tag) const;
|
|
|
|
void AddAcceptedEdgeTag(ON_SubDEdgeTag edge_tag);
|
|
|
|
void ClearEdgeTagFilter();
|
|
|
|
bool AcceptFaceEdgeCount(
|
|
unsigned face_edge_count
|
|
) const;
|
|
|
|
void SetFaceEdgeCountFilter(
|
|
unsigned minimum_face_edge_count,
|
|
unsigned maximum_face_edge_count
|
|
);
|
|
|
|
void ClearFaceEdgeCountFilter();
|
|
|
|
private:
|
|
bool m_bRejectVertices = false;
|
|
ON_SubDComponentFilter::Topology m_vertex_topology_filter = ON_SubDComponentFilter::Topology::Unset;
|
|
ON_SubDVertexTag m_vertex_tag_filter[4] = {};
|
|
|
|
bool m_bRejectEdges = false;
|
|
ON_SubDComponentFilter::Topology m_edge_topology_filter = ON_SubDComponentFilter::Topology::Unset;
|
|
ON_SubDEdgeTag m_edge_tag_filter[2] = {};
|
|
|
|
bool m_bRejectFaces = false;
|
|
ON_SubDComponentFilter::Topology m_face_topology_filter = ON_SubDComponentFilter::Topology::Unset;
|
|
unsigned m_minimum_face_edge_count = 0U;
|
|
unsigned m_maximum_face_edge_count = 0U;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class ON_SubDRTree : public ON_RTree
|
|
{
|
|
private:
|
|
ON_SubDRTree(const ON_SubDRTree&) = delete;
|
|
ON_SubDRTree& operator=(const ON_SubDRTree&) = delete;
|
|
|
|
public:
|
|
ON_SubDRTree() = default;
|
|
~ON_SubDRTree() = default;
|
|
|
|
public:
|
|
|
|
bool CreateSubDVertexRTree(
|
|
const ON_SubD& subd,
|
|
ON_SubDComponentLocation vertex_location
|
|
);
|
|
|
|
bool CreateSubDEmptyRTree(
|
|
const ON_SubD& subd
|
|
);
|
|
|
|
bool AddVertex(
|
|
const ON_SubDVertex* v,
|
|
ON_SubDComponentLocation vertex_location
|
|
);
|
|
|
|
const ON_SubDVertex* FindVertexAtPoint(
|
|
const ON_3dPoint P,
|
|
const double distance_tolerance
|
|
) const;
|
|
|
|
const ON_SubDVertex* FindMarkedVertexAtPoint(
|
|
const ON_3dPoint P,
|
|
const double distance_tolerance
|
|
) const;
|
|
|
|
const ON_SubDVertex* FindUnmarkedVertexAtPoint(
|
|
const ON_3dPoint P,
|
|
const double distance_tolerance
|
|
) const;
|
|
|
|
const ON_SubDVertex* FindVertex(
|
|
const class ON_SubDRTreeVertexFinder& vertex_finder,
|
|
const double distance_tolerance
|
|
) const;
|
|
|
|
const ON_SubD& SubD() const;
|
|
|
|
/*
|
|
Description:
|
|
CLears the refernce to the SubD and removes all RTree nodes.
|
|
*/
|
|
void Clear();
|
|
|
|
private:
|
|
// Shares contents with the referenced subd.
|
|
// Used to increment the reference count on the ON_SubDimple (not a real copy).
|
|
// This is used to insure the vertex pointers in the rtree nodes are valid.
|
|
ON_SubD m_subd;
|
|
};
|
|
|
|
class ON_SubDRTreeVertexFinder
|
|
{
|
|
public:
|
|
ON_SubDRTreeVertexFinder() = default;
|
|
~ON_SubDRTreeVertexFinder() = default;
|
|
ON_SubDRTreeVertexFinder(const ON_SubDRTreeVertexFinder&) = default;
|
|
ON_SubDRTreeVertexFinder& operator=(const ON_SubDRTreeVertexFinder&) = default;
|
|
|
|
static const ON_SubDRTreeVertexFinder Unset;
|
|
|
|
public:
|
|
static const ON_SubDRTreeVertexFinder Create(const ON_3dPoint P);
|
|
|
|
/*
|
|
Parameters:
|
|
bMarkFilter - [in]
|
|
Vertices with Mark = bMarkFilter are eligable to be found.
|
|
Vertices with Mark != bMarkFilter are ignored.
|
|
*/
|
|
static const ON_SubDRTreeVertexFinder Create(const ON_3dPoint P, bool bMarkFilter);
|
|
|
|
enum class MarkBitsFilter : unsigned char
|
|
{
|
|
None = 0,
|
|
Equal = 1,
|
|
NotEqual = 2
|
|
};
|
|
|
|
static const ON_SubDRTreeVertexFinder Create(
|
|
const ON_3dPoint P,
|
|
ON_SubDRTreeVertexFinder::MarkBitsFilter mark_bits_filter,
|
|
ON__UINT8 mark_bits
|
|
);
|
|
|
|
|
|
public:
|
|
ON_3dPoint m_P = ON_3dPoint::NanPoint;
|
|
double m_distance = ON_DBL_QNAN;
|
|
const ON_SubDVertex* m_v = nullptr;
|
|
|
|
// When m_bMarkFilterEnabled is true, then vertices with Mark() == m_bMarkFilter are eligable
|
|
// to be found and vertices with Mark() != m_bMarkFilter are ignored.
|
|
bool m_bMarkFilterEnabled = false;
|
|
bool m_bMarkFilter = false;
|
|
|
|
public:
|
|
ON_SubDRTreeVertexFinder::MarkBitsFilter m_mark_bits_filter = ON_SubDRTreeVertexFinder::MarkBitsFilter::None;
|
|
ON__UINT8 m_mark_bits = 0;
|
|
|
|
private:
|
|
unsigned int m_reserved2 = 0;
|
|
|
|
public:
|
|
|
|
static bool Callback(void* a_context, ON__INT_PTR a_id);
|
|
|
|
};
|
|
|
|
#if defined(ON_COMPILING_OPENNURBS)
|
|
/*
|
|
The ON_SubDAsUserData class is used to attach a subd to it proxy mesh
|
|
when writing V6 files in commercial rhino.
|
|
*/
|
|
class ON_SubDMeshProxyUserData : public ON_UserData
|
|
{
|
|
public:
|
|
/*
|
|
Returns:
|
|
A pointer to a mesh that now manages subd.
|
|
*/
|
|
static ON_Mesh* MeshProxyFromSubD(
|
|
const ON_SubD* subd
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
A pointer to a subd and deletes mesh.
|
|
*/
|
|
static ON_SubD* SubDFromMeshProxy(
|
|
const ON_Mesh* mesh
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
A pointer to a subd and deletes mesh.
|
|
*/
|
|
static bool IsSubDMeshProxy(
|
|
const ON_Mesh* mesh
|
|
);
|
|
|
|
static const ON_SubDDisplayParameters MeshProxyDisplayParameters();
|
|
|
|
private:
|
|
ON_OBJECT_DECLARE(ON_SubDMeshProxyUserData);
|
|
|
|
public:
|
|
ON_SubDMeshProxyUserData();
|
|
~ON_SubDMeshProxyUserData();
|
|
ON_SubDMeshProxyUserData(const ON_SubDMeshProxyUserData&);
|
|
ON_SubDMeshProxyUserData& operator=(const ON_SubDMeshProxyUserData&);
|
|
|
|
private:
|
|
// ON_Object overrides
|
|
bool Write(ON_BinaryArchive& archive) const override;
|
|
bool Read(ON_BinaryArchive& archive) override;
|
|
bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
|
|
|
|
bool ParentMeshValid() const;
|
|
|
|
private:
|
|
// ON_UserData overrides
|
|
bool GetDescription(ON_wString& description) override;
|
|
bool WriteToArchive(
|
|
const class ON_BinaryArchive& archive,
|
|
const class ON_Object* parent_object
|
|
) const override;
|
|
|
|
private:
|
|
// The subd
|
|
mutable ON_SubD* m_subd = nullptr;
|
|
|
|
private:
|
|
// information used to see if the parent mesh has been modified.
|
|
mutable unsigned int m_mesh_face_count = 0;
|
|
mutable unsigned int m_mesh_vertex_count = 0;
|
|
mutable ON_SHA1_Hash m_mesh_face_array_sha1 = ON_SHA1_Hash::EmptyContentHash;
|
|
mutable ON_SHA1_Hash m_mesh_vertex_array_sha1 = ON_SHA1_Hash::EmptyContentHash;
|
|
|
|
private:
|
|
void Internal_CopyFrom(const ON_SubDMeshProxyUserData& src);
|
|
void Internal_Destroy();
|
|
static const bool Internal_MeshHasFaces(const ON_Mesh* mesh);
|
|
static const ON_SHA1_Hash Internal_FaceSHA1(const ON_Mesh* mesh);
|
|
static const ON_SHA1_Hash Internal_VertexSHA1(const ON_Mesh* mesh);
|
|
};
|
|
#endif
|
|
|
|
#endif
|