mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-09-04 00:50:16 +08:00
Sync changes from upstream repository
This commit is contained in:
@@ -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 */,
|
||||
|
||||
@@ -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
@@ -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 > 0, then +1 is returned.
|
||||
/// If x < 0, then -1 is returned.
|
||||
/// Otherwise 0 is returned.
|
||||
/// </returns>
|
||||
static int Sign(double x);
|
||||
|
||||
/// <summary>
|
||||
/// All nans, +infinity, -infinity,
|
||||
/// x <= than ON_DBL::Unset and
|
||||
/// x >= 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 < x && x < 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 < rhs or IsNotNan(lhs) and IsNan(rhs).
|
||||
/// 0 if lhs == rhs or IsNan(lhs) && IsNan(rhs).
|
||||
/// +1 if lhs > rhs or IsNotNan(lhs) && 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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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] )
|
||||
|
||||
@@ -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
@@ -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]
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+262
-43
@@ -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
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user