Sync changes from upstream repository

This commit is contained in:
Bozo the Builder
2024-04-11 14:21:33 -07:00
parent 4ee707bee5
commit 4c9afdfe44
27 changed files with 3640 additions and 133 deletions
+2
View File
@@ -387,6 +387,7 @@ set( OPENNURBS_PLUS_HEADERS
opennurbs_plus_hiddenline.h
opennurbs_plus_hiddenline_impl.h
opennurbs_plus_idimage.h
opennurbs_plus_implicitfn.h
opennurbs_plus_massprop.h
opennurbs_plus_mesh_intersection.h
opennurbs_plus_mesh_marker.h
@@ -418,6 +419,7 @@ set( OPENNURBS_PLUS_SOURCES
opennurbs_plus_ginfinity.cpp
opennurbs_plus_hiddenline.cpp
opennurbs_plus_idimage.cpp
opennurbs_plus_implicitfn.cpp
opennurbs_plus_massprop.cpp
opennurbs_plus_memory.cpp
opennurbs_plus_memory_new.cpp
@@ -440,6 +440,10 @@
D6B06A951BC57E52000B5948 /* opennurbs_archive_manifest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6B06A941BC57E52000B5948 /* opennurbs_archive_manifest.cpp */; };
D6F232111C0086D700D1B680 /* opennurbs_file_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = D6F232101C0086D700D1B680 /* opennurbs_file_utilities.h */; };
D6F232131C0086E500D1B680 /* opennurbs_file_utilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6F232121C0086E500D1B680 /* opennurbs_file_utilities.cpp */; };
DE0517582BC6E45E00653EF9 /* opennurbs_plus_implicitfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEE5EF022BC668C5008B7FC3 /* opennurbs_plus_implicitfn.cpp */; };
DE05175B2BC6E47700653EF9 /* opennurbs_plus_implicitfn.h in Headers */ = {isa = PBXBuildFile; fileRef = DEE5EEFE2BC6689D008B7FC3 /* opennurbs_plus_implicitfn.h */; };
DEE5EF012BC6689D008B7FC3 /* opennurbs_plus_implicitfn.h in Headers */ = {isa = PBXBuildFile; fileRef = DEE5EEFE2BC6689D008B7FC3 /* opennurbs_plus_implicitfn.h */; };
DEE5EF032BC668C6008B7FC3 /* opennurbs_plus_implicitfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEE5EF022BC668C5008B7FC3 /* opennurbs_plus_implicitfn.cpp */; };
DF2447021BE96D2600FD193A /* opennurbs_md5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2446FE1BE96D2600FD193A /* opennurbs_md5.cpp */; };
DF2447031BE96D2600FD193A /* opennurbs_md5.h in Headers */ = {isa = PBXBuildFile; fileRef = DF2446FF1BE96D2600FD193A /* opennurbs_md5.h */; };
DF2447041BE96D2600FD193A /* opennurbs_sha1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2447001BE96D2600FD193A /* opennurbs_sha1.cpp */; };
@@ -1129,6 +1133,8 @@
D6B06A941BC57E52000B5948 /* opennurbs_archive_manifest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opennurbs_archive_manifest.cpp; sourceTree = "<group>"; };
D6F232101C0086D700D1B680 /* opennurbs_file_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opennurbs_file_utilities.h; sourceTree = "<group>"; };
D6F232121C0086E500D1B680 /* opennurbs_file_utilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opennurbs_file_utilities.cpp; sourceTree = "<group>"; };
DEE5EEFE2BC6689D008B7FC3 /* opennurbs_plus_implicitfn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opennurbs_plus_implicitfn.h; sourceTree = "<group>"; };
DEE5EF022BC668C5008B7FC3 /* opennurbs_plus_implicitfn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opennurbs_plus_implicitfn.cpp; sourceTree = "<group>"; };
DF2446FE1BE96D2600FD193A /* opennurbs_md5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opennurbs_md5.cpp; sourceTree = "<group>"; };
DF2446FF1BE96D2600FD193A /* opennurbs_md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opennurbs_md5.h; sourceTree = "<group>"; };
DF2447001BE96D2600FD193A /* opennurbs_sha1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opennurbs_sha1.cpp; sourceTree = "<group>"; };
@@ -1358,6 +1364,7 @@
D69DB7151A957AA10080DA91 /* opennurbs_plus_hiddenline_impl.h */,
D69DB7161A957AA10080DA91 /* opennurbs_plus_hiddenline.h */,
D6184CAB1B0F83560099E507 /* opennurbs_plus_idimage.h */,
DEE5EEFE2BC6689D008B7FC3 /* opennurbs_plus_implicitfn.h */,
DFFC2022169E4D36007E9A98 /* opennurbs_plus_massprop.h */,
1D0BCB481D7F6F2A00B5F9CD /* opennurbs_plus_mesh_intersection.h */,
E7DDF94D22958CEF00B22F2C /* opennurbs_plus_meshbooleans_impl.h */,
@@ -1576,6 +1583,7 @@
10A930DE0B2F16980022B2F6 /* opennurbs_plus_ginfinity.cpp */,
D69DB7191A957ABA0080DA91 /* opennurbs_plus_hiddenline.cpp */,
D66DBD861A67505A00125759 /* opennurbs_plus_idimage.cpp */,
DEE5EF022BC668C5008B7FC3 /* opennurbs_plus_implicitfn.cpp */,
DFFC2028169E4D6C007E9A98 /* opennurbs_plus_massprop.cpp */,
DFB8D1C92183D5DC00A0307C /* opennurbs_plus_memory_apple.cpp */,
10D7CFE609E04F0A0056FF9C /* opennurbs_plus_memory_new.cpp */,
@@ -1850,6 +1858,7 @@
369B20181CE520E000A5CB6E /* opennurbs_annotationbase.h in Headers */,
10D7D0F909E0523C0056FF9C /* opennurbs_pluginlist.h in Headers */,
10D7D0FA09E0523C0056FF9C /* opennurbs_point.h in Headers */,
DEE5EF012BC6689D008B7FC3 /* opennurbs_plus_implicitfn.h in Headers */,
10D7D0FB09E0523C0056FF9C /* opennurbs_pointcloud.h in Headers */,
10D7D0FC09E0523C0056FF9C /* opennurbs_pointgeometry.h in Headers */,
D69DB7181A957AA10080DA91 /* opennurbs_plus_hiddenline.h in Headers */,
@@ -1952,6 +1961,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
DE05175B2BC6E47700653EF9 /* opennurbs_plus_implicitfn.h in Headers */,
1D741C1621B9C5DC00AA10E5 /* opennurbs_sleeplock.h in Headers */,
99284D062800FD4B00CA9E82 /* opennurbs_render_channels.h in Headers */,
A165DED527C953020006F184 /* opennurbs_xml.h in Headers */,
@@ -2284,6 +2294,7 @@
1D496A012354FE1700BFB6AA /* opennurbs_plus_subd_facegroups.cpp in Sources */,
10D7D05E09E04F820056FF9C /* opennurbs_zlib_memory.cpp in Sources */,
10D7D05F09E04F820056FF9C /* opennurbs_zlib.cpp in Sources */,
DEE5EF032BC668C6008B7FC3 /* opennurbs_plus_implicitfn.cpp in Sources */,
1DB1AA931ED7B864007648CC /* opennurbs_plus_memory.cpp in Sources */,
10A930E50B2F16980022B2F6 /* opennurbs_plus_ctree.cpp in Sources */,
10A930E60B2F16980022B2F6 /* opennurbs_plus_ginfinity.cpp in Sources */,
@@ -2532,6 +2543,7 @@
1D496A022354FE1700BFB6AA /* opennurbs_plus_subd_facegroups.cpp in Sources */,
DF6D39021F2A72DF00D997E4 /* opennurbs_zlib_memory.cpp in Sources */,
DF6D39031F2A72DF00D997E4 /* opennurbs_zlib.cpp in Sources */,
DE0517582BC6E45E00653EF9 /* opennurbs_plus_implicitfn.cpp in Sources */,
DF6D39041F2A72DF00D997E4 /* opennurbs_plus_memory.cpp in Sources */,
DF6D39051F2A72DF00D997E4 /* opennurbs_plus_ctree.cpp in Sources */,
DF6D39061F2A72DF00D997E4 /* opennurbs_plus_ginfinity.cpp in Sources */,
+1 -1
View File
@@ -204,7 +204,7 @@ public:
/*
Returns:
Text information with rich text formatting insturctions removed.
Text information with rich text formatting instructions removed.
The result string from evaluating fields is included
Field results may be cached from previous evaluation
*/
+153 -1
View File
@@ -132,6 +132,7 @@
#endif
// ON_DEPRECATED is used to mark deprecated functions.
#if defined(ON_COMPILER_MSC)
#define ON_DEPRECATED __declspec(deprecated)
@@ -156,8 +157,40 @@
#else
#define ON_DEPRECATED
#define ON_DEPRECATED_MSG(s)
// Dale Lear 2024-March-14
// Why are ON_WIP_SDK and ON_INTERNAL_SDK defined here?
// This seems exactly the opposite of what should happen.
// I think these should be wrapped in a
// #if defined(OPENNURBS_IN_RHINO) ... #endif block
// and that change needs extensive testing.
//
// #if defined(OPENNURBS_IN_RHINO)
#define ON_WIP_SDK
#define ON_INTERNAL_SDK
// #endif
#endif
#if defined(ON_WIP_SDK)
// Functions with ON_WIP_DECL are works in progress.
// Classes with ON_WIP_CLASS are works in progress.
// Externals with ON_WIP_EXTERN_DECL are works in progress.
// These items can be seen and used in Rhino core code.
// These items are not part of the public SDK.
// These items can and will change or be removed at any time without notice.
// Any C++ code using ON_WIP_* features is likely to fail catastrophically
// at the most inconvenient time imaginable.
#define ON_WIP_CLASS ON_CLASS
#define ON_WIP_DECL ON_DECL
#define ON_WIP_EXTERN_DECL ON_EXTERN_DECL
#else
// This header is not being parsed while building core Rhino modules and plug-ins.
// Any 3rd party code linking with the public C++ Rhino SDK will be unable to link
// with the work-in-progess items. Code could
#define ON_WIP_CLASS
#define ON_WIP_DECL
#define ON_WIP_EXTERN_DECL
#endif
#if defined(PI)
@@ -314,7 +347,6 @@ extern ON_EXTERN_DECL const float ON_FLT_QNAN;
extern ON_EXTERN_DECL const float ON_FLT_PINF;
extern ON_EXTERN_DECL const float ON_FLT_NINF;
/*
The ON_PTR_SEMAPHORE* values are used in rare cases
when a special signal must be passed as a pointer argument.
@@ -387,6 +419,126 @@ ON__UINT64 ON_NextContentSerialNumber();
ON_END_EXTERNC
#if defined(ON_CPLUSPLUS)
class ON_WIP_CLASS ON_DBL
{
public:
/// <summary>
/// ON_DBL::Nan is an IEEE quiet nan (not a number).
/// </summary>
static const double Nan;
/// <summary>
/// ON_DBL::PositiveInfinity is IEEE +infinity.
/// </summary>
static const double PositiveInfinity;
/// <summary>
/// ON_DBL::NegativeInfinity is IEEE -infinity.
/// </summary>
static const double NegativeInfinity;
/// <summary>
/// ON_DBL::PositiveMax = +1.7976931348623158e+308
/// </summary>
static const double PositiveMax;
/// <summary>
/// ON_DBL::NegativeMax = -1.7976931348623158e+308
/// </summary>
static const double NegativeMax;
/// <summary>
/// ON_DBL::PositiveMax = +2.22507385850720200e-308
/// </summary>
static const double PositiveMin;
/// <summary>
/// ON_DBL::NegativeMax = -2.22507385850720200e-308
/// </summary>
static const double NegativeMin;
/// <summary>
/// ON_DBL::Unset = -1.23432101234321e+308
/// </summary>
static const double Unset;
/// <summary>
/// ON_DBL::PositiveUnset = +1.23432101234321e+308
/// </summary>
static const double PositiveUnset;
/// <param name="x"></param>
/// <returns>True if x is any type of nan (signaling or quiet).</returns>
static bool IsNan(double x);
/// <param name="x"></param>
/// <returns>True if x is any type of infinity (positive, negative, projective).</returns>
static bool IsInfinity(double x);
static bool IsPositiveInfinity(double x);
static bool IsNegativeInfinity(double x);
/// <param name="x"></param>
/// <returns>
/// If x &gt; 0, then +1 is returned.
/// If x &lt; 0, then -1 is returned.
/// Otherwise 0 is returned.
/// </returns>
static int Sign(double x);
/// <summary>
/// All nans, +infinity, -infinity,
/// x &lt;= than ON_DBL::Unset and
/// x &gt;= ON_DBL::PositiveUnset
/// are considered invalid because using them in typical calculations
/// almost always returns useless results.
/// </summary>
/// <param name="x">
/// value to test.
/// </param>
/// <returns>
/// (ON_DBL::Unset &lt; x &amp;&amp; x &lt; ON_DBL::PositiveUnset)
/// </returns>
static bool IsValid(double x);
/// <param name="x"></param>
/// <returns>True if x is not a nan..</returns>
static bool IsNotNan(double x);
static bool IsUnset(double x);
/// <summary>
/// Well ordered compare that handles nans and sorts them to the end.
/// ON_DBL::CompareValue(nan, nan) = 0;
/// ON_DBL::CompareValue(non_nan, nan) = -1;
/// ON_DBL::CompareValue(nan, non_nan) = +1;
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>
/// -1 if lhs &lt; rhs or IsNotNan(lhs) and IsNan(rhs).
/// 0 if lhs == rhs or IsNan(lhs) &amp;&amp; IsNan(rhs).
/// +1 if lhs &gt; rhs or IsNotNan(lhs) &amp;&amp; IsNan(rhs).
/// </returns>
static int CompareValue(double lhs, double rhs);
/// <summary>
/// Well ordered compare that handles nullpt and nans and sorts them
/// to the end.
/// ON_DBL::Compare(nullptr, nullptr) = 0;
/// ON_DBL::Compare(not nullptr, nullptr) = -1;
/// ON_DBL::Compare(nullptr, not nullptr) = +1;
/// ON_DBL::Compare(not nullptr, not nullptr) = ON_DBL::CompareValue(*lhs,*rhs);
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns></returns>
static int Compare(const double* lhs, const double* rhs);
};
ON_DECL
bool ON_IsNullPtr(const void* ptr);
+3 -1
View File
@@ -82,7 +82,9 @@ bool ON_Line::Create( const ON_2dPoint from_pt, const ON_2dPoint to_pt )
bool ON_Line::IsValid() const
{
return (from != to && from.IsValid() && to.IsValid());
bool from_rc = ON_CV_COORDINATE_IS_VALID(from.x) && ON_CV_COORDINATE_IS_VALID(from.y) && ON_CV_COORDINATE_IS_VALID(from.z);
bool to_rc = ON_CV_COORDINATE_IS_VALID(to.x) && ON_CV_COORDINATE_IS_VALID(to.y) && ON_CV_COORDINATE_IS_VALID(to.z);
return (from != to && true == from_rc && true == to_rc);
}
double ON_Line::Length() const
+12 -1
View File
@@ -186,7 +186,18 @@ ON_LineCurve::SwapCoordinates( int i, int j )
bool ON_LineCurve::IsValid( ON_TextLog* text_log ) const
{
return ( m_t[0] < m_t[1] && !m_line.from.IsCoincident(m_line.to) ) ? true : false;
bool rc = true;
if (m_t[0] > m_t[1])
{
if (text_log) text_log->Print(L"Line domain not valid.");
rc = false;
}
if (m_line.from.IsCoincident(m_line.to))
{
if (text_log) text_log->Print(L"Line points are coincident.");
rc = false;
}
return rc;
}
void ON_LineCurve::Dump( ON_TextLog& dump ) const
+97
View File
@@ -2314,6 +2314,87 @@ bool ON_Texture::IsWcsBoxProjected() const
return (m_mapping_channel_id == (unsigned int)MAPPING_CHANNEL::wcs_box_channel);
}
ON_3dPoint ON_Texture::WcsBoxMapping(const ON_3dPoint& pt, const ON_3dVector& n)
{
// This code is moved here from CRhRdkTexture::WcsBoxMapping
int side0 = 0;
const ON_3dPoint& rst(pt);
// set side0 = side closest to the point
int side1 = (std::abs(rst.x) >= std::abs(rst.y)) ? 0 : 1;
if (std::abs(rst.z) > std::abs(((double*)&rst.x)[side1]))
side1 = 2;
double t1 = (&rst.x)[side1];
if (t1 < 0.0)
side0 = 2 * side1 + 1;
else
side0 = 2 * side1 + 2;
side1 = (std::abs(n.x) >= std::abs(n.y)) ? 0 : 1;
if (std::abs(n.z) > std::abs((&n.x)[side1]))
{
side1 = 2;
}
t1 = n[side1];
if (0.0 != t1)
{
if (t1 < 0.0)
side0 = 2 * side1 + 1;
else
if (t1 > 0.0)
side0 = 2 * side1 + 2;
}
// side flag
// 1 = left side (x=-1)
// 2 = right side (x=+1)
// 3 = back side (y=-1)
// 4 = front side (y=+1)
// 5 = bottom side (z=-1)
// 6 = top side (z=+1)
ON_3dPoint v;
switch (side0)
{
case 1:
v.x = -pt.y;
v.y = pt.z;
v.z = pt.x;
break;
case 2:
v.x = pt.y;
v.y = pt.z;
v.z = pt.x;
break;
case 3:
v.x = pt.x;
v.y = pt.z;
v.z = pt.y;
break;
case 4:
v.x = -pt.x;
v.y = pt.z;
v.z = pt.y;
break;
case 5:
v.x = -pt.x;
v.y = pt.y;
v.z = pt.z;
break;
case 6:
default:
v.x = pt.x;
v.y = pt.y;
v.z = pt.z;
break;
}
return v;
}
ON_Texture::TYPE ON_Texture::TypeFromUnsigned(unsigned int type_as_unsigned)
{
switch (type_as_unsigned)
@@ -2622,6 +2703,8 @@ const ON_wString ON_TextureMapping::TypeToString(ON_TextureMapping::TYPE texture
ON_ENUM_TO_WIDE_STRING_CASE(ON_TextureMapping::TYPE::brep_mapping_primitive);
ON_ENUM_TO_WIDE_STRING_CASE(ON_TextureMapping::TYPE::ocs_mapping);
ON_ENUM_TO_WIDE_STRING_CASE(ON_TextureMapping::TYPE::false_colors);
ON_ENUM_TO_WIDE_STRING_CASE(ON_TextureMapping::TYPE::wcs_projection);
ON_ENUM_TO_WIDE_STRING_CASE(ON_TextureMapping::TYPE::wcsbox_projection);
}
ON_ERROR("Invalid texture_mapping_type value.");
@@ -3687,6 +3770,16 @@ int ON_TextureMapping::Evaluate(
rc = 0;
break;
case ON_TextureMapping::TYPE::wcs_projection:
*T = m_Pxyz * P;
rc = 1;
break;
case ON_TextureMapping::TYPE::wcsbox_projection:
*T = ON_Texture::WcsBoxMapping(m_Pxyz * P, m_Nxyz * N);
rc = 1;
break;
default:
rc = EvaluatePlaneMapping(P,N,T);
break;
@@ -3927,6 +4020,9 @@ bool ON_TextureMapping::RequiresVertexNormals() const
if(m_type == ON_TextureMapping::TYPE::box_mapping)
return true;
if(m_type == ON_TextureMapping::TYPE::cylinder_mapping && m_bCapped)
return true;
if (m_type == ON_TextureMapping::TYPE::wcsbox_projection)
return true;
return false;
@@ -4410,6 +4506,7 @@ bool ON_TextureMapping::GetTextureCoordinates(
|| ON_TextureMapping::TYPE::box_mapping == m_type
|| ON_TextureMapping::TYPE::cylinder_mapping == m_type
|| ON_TextureMapping::TYPE::mesh_mapping_primitive == m_type
|| ON_TextureMapping::TYPE::wcsbox_projection == m_type
)
)
{
+4
View File
@@ -469,6 +469,10 @@ private:
#define ON_IS_INFINITE_FLOAT(x) ((x) > 3.402823466e+38F || (x) < -3.402823466e+38F)
#define ON_IS_VALID(x) ((x) > ON_UNSET_VALUE && (x) < ON_UNSET_POSITIVE_VALUE)
// March 27, 2024 - Tim
// Fix for https://mcneel.myjetbrains.com/youtrack/issue/RH-81184
// The vertexes were crap just not quite ON_UNSET_VALUE crap
#define ON_CV_COORDINATE_IS_VALID(x) (-1.0e307 < x && x < 1.0e307)
#define ON_IS_VALID_FLOAT(x) ((x) > ON_UNSET_FLOAT && (x) < ON_UNSET_POSITIVE_FLOAT)
#define ON_IS_UNSET_DOUBLE(x) (ON_UNSET_VALUE == (x) || ON_UNSET_POSITIVE_VALUE == (x))
#define ON_IS_UNSET_FLOAT(x) (ON_UNSET_FLOAT == (x) || ON_UNSET_POSITIVE_FLOAT == (x))
+621 -14
View File
@@ -12,6 +12,8 @@
////////////////////////////////////////////////////////////////
#include "opennurbs.h"
#include <functional>
#include <unordered_map>
#if !defined(ON_COMPILING_OPENNURBS)
// This check is included in all opennurbs source .c and .cpp files to insure
@@ -4309,6 +4311,402 @@ bool ON_Mesh::HasCachedTextureCoordinates() const
return false;
}
// Note: We are exporting this function for use in CRhinoObject::SetCachedTextureCoordinatesFromPlugIn
ON_DECL bool ON_Mesh_Private_CacheMappingChannel(std::function<ON_TextureMapping(const ON_MappingChannel*)> get_mapping_func, const ON_MappingChannel* pMC, const ON_SimpleArray<ON_TextureMapping::TYPE>& mappings_to_cache, const int mapping_channel_id, std::unordered_map<unsigned int, ON_TextureMapping>& mapInOut)
{
const bool cache_all = (mappings_to_cache.Count() == 0);
if (nullptr == pMC)
{
const ON_TextureMapping& srfp_mapping = ON_TextureMapping::SurfaceParameterTextureMapping;
if(cache_all || mappings_to_cache.Search(srfp_mapping.m_type) >= 0)
{
// If the mapping channel is null, then we can assume that the textures implicitly
// reference the surface parameter mapping.
// This is done according to the documentation for ON_Texture::m_mapping_channel_id.
mapInOut[mapping_channel_id] = srfp_mapping;
}
}
else
{
ON_TextureMapping mapping = get_mapping_func(pMC);
if (mapping.m_type != ON_TextureMapping::TYPE::no_mapping)
{
// How to handle ON_TextureMapping::TYPE::ocs_mapping
// and ON_TextureMapping::TYPE::false_colors ?
if(cache_all || mappings_to_cache.Search(mapping.m_type) >= 0)
{
mapInOut[mapping_channel_id] = mapping;
}
}
}
return true;
}
// Note: We are exporting this function for use in CRhinoObject::SetCachedTextureCoordinatesFromPlugIn
ON_DECL bool ON_Mesh_Private_AddPerVertexMappingChannels(std::function<ON_TextureMapping(const ON_MappingChannel*)> get_texture_mapping_func, const ON_MappingRef* mapping_ref, const ON_SimpleArray<ON_TextureMapping::TYPE>& mappings_to_cache, const ON_Material& material, std::unordered_map<unsigned int, ON_TextureMapping>& mappings)
{
for (int i = 0; i < material.m_textures.Count(); i++)
{
if (material.m_textures[i].m_bOn)
{
// Get mapping channel id and check if mapping already is in the map
const unsigned int mapping_channel_id = material.m_textures[i].m_mapping_channel_id;
if (mappings.find(mapping_channel_id) == mappings.end())
{
const ON_MappingChannel* mapping_channel = nullptr;
if (mapping_ref)
{
// Get texture mapping and add it to the map
mapping_channel = mapping_ref->MappingChannel(mapping_channel_id);
if (mapping_channel == nullptr)
{
// If a mapping channel is not found using 'mapping_channel_id', then try with a mapping channel id of 1.
// This is done according to the documentation for ON_Texture::m_mapping_channel_id.
mapping_channel = mapping_ref->MappingChannel(1);
}
}
if (!ON_Mesh_Private_CacheMappingChannel(get_texture_mapping_func, mapping_channel, mappings_to_cache, mapping_channel_id, mappings))
return false;
}
}
}
// If we didn't cache any texture coordinates above, but we have a material with anisotropy,
// which requires tangents, which in turn requires texture coordinates, then we cache
// the texture coordinates from mapping channel 1.
if (mappings.size() == 0)
{
if (material.IsPhysicallyBased() && material.PhysicallyBased()->Anisotropic() > 0.0)
{
const ON_MappingChannel* mapping_channel = mapping_ref ? mapping_ref->MappingChannel(1) : nullptr;
if (!ON_Mesh_Private_CacheMappingChannel(get_texture_mapping_func, mapping_channel, mappings_to_cache, 1, mappings))
return false;
}
}
return true;
}
// Note: We are exporting this function for use in CRhinoObject::SetCachedTextureCoordinatesFromPlugIn
ON_DECL bool ON_Mesh_Private_SetCachedTextureCoordinatesFromMaterial(ON_SimpleArray<const ON_Mesh*>& meshes, std::unordered_map<unsigned int, ON_TextureMapping>& per_vertex_channels, const ON_MappingRef* mapping_ref, bool perform_cleanup, std::shared_ptr<class CRhVboData>* vbo_data)
{
ON_ClassArray<ON_SimpleArray<int>> indices_to_preserve;
indices_to_preserve.SetCapacity(meshes.Count());
indices_to_preserve.SetCount(meshes.Count());
// Set cached texture coordinates for each mapping on the map for every render mesh
for (auto pvcit = per_vertex_channels.begin(); pvcit != per_vertex_channels.end(); pvcit++)
{
const unsigned int mapping_channel_id = pvcit->first;
const ON_TextureMapping& mapping = pvcit->second;
// Get object mapping transformation
const ON_MappingChannel* pMC = mapping_ref ? mapping_ref->MappingChannel(mapping_channel_id) : nullptr;
const ON_Xform* pObjectXform = (pMC == nullptr || pMC->m_object_xform.IsIdentity() || pMC->m_object_xform.IsZero()) ? nullptr : &pMC->m_object_xform;
// Set cached texture coordinates for each of the render meshes
for (int mi = 0; mi < meshes.Count(); mi++)
{
// Const cast render mesh and set texture coordinates
ON_Mesh* pMesh = const_cast<ON_Mesh*>(meshes[mi]);
if (nullptr != pMesh)
{
bool has_matching_cached_tcs = false;
for (int i = 0; i < pMesh->m_TC.Count(); i++)
{
if (pMesh->VertexCount() == pMesh->m_TC[i].m_T.Count() && mapping.HasMatchingTextureCoordinates(pMesh->m_TC[i].m_tag, pObjectXform))
{
indices_to_preserve[mi].Append(i);
has_matching_cached_tcs = true;
break;
}
}
if (!has_matching_cached_tcs)
{
indices_to_preserve[mi].Append(pMesh->m_TC.Count());
const ON_TextureCoordinates* pTC = pMesh->SetCachedTextureCoordinatesEx(mapping, pObjectXform, true, false);
if(pTC && vbo_data)
vbo_data->reset();
}
}
}
}
if(perform_cleanup)
{
for (int mi = 0; mi < meshes.Count(); mi++)
{
ON_Mesh* pMesh = const_cast<ON_Mesh*>(meshes[mi]);
if (nullptr != pMesh)
{
const int tc_count = pMesh->m_TC.Count();
if (tc_count > per_vertex_channels.size())
{
int wcs_mapping_count = 0;
int wcs_box_mapping_count = 0;
ON_SimpleArray<int> indices_to_remove;
for (int tci = tc_count - 1; tci >= 0; tci--)
{
if (indices_to_preserve[mi].Search(tci) == -1)
{
ON_TextureMapping::TYPE mapping_type = pMesh->m_TC[tci].m_tag.m_mapping_type;
bool remove_index = true;
// Only clean up WCS and WCS Box mappings if there exist more recent versions
// in the array. They are considered more recent if they appear later in the array.
if(mapping_type == ON_TextureMapping::TYPE::wcs_projection && wcs_mapping_count++ == 0)
{
remove_index = false; // Don't remove first one we find
}
else if(mapping_type == ON_TextureMapping::TYPE::wcsbox_projection && wcs_box_mapping_count++ == 0)
{
remove_index = false; // Don't remove first one we find
}
if(remove_index)
indices_to_remove.Append(tci);
}
}
for (int tci = indices_to_remove.Count() - 1; tci >= 0; tci--)
pMesh->m_TC.Remove(indices_to_remove[tci]);
if(vbo_data && indices_to_remove.Count() > 0)
vbo_data->reset();
}
}
}
}
return true;
}
static ON_UUID WcsMappingId(const ON_Xform& ocsTransform, bool bBox)
{
// {47D62129-341E-4E3D-BF11-9C051AF4ED98}
static const ON_UUID uuidBaseWcs =
{ 0x47d62129, 0x341e, 0x4e3d, { 0xbf, 0x11, 0x9c, 0x5, 0x1a, 0xf4, 0xed, 0x98 } };
// {4DC9AA78-9617-46FB-923F-3E65E14182FC}
static const ON_UUID uuidBaseWcsBox =
{ 0x4dc9aa78, 0x9617, 0x46fb, { 0x92, 0x3f, 0x3e, 0x65, 0xe1, 0x41, 0x82, 0xfc } };
ON_UUID uuid = bBox ? uuidBaseWcsBox : uuidBaseWcs;
uuid.Data1 = ocsTransform.CRC32(uuid.Data1);
return uuid;
}
static ON_Xform GetOcsTransform(std::function<ON_TextureMapping(const ON_MappingChannel*)> get_mapping_func, const ON_MappingRef* mapping_ref)
{
ON_Xform ocsTransform = ON_Xform::IdentityTransformation;
if (nullptr != mapping_ref)
{
const ON_MappingChannel* pMC = mapping_ref->MappingChannel(ON_ObjectRenderingAttributes::OCSMappingChannelId());
if (nullptr != pMC)
{
const ON_TextureMapping tm = get_mapping_func(pMC);
ON_Xform inverseObjectTransform = pMC->m_object_xform;
if (inverseObjectTransform.Invert())
{
ocsTransform = tm.m_Pxyz * inverseObjectTransform;
}
else
{
ocsTransform = tm.m_Pxyz;
}
}
}
return ocsTransform;
}
static void CacheWcsProjections(const ON_Mesh& mesh, std::function<ON_TextureMapping(const ON_MappingChannel*)> get_mapping_func, const ON_Material& material, const ON_MappingRef* mapping_ref)
{
bool bWcsProjectionNeeded = false;
bool bWcsBoxProjectionNeeded = false;
for (int ti = 0; ti < material.m_textures.Count(); ti++)
{
if (material.m_textures[ti].IsWcsProjected())
bWcsProjectionNeeded = true;
if (material.m_textures[ti].IsWcsBoxProjected())
bWcsBoxProjectionNeeded = true;
}
if (bWcsProjectionNeeded)
{
const ON_Xform ocsTransform = GetOcsTransform(get_mapping_func, mapping_ref);
const ON_UUID uuidWcsMapping = WcsMappingId(ocsTransform, false);
ON_TextureMapping wcsMapping;
wcsMapping.m_type = ON_TextureMapping::TYPE::wcs_projection;
wcsMapping.SetId(uuidWcsMapping);
wcsMapping.m_Pxyz = ocsTransform;
if (!wcsMapping.HasMatchingCachedTextureCoordinates(mesh))
{
ON_TextureCoordinates& tcs = const_cast<ON_Mesh*>(&mesh)->m_TC.AppendNew();
wcsMapping.GetTextureCoordinates(mesh, tcs.m_T);
tcs.m_tag.Set(wcsMapping);
tcs.m_tag.m_mesh_xform = ON_Xform::ZeroTransformation;
tcs.m_dim = 2;
return;
}
}
if (bWcsBoxProjectionNeeded)
{
const ON_Xform ocsTransform = GetOcsTransform(get_mapping_func, mapping_ref);
const ON_UUID uuidWcsBoxMapping = WcsMappingId(ocsTransform, true);
ON_TextureMapping wcsBoxMapping;
wcsBoxMapping.m_type = ON_TextureMapping::TYPE::wcsbox_projection;
wcsBoxMapping.SetId(uuidWcsBoxMapping);
wcsBoxMapping.m_Pxyz = ocsTransform;
wcsBoxMapping.m_Pxyz.GetSurfaceNormalXform(wcsBoxMapping.m_Nxyz);
if (!wcsBoxMapping.HasMatchingCachedTextureCoordinates(mesh))
{
ON_TextureCoordinates& tcs = const_cast<ON_Mesh*>(&mesh)->m_TC.AppendNew();
wcsBoxMapping.GetTextureCoordinates(mesh, tcs.m_T);
tcs.m_tag.Set(wcsBoxMapping);
tcs.m_tag.m_mesh_xform = ON_Xform::ZeroTransformation;
tcs.m_dim = 2;
return;
}
}
}
bool SetCachedTextureCoordinatesFromMaterial(const ON_Mesh& mesh, std::function<ON_TextureMapping(const ON_MappingChannel*)> get_mapping_func, const ON_Material& material, const ON_MappingRef* mapping_ref, const ON_SimpleArray<ON_TextureMapping::TYPE>& mappings_to_cache, bool perform_cleanup)
{
// Create a map of all texture mappings that require per-vertex texture coordinates
std::unordered_map<unsigned int, ON_TextureMapping> per_vertex_channels;
if (!ON_Mesh_Private_AddPerVertexMappingChannels(get_mapping_func, mapping_ref, mappings_to_cache, material, per_vertex_channels))
return false;
ON_SimpleArray<const ON_Mesh*> meshes;
meshes.Append(&mesh);
CacheWcsProjections(mesh, get_mapping_func, material, mapping_ref);
return ON_Mesh_Private_SetCachedTextureCoordinatesFromMaterial(meshes, per_vertex_channels, mapping_ref, perform_cleanup, nullptr);
}
bool ON_Mesh::SetCachedTextureCoordinatesFromMaterial(const ONX_Model& onx_model, const ON_Material& material, const ON_MappingRef* mapping_ref) const
{
auto get_mapping_func = [&onx_model](const ON_MappingChannel* pMC)
{
ON_TextureMapping mapping = ON_TextureMapping::SurfaceParameterTextureMapping;
ONX_ModelComponentIterator it(onx_model, ON_ModelComponent::Type::TextureMapping);
for ( ON_ModelComponentReference cr = it.FirstComponentReference(); false == cr.IsEmpty(); cr = it.NextComponentReference())
{
const ON_TextureMapping* texture_mapping = ON_TextureMapping::Cast(cr.ModelComponent());
if (nullptr == texture_mapping)
continue;
if(ON_UuidCompare(&texture_mapping->Id(), &pMC->m_mapping_id) == 0)
{
mapping = *texture_mapping;
break;
}
}
return mapping;
};
ON_SimpleArray<ON_TextureMapping::TYPE> mappings_to_cache;
return ::SetCachedTextureCoordinatesFromMaterial(*this, get_mapping_func, material, mapping_ref, mappings_to_cache, false);
}
static const ON_TextureCoordinates* Internal_GetCachedTextureCoordinates(const ON_Mesh& mesh, std::function<ON_TextureMapping(const ON_MappingChannel*)> get_mapping_func, const ON_Texture& texture, const ON_MappingRef* mapping_ref)
{
if (texture.IsWcsProjected() || texture.IsWcsBoxProjected())
{
const ON_Xform ocsTransform = GetOcsTransform(get_mapping_func, mapping_ref);
const ON_UUID mappingId = WcsMappingId(ocsTransform, texture.IsWcsBoxProjected());
const ON_TextureCoordinates* pTCs = mesh.CachedTextureCoordinates(mappingId);
return pTCs;
}
else if (texture.m_mapping_channel_id >= 0)
{
if (nullptr != mapping_ref)
{
const ON_MappingChannel* pMC = mapping_ref->MappingChannel(texture.m_mapping_channel_id);
if (nullptr != pMC)
{
const ON_TextureCoordinates* pTCs = mesh.CachedTextureCoordinates(pMC->m_mapping_id);
// Probably best to not const cast and start setting the texture coordinates.
// All previously returned pointers to the m_TC should be kept valid.
//if (nullptr == pTCs)
//{
// ON_TextureMapping mapping = get_mapping_func(pMC);
// pTCs = const_cast<ON_Mesh*>(this)->SetCachedTextureCoordinatesEx(mapping, &pMC->m_object_xform, true, false);
//}
return pTCs;
}
}
else
{
// Return surface parameter mapping if there is nothing else
const ON_TextureCoordinates* pTCs = mesh.CachedTextureCoordinates(ON_TextureMapping::SurfaceParameterTextureMappingId);
return pTCs;
}
}
return nullptr;
}
const ON_TextureCoordinates* ON_Mesh::GetCachedTextureCoordinates(const ONX_Model& onx_model, const ON_Texture& texture, const ON_MappingRef* mapping_ref) const
{
auto get_mapping_func = [&onx_model](const ON_MappingChannel* pMC)
{
ON_TextureMapping mapping = ON_TextureMapping::SurfaceParameterTextureMapping;
ONX_ModelComponentIterator it(onx_model, ON_ModelComponent::Type::TextureMapping);
for (ON_ModelComponentReference cr = it.FirstComponentReference(); false == cr.IsEmpty(); cr = it.NextComponentReference())
{
const ON_TextureMapping* texture_mapping = ON_TextureMapping::Cast(cr.ModelComponent());
if (nullptr == texture_mapping)
continue;
if (ON_UuidCompare(&texture_mapping->Id(), &pMC->m_mapping_id) == 0)
{
mapping = *texture_mapping;
break;
}
}
return mapping;
};
return ::Internal_GetCachedTextureCoordinates(*this, get_mapping_func, texture, mapping_ref);
}
static GET_TEXMAP_FROM_DOCUMENT pFnGetTexMapFromDocument = nullptr;
// Note: We are exporting this function for use in CRhinoObject::SetCachedTextureCoordinatesFromPlugIn
ON_DECL std::function<ON_TextureMapping(const ON_MappingChannel*)> ON_Mesh_Private_GetTextureMappingFromDocumentLambda(const CRhinoDoc& rhino_doc)
{
return [&rhino_doc](const ON_MappingChannel* pMC)
{
if ( pFnGetTexMapFromDocument )
{
// Call into Rhino
return pFnGetTexMapFromDocument(rhino_doc, pMC);
}
else
{
return ON_TextureMapping::SurfaceParameterTextureMapping;
}
};
}
const ON_TextureCoordinates*
ON_Mesh::CachedTextureCoordinates( const ON_UUID& mapping_id ) const
{
@@ -4393,6 +4791,18 @@ bool ON_Mesh::SetCurvatureColorAnalysisColors(
ON_SurfaceCurvatureColorMapping kappa_colors
)
{
if (false == this->HasPrincipalCurvatures())
{
#if 0
// will be added April/May of 2024
if (kappa_colors.IsSet())
{
this->ComputeVertexPrincipalCurvatures(ON_Mesh::CurvatureSettingMethod::DiscreteDefault, false);
bLazy = false; // m_C[] is probably out of date even if the mapping tag is set.
}
#endif
return this->HasPrincipalCurvatures();
}
const bool bSetColors = kappa_colors.IsSet() && this->HasPrincipalCurvatures();
const ON_MappingTag Ctag = kappa_colors.ColorMappingTag();
if (bSetColors && bLazy && HasVertexColors() && this->m_Ctag == Ctag)
@@ -6274,6 +6684,40 @@ void ON_Mesh::Append(int mesh_count, const ON_Mesh* const* meshes)
}
}
bool bAllowNewCachedTCs = (vcount0 == 0);
for (mi = 0; mi < mesh_count; mi++)
{
m = meshes[mi];
if (0 == m)
continue;
if (bAllowNewCachedTCs)
{
m_TC = m->m_TC;
bAllowNewCachedTCs = false;
}
else
{
for (int tci = 0; tci < m_TC.Count(); tci++)
{
bool bKeep = false;
for (int tcimi = 0; tcimi < m->m_TC.Count(); tcimi++)
{
if (m_TC[tci].m_tag == m->m_TC[tcimi].m_tag)
{
m_TC[tci].m_T.Append(m->m_TC[tcimi].m_T.Count(), m->m_TC[tcimi].m_T.Array());
bKeep = true;
}
}
if (!bKeep)
{
m_TC.Remove(tci);
tci--;
}
}
}
}
SetClosed(-99);
SetSolidOrientation(-99);
InvalidateBoundingBoxes();
@@ -8163,6 +8607,10 @@ bool ON_Mesh::ConvertQuadsToTriangles()
double ON_TriangleArea3d(ON_3dPoint A, ON_3dPoint B, ON_3dPoint C)
{
// MF, March 18 24:
// a faster and numerically more robust version would be William Kahan's version of Heron's formula,
// see "Accuracy and Stability of Numerical Algorithms", N. Higham.
// speed this up if needed
return 0.5*ON_CrossProduct(B-A,C-A).Length();
}
@@ -8713,6 +9161,19 @@ bool ON_Mesh::ComputeVertexNormals()
return rc;
}
#if 0
// Will be added April/may of 2024
bool ON_Mesh::ComputeVertexPrincipalCurvatures(
ON_Mesh::CurvatureSettingMethod method,
bool bLazy
)
{
// NOT INCLUDED IN PUBLIC OPENNURBS
return false;
}
#endif
bool ON_Mesh::NormalizeTextureCoordinates()
{
ON_2fPoint t0;//, t1;
@@ -9352,6 +9813,123 @@ const ON_SurfaceCurvature ON_SurfaceCurvature::CreateFromPrincipalCurvatures(
return k;
}
const ON_SurfaceCurvature ON_SurfaceCurvature::CreateFromGaussianAndMeanCurvatures(
double gaussian_curvature,
double mean_curvature
)
{
if (ON_IS_VALID(gaussian_curvature) && ON_IS_VALID(mean_curvature))
{
const double r = mean_curvature * mean_curvature - gaussian_curvature;
if (r >= 0.0)
{
const double k1 = mean_curvature + sqrt(r);
const double k2 = mean_curvature - sqrt(r);
return ON_SurfaceCurvature::CreateFromPrincipalCurvatures(k1, k2);
}
else if (r < 0.0)
{
// Dale Lear - March 2024 - RH-81078
// We end up here when r < 0 and gaussian_curvature > 0.
// We are in one of 3 cases:
// 1) We are dealing with a very small and noisy negative r.
// 2) We are dealing with esimates of mean and gaussian.
// 3) Something else that is uncommon.
// In case 1, mean*mean and gaussian are both larger relative to fabs(r).
// We don't know which input value is more precise, but people typically
// care more about gaussian so we use k1=k2=sign(mean)*sqrt(gaussian) instead of
// k1 = k2 = mean.
//
// In case 2, the value of gaussian is typically more important than the value
// of mean, because people are often testing to see how a mesh can be flattened.
//
// So, we assume we are at or near an umbilic (k1=k2) and set them so that
// k1*k2 = gaussian_curvature and sign(k1+k2) = sign(mean).
// These choices preserve gaussian minimize fabs( 0.5*(k1+k2) - mean_curvature).
const double k1 = ((mean_curvature < 0.0) ? -1.0 : 1.0) * sqrt(gaussian_curvature);
const double k2 = k1;
return ON_SurfaceCurvature::CreateFromPrincipalCurvatures(k1, k2);
// put a breakpoint on the line above to dectect when we are in
// this unusual situation.
}
}
if (ON_IS_VALID(gaussian_curvature))
{
// It can happen that only Gaussian was estimated, whether on purpose or not.
const double k1 = sqrt(fabs(gaussian_curvature));
const double k2 = ((gaussian_curvature < 0.0) ? -1.0 : 1.0) * k1;
return ON_SurfaceCurvature::CreateFromPrincipalCurvatures(k1, k2);
}
if (ON_IS_VALID(mean_curvature))
{
// It can also happen that only mean was estimated, whether on purpose or not.
return ON_SurfaceCurvature::CreateFromPrincipalCurvatures(mean_curvature, mean_curvature);
}
return ON_SurfaceCurvature::Nan;
}
const ON_SurfaceCurvature ON_SurfaceCurvature::FlipSurfaceOrientation() const
{
// negate and reverse the order of (this->k1, this->k2)
return ON_SurfaceCurvature::CreateFromPrincipalCurvatures(-k2, -k1);
}
int ON_SurfaceCurvature::Compare(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
if (lhs.IsNan())
return rhs.IsNan() ? 0 : 1; // nans sort last
if (rhs.IsNan())
return -1; // nans sort last
if (lhs.k1 < rhs.k1)
return -1;
if (lhs.k1 > rhs.k1)
return 1;
if (lhs.k2 < rhs.k2)
return -1;
if (lhs.k2 > rhs.k2)
return 1;
return 0;
}
int ON_SurfaceCurvature::CompareMaximumAndMinimumPrincipalCurvatures(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
const int rc = ON_SurfaceCurvature::CompareMaximumPrincipalCurvature(lhs, rhs);
return 0 != rc ? rc : ON_SurfaceCurvature::CompareMinimumPrincipalCurvature(lhs, rhs);
}
int ON_SurfaceCurvature::CompareMaximumPrincipalCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
return ON_DBL::CompareValue(lhs.MaximumPrincipalCurvature(), rhs.MaximumPrincipalCurvature());
}
int ON_SurfaceCurvature::CompareMinimumPrincipalCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
return ON_DBL::CompareValue(lhs.MinimumPrincipalCurvature(), rhs.MinimumPrincipalCurvature());
}
int ON_SurfaceCurvature::CompareGaussianCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
return ON_DBL::CompareValue(lhs.GaussianCurvature(), rhs.GaussianCurvature());
}
int ON_SurfaceCurvature::CompareMeanCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
return ON_DBL::CompareValue(lhs.MeanCurvature(), rhs.MeanCurvature());
}
int ON_SurfaceCurvature::CompareMaximumRadius(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
return ON_DBL::CompareValue(lhs.MaximumRadius(), rhs.MaximumRadius());
}
int ON_SurfaceCurvature::CompareMinimumRadius(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs)
{
return ON_DBL::CompareValue(lhs.MinimumRadius(), rhs.MinimumRadius());
}
double ON_SurfaceCurvature::KappaValue(ON::curvature_style kappa_style) const
{
double k;
@@ -9497,10 +10075,28 @@ bool operator!=(const ON_SurfaceCurvatureColorMapping& lhs, const ON_SurfaceCurv
return false;
}
bool operator==(
const ON_SurfaceCurvature& lhs,
const ON_SurfaceCurvature& rhs
)
{
return (lhs.k1 == rhs.k1 && lhs.k2 == rhs.k2);
}
bool operator!=(
const ON_SurfaceCurvature& lhs,
const ON_SurfaceCurvature& rhs
)
{
// Note well:
// ON_SurfaceCurvature::IsNan() is true if either of k1 or k2 is a nan.
// and the code below is correct.
return (lhs.k1 != rhs.k1 || lhs.k2 != rhs.k2) || (lhs.IsNan() && rhs.IsNan());
}
bool ON_SurfaceCurvature::IsSet() const
{
return (ON_UNSET_VALUE < k1&& k1 < ON_UNSET_POSITIVE_VALUE&& ON_UNSET_VALUE < k2&& k2 < ON_UNSET_POSITIVE_VALUE);
return (ON_UNSET_VALUE < k1 && k1 < ON_UNSET_POSITIVE_VALUE && ON_UNSET_VALUE < k2 && k2 < ON_UNSET_POSITIVE_VALUE);
}
bool ON_SurfaceCurvature::IsZero() const
@@ -9513,25 +10109,30 @@ bool ON_SurfaceCurvature::IsUnset() const
return IsSet() ? false : true;
}
bool ON_SurfaceCurvature::IsNan() const
{
return (ON_IS_NAN(k1) || ON_IS_NAN(k2));
}
double ON_SurfaceCurvature::MaximumPrincipalCurvature() const
{
return IsSet() ? ((k1 >= k2) ? k1 : k2) : ON_DBL_QNAN;
}
double ON_SurfaceCurvature::MinimumPrincipalCurvature() const
{
return IsSet() ? ((k1 <= k2) ? k1 : k2) : ON_DBL_QNAN;
}
double ON_SurfaceCurvature::GaussianCurvature() const
{
if (ON_IS_VALID(k1) && ON_IS_VALID(k2))
{
return k1 * k2;
}
return ON_DBL_QNAN;
return (ON_IS_VALID(k1) && ON_IS_VALID(k2)) ? (k1 * k2) : ON_DBL_QNAN;
}
double ON_SurfaceCurvature::MeanCurvature() const
{
if (ON_IS_VALID(k1) && ON_IS_VALID(k2))
{
return 0.5 * (k1 + k2);
}
return ON_DBL_QNAN;
return (ON_IS_VALID(k1) && ON_IS_VALID(k2)) ? ((k1 == k2) ? k1 : 0.5 * (k1 + k2)) : ON_DBL_QNAN;
}
double ON_SurfaceCurvature::MinimumRadius() const
@@ -9557,7 +10158,7 @@ double ON_SurfaceCurvature::MaximumRadius() const
{
// k = minimum directional curvature
double k;
if (k1 * k2 <= 0.0 || fabs(k1) <= 1e-300 || fabs(k2) <= 1e-300)
if (ON_DBL::Sign(k1)*ON_DBL::Sign(k2) <= 0 || fabs(k1) <= 1e-300 || fabs(k2) <= 1e-300)
{
// If principal curvatures have opposite signs,
// there is a direction with zero directional curvature.
@@ -12731,6 +13332,12 @@ void ON_MappingTag::Dump( ON_TextLog& text_log ) const
case ON_TextureMapping::TYPE::false_colors:
text_log.Print("false colors");
break;
case ON_TextureMapping::TYPE::wcs_projection:
text_log.Print("wcs projection");
break;
case ON_TextureMapping::TYPE::wcsbox_projection:
text_log.Print("wcs box projection");
break;
}
text_log.Print("\n");
+204 -1
View File
@@ -4253,7 +4253,78 @@ Returns:
);
bool ComputeVertexNormals(); // uses face normals to cook up a vertex normal
#if 0
// Will be added April/may of 2024
#pragma region NOT_YET_RH_C_SHARED_ENUM [ON_Mesh::CurvatureSettingMethod] [Rhino.Geometry.MeshCurvatureSettingMethod] [byte]
/// <summary>
/// Enumberates the methods available to set the vertex principal curvature
/// values saved in the ON_Mesh m_K[] array.
/// </summary>
enum class CurvatureSettingMethod : unsigned char
{
/// <summary>
/// The most appropriate method for current context will be used.
/// </summary>
Unset = 0,
/// <summary>
/// The mesh is being created from a surface and the mesh's principal curvatures
/// will be set from the surface's first and second partial deriatives.
/// </summary>
SurfaceEvaluation = 1,
/// <summary>
/// The mesh's principal curvatures will be set using
/// ON_SurfaceCurvature::CreateFromGaussianAndMeanCurvatures()
/// with input values from
/// ON_Mesh::ComputeDiscreteGaussianMeshCurvature() and
/// ON_Mesh::ComputeDiscreteLaplacianMeanMeshCurvatures().
/// </summary>
DiscreteDefault = 2,
/// <summary>
/// The mesh's principal curvatures will be set using
/// ON_SurfaceCurvature::CreateFromGaussianAndMeanCurvatures()
/// with input values from
/// ON_Mesh::ComputeDiscreteGaussianMeshCurvature() and
/// ON_Mesh::ComputeDiscreteLaplacianMeanMeshCurvatures().
/// </summary>
DiscreteLaplacianMean = 3,
/// <summary>
/// The mesh's principal curvatures will be set using
/// ON_SurfaceCurvature::CreateFromGaussianAndMeanCurvatures()
/// with input values from
/// ON_Mesh::ComputeDiscreteGaussianMeshCurvature() and
/// ON_Mesh::ComputeDiscreteDihedralMeanMeshCurvature().
/// </summary>
DiscreteDihedralMean = 4
};
#pragma endregion
/// <summary>
/// Use discrete curvature estimates to set the principal curvature values
/// in the mesh's m_K[] array.
/// </summary>
/// <param name="method">
/// Specifies the method to use.
/// One of the discrete methods must be specified.
/// When in doubt, pass ON_Mesh::CurvatureSettingMethod::DiscreteDefault.
/// </param>
/// <param name="bLazy">
/// If bLazy=true, only unset m_K[] values will be set.
/// If bLazy=false, only unset m_K[] values will be set.
/// </param>
/// <returns></returns>
bool ComputeVertexPrincipalCurvatures(
ON_Mesh::CurvatureSettingMethod method,
bool bLazy
);
#endif
//////////
// Scales textures so the texture domains are [0,1] and
// eliminates any texture rotations.
@@ -4332,18 +4403,150 @@ Returns:
bool bSeamCheck = true
);
/*
Description:
Returns true if the mesh has at least one set of valid
cached texture coordinates in the m_TC array.
Returns:
True if the mesh contains cached texture coordinates.
See Also:
ON_Mesh::SetCachedTextureCoordinatesFromMaterial
ON_Mesh::CachedTextureCoordinates
ON_Mesh::SetCachedTextureCoordinatesEx
*/
bool HasCachedTextureCoordinates() const;
/*
Description:
Prepares the cached texture coordinates by filling the
m_TC array with the relevant texture coordinates needed
to render the provided material using the provided
mapping ref and ONX model.
Call this function first if you are planning on storing
the results from repeated calls to any of the following
methods:
* CachedTextureCoordinates
* SetCachedTextureCoordinates
* SetCachedTextureCoordinatesEx
* GetCachedTextureCoordinates
Parameters:
onx_model - [in]
The ONX model that contains the texture mappings.
material - [in]
The material which contains the textures we want to
calculate the texture coordinates for.
mapping_ref - [in]
The texture mapping ref to use to get at the texture mapping.
Returns:
True if successful.
See Also:
ON_Mesh::CachedTextureCoordinates
ON_Mesh::SetCachedTextureCoordinatesEx
*/
bool SetCachedTextureCoordinatesFromMaterial(const class ONX_Model& onx_model, const ON_Material& material, const ON_MappingRef* mapping_ref) const;
/*
Description:
Returns the cached texture coordinates corresponding to
the provided texture if they exist. If they don't
exist, they can be created using the following methods:
* SetCachedTextureCoordinatesFromMaterial
* SetCachedTextureCoordinates
* SetCachedTextureCoordinatesEx
NOTE: If you store the pointers of the results from this
function, you need to first call
SetCachedTextureCoordinatesFromMaterial to make sure the
pointers don't get invalidated by subsequent calls to
functions like SetCachedTextureCoordinates and
SetCachedTextureCoordinatesEx.
Parameters:
onx_model - [in]
The ONX model that contains the texture mappings.
texture - [in]
The texture to calculate the texture coordinates for.
mapping_ref - [in]
The texture mapping ref to use to get at the texture mapping.
Returns:
A pointer to the matching cached texture coordinates,
nullptr if none exist.
See Also:
ON_Mesh::SetCachedTextureCoordinatesFromMaterial
ON_Mesh::SetCachedTextureCoordinatesEx
*/
const ON_TextureCoordinates* GetCachedTextureCoordinates(const class ONX_Model& onx_model, const ON_Texture& texture, const ON_MappingRef* mapping_ref) const;
/*
Description:
Returns the cached texture coordinates corresponding to
the provided mapping id if they exist. If they don't
exist, they can be created using the following methods:
* SetCachedTextureCoordinatesFromMaterial
* SetCachedTextureCoordinates
* SetCachedTextureCoordinatesEx
NOTE: If you store the pointers of the results from this
function, you need to first call
SetCachedTextureCoordinatesFromMaterial to make sure the
pointers don't get invalidated by subsequent calls to
functions like SetCachedTextureCoordinates and
SetCachedTextureCoordinatesEx.
Parameters:
mapping_id - [in]
The texture mapping to use for the calculation.
Returns:
A pointer to the matching cached texture coordinates,
nullptr if none exist.
See Also:
ON_Mesh::SetCachedTextureCoordinatesFromMaterial
ON_Mesh::SetCachedTextureCoordinatesEx
*/
const ON_TextureCoordinates* CachedTextureCoordinates(
const ON_UUID& mapping_id
) const;
// Use SetCachedTextureCoordinatesEx instead
const ON_TextureCoordinates* SetCachedTextureCoordinates(
const class ON_TextureMapping& mapping,
const class ON_Xform* mesh_xform = 0,
bool bLazy = true
);
/*
Description:
Returns the cached texture coordinates corresponding to
the provided mapping and other parameters. If they don't
exist, this function will attempt to create them first.
If they do exist and bLazy is true, then no calculation
is performed.
NOTE: Subsequent calls to this function with different
parameters can invalidate previously returned
ON_TextureCoordinates pointers. If you want store the
pointers of previous results, you need to first call
SetCachedTextureCoordinatesFromMaterial.
Parameters:
mapping - [in]
The texture mapping to use for the calculation.
mesh_xform - [in]
If not nullptr, the mapping calculation is performed as
if the mesh were transformed by mesh_xform
bLazy - [in]
If true and the m_TC[] values were set using the same
mapping parameters, then no calculation is performed.
bSeamCheck - [in]
If true then some mesh edges might be unwelded to better
represent UV discontinuities in the texture mapping.
This only happens for the following mappings:
Box, Sphere, Cylinder.
Returns:
A pointer to the cached texture coordinates, nullptr if
the function failed to calculate the texture coordinates.
See Also:
ON_Mesh::SetCachedTextureCoordinatesFromMaterial
ON_Mesh::CachedTextureCoordinates
*/
const ON_TextureCoordinates* SetCachedTextureCoordinatesEx(
const class ON_TextureMapping& mapping,
const class ON_Xform* mesh_xform = 0,
+18 -2
View File
@@ -580,8 +580,7 @@ bool ON_NurbsSurface::IsValid( ON_TextLog* text_log ) const
else
{
rc = true;
int i;
for ( i = 0; i < 2 && rc; i++ )
for ( int i = 0; i < 2 && rc; i++ )
{
rc = false;
if (m_order[i] < 2 )
@@ -640,6 +639,23 @@ bool ON_NurbsSurface::IsValid( ON_TextLog* text_log ) const
}
}
}
if (rc)
{
const int cvdim = CVSize();
for (int i = 0; m_cv_count[0] > i; ++i)
{
for (int j = 0; m_cv_count[1] > j; ++j)
{
const double* cv = CV(i, j);
for (int k = 0; cvdim > k; ++k)
{
if (false == ON_CV_COORDINATE_IS_VALID(cv[k]))
return false;
}
}
}
}
}
return rc;
+174 -2
View File
@@ -2253,12 +2253,136 @@ double ON_MaximumCoordinate(const double* data, int dim, bool is_rat, int count,
class ON_CLASS ON_SurfaceCurvature
{
public:
/// <summary>
/// Create an ON_SurfaceCurvature from the principal curvature values.
/// The principal curvature values are the most fundamental curvature properties
/// of a surface. Other curvatures are calculated from them. For example
/// gaussian curvature = k1 * k2 and mean curvature = (k1 + k2)/2.
/// </summary>
/// <param name="k1"></param>
/// <param name="k2"></param>
/// <returns>
/// An ON_SurfaceCurvature with the specified principal curvatures.
/// </returns>
static const ON_SurfaceCurvature CreateFromPrincipalCurvatures(
double k1,
double k2
);
/// <summary>
/// Create an ON_SurfaceCurvature from a gaussian and mean curvature values using the relationsip
/// between the principal curvatures, gaussian and mean.
/// k1 = mean + sqrt(mean*mean - gaussian)
/// k2 = mean - sqrt(mean*mean - gaussian)
/// If the radicand is negative, we assume we're dealing with a bit of numerical noise or
/// estimates and set the principal curvatures
/// k1 = k2 = sign(mean)*sqrt(gaussian)
/// </summary>
/// <param name="gaussian_curvature"></param>
/// Gaussian curvature = k1*k2 (product of principal curvatures).
/// <param name="mean_curvature">
/// Mean curvature = (k1+k2)/2 (average of principal curvatures).
/// </param>
/// <returns>
/// A surface curvature with GaussianCurvature() = gaussian_curvature
/// and MeanCurvature() = gaussian_curvature.
/// </returns>
static const ON_SurfaceCurvature CreateFromGaussianAndMeanCurvatures(
double gaussian_curvature,
double mean_curvature
);
/// <summary>
/// The sign of the principal curvatures are with respect to a choice
/// of surface orientation. This function returns the principal curvatures
/// of the surface with opposite choice of orientation.
/// </summary>
/// <returns>
/// ON_SurfaceCurvature::CreateFromPrincipalCurvatures(-this->k2, -this->k1);
/// </returns>
const ON_SurfaceCurvature FlipSurfaceOrientation() const;
/// <summary>
/// Dictionary compare k1 and k2. Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int Compare(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// Dictionary compare lhs.MaximumPrincipalCurvature() and rhs.MaximumPrincipalCurvature().
/// Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int CompareMaximumAndMinimumPrincipalCurvatures(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// Compare lhs.MaximumPrincipalCurvature() and rhs.MaximumPrincipalCurvature().
/// Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int CompareMaximumPrincipalCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// Compare lhs.MinimumPrincipalCurvature() and rhs.MinimumPrincipalCurvature().
/// Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int CompareMinimumPrincipalCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// Compare lhs.MaximumRadius() and rhs.MaximumRadius().
/// Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int CompareMaximumRadius(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// Compare lhs.MinimumRadius() and rhs.MinimumRadius().
/// Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int CompareMinimumRadius(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// Compare lhs.GaussianCurvature() and rhs.GaussianCurvature().
/// Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int CompareGaussianCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// Compare lhs.MeanCurvature() and rhs.MeanCurvature().
/// Values with nans sort last.
/// </summary>
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>-1, 0 or +1.</returns>
static int CompareMeanCurvature(const ON_SurfaceCurvature& lhs, const ON_SurfaceCurvature& rhs);
/// <summary>
/// k1 = k2 = ON_DBL_QNAN
/// </summary>
static const ON_SurfaceCurvature Nan;
/// <summary>
/// k1 = k2 = 0
/// </summary>
static const ON_SurfaceCurvature Zero;
/// <summary>
@@ -2270,21 +2394,36 @@ public:
double k1, k2; // principal curvatures
public:
/// <returns>True if k1 and k2 are both valid finite values.</returns>
bool IsSet() const;
/// <returns>True if k1 and k2 are both zero.</returns>
bool IsZero() const;
/// <returns>True if either of k1 or k2 is not a valid finite value.</returns>
bool IsUnset() const;
/// <returns>True if either of k1 or k2 is a nan.</returns>
bool IsNan() const;
public:
/// <summary>
/// The Gaussian curvature is k1*k2.
/// </summary>
/// <returns>The Gausian curvature.</returns>
/// <returns>
/// If this is set, the Gausian curvature is returned.
/// Otherwise ON_DBL_QNAN is returned.
/// </returns>
double GaussianCurvature() const;
/// <summary>
/// The mean curvature is (k1+k2)/2.
/// </summary>
/// <returns>The signed mean curvature.</returns>
/// <returns>
/// If this is set, the signed mean curvature is returned.
/// Otherwise ON_DBL_QNAN is returned.
/// </returns>
double MeanCurvature() const;
/// <summary>
@@ -2328,9 +2467,42 @@ public:
/// </returns>
double KappaValue(ON::curvature_style kappa_style) const;
/// <returns>
/// If this is set, the maximum of k1 and k2 is returned.
/// Otherwise ON_DBL_QNAN is returned.
/// </returns>
double MaximumPrincipalCurvature() const;
/// <returns>
/// If this is set, the minimum of k1 and k2.
/// Otherwise ON_DBL_QNAN is returned.
/// </returns>
double MinimumPrincipalCurvature() const;
};
ON_DECL
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>
/// Returns (lhs.k1==rhs.k1 && lhs.k2==rhs.k2)
/// Note that if any princial curvature is a nan, then false is returned.
/// </returns>
bool operator==(
const ON_SurfaceCurvature& lhs,
const ON_SurfaceCurvature& rhs
);
ON_DECL
/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>
/// Returns (lhs.k1 != rhs.k1 || lhs.k2!=rhs.k2) || (lhs.IsNan() && rhs.IsNan()).
/// </returns>
bool operator!=(
const ON_SurfaceCurvature& lhs,
const ON_SurfaceCurvature& rhs
);
#if defined(ON_DLL_TEMPLATE)
+8 -3
View File
@@ -38,16 +38,21 @@ bool ON_Polyline::IsValid( double tolerance ) const
{
for ( i = 1; rc && i < m_count; i++ )
{
if ( m_a[i].DistanceTo(m_a[i-1]) <= tolerance )
if (false == m_a[i].IsValid() || false == m_a[i-1].IsValid())
rc = false;
else if ( m_a[i].DistanceTo(m_a[i-1]) <= tolerance )
rc = false;
}
if ( rc && m_count < 4 && m_a[0].DistanceTo(m_a[m_count-1]) <= tolerance )
rc = false;
}
else {
else
{
for ( i = 1; rc && i < m_count && rc; i++ )
{
if ( m_a[i] == m_a[i-1] )
if (false == m_a[i].IsValid() || false == m_a[i - 1].IsValid())
rc = false;
else if ( m_a[i] == m_a[i-1] )
rc = false;
}
if ( rc && m_count < 4 && m_a[0] == m_a[m_count-1] )
+9 -9
View File
@@ -6,7 +6,7 @@
// To update version numbers, edit ..\build\build_dates.msbuild
#define RMA_VERSION_MAJOR 8
#define RMA_VERSION_MINOR 6
#define RMA_VERSION_MINOR 7
////////////////////////////////////////////////////////////////
//
@@ -15,8 +15,8 @@
//
#define RMA_VERSION_YEAR 2024
#define RMA_VERSION_MONTH 4
#define RMA_VERSION_DATE 10
#define RMA_VERSION_HOUR 5
#define RMA_VERSION_DATE 11
#define RMA_VERSION_HOUR 13
#define RMA_VERSION_MINUTE 0
////////////////////////////////////////////////////////////////
@@ -35,8 +35,8 @@
// 3 = build system release build
#define RMA_VERSION_BRANCH 0
#define VERSION_WITH_COMMAS 8,6,24101,5000
#define VERSION_WITH_PERIODS 8.6.24101.05000
#define VERSION_WITH_COMMAS 8,7,24102,13000
#define VERSION_WITH_PERIODS 8.7.24102.13000
#define COPYRIGHT "Copyright (C) 1993-2024, Robert McNeel & Associates. All Rights Reserved."
#define SPECIAL_BUILD_DESCRIPTION "Public OpenNURBS C++ 3dm file IO library."
@@ -44,11 +44,11 @@
#define RMA_VERSION_NUMBER_MAJOR_WSTRING L"8"
#define RMA_PREVIOUS_VERSION_NUMBER_MAJOR_WSTRING L"7"
#define RMA_VERSION_NUMBER_SR_STRING "SR6"
#define RMA_VERSION_NUMBER_SR_WSTRING L"SR6"
#define RMA_VERSION_NUMBER_SR_STRING "SR7"
#define RMA_VERSION_NUMBER_SR_WSTRING L"SR7"
#define RMA_VERSION_WITH_PERIODS_STRING "8.6.24101.05000"
#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.6.24101.05000"
#define RMA_VERSION_WITH_PERIODS_STRING "8.7.24102.13000"
#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.7.24102.13000"
+2 -3
View File
@@ -186,9 +186,8 @@ public:
/*
Description:
Places two Gaussians with mean zero and standard devation one,
generated by a Box-Muller transform, into the doubles pointed to by its arguments.
/*
Places two Gaussians with mean zero and standard devation one,
generated by a Box-Muller transform, into the doubles pointed to by its arguments.
Parameters:
u - [out]
v - [out]
+87
View File
@@ -287,6 +287,85 @@ const double ON_DBL_QNAN = Internal_ON__dblinithelper(1);
const double ON_DBL_PINF = Internal_ON__dblinithelper(2);
const double ON_DBL_NINF = -Internal_ON__dblinithelper(2);
const double ON_DBL::Nan = ON_DBL_QNAN;
const double ON_DBL::PositiveInfinity = ON_DBL_PINF;
const double ON_DBL::NegativeInfinity = ON_DBL_NINF;
const double ON_DBL::PositiveMax = ON_DBL_MAX;
const double ON_DBL::NegativeMax = -ON_DBL_MAX;
const double ON_DBL::PositiveMin = ON_DBL_MIN;
const double ON_DBL::NegativeMin = -ON_DBL_MIN;
const double ON_DBL::Unset = ON_UNSET_VALUE;
const double ON_DBL::PositiveUnset = ON_UNSET_POSITIVE_VALUE;
bool ON_DBL::IsValid(double x)
{
return x > ON_UNSET_VALUE && x < ON_UNSET_POSITIVE_VALUE;
}
bool ON_DBL::IsNan(double x)
{
return (x == x) ? false : true;
}
int ON_DBL::Sign(double x)
{
return (x > 0.0 ? 1 : ((x < 0.0) ? -1 : 0));
}
bool ON_DBL::IsInfinity(double x)
{
return (x >= ON_DBL_PINF || x <= ON_DBL_NINF);
}
bool ON_DBL::IsPositiveInfinity(double x)
{
return (x >= ON_DBL_PINF);
}
bool ON_DBL::IsNegativeInfinity(double x)
{
return (x <= ON_DBL_NINF);
}
bool ON_DBL::IsNotNan(double x)
{
return (x == x);
}
bool ON_DBL::IsUnset(double x)
{
return (ON_UNSET_VALUE == fabs(x));
}
int ON_DBL::CompareValue(double lhs, double rhs)
{
if (lhs < rhs)
return -1;
if (lhs > rhs)
return 1;
if (lhs == rhs)
return 0;
// At least one of lhs or rhs is a nan. Sort nans to end
return (ON_IS_NAN(lhs) ? 1 : 0) - (ON_IS_NAN(rhs) ? 1 : 0);
}
int ON_DBL::Compare(const double* lhs, const double* rhs)
{
// sort nullpt to the end
if (lhs == rhs)
return 0;
if (nullptr == lhs)
return 1;
if (nullptr == rhs)
return -1;
return ON_DBL::CompareValue(*lhs, *rhs);
}
const float ON_FLT_QNAN = Internal_ON__fltinithelper(1);
const float ON_FLT_PINF = Internal_ON__fltinithelper(2);
const float ON_FLT_NINF = -Internal_ON__fltinithelper(2);
@@ -334,6 +413,10 @@ const ON_SubDEdgeSharpness ON_SubDEdgeSharpness::Nan = ON_SubDEdgeSharpness::Fro
const ON_SubDEdgeSharpness ON_SubDEdgeSharpness::Crease = ON_SubDEdgeSharpness::FromConstant(ON_SubDEdgeSharpness::CreaseValue);
const ON_SubDFaceCornerDex ON_SubDFaceCornerDex::Unset(0, 0);
const ON_SubDFaceParameter ON_SubDFaceParameter::Nan = { ON_SubDFaceCornerDex::Unset, ON_DBL_QNAN, ON_DBL_QNAN };
const double ON_SubDSectorType::MinimumCornerAngleRadians = (2.0*ON_PI)/((double)(ON_SubDSectorType::MaximumCornerAngleIndex));
const double ON_SubDSectorType::MaximumCornerAngleRadians = 2.0*ON_PI - ON_SubDSectorType::MinimumCornerAngleRadians;
@@ -2757,6 +2840,10 @@ const ON_SubDComponentPtr ON_SubDComponentPtr::NullVertex = { 2 };
const ON_SubDComponentPtr ON_SubDComponentPtr::NullEdge = { 4 };
const ON_SubDComponentPtr ON_SubDComponentPtr::NullFace = { 6 };
const ON_SubDComponentId ON_SubDComponentId::Unset(ON_SubDComponentPtr::Null);
const ON_SubDComponentParameter ON_SubDComponentParameter::Unset = {};
const ON_SubDComponentPtrPair ON_SubDComponentPtrPair::Null = ON_SubDComponentPtrPair::Create(ON_SubDComponentPtr::Null,ON_SubDComponentPtr::Null);
const ON_SubDComponentAndNumber ON_SubDComponentAndNumber::NullAndNan = ON_SubDComponentAndNumber::Create(ON_SubDComponentPtr::Null, ON_DBL_QNAN);
+295 -12
View File
@@ -1543,7 +1543,12 @@ bool ON_SubDComponentTest::Passes(const ON_SubDFace* f) const
ON_SubDComponentId::ON_SubDComponentId(ON_SubDComponentPtr::Type component_type, unsigned int component_id)
: m_id(component_id)
, m_type(component_type)
, m_type_and_dir((unsigned char)component_type)
{}
ON_SubDComponentId::ON_SubDComponentId(ON_SubDComponentPtr::Type component_type, unsigned int component_id, ON__UINT_PTR dir)
: m_id(component_id)
, m_type_and_dir(((unsigned char)component_type) | ((unsigned char)(dir%2)))
{}
ON_SubDComponentId::ON_SubDComponentId(ON_SubDComponentPtr cptr)
@@ -1552,7 +1557,8 @@ ON_SubDComponentId::ON_SubDComponentId(ON_SubDComponentPtr cptr)
if (nullptr != b)
{
m_id = b->m_id;
m_type = cptr.ComponentType();
Internal_SetType(cptr.ComponentType());
Internal_SetDir(0 == cptr.ComponentDirection() ? 0u : 1u);
}
}
@@ -1561,7 +1567,18 @@ ON_SubDComponentId::ON_SubDComponentId(const class ON_SubDVertex* v)
if (nullptr != v)
{
m_id = v->m_id;
m_type = ON_SubDComponentPtr::Type::Vertex;
Internal_SetType(ON_SubDComponentPtr::Type::Vertex);
}
}
ON_SubDComponentId::ON_SubDComponentId(const class ON_SubDVertexPtr vptr)
{
const ON_SubDVertex* v = vptr.Vertex();
if (nullptr != v)
{
m_id = v->m_id;
Internal_SetType(ON_SubDComponentPtr::Type::Vertex);
Internal_SetDir(0 == vptr.VertexDirection() ? 0u : 1u);
}
}
@@ -1570,7 +1587,18 @@ ON_SubDComponentId::ON_SubDComponentId(const class ON_SubDEdge* e)
if (nullptr != e)
{
m_id = e->m_id;
m_type = ON_SubDComponentPtr::Type::Edge;
Internal_SetType(ON_SubDComponentPtr::Type::Edge);
}
}
ON_SubDComponentId::ON_SubDComponentId(ON_SubDEdgePtr eptr)
{
const ON_SubDEdge* e = eptr.Edge();
if (nullptr != e)
{
m_id = e->m_id;
Internal_SetType(ON_SubDComponentPtr::Type::Edge);
Internal_SetDir(0 == eptr.EdgeDirection() ? 0u : 1u);
}
}
@@ -1579,16 +1607,60 @@ ON_SubDComponentId::ON_SubDComponentId(const class ON_SubDFace* f)
if (nullptr != f)
{
m_id = f->m_id;
m_type = ON_SubDComponentPtr::Type::Face;
Internal_SetType(ON_SubDComponentPtr::Type::Face);
}
}
ON_SubDComponentId::ON_SubDComponentId(ON_SubDFacePtr fptr)
{
const ON_SubDFace* f = fptr.Face();
if (nullptr != f)
{
m_id = f->m_id;
Internal_SetType(ON_SubDComponentPtr::Type::Face);
Internal_SetDir(0 == fptr.FaceDirection() ? 0u : 1u);
}
}
ON_SubDComponentId::ON_SubDComponentId(const class ON_SubDFace* f, unsigned face_corner_index)
{
if (nullptr != f)
{
m_id = f->m_id;
Internal_SetType(ON_SubDComponentPtr::Type::Face);
if (face_corner_index < (unsigned)f->m_edge_count && (unsigned)f->m_edge_count < 4096u)
{
Internal_SetValueA(face_corner_index);
Internal_SetValueB(f->m_edge_count);
}
}
}
ON_SubDComponentId::ON_SubDComponentId(ON_SubDFacePtr fptr, unsigned face_corner_index)
{
const ON_SubDFace* f = fptr.Face();
if (nullptr != f)
{
m_id = f->m_id;
Internal_SetType(ON_SubDComponentPtr::Type::Face);
Internal_SetDir(0 == fptr.FaceDirection() ? 0u : 1u);
if (face_corner_index < (unsigned)f->m_edge_count && (unsigned)f->m_edge_count < 4096u)
{
Internal_SetValueA(face_corner_index);
Internal_SetValueB(f->m_edge_count);
}
}
}
int ON_SubDComponentId::CompareTypeAndId(const ON_SubDComponentId& lhs, const ON_SubDComponentId& rhs)
{
if (static_cast<unsigned char>(lhs.m_type) < static_cast<unsigned char>(rhs.m_type))
const unsigned char lhs_type = (lhs.m_type_and_dir & ON_SubDComponentId::bits_type_mask);
const unsigned char rhs_type = (rhs.m_type_and_dir & ON_SubDComponentId::bits_type_mask);
if (lhs_type < rhs_type)
return -1;
if (static_cast<unsigned char>(lhs.m_type) > static_cast<unsigned char>(rhs.m_type))
if (lhs_type > rhs_type)
return 1;
if (lhs.m_id < rhs.m_id)
return -1;
@@ -1597,6 +1669,22 @@ int ON_SubDComponentId::CompareTypeAndId(const ON_SubDComponentId& lhs, const ON
return 0;
}
int ON_SubDComponentId::CompareTypeAndIdAndDirection(const ON_SubDComponentId& lhs, const ON_SubDComponentId& rhs)
{
const int rc = CompareTypeAndId(lhs, rhs);
if (0 != rc)
return rc;
// compare dir
const unsigned char lhs_dir = (lhs.m_type_and_dir & ON_SubDComponentId::bits_dir_mask);
const unsigned char rhs_dir = (rhs.m_type_and_dir & ON_SubDComponentId::bits_dir_mask);
if (lhs_dir < rhs_dir)
return -1;
if (lhs_dir > rhs_dir)
return 1;
return 0;
}
int ON_SubDComponentId::CompareTypeAndIdFromPointer(const ON_SubDComponentId* lhs, const ON_SubDComponentId* rhs)
{
if (lhs == rhs)
@@ -1608,14 +1696,20 @@ int ON_SubDComponentId::CompareTypeAndIdFromPointer(const ON_SubDComponentId* lh
if (nullptr == rhs)
return -1;
if (static_cast<unsigned char>(lhs->m_type) < static_cast<unsigned char>(rhs->m_type))
// compare type
const unsigned char lhs_type = (lhs->m_type_and_dir & ON_SubDComponentId::bits_type_mask);
const unsigned char rhs_type = (rhs->m_type_and_dir & ON_SubDComponentId::bits_type_mask);
if (lhs_type < rhs_type)
return -1;
if (static_cast<unsigned char>(lhs->m_type) > static_cast<unsigned char>(rhs->m_type))
if (lhs_type > rhs_type)
return 1;
// compare id
if (lhs->m_id < rhs->m_id)
return -1;
if (lhs->m_id > rhs->m_id)
return 1;
return 0;
}
@@ -1624,14 +1718,198 @@ unsigned int ON_SubDComponentId::ComponentId() const
return m_id;
}
void ON_SubDComponentId::Internal_SetType(ON_SubDComponentPtr::Type type)
{
m_type_and_dir &= ~((unsigned char)ON_SubDComponentId::bits_type_mask);
m_type_and_dir |= (((unsigned char)type) & ON_SubDComponentId::bits_type_mask);
}
void ON_SubDComponentId::Internal_SetDir(unsigned dir)
{
// invalid dir is treaded as 0
if (1 == dir)
m_type_and_dir |= ((unsigned char)ON_SubDComponentId::bits_dir_mask);
else
m_type_and_dir &= ~((unsigned char)ON_SubDComponentId::bits_dir_mask);
}
void ON_SubDComponentId::Internal_SetValueA(unsigned a)
{
if (a < 0x0FFFu)
{
m_valueAB[0] = (unsigned char)(a & 0x00FFu);
const unsigned char ahigh = (unsigned char)((a & 0x0F00u) >> 8);
m_valueAB[2] = (m_valueAB[2] & 0xF0u) | ahigh;
}
}
void ON_SubDComponentId::Internal_SetValueB(unsigned b)
{
if (b < 0x0FFFu)
{
m_valueAB[1] = (unsigned char)(b & 0x00FFu);
const unsigned char bhigh = (unsigned char)((b & 0x0F00u) >> 4);
m_valueAB[2] = (m_valueAB[2] & 0x0Fu) | bhigh;
}
}
unsigned ON_SubDComponentId::Internal_ValueA() const
{
const unsigned alow = m_valueAB[0];
const unsigned ahigh = ((unsigned)(m_valueAB[2] & 0x0Fu)) << 8;
return alow | ahigh;
}
unsigned ON_SubDComponentId::Internal_ValueB() const
{
const unsigned blow = m_valueAB[0];
const unsigned bhigh = ((unsigned)(m_valueAB[2] & 0xF0u)) << 4;
return blow | bhigh;
}
unsigned ON_SubDComponentId::ComponentDirection() const
{
return (m_type_and_dir & ON_SubDComponentId::bits_dir_mask);
}
ON_SubDComponentPtr::Type ON_SubDComponentId::ComponentType() const
{
return m_type;
return ON_SubDComponentPtr::ComponentPtrTypeFromUnsigned(m_type_and_dir & ON_SubDComponentId::bits_type_mask);
}
bool ON_SubDComponentId::IsSet() const
{
return 0 != m_id && ON_SubDComponentPtr::Type::Unset != m_type;
return 0 != m_id && ON_SubDComponentPtr::Type::Unset != ComponentType();
}
bool ON_SubDComponentId::IsNotSet() const
{
return 0 == m_id || ON_SubDComponentPtr::Type::Unset == ComponentType();
}
bool ON_SubDComponentId::IsVertexId() const
{
return m_id > 0 && ON_SubDComponentPtr::Type::Vertex == this->ComponentType();
}
bool ON_SubDComponentId::IsEdgeId() const
{
return m_id > 0 && ON_SubDComponentPtr::Type::Edge == this->ComponentType();
}
bool ON_SubDComponentId::IsFaceId() const
{
return m_id > 0 && ON_SubDComponentPtr::Type::Face == this->ComponentType();
}
const ON_SubDComponentId ON_SubDComponentId::Reversed() const
{
ON_SubDComponentId c = *this;
c.Internal_SetDir(1u - this->ComponentDirection());
return c;
}
const ON_SubDComponentPtr ON_SubDComponentId::ComponentPtr(const class ON_SubD* subd) const
{
return nullptr != subd ? this->ComponentPtr(*subd) : ON_SubDComponentPtr::Null;
}
const ON_SubDComponentPtr ON_SubDComponentId::ComponentPtr(const class ON_SubD& subd) const
{
if (0 != m_id)
{
ON_SubDComponentPtr cptr;
switch (this->ComponentType())
{
case ON_SubDComponentPtr::Type::Vertex:
cptr = ON_SubDComponentPtr::Create(subd.VertexFromId(m_id));
break;
case ON_SubDComponentPtr::Type::Edge:
cptr = ON_SubDComponentPtr::Create(subd.EdgeFromId(m_id));
break;
case ON_SubDComponentPtr::Type::Face:
cptr = ON_SubDComponentPtr::Create(subd.FaceFromId(m_id));
break;
default:
cptr = ON_SubDComponentPtr::Null;
break;
}
if (cptr.IsNotNull() && 0 != (m_type_and_dir & ON_SubDComponentId::bits_dir_mask))
cptr.SetComponentDirection(1);
return cptr;
}
return ON_SubDComponentPtr::Null;
}
const ON_SubDVertex* ON_SubDComponentId::Vertex(const class ON_SubD& subd) const
{
return this->ComponentPtr(subd).Vertex();
}
const ON_SubDVertexPtr ON_SubDComponentId::VertexPtr(const class ON_SubD& subd) const
{
return this->ComponentPtr(subd).VertexPtr();
}
const ON_SubDVertex* ON_SubDComponentId::Vertex(const class ON_SubD* subd) const
{
return (nullptr != subd) ? this->ComponentPtr(*subd).Vertex() : nullptr;
}
const ON_SubDVertexPtr ON_SubDComponentId::VertexPtr(const class ON_SubD* subd) const
{
return (nullptr != subd) ? this->ComponentPtr(*subd).VertexPtr() : ON_SubDVertexPtr::Null;
}
const ON_SubDEdge* ON_SubDComponentId::Edge(const class ON_SubD& subd) const
{
return this->ComponentPtr(subd).Edge();
}
const ON_SubDEdgePtr ON_SubDComponentId::EdgePtr(const class ON_SubD& subd) const
{
return this->ComponentPtr(subd).EdgePtr();
}
const ON_SubDEdge* ON_SubDComponentId::Edge(const class ON_SubD* subd) const
{
return (nullptr != subd) ? this->ComponentPtr(*subd).Edge() : nullptr;
}
const ON_SubDEdgePtr ON_SubDComponentId::EdgePtr(const class ON_SubD* subd) const
{
return (nullptr != subd) ? this->ComponentPtr(*subd).EdgePtr() : ON_SubDEdgePtr::Null;
}
const ON_SubDFace* ON_SubDComponentId::Face(const class ON_SubD& subd) const
{
return this->ComponentPtr(subd).Face();
}
const ON_SubDFacePtr ON_SubDComponentId::FacePtr(const class ON_SubD& subd) const
{
return this->ComponentPtr(subd).FacePtr();
}
const ON_SubDFace* ON_SubDComponentId::Face(const class ON_SubD* subd) const
{
return (nullptr != subd) ? this->ComponentPtr(*subd).Face() : nullptr;
}
const ON_SubDFacePtr ON_SubDComponentId::FacePtr(const class ON_SubD* subd) const
{
return (nullptr != subd) ? this->ComponentPtr(*subd).FacePtr() : ON_SubDFacePtr::Null;
}
const ON_SubDFaceCornerDex ON_SubDComponentId::FaceCornerDex() const
{
if (IsFaceId())
{
const ON_SubDFaceCornerDex cid(this->Internal_ValueA(), this->Internal_ValueB());
if (cid.IsSet())
return cid;
}
return ON_SubDFaceCornerDex::Unset;
}
bool ON_SubDComponentIdList::Passes(const ON_SubDComponentPtr cptr) const
@@ -9116,6 +9394,12 @@ unsigned int ON_SubD::DumpTopology(
case ON_TextureMapping::TYPE::false_colors:
text_log.Print("false colors");
break;
case ON_TextureMapping::TYPE::wcs_projection :
text_log.Print("wcs projection");
break;
case ON_TextureMapping::TYPE::wcsbox_projection :
text_log.Print("wcs box projection");
break;
}
text_log.PrintNewLine();
text_log.Print("m_mapping_id = ");
@@ -28053,4 +28337,3 @@ double ON_SubDExpandEdgesParameters::CleanupOffset(double x)
}
+926 -29
View File
File diff suppressed because it is too large Load Diff
+262 -43
View File
@@ -573,7 +573,7 @@ std::shared_ptr<const ON_SubDFace*> ON_SubDLevel::FaceArray() const
//////////////////////////////////////////////////////////////////////////
//
// ON_SubD::Tranxform
// ON_SubD::Transform
// ON_SubDimple::Transform
// ON_SubDLevel::Transform
// ON_SubDVertex::Transform
@@ -632,6 +632,18 @@ bool ON_SubDSectorSurfacePoint::Transform(
return rc;
}
bool ON_SubDSectorSurfacePoint::Transform(
const ON_Xform& xform,
const ON_Xform& xformNormals
)
{
TransformPoint(&xform.m_xform[0][0], m_limitP);
TransformVector(&xform.m_xform[0][0], m_limitT1);
TransformVector(&xform.m_xform[0][0], m_limitT2);
TransformVector(&xformNormals.m_xform[0][0], m_limitN);
return true;
}
bool ON_SubDVertex::Transform(
bool bTransformationSavedSubdivisionPoint,
@@ -671,6 +683,46 @@ bool ON_SubDVertex::Transform(
return true;
}
bool ON_SubDVertex::Transform(
bool bTransformationSavedSubdivisionPoint,
const class ON_Xform& xform,
const class ON_Xform& xformNormals
)
{
TransformPoint(&xform.m_xform[0][0],m_P);
if (bTransformationSavedSubdivisionPoint)
{
// Transform saved subdivision point
Internal_TransformComponentBase(bTransformationSavedSubdivisionPoint, xform);
// NOTE WELL:
// If the vertex
// is tagged as ON_SubDVertexTag::Corner
// and bTransformationSavedSubdivisionPoint is true,
// and the corner sector(s) contains interior smooth edges,
// and the transformation changes the angle between a corner sector's crease boundary,
// then the sector's interior smooth edge's m_sector_coefficient[] could change
// and invalidate the subdivison points and limit points.
// This is only possible for uncommon (in practice) transformations
// and corner sectors and will require a fair bit of testing for
// now it's easier to simply set bTransformationSavedSubdivisionPoint to false
// at a higher level when these types of transformations are encountered.
if (bTransformationSavedSubdivisionPoint && Internal_SurfacePointFlag())
{
for (const ON_SubDSectorSurfacePoint* lp = &m_limit_point; nullptr != lp; lp = lp->m_next_sector_limit_point)
const_cast<ON_SubDSectorSurfacePoint*>(lp)->Transform(xform, xformNormals);
}
else
Internal_ClearSurfacePointFlag();
}
else
this->ClearSavedSubdivisionPoints();
return true;
}
void ON_SubDVertex::UnsetControlNetPoint()
{
m_P[0] = ON_DBL_QNAN;
@@ -836,6 +888,41 @@ bool ON_SubDFace::Transform(
bool bTransformationSavedSubdivisionPoint,
const class ON_Xform& xform
)
{
ON_Xform xformNormals{ ON_Xform::IdentityTransformation };
const double det{ xform.GetSurfaceNormalXform(xformNormals) };
ON_Xform xformCurvatures{ ON_Xform::IdentityTransformation };
if (abs(det) > ON_EPSILON) {
xformNormals = xformNormals * ON_Xform::ScaleTransformation(ON_3dPoint::Origin, 1. / det);
xformCurvatures = xformCurvatures * ON_Xform::ScaleTransformation(ON_3dPoint::Origin, 1. / det);
}
const bool bKeepCurvatures{ xform.IsSimilarity() != 0 };
const bool bKeepTextures{ true };
const bool bKeepColors{ xform.IsRigid() != 0 };
// bTransformationSavedSubdivisionPoint = true should mean that
// xform is a similarity.
// If it's more complicated than this, the calling code should
// reset or adjust colors as needed based on information in the
// SubD's texture coordinate mapping tag and color mapping tag.
// Note that both of those tags have their transformation updated
// so intelligent decisions can be made at a higher level where
// there is enough context to make the correct decision.
return Transform(bTransformationSavedSubdivisionPoint, bKeepCurvatures, bKeepTextures, bKeepColors, xform, xformNormals, xformCurvatures, ON_Xform::IdentityTransformation, ON_Xform::IdentityTransformation);
}
bool ON_SubDFace::Transform(
bool bTransformationSavedSubdivisionPoint,
bool bKeepCurvatures,
bool bKeepTextures,
bool bKeepColors,
const ON_Xform& xform,
const ON_Xform& xformNormals,
const ON_Xform& xformCurvatures,
const ON_Xform& xformTextures,
const ON_Xform& xformColors
)
{
if (bTransformationSavedSubdivisionPoint)
{
@@ -843,15 +930,8 @@ bool ON_SubDFace::Transform(
if (Internal_SurfacePointFlag())
{
// bTransformationSavedSubdivisionPoint = true means xform is an isometry.
// If its more complicated than this, the calling code should
// reset or addjut colors as needed based on information in the
// SubD's texture coordinate mapping tag and color mapping tag.
// Note that both of those tags have their transformation updated
// so intelligent decisions can be made at a higher level where
// there is enough context to make the correct decision.
for (ON_SubDMeshFragment* f = m_mesh_fragments; nullptr != f; f = f->m_next_fragment)
f->Transform(true, true, true, xform);
f->Transform(bKeepCurvatures, bKeepTextures, bKeepColors, xform, xformNormals, xformCurvatures, xformTextures, xformColors);
}
else
Internal_ClearSurfacePointFlag();
@@ -868,12 +948,25 @@ bool ON_SubDLevel::Transform(
)
{
bool rc = true;
ON_Xform xformNormals{ ON_Xform::IdentityTransformation };
const double det{ xform.GetSurfaceNormalXform(xformNormals) };
ON_Xform xformCurvatures{ ON_Xform::IdentityTransformation };
if (abs(det) > ON_EPSILON) {
xformNormals = xformNormals * ON_Xform::ScaleTransformation(ON_3dPoint::Origin, 1. / det);
xformCurvatures = xformCurvatures * ON_Xform::ScaleTransformation(ON_3dPoint::Origin, 1. / det);
}
else {
rc = false;
}
const bool bKeepCurvatures{ xform.IsSimilarity() != 0 };
const bool bKeepTextures{ true };
const bool bKeepColors{ xform.IsRigid() != 0 };
m_aggregates.m_bDirtyBoundingBox = true;
for (const ON_SubDVertex* vertex = m_vertex[0]; nullptr != vertex; vertex = vertex->m_next_vertex)
{
if (false == const_cast<ON_SubDVertex*>(vertex)->Transform(bTransformationSavedSubdivisionPoint, xform))
if (false == const_cast<ON_SubDVertex*>(vertex)->Transform(bTransformationSavedSubdivisionPoint, xform, xformNormals))
rc = false;
}
@@ -885,14 +978,23 @@ bool ON_SubDLevel::Transform(
for (const ON_SubDFace* face = m_face[0]; nullptr != face; face = face->m_next_face)
{
if (false == const_cast<ON_SubDFace*>(face)->Transform(bTransformationSavedSubdivisionPoint, xform))
if (false == const_cast<ON_SubDFace*>(face)->Transform(
bTransformationSavedSubdivisionPoint, bKeepCurvatures, bKeepTextures, bKeepColors,
xform, xformNormals, xformCurvatures, ON_Xform::IdentityTransformation, ON_Xform::IdentityTransformation
))
rc = false;
}
if (false == m_surface_mesh.Transform(xform))
if (false == m_surface_mesh.Transform(
bKeepCurvatures, bKeepTextures, bKeepColors,
xform, xformNormals, xformCurvatures, ON_Xform::IdentityTransformation, ON_Xform::IdentityTransformation
))
rc = false;
if (false == m_control_net_mesh.Transform(xform))
if (false == m_control_net_mesh.Transform(
bKeepCurvatures, bKeepTextures, bKeepColors,
xform, xformNormals, xformCurvatures, ON_Xform::IdentityTransformation, ON_Xform::IdentityTransformation
))
rc = false;
if (rc)
@@ -918,6 +1020,30 @@ bool ON_SubDMesh::Transform(
return impl->Transform(xform);
}
bool ON_SubDMesh::Transform(
bool bKeepCurvatures,
bool bKeepTextures,
bool bKeepColors,
const ON_Xform& xform,
const ON_Xform& xformNormals,
const ON_Xform& xformCurvatures,
const ON_Xform& xformTextures,
const ON_Xform& xformColors
)
{
if (false == xform.IsValid())
return false;
if (xform.IsIdentity())
return true;
if (xform.IsZero())
return false;
ON_SubDMeshImpl* impl = m_impl_sp.get();
if ( nullptr == impl )
return true; // transform applied to empty mesh is true on purpose. Changing to false will break other code.
return impl->Transform(bKeepCurvatures, bKeepTextures, bKeepColors, xform, xformNormals, xformCurvatures, xformTextures, xformColors);
}
bool ON_SubDimple::Transform(
const ON_Xform& xform
)
@@ -949,14 +1075,14 @@ bool ON_SubDimple::Transform(
// If
// 1) The transformation is being applied to every vertex, edge and
// face in every level of a subdivision object, and
// 2) the transformation is an isometry (rotation, translation, ...),
// 2) the transformation is an isometry (rotation, translation, mirror, ...),
// 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.
const bool bTransformationSavedSubdivisionPoint = (1 == xform.IsRigid());
const bool bTransformationSavedSubdivisionPoint = (0 != xform.IsSimilarity());
bool bHasTextures = false;
bool bHasColors = false;
@@ -1058,15 +1184,47 @@ bool ON_SubDMeshFragment::Transform(
const ON_Xform& xform
)
{
return this->Transform(true, true, true, xform);
const bool bKeepCurvatures{ xform.IsSimilarity() != 0 };
const bool bKeepTextures{ true };
const bool bKeepColors{ xform.IsRigid() != 0 };
return this->Transform(bKeepCurvatures, bKeepTextures, bKeepColors, xform);
}
bool ON_SubDMeshFragment::Transform(
bool bKeepCurvatures,
bool bKeepTextureCoordinates,
bool bKeepTextures,
bool bKeepColors,
const ON_Xform& xform
)
{
ON_Xform xformNormals{ON_Xform::IdentityTransformation};
const double det{xform.GetSurfaceNormalXform(xformNormals)};
ON_Xform xformCurvatures{ON_Xform::IdentityTransformation};
if (abs(det) > ON_EPSILON) {
xformNormals = xformNormals * ON_Xform::ScaleTransformation(ON_3dPoint::Origin, 1. / det);
xformCurvatures = xformCurvatures * ON_Xform::ScaleTransformation(ON_3dPoint::Origin, 1. / det);
}
else {
return ON_SUBD_RETURN_ERROR(false);
}
return this->Transform(
bKeepCurvatures, bKeepTextures, bKeepColors,
xform, xformNormals, xformCurvatures, ON_Xform::IdentityTransformation, ON_Xform::IdentityTransformation
);
}
bool ON_SubDMeshFragment::Transform(
bool bKeepCurvatures,
bool bKeepTextures,
bool bKeepColors,
const ON_Xform& xform,
const ON_Xform& xformNormals,
const ON_Xform& xformCurvatures,
const ON_Xform& xformTextures,
const ON_Xform& xformColors
)
{
const unsigned count = PointCount();
if (0 == count)
@@ -1078,7 +1236,7 @@ bool ON_SubDMeshFragment::Transform(
return ON_SUBD_RETURN_ERROR(false);
if (count == NormalCount())
{
if (false == ON_TransformVectorList(3, count, (int)m_N_stride, m_N, xform))
if (false == ON_TransformVectorList(3, count, (int)m_N_stride, m_N, xformNormals))
return ON_SUBD_RETURN_ERROR(false);
}
if (0 != (ON_SubDMeshFragment::EtcControlNetQuadBit & m_vertex_count_etc))
@@ -1102,9 +1260,7 @@ bool ON_SubDMeshFragment::Transform(
const ON_3dVector A(m_ctrlnetN);
if (A.IsNotZero())
{
ON_3dVector B = xform * A;
if ( A.IsUnitVector() && false == B.IsUnitVector() )
B = B.UnitVector();
ON_3dVector B = xformNormals * A;
m_ctrlnetN[0] = B.x;
m_ctrlnetN[1] = B.y;
m_ctrlnetN[2] = B.z;
@@ -1112,43 +1268,106 @@ bool ON_SubDMeshFragment::Transform(
}
ON_GetPointListBoundingBox(3,0,count,(int)m_P_stride,m_P,&m_surface_bbox.m_min.x,&m_surface_bbox.m_max.x,false);
if (false == bKeepTextureCoordinates)
{
this->SetTextureCoordinatesExistForExperts(false);
double* p = &this->m_ctrlnetT[0][0];
double* p1 = p + sizeof(this->m_ctrlnetT) / sizeof(this->m_ctrlnetT[0][0]);
while (p < p1)
*p++ = ON_DBL_QNAN;
if (TextureCoordinatesExistForExperts()) {
this->SetTextureCoordinatesExistForExperts(bKeepTextures);
if (bKeepTextures) {
if (xformTextures.IsNotIdentity()) {
double* p = &this->m_ctrlnetT[0][0];
constexpr unsigned dim = sizeof(this->m_ctrlnetT[0]) / sizeof(this->m_ctrlnetT[0][0]);
constexpr unsigned tcount = sizeof(this->m_ctrlnetT) / sizeof(this->m_ctrlnetT[0]);
if (false == ON_TransformPointList(dim, false, tcount, dim, p, xformTextures))
return ON_SUBD_RETURN_ERROR(false);
}
}
else {
double* p = &this->m_ctrlnetT[0][0];
const double* p1 = p + sizeof(this->m_ctrlnetT) / sizeof(this->m_ctrlnetT[0][0]);
while (p < p1)
*p++ = ON_DBL_QNAN;
}
}
if (false == bKeepCurvatures)
{
this->SetCurvaturesExistForExperts(false);
this->m_ctrlnetK[0] = ON_SurfaceCurvature::Nan;
this->m_ctrlnetK[1] = ON_SurfaceCurvature::Nan;
this->m_ctrlnetK[2] = ON_SurfaceCurvature::Nan;
this->m_ctrlnetK[3] = ON_SurfaceCurvature::Nan;
if (CurvaturesExistForExperts()) {
this->SetCurvaturesExistForExperts(bKeepCurvatures);
if (bKeepCurvatures) {
if (xformCurvatures.IsNotIdentity()) {
constexpr unsigned dim{sizeof(ON_SurfaceCurvature) / sizeof(double)};
constexpr unsigned ccount{sizeof(m_ctrlnetK) / sizeof(m_ctrlnetK[0])};
if (false == ON_TransformVectorList(dim, ccount, dim, (double*)m_ctrlnetK, xformCurvatures))
return ON_SUBD_RETURN_ERROR(false);
}
}
else {
this->m_ctrlnetK[0] = ON_SurfaceCurvature::Nan;
this->m_ctrlnetK[1] = ON_SurfaceCurvature::Nan;
this->m_ctrlnetK[2] = ON_SurfaceCurvature::Nan;
this->m_ctrlnetK[3] = ON_SurfaceCurvature::Nan;
}
}
if (false == bKeepColors)
{
this->SetColorsExistForExperts(false);
this->m_ctrlnetC[0] = ON_Color::UnsetColor;
this->m_ctrlnetC[1] = ON_Color::UnsetColor;
this->m_ctrlnetC[2] = ON_Color::UnsetColor;
this->m_ctrlnetC[3] = ON_Color::UnsetColor;
if (ColorsExistForExperts()) {
this->SetColorsExistForExperts(bKeepColors);
if (bKeepColors) {
if (xformColors.IsNotIdentity()) {
for (int i = 0; i < 4; ++i) {
ON_Color& color{ m_ctrlnetC[i] };
ON_4dPoint rgba{ (double)color.Red(), (double)color.Green(), (double)color.Blue(), (double)color.Alpha() };
rgba.Transform(xformColors);
m_ctrlnetC->SetRGBA((int)rgba[0], (int)rgba[1], (int)rgba[2], (int)rgba[3]);
}
}
}
else {
this->m_ctrlnetC[0] = ON_Color::UnsetColor;
this->m_ctrlnetC[1] = ON_Color::UnsetColor;
this->m_ctrlnetC[2] = ON_Color::UnsetColor;
this->m_ctrlnetC[3] = ON_Color::UnsetColor;
}
}
return true;
}
bool ON_SubDMeshImpl::Transform(
const ON_Xform& xform
)
{
m_bbox = ON_BoundingBox::EmptyBoundingBox;
ON_BoundingBox bbox = ON_BoundingBox::EmptyBoundingBox;
for (const ON_SubDMeshFragment* fragment = m_first_fragment; nullptr != fragment; fragment = fragment->m_next_fragment)
{
if (false == const_cast<ON_SubDMeshFragment*>(fragment)->Transform(xform))
return ON_SUBD_RETURN_ERROR(false);
if (fragment == m_first_fragment)
bbox = fragment->m_surface_bbox;
else
bbox.Union(fragment->m_surface_bbox);
}
m_bbox = bbox;
ChangeContentSerialNumber();
return true;
}
bool ON_SubDMeshImpl::Transform(
bool bKeepCurvatures,
bool bKeepTextures,
bool bKeepColors,
const ON_Xform& xform,
const ON_Xform& xformNormals,
const ON_Xform& xformCurvatures,
const ON_Xform& xformTextures,
const ON_Xform& xformColors
)
{
const bool bIsometry = (1 == xform.IsRigid());
m_bbox = ON_BoundingBox::EmptyBoundingBox;
ON_BoundingBox bbox = ON_BoundingBox::EmptyBoundingBox;
for ( const ON_SubDMeshFragment* fragment = m_first_fragment; nullptr != fragment; fragment = fragment->m_next_fragment)
{
if ( false == const_cast<ON_SubDMeshFragment*>(fragment)->Transform(bIsometry, bIsometry, bIsometry, xform) )
if ( false == const_cast<ON_SubDMeshFragment*>(fragment)->Transform(
bKeepCurvatures, bKeepTextures, bKeepColors,
xform, xformNormals, xformCurvatures, xformTextures, xformColors
) )
return ON_SUBD_RETURN_ERROR(false);
if ( fragment == m_first_fragment )
bbox = fragment->m_surface_bbox;
+12 -1
View File
@@ -3000,9 +3000,20 @@ public:
void ClearTree();
bool Transform(
bool Transform(
const ON_Xform& xform
);
bool Transform(
bool bKeepCurvatures,
bool bKeepTextures,
bool bKeepColors,
const ON_Xform& xform,
const ON_Xform& xformNormals,
const ON_Xform& xformCurvatures,
const ON_Xform& xformTextures,
const ON_Xform& xformColors
);
bool GetTightBoundingBox(
+611
View File
@@ -1414,3 +1414,614 @@ const ON_Plane ON_SubDFace::ControlNetCenterFrame() const
}
return ON_Plane::NanPlane;
}
int ON_SubDFaceCornerDex::CompareAll(const ON_SubDFaceCornerDex& lhs, const ON_SubDFaceCornerDex& rhs)
{
// invalids go to the end
int i = lhs.IsSet() ? 0 : 1;
int j = lhs.IsSet() ? 0 : 1;
if (i < j)
return -1;
if (i > j)
return -1;
if (lhs.m_edge_count < rhs.m_edge_count)
return -1;
if (lhs.m_edge_count > rhs.m_edge_count)
return 1;
if (lhs.m_corner_index < rhs.m_corner_index)
return -1;
if (lhs.m_corner_index > rhs.m_corner_index)
return 1;
return 0;
}
int ON_SubDFaceCornerDex::Compare(const ON_SubDFaceCornerDex* lhs, const ON_SubDFaceCornerDex* rhs)
{
// sort nullptr to end
if (lhs == rhs)
return 0;
if (nullptr == lhs)
return 1;
if (nullptr == rhs)
return -1;
return ON_SubDFaceCornerDex::CompareAll(*lhs, *rhs);
}
bool ON_SubDFaceCornerDex::IsSet() const
{
return m_corner_index < m_edge_count && m_edge_count >= 3;
}
bool ON_SubDFaceCornerDex::IsNotSet() const
{
return m_corner_index >= m_edge_count || m_edge_count < 3;
}
bool ON_SubDFaceCornerDex::IsValid(const ON_SubDFace* face) const
{
return nullptr != face && face->m_edge_count == m_edge_count && IsSet();
}
unsigned ON_SubDFaceCornerDex::CornerIndex() const
{
return m_corner_index;
}
unsigned ON_SubDFaceCornerDex::EdgeCount() const
{
return m_edge_count;
}
bool ON_SubDFaceCornerDex::IsQuadFace() const
{
return 4 == m_edge_count && IsSet();
}
const ON_SubDFaceCornerDex ON_SubDFaceCornerDex::NextCornerDex() const
{
if (IsSet())
{
ON_SubDFaceCornerDex c;
c.m_corner_index = (m_corner_index + 1u) % m_edge_count;
c.m_edge_count = m_edge_count;
return c;
}
return ON_SubDFaceCornerDex::Unset;
}
const ON_SubDFaceCornerDex ON_SubDFaceCornerDex::PreviousCornerDex() const
{
if (IsSet())
{
ON_SubDFaceCornerDex c;
c.m_corner_index = (m_corner_index + m_edge_count - 1u) % m_edge_count;
c.m_edge_count = m_edge_count;
return c;
}
return ON_SubDFaceCornerDex::Unset;
}
const ON_SubDVertex* ON_SubDFaceCornerDex::CornerVertex(const ON_SubDFace* face) const
{
return IsValid(face) ? face->Vertex(m_corner_index) : nullptr;
}
const ON_SubDVertex* ON_SubDFaceCornerDex::PreviousCornerVertex(const ON_SubDFace* face) const
{
return this->PreviousCornerDex().CornerVertex(face);
}
const ON_SubDVertex* ON_SubDFaceCornerDex::NextCornerVertex(const ON_SubDFace* face) const
{
return this->NextCornerDex().CornerVertex(face);
}
const ON_SubDEdgePtr ON_SubDFaceCornerDex::EdgePtr(const ON_SubDFace* face, unsigned corner_edge_dex) const
{
if (0 == corner_edge_dex)
return this->LeftEdgePtr(face);
if (0 == corner_edge_dex)
return this->RightEdgePtr(face);
return ON_SubDEdgePtr::Null;
}
const ON_SubDEdgePtr ON_SubDFaceCornerDex::LeftEdgePtr(const ON_SubDFace* face) const
{
return this->PreviousCornerDex().RightEdgePtr(face);
}
const ON_SubDEdgePtr ON_SubDFaceCornerDex::RightEdgePtr(const ON_SubDFace* face) const
{
return IsValid(face) ? face->EdgePtr(m_corner_index) : ON_SubDEdgePtr::Null;
}
ON_SubDFaceCornerDex::ON_SubDFaceCornerDex(unsigned corner_index, unsigned edge_count)
{
if (corner_index < edge_count && edge_count >= 3 && edge_count <= ON_SubDFace::MaximumEdgeCount)
{
m_corner_index = (unsigned short)corner_index;
m_edge_count = (unsigned short)edge_count;
}
else
{
m_corner_index = 0;
m_edge_count = 0;
}
}
bool ON_SubDComponentParameter::Internal_Init(ON_SubDComponentId cid)
{
if (cid.IsSet())
{
switch (cid.ComponentType())
{
case ON_SubDComponentPtr::Type::Vertex:
m_cid = cid;
m_p0.v_active_e = ON_SubDEdgePtr::Null;
m_p1.v_active_f = ON_SubDFacePtr::Null;
break;
case ON_SubDComponentPtr::Type::Edge:
m_cid = cid;
m_p0.eptr_s = ON_DBL_QNAN;
m_p1.e_active_f = ON_SubDFacePtr::Null;
break;
case ON_SubDComponentPtr::Type::Face:
m_cid = cid;
m_p0.f_corner_s = ON_DBL_QNAN;
m_p1.f_corner_t = ON_DBL_QNAN;
break;
default:
m_cid = ON_SubDComponentParameter::Unset.m_cid;
m_p0.f_corner_s = 0.0;
m_p1.f_corner_t = 0.0;
break;
}
return true;
}
return false;
}
ON_SubDFaceParameter::ON_SubDFaceParameter(ON_SubDFaceCornerDex cdex, double s, double t)
: m_cdex(cdex)
, m_s((0.0 <= s && s <= 1.0) ? s : ON_DBL_QNAN)
, m_t((0.0 <= t && t <= 1.0) ? t : ON_DBL_QNAN)
{}
bool ON_SubDFaceParameter::IsSet()
{
return m_cdex.IsSet() && 0.0 <= m_s && m_s <= 0.5 && 0.0 <= m_t && m_t <= 0.5;
}
/// <returns>True if all values are not valid.</returns>
bool ON_SubDFaceParameter::IsNotSet()
{
return ON_SubDFaceParameter::IsSet() ? false : true;
}
const ON_SubDFaceParameter ON_SubDFaceParameter::CreateFromQuadFaceParameteters(double quad_face_s, double quad_face_t)
{
if (0.0 <= quad_face_s && 0.0 <= quad_face_t)
{
if (quad_face_t <= 0.5)
{
if (quad_face_s <= 0.5)
return ON_SubDFaceParameter(ON_SubDFaceCornerDex(0, 4), quad_face_s, quad_face_t);
if (quad_face_s <= 1.0)
return ON_SubDFaceParameter(ON_SubDFaceCornerDex(1, 4), quad_face_t, 1.0 - quad_face_s);
}
else if (quad_face_s <= 1.0 && quad_face_t <= 1.0)
{
if (quad_face_s >= 0.5)
return ON_SubDFaceParameter(ON_SubDFaceCornerDex(2, 4), 1.0 - quad_face_s, 1.0 - quad_face_t);
return ON_SubDFaceParameter(ON_SubDFaceCornerDex(3, 4), 1.0 - quad_face_t, quad_face_s);
}
}
return ON_SubDFaceParameter::Nan;
}
int ON_SubDFaceParameter::CompareAll(const ON_SubDFaceParameter& lhs, const ON_SubDFaceParameter& rhs)
{
// invalids go to the end
int i = lhs.IsSet() ? 0 : 1;
int j = rhs.IsSet() ? 0 : 1;
if (i < j)
return -1;
if (i > j)
return 1;
int rc = ON_SubDFaceCornerDex::CompareAll(lhs.m_cdex, rhs.m_cdex);
if (0 == rc)
{
rc = ON_DBL::CompareValue(lhs.m_s, rhs.m_s);
if (0 == rc)
rc = ON_DBL::CompareValue(lhs.m_t, rhs.m_t);
}
return rc;
}
int ON_SubDFaceParameter::Compare(const ON_SubDFaceParameter* lhs, const ON_SubDFaceParameter* rhs)
{
if (lhs == rhs)
return 0;
if (nullptr == lhs)
return 1;
if (nullptr == rhs)
return -1;
return ON_SubDFaceParameter::CompareAll(*lhs, *rhs);
}
bool ON_SubDFaceParameter::IsSet() const
{
return m_cdex.IsSet() && 0.0 <= m_s && m_s <= 0.5 && 0.0 <= m_t && m_t <= 0.5;
}
bool ON_SubDFaceParameter::IsNotSet() const
{
return IsSet() ? false : true;
}
const ON_SubDFaceCornerDex ON_SubDFaceParameter::FaceCornerDex() const
{
return m_cdex;
}
const ON_2dPoint ON_SubDFaceParameter::FaceCornerParameters() const
{
return IsSet() ? ON_2dPoint(m_s, m_t) : ON_2dPoint::NanPoint;
}
const ON_2dPoint ON_SubDFaceParameter::QuadFaceParameters() const
{
if (IsSet() && m_cdex.IsQuadFace())
{
switch (m_cdex.CornerIndex())
{
case 0:
return ON_2dPoint(m_s, m_t);
break;
case 1:
return ON_2dPoint(1.0 - m_t, m_s);
break;
case 2:
return ON_2dPoint(1.0 - m_s, 1.0 - m_t);
break;
case 3:
return ON_2dPoint(m_t, 1.0 - m_s);
break;
}
}
return ON_2dPoint::NanPoint;
}
ON_SubDComponentParameter::ON_SubDComponentParameter(ON_SubDComponentId cid)
{
Internal_Init(cid);
}
ON_SubDComponentParameter::ON_SubDComponentParameter(ON_SubDComponentPtr cptr)
{
Internal_Init(ON_SubDComponentId(cptr));
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const ON_SubDVertex* v,
const class ON_SubDEdge* active_edge,
const class ON_SubDFace* active_face
)
{
if (Internal_Init(ON_SubDComponentId(v)))
{
if (nullptr != active_edge)
{
const int vei = v->EdgeArrayIndex(active_edge);
m_p0.v_active_e = ON_SubDComponentId(v->EdgePtr(vei));
}
if (nullptr != active_face)
{
const int vfi = v->FaceArrayIndex(active_face);
m_p1.v_active_f = ON_SubDComponentId(v->Face(vfi));
}
}
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const ON_SubDVertexPtr vptr,
const class ON_SubDEdge* active_edge,
const class ON_SubDFace* active_face
)
{
if (Internal_Init(ON_SubDComponentId(vptr)))
{
const ON_SubDVertex* v = vptr.Vertex();
if (nullptr != v)
{
if (nullptr != active_edge)
{
const int vei = v->EdgeArrayIndex(active_edge);
m_p0.v_active_e = ON_SubDComponentId(v->EdgePtr(vei));
}
if (nullptr != active_face)
{
const int vfi = v->FaceArrayIndex(active_face);
m_p1.v_active_f = ON_SubDComponentId(v->Face(vfi));
}
}
}
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const ON_SubDEdge* e,
double edge_s,
const class ON_SubDFace* active_face
)
{
if (Internal_Init(ON_SubDComponentId(e)))
{
m_p0.eptr_s = (edge_s >= 0.0 && edge_s <= 1.0) ? edge_s : ON_DBL_QNAN;
if (nullptr != active_face)
{
const unsigned efi = e->FaceArrayIndex(active_face);
m_p1.e_active_f = e->FacePtr(efi);
}
}
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const ON_SubDEdgePtr eptr,
double edge_s,
const class ON_SubDFace* active_face
)
{
if (Internal_Init(ON_SubDComponentId(eptr)))
{
const ON_SubDEdge* e = eptr.Edge();
if (nullptr != e)
{
m_p0.eptr_s = (edge_s >= 0.0 && edge_s <= 1.0) ? edge_s : ON_DBL_QNAN;
if (nullptr != active_face)
{
const unsigned efi = e->FaceArrayIndex(active_face);
m_p1.e_active_f = e->FacePtr(efi);
}
}
}
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const ON_SubDFace* f,
ON_SubDFaceParameter fp
)
{
if (Internal_Init(ON_SubDComponentId(f)) && fp.IsSet())
{
const ON_SubDFaceCornerDex cdex = fp.FaceCornerDex();
if (cdex.IsSet() && cdex.EdgeCount() == f->EdgeCount())
{
const ON_2dPoint p = fp.FaceCornerParameters();
if (p.IsValid())
{
this->m_cid = ON_SubDComponentId(f, cdex.CornerIndex());
this->m_p0.f_corner_s = p.x;
this->m_p1.f_corner_t = p.y;
}
}
}
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const ON_SubDFacePtr fptr,
ON_SubDFaceParameter fp
)
{
if (Internal_Init(ON_SubDComponentId(fptr)) && fp.IsSet())
{
const ON_SubDFaceCornerDex cdex = fp.FaceCornerDex();
if (cdex.IsSet() && cdex.EdgeCount() == fptr.FaceEdgeCount())
{
const ON_2dPoint p = fp.FaceCornerParameters();
if (p.IsValid())
{
this->m_cid = ON_SubDComponentId(fptr, cdex.CornerIndex());
this->m_p0.f_corner_s = p.x;
this->m_p1.f_corner_t = p.y;
}
}
}
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const class ON_SubDFace* quad_face,
double quad_s,
double quad_t
)
{
if (
nullptr != quad_face
&& 4 == quad_face->m_edge_count
&& Internal_Init(quad_face)
)
{
const ON_SubDFaceParameter fp = ON_SubDFaceParameter::CreateFromQuadFaceParameteters(quad_s, quad_t);
const ON_2dPoint p = fp.FaceCornerParameters();
this->m_p0.f_corner_s = p.x;
this->m_p1.f_corner_t = p.y;
}
}
ON_SubDComponentParameter::ON_SubDComponentParameter(
const ON_SubDFacePtr quad_fptr,
double quad_s,
double quad_t
)
{
if (
quad_fptr.IsNotNull()
&& 4 == quad_fptr.FaceEdgeCount()
&& Internal_Init(quad_fptr)
)
{
const ON_SubDFaceParameter fp = ON_SubDFaceParameter::CreateFromQuadFaceParameteters(quad_s, quad_t);
const ON_2dPoint p = fp.FaceCornerParameters();
this->m_p0.f_corner_s = p.x;
this->m_p1.f_corner_t = p.y;
}
}
ON_SubDComponentPtr::Type ON_SubDComponentParameter::ComponentType() const
{
return m_cid.ComponentType();
}
int ON_SubDComponentParameter::CompareComponentTypeAndId(const ON_SubDComponentParameter& lhs, const ON_SubDComponentParameter& rhs)
{
return ON_SubDComponentId::CompareTypeAndId(lhs.m_cid, rhs.m_cid);
}
int ON_SubDComponentParameter::CompareComponentTypeAndIdAndDirection(const ON_SubDComponentParameter& lhs, const ON_SubDComponentParameter& rhs)
{
return ON_SubDComponentId::CompareTypeAndIdAndDirection(lhs.m_cid, rhs.m_cid);
}
int ON_SubDComponentParameter::CompareAll(const ON_SubDComponentParameter& lhs, const ON_SubDComponentParameter& rhs)
{
int rc = ON_SubDComponentParameter::CompareComponentTypeAndIdAndDirection(lhs, rhs);
if (0 == rc)
{
switch (lhs.m_cid.ComponentType())
{
case ON_SubDComponentPtr::Type::Vertex:
rc = ON_SubDComponentId::CompareTypeAndIdAndDirection(lhs.m_p0.v_active_e, rhs.m_p0.v_active_e);
if (0 == rc)
rc = ON_SubDComponentId::CompareTypeAndIdAndDirection(lhs.m_p1.v_active_f, rhs.m_p1.v_active_f);
break;
case ON_SubDComponentPtr::Type::Edge:
rc = ON_DBL::CompareValue(lhs.m_p0.eptr_s, rhs.m_p0.eptr_s);
if (0 == rc)
rc = ON_SubDComponentId::CompareTypeAndIdAndDirection(lhs.m_p1.e_active_f, rhs.m_p1.e_active_f);
break;
case ON_SubDComponentPtr::Type::Face:
rc = ON_SubDFaceParameter::CompareAll(lhs.FaceParameter(), rhs.FaceParameter());
break;
default:
break;
}
}
return rc;
}
const ON_SubDComponentId ON_SubDComponentParameter::ComponentIdAndType() const
{
return m_cid;
}
unsigned ON_SubDComponentParameter::ComponentId() const
{
return m_cid.ComponentId();
}
unsigned ON_SubDComponentParameter::ComponentDirection() const
{
return m_cid.ComponentDirection();
}
bool ON_SubDComponentParameter::IsVertexParameter() const
{
return ON_SubDComponentPtr::Type::Vertex == this->ComponentType();
}
bool ON_SubDComponentParameter::IsEdgeParameter() const
{
return ON_SubDComponentPtr::Type::Edge == this->ComponentType();
}
bool ON_SubDComponentParameter::IsFaceParameter() const
{
return ON_SubDComponentPtr::Type::Face == this->ComponentType();
}
const ON_SubDVertex* ON_SubDComponentParameter::Vertex(const ON_SubD* subd) const
{
return this->ComponentPtr(subd).Vertex();
}
const ON_SubDEdge* ON_SubDComponentParameter::Edge(const ON_SubD* subd) const
{
return this->ComponentPtr(subd).Edge();
}
const ON_SubDFace* ON_SubDComponentParameter::Face(const ON_SubD* subd) const
{
return this->ComponentPtr(subd).Face();
}
const ON_SubDComponentPtr ON_SubDComponentParameter::ComponentPtr(const ON_SubD* subd) const
{
return m_cid.ComponentPtr(subd);
}
const ON_SubDComponentPtr ON_SubDComponentParameter::ComponentPtr(const ON_SubD& subd) const
{
return m_cid.ComponentPtr(subd);
}
const ON_SubDVertexPtr ON_SubDComponentParameter::VertexPtr(const ON_SubD* subd) const
{
return this->ComponentPtr(subd).VertexPtr();
}
const ON_SubDEdgePtr ON_SubDComponentParameter::EdgePtr(const ON_SubD* subd) const
{
return this->ComponentPtr(subd).EdgePtr();
}
const ON_SubDFacePtr ON_SubDComponentParameter::FacePtr(const ON_SubD* subd) const
{
return this->ComponentPtr(subd).FacePtr();
}
const ON_SubDFaceParameter ON_SubDComponentParameter::FaceParameter() const
{
if (
this->IsFaceParameter()
&& 0.0 <= m_p0.f_corner_s && m_p0.f_corner_s <= 0.5
&& 0.0 <= m_p1.f_corner_t && m_p1.f_corner_t <= 0.5
)
{
const ON_SubDFaceCornerDex cdex = m_cid.FaceCornerDex();
if (cdex.IsSet())
{
return ON_SubDFaceParameter(cdex, m_p0.f_corner_s, m_p1.f_corner_t);
}
}
return ON_SubDFaceParameter::Nan;
}
const ON_SubDComponentId ON_SubDComponentParameter::VertexEdge() const
{
return this->IsVertexParameter() ? m_p0.v_active_e : ON_SubDComponentId::Unset;
}
const ON_SubDComponentId ON_SubDComponentParameter::VertexFace() const
{
return this->IsVertexParameter() ? m_p1.v_active_f : ON_SubDComponentId::Unset;
}
const ON_SubDComponentId ON_SubDComponentParameter::EdgeFace() const
{
return this->IsEdgeParameter() ? m_p1.e_active_f : ON_SubDComponentId::Unset;
}
double ON_SubDComponentParameter::EdgeParameter() const
{
return this->IsEdgeParameter() ? m_p0.eptr_s : ON_DBL_QNAN;
}
+78
View File
@@ -1801,6 +1801,84 @@ const ON_3dVector ON_SubDMeshFragment::VertexNormal(
;
}
const ON_SubDFaceParameter ON_SubDMeshFragment::VertexSubDFaceParameter(
ON_2udex grid2dex
) const
{
return VertexSubDFaceParameter(grid2dex.i, grid2dex.j);
}
const ON_SubDFaceParameter ON_SubDMeshFragment::VertexSubDFaceParameter(
unsigned grid2dex_i,
unsigned grid2dex_j
) const
{
for (;;)
{
const ON_3dPoint debugP = VertexPoint(grid2dex_i, grid2dex_j);
if (false == debugP.IsValid())
break;
const unsigned gc = m_grid.SideSegmentCount();
if (gc < 1)
break;
if (grid2dex_i > gc || grid2dex_j > gc)
break;
// quad faces have m_face_fragment_count = 1;
// n-gon faces have m_face_fragment_count = n (n = 3 or n >= 5)
const unsigned face_edge_count
= (1 == m_face_fragment_count)
? 4u
: ((unsigned)m_face_fragment_count);
if (face_edge_count < 3)
break;
if (4 == face_edge_count)
{
// quad face
if (0 != m_face_fragment_index)
break;
// quad parameters run from 0.0 to 1.0.
const double gdelta = 1.0 / ((double)gc);
const double quad_s = gdelta * grid2dex_i;
const double quad_t = gdelta * grid2dex_j;
const ON_SubDFaceParameter p = ON_SubDFaceParameter::CreateFromQuadFaceParameteters(quad_s, quad_t);
if (p.IsNotSet())
break;
return p;
}
// ngon face
if (0 != m_face_fragment_index >= face_edge_count)
break;
// corner parameters run from 0.0 to 0.5.
const double gdelta = 0.5 / ((double)gc);
const double corner_s = gdelta * grid2dex_i;
const double corner_t = gdelta * grid2dex_j;
const ON_SubDFaceCornerDex cdex(m_face_fragment_index, face_edge_count);
const ON_SubDFaceParameter p(cdex, corner_s, corner_t);
if (p.IsNotSet())
break;
return p;
}
return ON_SubDFaceParameter::Nan;
}
const ON_SubDFaceParameter ON_SubDMeshFragment::VertexSubDFaceParameter(
unsigned grid_point_index
) const
{
return
(grid_point_index < VertexCount())
? VertexSubDFaceParameter(m_grid.Grid2dexFromPointIndex(grid_point_index))
: ON_SubDFaceParameter::Nan;
}
const class ON_SubDEdge* ON_SubDMeshFragment::SubDEdge(
unsigned int grid_side_index
) const
+32 -8
View File
@@ -553,6 +553,24 @@ void ON_SunEngine::ConvertSolarVectorToHorizonCoords(const double* dVector, doub
dAzimuth += 360.0;
}
void ON_SunEngine::GetCurrentLocalDateTime(int& y, int& m, int& d, double& h)
{
const time_t time = ON_SecondsSinceJanOne1970UTC();
tm ttm = { 0 };
#ifdef ON_RUNTIME_WIN
_localtime64_s(&ttm, &time);
#else
ttm = *localtime(&time);
#endif
y = ttm.tm_year + 1900;
m = ttm.tm_mon + 1;
d = ttm.tm_mday;
h = ttm.tm_hour + (ttm.tm_min / 60.0) + (ttm.tm_sec / 3600.0);
}
class ON_Sun::CImpl : public ON_InternalXMLImpl
{
public:
@@ -793,11 +811,14 @@ void ON_Sun::CImpl::SetDaylightSavingMinutes(int minutes)
void ON_Sun::CImpl::LocalDateTime(int& year, int& month, int& day, double& hours) const
{
int cy = 0, cm = 0, cd = 0; double ch = 0.0;
ON_SunEngine::GetCurrentLocalDateTime(cy, cm, cd, ch);
const wchar_t* s = XMLPath_Sun();
year = GetParameter(s, ON_RDK_SUN_DATE_YEAR, 2000);
month = GetParameter(s, ON_RDK_SUN_DATE_MONTH, 1);
day = GetParameter(s, ON_RDK_SUN_DATE_DAY, 1);
hours = GetParameter(s, ON_RDK_SUN_TIME_HOURS, 0.0);
year = GetParameter(s, ON_RDK_SUN_DATE_YEAR, cy);
month = GetParameter(s, ON_RDK_SUN_DATE_MONTH, cm);
day = GetParameter(s, ON_RDK_SUN_DATE_DAY, cd);
hours = GetParameter(s, ON_RDK_SUN_TIME_HOURS, ch);
}
bool ON_Sun::CImpl::SetLocalDateTime(int year, int month, int day, double hours)
@@ -1322,10 +1343,13 @@ void ON_Sun::LoadFromXMLNode(const ON_XMLNode& node)
{
ON_XMLParameters p(node);
const auto y = p.GetParam(ON_RDK_SUN_DATE_YEAR, 2000).AsInteger();
const auto m = p.GetParam(ON_RDK_SUN_DATE_MONTH, 1).AsInteger();
const auto d = p.GetParam(ON_RDK_SUN_DATE_DAY, 1).AsInteger();
const auto h = p.GetParam(ON_RDK_SUN_TIME_HOURS, 12.0).AsDouble();
int cy = 0, cm = 0, cd = 0; double ch = 0.0;
ON_SunEngine::GetCurrentLocalDateTime(cy, cm, cd, ch);
const auto y = p.GetParam(ON_RDK_SUN_DATE_YEAR, cy).AsInteger();
const auto m = p.GetParam(ON_RDK_SUN_DATE_MONTH, cm).AsInteger();
const auto d = p.GetParam(ON_RDK_SUN_DATE_DAY, cd).AsInteger();
const auto h = p.GetParam(ON_RDK_SUN_TIME_HOURS, ch).AsDouble();
SetLocalDateTime(y, m, d, h);
SetEnableAllowed (p.GetParam(ON_RDK_SUN_ENABLE_ALLOWED, false));
+3
View File
@@ -101,6 +101,9 @@ public:
// Helper function; converts unit vector to azimuth and altitude.
static void ConvertSolarVectorToHorizonCoords(const double* dVector, double& dAzimuth, double& dAltitude);
// Helper function; gets the current local date and time.
static void GetCurrentLocalDateTime(int& y, int& m, int& d, double& h);
private:
class CImpl;
CImpl* _impl;
+6
View File
@@ -292,6 +292,12 @@ public:
*/
bool IsWcsBoxProjected() const;
/*
Description:
Evaluates WCS box projection at point pt with normal n.
*/
static ON_3dPoint WcsBoxMapping(const ON_3dPoint& pt, const ON_3dVector& n);
// If the m_mapping_channel_id value is one of the built-in
// mappings listed in the MAPPING_CHANNEL enum, then that
// mapping is used. Otherwise, if an object has rendering
+4 -1
View File
@@ -30,6 +30,7 @@ class ON_3dPoint;
typedef int ( *TEXMAP_INTERSECT_LINE_SURFACE )( const ON_Line*, const ON_BrepFace*, ON_SimpleArray<ON_X_EVENT>& );
typedef bool ( *TEXMAP_BREP_FACE_CLOSEST_POINT )( const ON_BrepFace*, const ON_3dPoint*, ON_3dPoint& );
typedef ON_TextureMapping ( *GET_TEXMAP_FROM_DOCUMENT )( const class CRhinoDoc&, const ON_MappingChannel* );
class ON_CLASS ON_TextureMapping : public ON_ModelComponent
{
@@ -91,7 +92,9 @@ public:
srf_mapping_primitive = 7, // m_mapping_primitive is an ON_Surface
brep_mapping_primitive = 8, // m_mapping_primitive is an ON_Brep
ocs_mapping = 9, // same as plane_mapping - used to differentiate between OCS and plane mapping in the UI
false_colors = 10 // some kind of false color mapping used to set per vertex colors.
false_colors = 10, // some kind of false color mapping used to set per vertex colors.
wcs_projection = 11, // used for ON_MappingTag when creating texture coordinates for WCS projections
wcsbox_projection = 12 // used for ON_MappingTag when creating texture coordinates for WCS box projections
};
static ON_TextureMapping::TYPE TypeFromUnsigned(
+4 -1
View File
@@ -5339,8 +5339,11 @@ void ON_RdkDocumentDefaults::CreateXML(void)
p.SetParam(ON_RDK_SUN_DAYLIGHT_SAVING_ON, false);
p.SetParam(ON_RDK_SUN_DAYLIGHT_SAVING_MINUTES, 60);
int cy = 0, cm = 0, cd = 0; double ch = 0.0;
ON_SunEngine::GetCurrentLocalDateTime(cy, cm, cd, ch);
ON_SunEngine engine(ON_SunEngine::Accuracy::Minimum);
engine.SetLocalDateTime(2000, 1, 1, 12.0);
engine.SetLocalDateTime(cy, cm, cd, ch);
int y = 0, m = 0, d = 0; double h = 0.0;
engine.LocalDateTime(y, m, d, h);
p.SetParam(ON_RDK_SUN_DATE_YEAR, y);