Changeset View
Changeset View
Standalone View
Standalone View
extern/opennurbs/opennurbs_subd_sector.cpp
- This file was added.
| #include "opennurbs.h" | |||||
| #if !defined(ON_COMPILING_OPENNURBS) | |||||
| // This check is included in all opennurbs source .c and .cpp files to insure | |||||
| // ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled. | |||||
| // When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined | |||||
| // and the opennurbs .h files alter what is declared and how it is declared. | |||||
| #error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs | |||||
| #endif | |||||
| #include "opennurbs_subd_data.h" | |||||
| /* $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>. | |||||
| // | |||||
| //////////////////////////////////////////////////////////////// | |||||
| */ | |||||
| /* | |||||
| 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 Unset; | |||||
| bool IsValid() const; | |||||
| static ON_SubDSectorType Create( | |||||
| ON_SubD::SubDType subd_type, | |||||
| ON_SubD::VertexTag vertex_tag, | |||||
| unsigned int sector_edge_count, | |||||
| double sector_angle_radians | |||||
| ); | |||||
| static ON_SubDSectorType CreateSmooth( | |||||
| ON_SubD::SubDType subd_type, | |||||
| unsigned int sector_edge_count | |||||
| ); | |||||
| static ON_SubDSectorType CreateCrease( | |||||
| ON_SubD::SubDType subd_type, | |||||
| unsigned int sector_edge_count | |||||
| ); | |||||
| static ON_SubDSectorType CreateDart( | |||||
| ON_SubD::SubDType subd_type, | |||||
| unsigned int sector_edge_count | |||||
| ); | |||||
| static ON_SubDSectorType CreateCorner( | |||||
| ON_SubD::SubDType subd_type, | |||||
| unsigned int sector_edge_count, | |||||
| double sector_corner_angle_radians | |||||
| ); | |||||
| static int Compare( | |||||
| const ON_SubDSectorType& a, | |||||
| const ON_SubDSectorType& b | |||||
| ); | |||||
| ON_SubD::SubDType m_subd_type = ON_SubD::SubDType::Unset; | |||||
| ON_SubD::VertexTag m_vertex_tag = ON_SubD::VertexTag::Unset; | |||||
| private: | |||||
| unsigned char m_reserved1 = 0; | |||||
| unsigned char m_reserved2 = 0; | |||||
| unsigned int m_reserved3 = 0; | |||||
| public: | |||||
| unsigned int m_sector_edge_count = 0; | |||||
| unsigned int m_sector_face_count = 0; | |||||
| double m_sector_angle_radians = 0.0; | |||||
| double m_sector_weight = 0.0; | |||||
| }; | |||||
| */ | |||||
| double ON_SubDSectorType::SectorCoefficientCalculationError() | |||||
| { | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorCoefficient); | |||||
| } | |||||
| bool ON_SubDSectorType::IsValid() const | |||||
| { | |||||
| if ( 0 == m_hash) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| if ( m_sector_face_count < ON_SubDSectorType::MinimumSectorFaceCount(m_vertex_tag)) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| if ( m_sector_face_count > ON_SubDVertex::MaximumFaceCount) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| switch (m_vertex_tag) | |||||
| { | |||||
| case ON_SubD::VertexTag::Smooth: | |||||
| if (!(m_corner_sector_angle_radians == ON_SubDSectorType::IgnoredCornerSectorAngle)) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| if (!(m_sector_coefficient == ON_SubDSectorType::IgnoredSectorCoefficient)) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| break; | |||||
| case ON_SubD::VertexTag::Crease: | |||||
| if (!(m_corner_sector_angle_radians == ON_SubDSectorType::IgnoredCornerSectorAngle)) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| if (!(m_sector_coefficient == ON_SubDSectorType::CreaseSectorCoefficient(m_sector_face_count))) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| break; | |||||
| case ON_SubD::VertexTag::Corner: | |||||
| if (!(m_corner_sector_angle_radians > 0.0 && m_corner_sector_angle_radians < ON_2PI)) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| if (!(m_sector_coefficient == ON_SubDSectorType::CornerSectorCoefficient(m_sector_face_count,m_corner_sector_angle_radians))) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| break; | |||||
| case ON_SubD::VertexTag::Dart: | |||||
| if (!(m_corner_sector_angle_radians == ON_SubDSectorType::IgnoredCornerSectorAngle)) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| if (!(m_sector_coefficient == ON_SubDSectorType::DartSectorCoefficient(m_sector_face_count))) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| break; | |||||
| default: | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| break; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| ON_SubD::VertexTag ON_SubDSectorType::VertexTag() const | |||||
| { | |||||
| return m_vertex_tag; | |||||
| } | |||||
| unsigned int ON_SubDSectorType::FacetEdgeCount() const | |||||
| { | |||||
| return 4; | |||||
| } | |||||
| double ON_SubDSectorType::CornerSectorAngleRadians() const | |||||
| { | |||||
| return | |||||
| (ON_SubD::VertexTag::Corner == m_vertex_tag) | |||||
| ? m_corner_sector_angle_radians | |||||
| : ON_SubDSectorType::ErrorCornerSectorAngle; | |||||
| } | |||||
| unsigned int ON_SubDSectorType::CornerSectorAngleIndex() const | |||||
| { | |||||
| return (m_vertex_tag == ON_SubD::VertexTag::Corner) ? m_corner_sector_angle_index : ON_UNSET_UINT_INDEX; | |||||
| } | |||||
| bool ON_SubDSectorType::IsSmoothSector() const | |||||
| { | |||||
| return (m_vertex_tag == ON_SubD::VertexTag::Smooth); | |||||
| } | |||||
| bool ON_SubDSectorType::IsDartSector() const | |||||
| { | |||||
| return (m_vertex_tag == ON_SubD::VertexTag::Dart); | |||||
| } | |||||
| bool ON_SubDSectorType::IsCreaseSector() const | |||||
| { | |||||
| return (m_vertex_tag == ON_SubD::VertexTag::Crease); | |||||
| } | |||||
| bool ON_SubDSectorType::IsCornerSector() const | |||||
| { | |||||
| return (m_vertex_tag == ON_SubD::VertexTag::Corner && m_corner_sector_angle_index <= ON_SubDSectorType::MaximumCornerAngleIndex); | |||||
| } | |||||
| bool ON_SubDSectorType::IsConvexCornerSector() const | |||||
| { | |||||
| return (m_vertex_tag == ON_SubD::VertexTag::Corner && 2*m_corner_sector_angle_index >= ON_SubDSectorType::MaximumCornerAngleIndex); | |||||
| } | |||||
| bool ON_SubDSectorType::IsConcaveCornerSector() const | |||||
| { | |||||
| return (m_vertex_tag == ON_SubD::VertexTag::Corner && 2*m_corner_sector_angle_index <= ON_SubDSectorType::MaximumCornerAngleIndex); | |||||
| } | |||||
| unsigned int ON_SubDSectorType::EdgeCount() const | |||||
| { | |||||
| if (m_sector_face_count >= ON_SubDSectorType::MinimumSectorFaceCount(m_vertex_tag)) | |||||
| { | |||||
| switch (m_vertex_tag) | |||||
| { | |||||
| case ON_SubD::VertexTag::Smooth: | |||||
| return m_sector_face_count; | |||||
| break; | |||||
| case ON_SubD::VertexTag::Crease: | |||||
| return m_sector_face_count + 1; | |||||
| break; | |||||
| case ON_SubD::VertexTag::Corner: | |||||
| return m_sector_face_count + 1; | |||||
| break; | |||||
| case ON_SubD::VertexTag::Dart: | |||||
| return m_sector_face_count; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(0); | |||||
| } | |||||
| unsigned int ON_SubDSectorType::FaceCount() const | |||||
| { | |||||
| if ( m_sector_face_count >= ON_SubDSectorType::MinimumSectorFaceCount(m_vertex_tag)) | |||||
| return m_sector_face_count; | |||||
| return ON_SUBD_RETURN_ERROR(0); | |||||
| } | |||||
| unsigned int ON_SubDSectorType::ComponentRingCount() const | |||||
| { | |||||
| return 1 + m_sector_face_count + EdgeCount(); | |||||
| } | |||||
| unsigned int ON_SubDSectorType::PointRingCount() const | |||||
| { | |||||
| return ON_SubDSectorType::SectorPointRingCountFromFaceCount( | |||||
| m_vertex_tag, | |||||
| m_sector_face_count | |||||
| ); | |||||
| } | |||||
| double ON_SubDSectorType::CreaseSectorTheta( | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| if (sector_face_count >= 1) | |||||
| return (ON_PI / ((double)sector_face_count)); | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorTheta); | |||||
| } | |||||
| double ON_SubDSectorType::DartSectorTheta( | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| if (sector_face_count >= 2) | |||||
| return (ON_2PI / ((double)sector_face_count)); | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorTheta); | |||||
| } | |||||
| unsigned int ON_SubDSectorType::CornerAngleIndexFromCornerAngleRadians( | |||||
| double corner_sector_angle_radians | |||||
| ) | |||||
| { | |||||
| corner_sector_angle_radians = ON_SubDSectorType::ClampCornerSectorAngleRadians(corner_sector_angle_radians); | |||||
| if (ON_SubDSectorType::IsValidCornerSectorAngleRadians(corner_sector_angle_radians)) | |||||
| { | |||||
| if (corner_sector_angle_radians <= ON_SubDSectorType::MinimumCornerAngleRadians) | |||||
| return 1; | |||||
| if (corner_sector_angle_radians >= ON_SubDSectorType::MaximumCornerAngleRadians) | |||||
| return ON_SubDSectorType::MaximumCornerAngleIndex - 1; | |||||
| const double max_index = ON_SubDSectorType::MaximumCornerAngleIndex; | |||||
| unsigned int i = (unsigned int)floor(max_index*(corner_sector_angle_radians / ON_2PI)); | |||||
| if (i >= ON_SubDSectorType::MaximumCornerAngleIndex - 1) | |||||
| i = ON_SubDSectorType::MaximumCornerAngleIndex - 1; | |||||
| else if (i < 1) | |||||
| i = 1; | |||||
| else if (i < ON_SubDSectorType::MaximumCornerAngleIndex-1) | |||||
| { | |||||
| double a0 = ON_SubDSectorType::AngleRadiansFromCornerAngleIndex(i); | |||||
| double a1 = ON_SubDSectorType::AngleRadiansFromCornerAngleIndex(i+1); | |||||
| double d0 = fabs(a0 - corner_sector_angle_radians); | |||||
| double d1 = fabs(a1 - corner_sector_angle_radians); | |||||
| if (d1 < d0) | |||||
| i++; | |||||
| } | |||||
| return i; | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_UNSET_UINT_INDEX); | |||||
| } | |||||
| double ON_SubDSectorType::AngleRadiansFromCornerAngleIndex( | |||||
| unsigned int corner_sector_angle_index | |||||
| ) | |||||
| { | |||||
| if (corner_sector_angle_index <= ON_SubDSectorType::MaximumCornerAngleIndex) | |||||
| { | |||||
| //const double max_index = ON_SubDSectorType::MaximumCornerAngleIndex; | |||||
| double corner_angle_radians; | |||||
| switch (corner_sector_angle_index) | |||||
| { | |||||
| case 0: | |||||
| corner_angle_radians = 0.0; | |||||
| break; | |||||
| case (ON_SubDSectorType::MaximumCornerAngleIndex/12): | |||||
| corner_angle_radians = ON_PI/6.0; | |||||
| break; | |||||
| case (ON_SubDSectorType::MaximumCornerAngleIndex/8): | |||||
| corner_angle_radians = 0.25*ON_PI; | |||||
| break; | |||||
| case (ON_SubDSectorType::MaximumCornerAngleIndex/6): | |||||
| corner_angle_radians = ON_PI/3.0; | |||||
| break; | |||||
| case (ON_SubDSectorType::MaximumCornerAngleIndex/4): | |||||
| corner_angle_radians = 0.5*ON_PI; | |||||
| break; | |||||
| case (ON_SubDSectorType::MaximumCornerAngleIndex/3): | |||||
| corner_angle_radians = ON_2PI/3.0; | |||||
| break; | |||||
| case (3*ON_SubDSectorType::MaximumCornerAngleIndex*8): | |||||
| corner_angle_radians = 0.75*ON_PI; | |||||
| break; | |||||
| case (5*ON_SubDSectorType::MaximumCornerAngleIndex/12): | |||||
| corner_angle_radians = (5.0*ON_PI)/6.0; | |||||
| break; | |||||
| case (ON_SubDSectorType::MaximumCornerAngleIndex/2): | |||||
| corner_angle_radians = ON_PI; | |||||
| break; | |||||
| case (5*ON_SubDSectorType::MaximumCornerAngleIndex/8): | |||||
| corner_angle_radians = 1.25*ON_PI; | |||||
| break; | |||||
| case (3*ON_SubDSectorType::MaximumCornerAngleIndex/2): | |||||
| corner_angle_radians = 1.5*ON_PI; | |||||
| break; | |||||
| case (7*ON_SubDSectorType::MaximumCornerAngleIndex/8): | |||||
| corner_angle_radians = 1.75*ON_PI; | |||||
| break; | |||||
| case ON_SubDSectorType::MaximumCornerAngleIndex: | |||||
| corner_angle_radians = ON_2PI; | |||||
| break; | |||||
| default: | |||||
| corner_angle_radians = ((double)(corner_sector_angle_index))*ON_SubDSectorType::MinimumCornerAngleRadians; | |||||
| break; | |||||
| } | |||||
| return corner_angle_radians; | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_UNSET_VALUE); | |||||
| } | |||||
| double ON_SubDSectorType::CornerSectorThetaFromCornerAngle( | |||||
| unsigned int sector_face_count, | |||||
| double corner_sector_angle_radians | |||||
| ) | |||||
| { | |||||
| if (sector_face_count >= ON_SubDSectorType::MinimumSectorFaceCount(ON_SubD::VertexTag::Corner) | |||||
| && sector_face_count <= ON_SubDVertex::MaximumFaceCount | |||||
| ) | |||||
| { | |||||
| unsigned int corner_index = ON_SubDSectorType::CornerAngleIndexFromCornerAngleRadians(corner_sector_angle_radians); | |||||
| if (corner_index <= ON_SubDSectorType::MaximumCornerAngleIndex) | |||||
| { | |||||
| if (2*corner_index > ON_SubDSectorType::MaximumCornerAngleIndex) | |||||
| { | |||||
| // concave corner - theta = (2 pi - corner_sector_angle_radians)/sector_face_count | |||||
| corner_index = ON_SubDSectorType::MaximumCornerAngleIndex - corner_index; | |||||
| } | |||||
| double a = ((corner_index/((double)ON_SubDSectorType::MaximumCornerAngleIndex))*ON_PI)/((double)sector_face_count); | |||||
| return a; | |||||
| } | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorTheta); | |||||
| } | |||||
| double ON_SubDSectorType::SectorTheta() const | |||||
| { | |||||
| return m_sector_theta; | |||||
| } | |||||
| double ON_SubDSectorType::CornerSectorAngleRadiansFromEdges( | |||||
| ON_SubDEdgePtr sector_boundary_edge0_ptr, | |||||
| ON_SubDEdgePtr sector_boundary_edge1_ptr | |||||
| ) | |||||
| { | |||||
| const ON_SubDEdge* edges[2] = { ON_SUBD_EDGE_POINTER(sector_boundary_edge0_ptr.m_ptr), ON_SUBD_EDGE_POINTER(sector_boundary_edge1_ptr.m_ptr) }; | |||||
| if (nullptr == edges[0] || nullptr == edges[1]) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorCornerSectorAngle); | |||||
| if (edges[0] == edges[1]) | |||||
| { | |||||
| // occurs in nonmanifold cases like RH-49843 | |||||
| // When an interior nonmanifold edge terminates a corner | |||||
| // and is the only crease edge is a sector for some | |||||
| // faces attached to the edge. | |||||
| return ON_SubDSectorType::MaximumCornerAngleRadians; | |||||
| //return ON_SUBD_RETURN_ERROR(0.0); | |||||
| } | |||||
| ON__UINT_PTR edge_ends[2] = { ON_SUBD_EDGE_DIRECTION(sector_boundary_edge0_ptr.m_ptr), ON_SUBD_EDGE_DIRECTION(sector_boundary_edge1_ptr.m_ptr) }; | |||||
| const ON_SubDVertex* V[2] = { edges[0]->m_vertex[1 - edge_ends[0]], edges[1]->m_vertex[1 - edge_ends[1]] }; | |||||
| if (nullptr == V[0] || nullptr == V[1]) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorCornerSectorAngle); | |||||
| const ON_SubDVertex* corner_vertex = edges[0]->m_vertex[edge_ends[0]]; | |||||
| if (nullptr == corner_vertex || corner_vertex != edges[1]->m_vertex[edge_ends[1]]) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorCornerSectorAngle); | |||||
| const double* cornerP = corner_vertex->m_P; | |||||
| const double* endP[2] = { V[0]->m_P, V[1]->m_P }; | |||||
| // A = vector from cornerP to endP[0] | |||||
| ON_3dVector A(endP[0][0] - cornerP[0], endP[0][1] - cornerP[1], endP[0][2] - cornerP[2]); | |||||
| // B = vector from cornerP to endP[1] | |||||
| ON_3dVector B(endP[1][0] - cornerP[0], endP[1][1] - cornerP[1], endP[1][2] - cornerP[2]); | |||||
| // Unitize A and B | |||||
| A.Unitize(); | |||||
| B.Unitize(); | |||||
| // calculate angle between A and B | |||||
| // In reality, we will be lucky if we get 3 digits of precision in the trig functions | |||||
| // using the dot and cross of unitized differences. | |||||
| double cos_alpha = A*B; | |||||
| double sin_alpha = ON_CrossProduct(A, B).Length(); // NOTE WELL:: sin_alpha >= 0.0 or is invalid | |||||
| const double trig_zero_tol = 0.002; | |||||
| if (fabs(cos_alpha) <= trig_zero_tol) | |||||
| cos_alpha = 0.0; | |||||
| if (fabs(sin_alpha) <= trig_zero_tol) | |||||
| sin_alpha = 0.0; | |||||
| if ( fabs(cos_alpha*cos_alpha + sin_alpha*sin_alpha - 1.0) <= 0.125 ) | |||||
| { | |||||
| // valid sin and cos and no NaNs | |||||
| const double trig_one_tol = 0.999; | |||||
| double alpha = ON_DBL_QNAN; | |||||
| if ( 0.0 == cos_alpha || fabs(sin_alpha) >= trig_one_tol) | |||||
| alpha = (sin_alpha < 0.0) ? 1.5*ON_PI : 0.5*ON_PI; | |||||
| else if ( 0.0 == sin_alpha || fabs(cos_alpha) >= trig_one_tol) | |||||
| alpha = (cos_alpha < 0.0) ? ON_PI : 0.0; | |||||
| else | |||||
| { | |||||
| alpha = atan2(sin_alpha, cos_alpha); | |||||
| if (!ON_IsValid(alpha)) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorCornerSectorAngle); | |||||
| if (alpha < 0.0) | |||||
| { | |||||
| alpha += 2.0*ON_PI; | |||||
| if (alpha >= 2.0*ON_PI) | |||||
| alpha = 0.0; | |||||
| } | |||||
| } | |||||
| if (alpha >= 0.0 && alpha <= (1.0 + ON_EPSILON)*2.0*ON_PI) | |||||
| { | |||||
| if (alpha <= ON_SubDSectorType::MinimumCornerAngleRadians) | |||||
| alpha = ON_SubDSectorType::MinimumCornerAngleRadians; | |||||
| else if (alpha >= ON_SubDSectorType::MaximumCornerAngleRadians) | |||||
| alpha = ON_SubDSectorType::MaximumCornerAngleRadians; | |||||
| else if (fabs(alpha - ON_PI) <= 0.002) | |||||
| { | |||||
| // straight "corner" | |||||
| alpha = ON_PI; | |||||
| } | |||||
| return alpha; | |||||
| } | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorCornerSectorAngle); | |||||
| } | |||||
| double ON_SubDSectorType::SectorCoefficientFromTheta( | |||||
| double sector_theta | |||||
| ) | |||||
| { | |||||
| if (!(sector_theta > 0.0 && sector_theta <= ON_PI)) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorCoefficient); | |||||
| double cos_theta = cos(sector_theta); | |||||
| // If cos_theta is near 0, +1/2, -1/2, +1 or -1, then use those values | |||||
| // so the weights have the easily identified values associated with the | |||||
| // most common cases. | |||||
| const double cos_tol = 1e-6; | |||||
| const double abs_cos_theta = fabs(cos_theta); | |||||
| if (fabs(abs_cos_theta) <= cos_tol) | |||||
| cos_theta = 0.0; | |||||
| else if (fabs(abs_cos_theta - 0.5) <= cos_tol) | |||||
| cos_theta = (cos_theta < 0.0) ? -0.5 : 0.5; | |||||
| else if (abs_cos_theta + cos_tol >= 1.0) | |||||
| cos_theta = (cos_theta < 0.0) ? -1.0 : 1.0; | |||||
| // Quadrangle case: w = 1/2 + 1/3*cos(theta); | |||||
| const double wrange[2] = { 1.0 / 6.0, 5.0 / 6.0 }; | |||||
| if (cos_theta > -1.0 && cos_theta < 1.0) | |||||
| { | |||||
| const double w = 0.5 + cos_theta / 3.0; | |||||
| if (w > wrange[0] && w < wrange[1]) | |||||
| return w; | |||||
| if (w <= wrange[0]) | |||||
| return wrange[0]; | |||||
| if (w >= wrange[1]) | |||||
| return wrange[1]; | |||||
| } | |||||
| if (cos_theta >= 1.0) | |||||
| return wrange[1]; | |||||
| if (cos_theta <= -1.0) | |||||
| return wrange[0]; | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorCoefficient); | |||||
| } | |||||
| double ON_SubDSectorType::SectorCoefficient() const | |||||
| { | |||||
| return m_sector_coefficient; | |||||
| } | |||||
| bool ON_SubDSectorType::IsValidSectorCoefficientValue( | |||||
| double weight_value, | |||||
| bool bAllowUnsetTaggedEndCoefficient | |||||
| ) | |||||
| { | |||||
| return ((weight_value >= 0.0 && weight_value < 1.0) || (bAllowUnsetTaggedEndCoefficient && ON_SubDSectorType::UnsetSectorCoefficient == weight_value)); | |||||
| } | |||||
| bool ON_SubDSectorType::IsValidCornerSectorAngleRadians( | |||||
| double corner_sector_angle_radians | |||||
| ) | |||||
| { | |||||
| return (corner_sector_angle_radians >= 0.0 && corner_sector_angle_radians <= ON_2PI); | |||||
| } | |||||
| double ON_SubDSectorType::ClampCornerSectorAngleRadians( | |||||
| double corner_sector_angle_radians | |||||
| ) | |||||
| { | |||||
| if ( corner_sector_angle_radians < -ON_PI ) | |||||
| corner_sector_angle_radians += ON_2PI; | |||||
| else if ( corner_sector_angle_radians > 3.0*ON_PI ) | |||||
| corner_sector_angle_radians -= 2.0*ON_PI; | |||||
| const double angle_tol = 0.25*(ON_PI/180.0); // 1/4 degree. | |||||
| if (fabs(corner_sector_angle_radians - ON_PI) <= angle_tol) | |||||
| return ON_PI; | |||||
| if (fabs(corner_sector_angle_radians + ON_PI) <= angle_tol) | |||||
| return -ON_PI; | |||||
| if (fabs(corner_sector_angle_radians - ON_2PI) <= angle_tol) | |||||
| return ON_2PI; | |||||
| return corner_sector_angle_radians; | |||||
| } | |||||
| double ON_SubDSectorType::SmoothSectorCoefficient() | |||||
| { | |||||
| return ON_SubDSectorType::IgnoredSectorCoefficient; | |||||
| } | |||||
| double ON_SubDSectorType::CreaseSectorCoefficient( | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| if (sector_face_count < 1) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorCoefficient); | |||||
| double sector_theta = ON_SubDSectorType::CreaseSectorTheta(sector_face_count); | |||||
| return ON_SubDSectorType::SectorCoefficientFromTheta(sector_theta); | |||||
| } | |||||
| double ON_SubDSectorType::DartSectorCoefficient( | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| if (sector_face_count < 2) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorCoefficient); | |||||
| double sector_theta = ON_SubDSectorType::DartSectorTheta(sector_face_count); | |||||
| return ON_SubDSectorType::SectorCoefficientFromTheta(sector_theta); | |||||
| } | |||||
| double ON_SubDSectorType::CornerSectorCoefficient( | |||||
| unsigned int sector_face_count, | |||||
| double corner_sector_angle_radians | |||||
| ) | |||||
| { | |||||
| corner_sector_angle_radians = ON_SubDSectorType::ClampCornerSectorAngleRadians(corner_sector_angle_radians); | |||||
| if (ON_SubDSectorType::IsValidCornerSectorAngleRadians(corner_sector_angle_radians) | |||||
| && sector_face_count >= ON_SubDSectorType::MinimumSectorFaceCount(ON_SubD::VertexTag::Corner) | |||||
| && sector_face_count <= ON_SubDVertex::MaximumFaceCount | |||||
| ) | |||||
| { | |||||
| const double sector_theta = ON_SubDSectorType::CornerSectorThetaFromCornerAngle(sector_face_count,corner_sector_angle_radians); | |||||
| if (sector_theta >= 0.0) | |||||
| return ON_SubDSectorType::SectorCoefficientFromTheta(sector_theta); | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::ErrorSectorCoefficient); | |||||
| } | |||||
| static int CompareUnsinged(unsigned int a, unsigned int b) | |||||
| { | |||||
| if (a < b) | |||||
| return -1; | |||||
| if (a > b) | |||||
| return 1; | |||||
| return 0; | |||||
| } | |||||
| int ON_SubDSectorType::Compare(const ON_SubDSectorType* a, const ON_SubDSectorType* b) | |||||
| { | |||||
| if ( a == b ) | |||||
| return 0; | |||||
| if (nullptr == a) | |||||
| return -1; | |||||
| if (nullptr == b) | |||||
| return 1; | |||||
| int rc = 0; | |||||
| for (;;) | |||||
| { | |||||
| rc = CompareUnsinged((unsigned int)a->m_vertex_tag,(unsigned int)b->m_vertex_tag); | |||||
| if (0 != rc) | |||||
| { | |||||
| // bias towards valid tags | |||||
| if ( ON_SubD::VertexTag::Unset == b->m_vertex_tag) | |||||
| rc = -1; | |||||
| else if ( ON_SubD::VertexTag::Unset == a->m_vertex_tag) | |||||
| rc = 1; | |||||
| break; | |||||
| } | |||||
| rc = CompareUnsinged(a->m_sector_face_count,b->m_sector_face_count); | |||||
| if (0 != rc) | |||||
| { | |||||
| // bias towards valid m_sector_face_count bug small | |||||
| if ( 0 == b->m_sector_face_count) | |||||
| rc = -1; | |||||
| else if ( 0 == a->m_sector_face_count) | |||||
| rc = 1; | |||||
| break; | |||||
| } | |||||
| if (ON_SubD::VertexTag::Corner == a->m_vertex_tag) | |||||
| { | |||||
| rc = CompareUnsinged(a->m_corner_sector_angle_index, b->m_corner_sector_angle_index); | |||||
| if (0 != rc) | |||||
| break; | |||||
| } | |||||
| return 0; // equal | |||||
| } | |||||
| return rc; // not equal | |||||
| } | |||||
| void ON_SubDSectorType::SetHash() | |||||
| { | |||||
| unsigned int hash = 0; | |||||
| hash = ON_CRC32(hash,sizeof(m_vertex_tag),&m_vertex_tag); | |||||
| hash = ON_CRC32(hash,sizeof(m_sector_face_count),&m_sector_face_count); | |||||
| if ( ON_SubD::VertexTag::Corner == m_vertex_tag) | |||||
| hash = ON_CRC32(hash,sizeof(m_corner_sector_angle_index),&m_corner_sector_angle_index); | |||||
| if ( 0 == hash ) | |||||
| hash = 1; | |||||
| m_hash = hash; | |||||
| } | |||||
| unsigned int ON_SubDSectorType::SectorTypeHash() const | |||||
| { | |||||
| return m_hash; | |||||
| } | |||||
| static bool ON_SubDSectorType_IsValidFaceCount( | |||||
| ON_SubD::VertexTag vertex_tag, | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| return (sector_face_count >= ON_SubDSectorType::MinimumSectorFaceCount(vertex_tag) && sector_face_count <= ON_SubDVertex::MaximumFaceCount); | |||||
| } | |||||
| static bool ON_SubDSectorType_IsValidFaceCountForCreate( | |||||
| ON_SubD::VertexTag vertex_tag, | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| return ( 0 == sector_face_count || ON_UNSET_UINT_INDEX == sector_face_count || ON_SubDSectorType_IsValidFaceCount(vertex_tag,sector_face_count)); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::CreateSmoothSectorType( | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| const ON_SubD::VertexTag vertex_tag = ON_SubD::VertexTag::Smooth; | |||||
| if (ON_SubDSectorType_IsValidFaceCountForCreate(vertex_tag,sector_face_count)) | |||||
| { | |||||
| ON_SubDSectorType st; | |||||
| st.m_vertex_tag = vertex_tag; | |||||
| st.m_sector_face_count | |||||
| = ON_SubDSectorType_IsValidFaceCount(vertex_tag,sector_face_count) | |||||
| ? sector_face_count | |||||
| : 0; | |||||
| st.m_sector_coefficient | |||||
| = (st.m_sector_face_count>0) | |||||
| ? ON_SubDSectorType::IgnoredSectorCoefficient | |||||
| : ON_SubDSectorType::UnsetSectorCoefficient; | |||||
| st.m_sector_theta | |||||
| = (st.m_sector_face_count>0) | |||||
| ? ON_SubDSectorType::SmoothSectorTheta | |||||
| : ON_SubDSectorType::UnsetSectorTheta; | |||||
| st.SetHash(); | |||||
| return st; | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::CreateCreaseSectorType( | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| const ON_SubD::VertexTag vertex_tag = ON_SubD::VertexTag::Crease; | |||||
| if (ON_SubDSectorType_IsValidFaceCountForCreate(vertex_tag,sector_face_count)) | |||||
| { | |||||
| ON_SubDSectorType st; | |||||
| st.m_vertex_tag = vertex_tag; | |||||
| st.m_sector_face_count | |||||
| = ON_SubDSectorType_IsValidFaceCount(vertex_tag,sector_face_count) | |||||
| ? sector_face_count | |||||
| : 0; | |||||
| st.m_sector_coefficient | |||||
| = (st.m_sector_face_count>0) | |||||
| ? ON_SubDSectorType::CreaseSectorCoefficient(sector_face_count) | |||||
| : ON_SubDSectorType::UnsetSectorCoefficient; | |||||
| st.m_sector_theta | |||||
| = (st.m_sector_face_count>0) | |||||
| ? ON_SubDSectorType::CreaseSectorTheta(sector_face_count) | |||||
| : ON_SubDSectorType::UnsetSectorTheta; | |||||
| st.SetHash(); | |||||
| return st; | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::CreateDartSectorType( | |||||
| unsigned int sector_face_count | |||||
| ) | |||||
| { | |||||
| const ON_SubD::VertexTag vertex_tag = ON_SubD::VertexTag::Dart; | |||||
| if ( ON_SubDSectorType_IsValidFaceCountForCreate(vertex_tag,sector_face_count) ) | |||||
| { | |||||
| ON_SubDSectorType st; | |||||
| st.m_vertex_tag = vertex_tag; | |||||
| st.m_sector_face_count | |||||
| = ON_SubDSectorType_IsValidFaceCount(vertex_tag,sector_face_count) | |||||
| ? sector_face_count | |||||
| : 0; | |||||
| st.m_sector_coefficient | |||||
| = (st.m_sector_face_count>0) | |||||
| ? ON_SubDSectorType::DartSectorCoefficient(sector_face_count) | |||||
| : ON_SubDSectorType::UnsetSectorCoefficient; | |||||
| st.m_sector_theta | |||||
| = (st.m_sector_face_count>0) | |||||
| ? ON_SubDSectorType::DartSectorTheta(sector_face_count) | |||||
| : ON_SubDSectorType::UnsetSectorTheta; | |||||
| st.SetHash(); | |||||
| return st; | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::CreateCornerSectorType( | |||||
| unsigned int sector_face_count, | |||||
| double corner_sector_angle_radians | |||||
| ) | |||||
| { | |||||
| if (ON_SubDSectorType::UnsetCornerSectorAngle != corner_sector_angle_radians) | |||||
| { | |||||
| if (ON_UNSET_VALUE == corner_sector_angle_radians) | |||||
| { | |||||
| corner_sector_angle_radians = ON_SubDSectorType::UnsetCornerSectorAngle; | |||||
| } | |||||
| else | |||||
| { | |||||
| corner_sector_angle_radians = ON_SubDSectorType::ClampCornerSectorAngleRadians(corner_sector_angle_radians); | |||||
| } | |||||
| } | |||||
| if (ON_SubDSectorType::UnsetCornerSectorAngle == corner_sector_angle_radians | |||||
| || ON_SubDSectorType::IsValidCornerSectorAngleRadians(corner_sector_angle_radians) | |||||
| ) | |||||
| { | |||||
| const ON_SubD::VertexTag vertex_tag = ON_SubD::VertexTag::Corner; | |||||
| if (ON_SubDSectorType_IsValidFaceCountForCreate(vertex_tag,sector_face_count)) | |||||
| { | |||||
| unsigned int corner_sector_angle_index | |||||
| = (ON_SubDSectorType::UnsetCornerSectorAngle == corner_sector_angle_radians) | |||||
| ? 0 | |||||
| : ON_SubDSectorType::CornerAngleIndexFromCornerAngleRadians(corner_sector_angle_radians); | |||||
| if (corner_sector_angle_index <= ON_SubDSectorType::MaximumCornerAngleIndex) | |||||
| { | |||||
| ON_SubDSectorType st; | |||||
| st.m_vertex_tag = vertex_tag; | |||||
| st.m_sector_face_count | |||||
| = ON_SubDSectorType_IsValidFaceCount(vertex_tag,sector_face_count) | |||||
| ? sector_face_count | |||||
| : 0; | |||||
| st.m_sector_coefficient | |||||
| = (st.m_sector_face_count > 0 && ON_SubDSectorType::UnsetCornerSectorAngle != corner_sector_angle_radians) | |||||
| ? ON_SubDSectorType::CornerSectorCoefficient( sector_face_count, corner_sector_angle_radians) | |||||
| : ON_SubDSectorType::UnsetSectorCoefficient; | |||||
| st.m_sector_theta | |||||
| = (st.m_sector_face_count > 0 && ON_SubDSectorType::UnsetCornerSectorAngle != corner_sector_angle_radians) | |||||
| ? ON_SubDSectorType::CornerSectorThetaFromCornerAngle(sector_face_count, corner_sector_angle_radians) | |||||
| : ON_SubDSectorType::UnsetSectorTheta; | |||||
| st.m_corner_sector_angle_index = (unsigned char)corner_sector_angle_index; | |||||
| st.m_corner_sector_angle_radians = corner_sector_angle_radians; | |||||
| st.SetHash(); | |||||
| return st; | |||||
| } | |||||
| } | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::Create( | |||||
| ON_SubD::VertexTag vertex_tag, | |||||
| unsigned int sector_face_count, | |||||
| double corner_sector_angle_radians | |||||
| ) | |||||
| { | |||||
| if (ON_SubD::VertexTag::Unset == vertex_tag && 0 == sector_face_count) | |||||
| return ON_SubDSectorType::Empty; | |||||
| switch (vertex_tag) | |||||
| { | |||||
| case ON_SubD::VertexTag::Smooth: | |||||
| return ON_SubDSectorType::CreateSmoothSectorType(sector_face_count); | |||||
| break; | |||||
| case ON_SubD::VertexTag::Crease: | |||||
| return ON_SubDSectorType::CreateCreaseSectorType(sector_face_count); | |||||
| break; | |||||
| case ON_SubD::VertexTag::Corner: | |||||
| return ON_SubDSectorType::CreateCornerSectorType(sector_face_count,corner_sector_angle_radians); | |||||
| break; | |||||
| case ON_SubD::VertexTag::Dart: | |||||
| return ON_SubDSectorType::CreateDartSectorType(sector_face_count); | |||||
| break; | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::Create( | |||||
| const ON_SubDSectorIterator& sit | |||||
| ) | |||||
| { | |||||
| const ON_SubDVertex* center_vertex = sit.CenterVertex(); | |||||
| if (nullptr == center_vertex ) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| ON_SubDSectorIterator local_sit(sit); | |||||
| const ON_SubD::VertexTag vertex_tag = center_vertex->m_vertex_tag; | |||||
| const ON_SubDFace* face0; | |||||
| ON_SubDEdgePtr edge0ptr = ON_SubDEdgePtr::Null; | |||||
| if (ON_SubD::VertexTag::Smooth == vertex_tag) | |||||
| { | |||||
| face0 = local_sit.CurrentFace(); | |||||
| if (nullptr == face0 ) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| } | |||||
| else | |||||
| { | |||||
| face0 = nullptr; | |||||
| if (nullptr == local_sit.IncrementToCrease(-1)) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| edge0ptr = local_sit.CurrentEdgePtr(0); | |||||
| } | |||||
| const unsigned int vertex_face_count = center_vertex->m_face_count; | |||||
| unsigned int sector_face_count = 0; | |||||
| while(sector_face_count < vertex_face_count) | |||||
| { | |||||
| sector_face_count++; | |||||
| if ( sector_face_count > vertex_face_count ) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| if (face0 == local_sit.NextFace(ON_SubDSectorIterator::StopAt::AnyCrease)) | |||||
| { | |||||
| double corner_sector_angle_radians | |||||
| = (ON_SubD::VertexTag::Corner == vertex_tag) | |||||
| ? ON_SubDSectorType::CornerSectorAngleRadiansFromEdges(edge0ptr,local_sit.CurrentEdgePtr(0)) | |||||
| : 0.0; | |||||
| return ON_SubDSectorType::Create(vertex_tag,sector_face_count,corner_sector_angle_radians); | |||||
| } | |||||
| } | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::Create( | |||||
| const class ON_SubDFace* face, | |||||
| unsigned int face_vertex_index | |||||
| ) | |||||
| { | |||||
| if (nullptr == face) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| if (face_vertex_index >= face->m_edge_count) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| ON_SubDSectorIterator sit; | |||||
| sit.Initialize(face,0,face_vertex_index); | |||||
| return ON_SubDSectorType::Create(sit); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::Create( | |||||
| const class ON_SubDFace* face, | |||||
| const class ON_SubDVertex* vertex | |||||
| ) | |||||
| { | |||||
| if (nullptr == face) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| if (nullptr == vertex) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| unsigned int face_vertex_index = face->VertexIndex(vertex); | |||||
| if (face_vertex_index >= face->m_edge_count) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| return ON_SubDSectorType::Create(face,face_vertex_index); | |||||
| } | |||||
| ON_SubDSectorType ON_SubDSectorType::Create( | |||||
| const class ON_SubDEdge* edge, | |||||
| unsigned int edge_vertex_index | |||||
| ) | |||||
| { | |||||
| if (nullptr == edge) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| const ON_SubDVertex* vertex = edge->Vertex(edge_vertex_index); | |||||
| if (nullptr == vertex) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| const ON_SubDFace* face = edge->Face(0); | |||||
| if (nullptr == face) | |||||
| return ON_SUBD_RETURN_ERROR(ON_SubDSectorType::Empty); | |||||
| return ON_SubDSectorType::Create(face,vertex); | |||||
| } | |||||