From 76f86d7e68341f3c80be8fcf50f3312c112072bd Mon Sep 17 00:00:00 2001 From: Bozo the Builder Date: Tue, 13 May 2025 04:08:15 -0700 Subject: [PATCH] Sync changes from upstream repository --- opennurbs_array.cpp | 4 - opennurbs_array.h | 183 +++++++++++----------- opennurbs_decals.cpp | 307 +++++++++++++++++++++++++------------ opennurbs_decals.h | 97 +++++++++++- opennurbs_input_libsdir.h | 6 + opennurbs_mesh.cpp | 12 +- opennurbs_mesh.h | 2 + opennurbs_nurbssurface.cpp | 159 +++++++++++++------ opennurbs_public.vcxproj | 1 + opennurbs_public_version.h | 20 +-- opennurbs_subd.h | 203 ++++++++++++++++++++++-- opennurbs_sun.cpp | 21 +++ opennurbs_xml.cpp | 28 +++- opennurbs_xml.h | 2 + opennurbs_zlib.cpp | 16 +- 15 files changed, 779 insertions(+), 282 deletions(-) diff --git a/opennurbs_array.cpp b/opennurbs_array.cpp index 8c870636..7264e9aa 100644 --- a/opennurbs_array.cpp +++ b/opennurbs_array.cpp @@ -1189,10 +1189,6 @@ ON_UuidPtr* ON_UuidPtrList::SearchHelper(const ON_UUID* uuid) const return p; } -// static_assert(sizeof(ON_UuidPairList) == sizeof(ON_UuidPairList2), "ON_UuidPairList and ON_UuidPairList2 are not the same size"); -// static_assert(sizeof(ON_UuidPtrList) == sizeof(ON_UuidPtrList2), "ON_UuidPtrList and ON_UuidPtrList2 are not the same size"); -// static_assert(sizeof(ON_UuidIndexList) == sizeof(ON_UuidIndexList2), "ON_UuidIndexList and ON_UuidIndexList2 are not the same size"); - template struct ON_UuidList2_Private { diff --git a/opennurbs_array.h b/opennurbs_array.h index 46053ece..7e51a018 100644 --- a/opennurbs_array.h +++ b/opennurbs_array.h @@ -1282,104 +1282,7 @@ private: }; -class ON_CLASS ON_UuidPtrList2 -{ -public: - ON_UuidPtrList2(); - ~ON_UuidPtrList2(); - ON_UuidPtrList2(const ON_UuidPtrList2& src); - ON_UuidPtrList2& operator=(const ON_UuidPtrList2& src); - unsigned int Count() const; - void RemoveAll(); - void Reserve(size_t capacity); - bool AddUuidPtr(const ON_UUID& uuid, ON__UINT_PTR ptr); - bool RemoveUuid(const ON_UUID& uuid); - bool FindUuid(const ON_UUID& uuid) const; - bool FindUuid(const ON_UUID& uuid, ON__UINT_PTR* ptr) const; - bool FindUuidPtr(const ON_UUID& uuid, ON__UINT_PTR index) const; - unsigned int GetUuids(ON_SimpleArray& uuid_list) const; - void ImproveSearchSpeed(); - -private: -#pragma warning (push) -#pragma warning (disable : 4251) - std::unique_ptr m_private; - unsigned int padding[2]; -#if defined (ON_RUNTIME_ANDROID) //Android has 32-bit pointers? - unsigned char padding_array[12]; -#else - unsigned char padding_array[16]; -#endif -#pragma warning (pop) -}; - -class ON_CLASS ON_UuidPairList2 -{ -public: - ON_UuidPairList2(); - ~ON_UuidPairList2(); - ON_UuidPairList2(const ON_UuidPairList2& src); - ON_UuidPairList2& operator=(const ON_UuidPairList2& src); - - static const ON_UuidPairList2 EmptyList; - - unsigned int Count() const; - void Empty(); - void Reserve(size_t capacity); - bool AddPair(const ON_UUID& id1, const ON_UUID& id2); - bool RemovePair(const ON_UUID& id1); - bool RemovePair(const ON_UUID& id1, const ON_UUID& id2); - bool FindId1(const ON_UUID& id1, ON_UUID* id2 = 0) const; - bool FindPair(const ON_UUID& id1, const ON_UUID& id2) const; - int GetId1s(ON_SimpleArray& uuid_list) const; - - void ImproveSearchSpeed(); - -private: -#pragma warning (push) -#pragma warning (disable : 4251) - std::unique_ptr m_private; - unsigned int padding[2]; -#if defined (ON_RUNTIME_ANDROID) //Android has 32-bit pointers? - unsigned char padding_array[12]; -#else - unsigned char padding_array[16]; -#endif -#pragma warning (pop) -}; - -class ON_CLASS ON_UuidIndexList2 -{ -public: - ON_UuidIndexList2(); - ~ON_UuidIndexList2(); - ON_UuidIndexList2(const ON_UuidIndexList2& src); - ON_UuidIndexList2& operator=(const ON_UuidIndexList2& src); - - unsigned int Count() const; - void RemoveAll(); - void Reserve(size_t capacity); - bool AddUuidIndex(const ON_UUID& uuid, int index); - bool RemoveUuid(const ON_UUID& uuid); - bool FindUuid(const ON_UUID& uuid) const; - bool FindUuid(const ON_UUID& uuid, int* index) const; - bool FindUuidIndex(const ON_UUID& uuid, int index) const; - unsigned int GetUuids(ON_SimpleArray& uuid_list) const; - void ImproveSearchSpeed(); - -private: -#pragma warning (push) -#pragma warning (disable : 4251) - std::unique_ptr m_private; - unsigned int padding[2]; -#if defined (ON_RUNTIME_ANDROID) //Android has 32-bit pointers? - unsigned char padding_array[12]; -#else - unsigned char padding_array[16]; -#endif -#pragma warning (pop) -}; @@ -1536,6 +1439,92 @@ private: +class ON_CLASS ON_UuidPtrList2 +{ +public: + ON_UuidPtrList2(); + ~ON_UuidPtrList2(); + ON_UuidPtrList2(const ON_UuidPtrList2& src); + ON_UuidPtrList2& operator=(const ON_UuidPtrList2& src); + + unsigned int Count() const; + void RemoveAll(); + void Reserve(size_t capacity); + bool AddUuidPtr(const ON_UUID& uuid, ON__UINT_PTR ptr); + bool RemoveUuid(const ON_UUID& uuid); + bool FindUuid(const ON_UUID& uuid) const; + bool FindUuid(const ON_UUID& uuid, ON__UINT_PTR* ptr) const; + bool FindUuidPtr(const ON_UUID& uuid, ON__UINT_PTR index) const; + unsigned int GetUuids(ON_SimpleArray& uuid_list) const; + void ImproveSearchSpeed(); + +private: +#pragma warning (push) +#pragma warning (disable : 4251) + std::unique_ptr m_private; + unsigned char padding[sizeof(ON_UuidPtrList) - sizeof(m_private)]; +#pragma warning (pop) +}; + +class ON_CLASS ON_UuidPairList2 +{ +public: + ON_UuidPairList2(); + ~ON_UuidPairList2(); + ON_UuidPairList2(const ON_UuidPairList2& src); + ON_UuidPairList2& operator=(const ON_UuidPairList2& src); + + static const ON_UuidPairList2 EmptyList; + + unsigned int Count() const; + void Empty(); + void Reserve(size_t capacity); + bool AddPair(const ON_UUID& id1, const ON_UUID& id2); + bool RemovePair(const ON_UUID& id1); + bool RemovePair(const ON_UUID& id1, const ON_UUID& id2); + bool FindId1(const ON_UUID& id1, ON_UUID* id2 = 0) const; + bool FindPair(const ON_UUID& id1, const ON_UUID& id2) const; + int GetId1s(ON_SimpleArray& uuid_list) const; + + void ImproveSearchSpeed(); + +private: +#pragma warning (push) +#pragma warning (disable : 4251) + std::unique_ptr m_private; + unsigned char padding[sizeof(ON_UuidPairList) - sizeof(m_private)]; +#pragma warning (pop) +}; + +class ON_CLASS ON_UuidIndexList2 +{ +public: + ON_UuidIndexList2(); + ~ON_UuidIndexList2(); + ON_UuidIndexList2(const ON_UuidIndexList2& src); + ON_UuidIndexList2& operator=(const ON_UuidIndexList2& src); + + unsigned int Count() const; + void RemoveAll(); + void Reserve(size_t capacity); + bool AddUuidIndex(const ON_UUID& uuid, int index); + bool RemoveUuid(const ON_UUID& uuid); + bool FindUuid(const ON_UUID& uuid) const; + bool FindUuid(const ON_UUID& uuid, int* index) const; + bool FindUuidIndex(const ON_UUID& uuid, int index) const; + unsigned int GetUuids(ON_SimpleArray& uuid_list) const; + void ImproveSearchSpeed(); + +private: +#pragma warning (push) +#pragma warning (disable : 4251) + std::unique_ptr m_private; + unsigned char padding[sizeof(ON_UuidIndexList) - sizeof(m_private)]; +#pragma warning (pop) +}; + + + class ON_CLASS ON_2dexMap : private ON_SimpleArray { diff --git a/opennurbs_decals.cpp b/opennurbs_decals.cpp index 4ad1dbd2..bbe05b96 100644 --- a/opennurbs_decals.cpp +++ b/opennurbs_decals.cpp @@ -26,7 +26,7 @@ static ON_4dPoint UNSET_4D_POINT = ON_4dPoint(ON_UNSET_VALUE, ON_UNSET_VALUE, ON_UNSET_VALUE, ON_UNSET_VALUE); -ON__UINT32 ON_DecalCRCFromNode(const ON_XMLNode& node) +ON_DECAL_CRC ON_DecalCRCFromNode(const ON_XMLNode& node) { return ON_Decal::ComputeDecalCRC(0, node); } @@ -34,8 +34,9 @@ ON__UINT32 ON_DecalCRCFromNode(const ON_XMLNode& node) class ON_Decal::CImpl : public ON_InternalXMLImpl { public: - CImpl() { ON_CreateUuid(_decal_id); } - CImpl(ON_DecalCollection& dc, ON_XMLNode& node) : _collection(&dc), ON_InternalXMLImpl(&node) { ON_CreateUuid(_decal_id); } + CImpl(); + CImpl(ON_DecalCollection* dc, ON_XMLNode& node); + CImpl(ON_DecalCollection* dc, const ON_XMLNode& node); ON_UUID TextureInstanceId(void) const; void SetTextureInstanceId(const ON_UUID& id); @@ -110,6 +111,27 @@ static ON_Decal::Mappings MappingFromString(const ON_wString& s) return ON_Decal::Mappings::None; } +ON_Decal::CImpl::CImpl() +{ + ON_CreateUuid(_decal_id); +} + +ON_Decal::CImpl::CImpl(ON_DecalCollection* dc, ON_XMLNode& node) + : + _collection(dc), + ON_InternalXMLImpl(&node) +{ + ON_CreateUuid(_decal_id); +} + +ON_Decal::CImpl::CImpl(ON_DecalCollection* dc, const ON_XMLNode& node) + : + _collection(dc), + ON_InternalXMLImpl(&const_cast(node)) +{ + ON_CreateUuid(_decal_id); +} + ON_XMLVariant ON_Decal::CImpl::GetParameter(const wchar_t* param_name, const ON_XMLVariant& def) const { return ON_InternalXMLImpl::GetParameter(L"", param_name, def); @@ -462,11 +484,25 @@ ON_Decal::ON_Decal() _impl = new CImpl; } +ON_Decal::ON_Decal(ON_XMLNode& node) +{ + ON_ASSERT(node.TagName() == ON_RDK_DECAL); + + _impl = new CImpl(nullptr, node); +} + +ON_Decal::ON_Decal(const ON_XMLNode& node) +{ + ON_ASSERT(node.TagName() == ON_RDK_DECAL); + + _impl = new CImpl(nullptr, node); +} + ON_Decal::ON_Decal(ON_DecalCollection& dc, ON_XMLNode& node) { ON_ASSERT(node.TagName() == ON_RDK_DECAL); - _impl = new CImpl(dc, node); + _impl = new CImpl(&dc, node); } ON_Decal::ON_Decal(const ON_Decal& d) @@ -679,9 +715,9 @@ ON_UUID ON_Decal::Id(void) const return _impl->Id(); } -ON__UINT32 ON_Decal::DecalCRC(void) const +ON_DECAL_CRC ON_Decal::DecalCRC(void) const { - return DataCRC(0); + return ComputeDecalCRC(0, _impl->Node()); } ON__UINT32 ON_Decal::DataCRC(ON__UINT32 current_remainder) const @@ -734,6 +770,21 @@ bool ON_Decal::SetCustomXML(const ON_UUID& renderEngineId, const ON_XMLNode& cus return true; } +void ON_Decal::AppendCustomXML(const ON_XMLNode& custom_node) +{ + // This function only exists to support the RDK. + + ON_ASSERT(custom_node.TagName() == L"entire-custom-xml"); + + ON_XMLNode* child = custom_node.FirstChild(); + while (nullptr != child) + { + _impl->Node().AttachChildNode(new ON_XMLNode(*child)); + + child = custom_node.NextSibling(); + } +} + // Copied from IRhRdkDecal::GetTextureMapping -- TODO: Refactor. [JOHN-DECAL-FIX] bool ON_Decal::GetTextureMapping(ON_TextureMapping& mappingOut) const { @@ -810,24 +861,24 @@ bool ON_Decal::GetTextureMapping(ON_TextureMapping& mappingOut) const This object encapsulates the reading of all decal properties from XML nodes. It is used by the decal CRC calculation in ComputeDecalCRC(). - TODO: It could also be used by the ON_Decal XML node access. + TODO: It could also be used by the ON_Decal XML node access (for Rhino 9). */ class ON_DecalNodeReader { public: - ON_DecalNodeReader(const ON_XMLNode* p) : m_pNode(p) { } + ON_DecalNodeReader(const ON_XMLNode* decal_node); ON_XMLVariant Mapping(void) const { return Value(ON_RDK_DECAL_MAPPING, ON_RDK_DECAL_MAPPING_NONE); } ON_XMLVariant Projection(void) const { return Value(ON_RDK_DECAL_PROJECTION, ON_RDK_DECAL_PROJECTION_NONE); } - ON_XMLVariant MapToInside(void) const { return Value(ON_RDK_DECAL_MAP_TO_INSIDE_ON, m_def.MapToInside()); } - ON_XMLVariant Transparency(void) const { return Value(ON_RDK_DECAL_TRANSPARENCY , m_def.Transparency()); } - ON_XMLVariant TextureInstanceId(void) const { return Value(ON_RDK_DECAL_TEXTURE_INSTANCE, m_def.TextureInstanceId()); } - ON_XMLVariant Height(void) const { return Value(ON_RDK_DECAL_HEIGHT , m_def.Height()); } - ON_XMLVariant Radius(void) const { return Value(ON_RDK_DECAL_RADIUS , m_def.Radius()); } - ON_XMLVariant Origin(void) const { return Value(ON_RDK_DECAL_ORIGIN , m_def.Origin()); } - ON_XMLVariant VectorUp(void) const { return Value(ON_RDK_DECAL_VECTOR_UP , ON_3dPoint(m_def.VectorUp())); } - ON_XMLVariant VectorAcross(void) const { return Value(ON_RDK_DECAL_VECTOR_ACROSS , ON_3dPoint(m_def.VectorAcross())); } + ON_XMLVariant MapToInside(void) const { return Value(ON_RDK_DECAL_MAP_TO_INSIDE_ON, _def.MapToInside()); } + ON_XMLVariant Transparency(void) const { return Value(ON_RDK_DECAL_TRANSPARENCY , _def.Transparency()); } + ON_XMLVariant TextureInstanceId(void) const { return Value(ON_RDK_DECAL_TEXTURE_INSTANCE, _def.TextureInstanceId()); } + ON_XMLVariant Height(void) const { return Value(ON_RDK_DECAL_HEIGHT , _def.Height()); } + ON_XMLVariant Radius(void) const { return Value(ON_RDK_DECAL_RADIUS , _def.Radius()); } + ON_XMLVariant Origin(void) const { return Value(ON_RDK_DECAL_ORIGIN , _def.Origin()); } + ON_XMLVariant VectorUp(void) const { return Value(ON_RDK_DECAL_VECTOR_UP , ON_3dPoint(_def.VectorUp())); } + ON_XMLVariant VectorAcross(void) const { return Value(ON_RDK_DECAL_VECTOR_ACROSS , ON_3dPoint(_def.VectorAcross())); } ON_XMLVariant HorzSweepSta(void) const { return Value(ON_RDK_DECAL_HORZ_SWEEP_STA , DefaultHorzSweepSta()); } ON_XMLVariant HorzSweepEnd(void) const { return Value(ON_RDK_DECAL_HORZ_SWEEP_END , DefaultHorzSweepEnd()); } ON_XMLVariant VertSweepSta(void) const { return Value(ON_RDK_DECAL_VERT_SWEEP_STA , DefaultVertSweepSta()); } @@ -837,109 +888,79 @@ public: ON_XMLVariant MaxU(void) const { return Value(ON_RDK_DECAL_MAX_U , DefaultMaxU()); } ON_XMLVariant MaxV(void) const { return Value(ON_RDK_DECAL_MAX_V , DefaultMaxV()); } ON_XMLVariant IsTemporary(void) const { return Value(ON_RDK_DECAL_IS_TEMPORARY , false); } - ON_XMLVariant IsVisible(void) const { return Value(ON_RDK_DECAL_IS_VISIBLE , m_def.IsVisible()); } - ON_XMLVariant InstanceId(void) const { return Value(ON_RDK_DECAL_INSTANCE_ID , m_def.Id()); } + ON_XMLVariant IsVisible(void) const { return Value(ON_RDK_DECAL_IS_VISIBLE , _def.IsVisible()); } + ON_XMLVariant InstanceId(void) const { return Value(ON_RDK_DECAL_INSTANCE_ID , _def.Id()); } private: ON_XMLVariant Value(const wchar_t* wszName, const ON_XMLVariant& vDefault) const; - double DefaultHorzSweepSta(void) const { double a, b; m_def.GetHorzSweep(a, b); return a; } - double DefaultHorzSweepEnd(void) const { double a, b; m_def.GetHorzSweep(a, b); return b; } - double DefaultVertSweepSta(void) const { double a, b; m_def.GetVertSweep(a, b); return a; } - double DefaultVertSweepEnd(void) const { double a, b; m_def.GetVertSweep(a, b); return b; } + double DefaultHorzSweepSta(void) const { double a, b; _def.GetHorzSweep(a, b); return a; } + double DefaultHorzSweepEnd(void) const { double a, b; _def.GetHorzSweep(a, b); return b; } + double DefaultVertSweepSta(void) const { double a, b; _def.GetVertSweep(a, b); return a; } + double DefaultVertSweepEnd(void) const { double a, b; _def.GetVertSweep(a, b); return b; } - double DefaultMinU(void) const { double a, b, c, d; m_def.GetUVBounds(a, b, c, d); return a; } - double DefaultMinV(void) const { double a, b, c, d; m_def.GetUVBounds(a, b, c, d); return b; } - double DefaultMaxU(void) const { double a, b, c, d; m_def.GetUVBounds(a, b, c, d); return c; } - double DefaultMaxV(void) const { double a, b, c, d; m_def.GetUVBounds(a, b, c, d); return d; } + double DefaultMinU(void) const { double a, b, c, d; _def.GetUVBounds(a, b, c, d); return a; } + double DefaultMinV(void) const { double a, b, c, d; _def.GetUVBounds(a, b, c, d); return b; } + double DefaultMaxU(void) const { double a, b, c, d; _def.GetUVBounds(a, b, c, d); return c; } + double DefaultMaxV(void) const { double a, b, c, d; _def.GetUVBounds(a, b, c, d); return d; } private: - const ON_XMLNode* m_pNode; - const ON_Decal m_def; + const ON_XMLNode* _decal_node; + const ON_Decal _def; }; +ON_DecalNodeReader::ON_DecalNodeReader(const ON_XMLNode* decal_node) + : + _decal_node(decal_node) +{ + ON_ASSERT(_decal_node && (_decal_node->TagName() == ON_RDK_DECAL)); +} + ON_XMLVariant ON_DecalNodeReader::Value(const wchar_t* wszName, const ON_XMLVariant& vDefault) const { ON_XMLVariant vValue = vDefault; - if (nullptr != m_pNode) + if (nullptr != _decal_node) { - const ON_XMLParameters p(*m_pNode); + const ON_XMLParameters p(*_decal_node); p.GetParam(wszName, vValue); } return vValue; } -static void DecalUpdateCRC(ON__UINT32& crc, const ON_XMLVariant value) +#if (defined _DEBUG) && (defined HUMAN_READABLE_DECAL_CRC) +#define ON_DECAL_PROP_NAME(s) , s +static void DecalUpdateCRC(ON_DECAL_CRC& crc, const ON_XMLVariant value, const wchar_t* name) +{ + crc = value.DataCRC(crc); + crc._info1 += ON_wString(name) + L"=" + value.AsString() + ON_wString(L" "); + crc._info2 += ON_wString(name) + L"=" + value.AsString() + ON_wString(L"\n"); +} +#else +#define ON_DECAL_PROP_NAME(s) +static void DecalUpdateCRC(ON_DECAL_CRC& crc, const ON_XMLVariant& value) { crc = value.DataCRC(crc); } +#endif -ON__UINT32 ON_Decal::ComputeDecalCRC(ON__UINT32 crc, const ON_XMLNode& node) // Static. +static void DecalUpdateCRC_Custom(const ON_XMLNode& decal_node, ON_DECAL_CRC& crc) { - const ON_DecalNodeReader d(&node); - - const ON_wString s = d.Mapping().AsString(); - const auto mapping = MappingFromString(s); - - DecalUpdateCRC(crc, d.Mapping()); - DecalUpdateCRC(crc, d.IsVisible()); - DecalUpdateCRC(crc, d.IsTemporary()); - DecalUpdateCRC(crc, d.Transparency()); - DecalUpdateCRC(crc, d.TextureInstanceId()); - - if (Mappings::Planar == mapping) - { - DecalUpdateCRC(crc, d.MinU()); - DecalUpdateCRC(crc, d.MinV()); - DecalUpdateCRC(crc, d.MaxU()); - DecalUpdateCRC(crc, d.MaxV()); - } - else - { - DecalUpdateCRC(crc, d.Origin()); - DecalUpdateCRC(crc, d.VectorUp()); - DecalUpdateCRC(crc, d.VectorAcross()); - DecalUpdateCRC(crc, d.Projection()); - - if ((Mappings::Cylindrical == mapping) || (Mappings::Spherical == mapping)) - { - DecalUpdateCRC(crc, d.Radius()); - DecalUpdateCRC(crc, d.MapToInside()); - DecalUpdateCRC(crc, d.HorzSweepSta()); - DecalUpdateCRC(crc, d.HorzSweepEnd()); - - if (Mappings::Cylindrical == mapping) - { - DecalUpdateCRC(crc, d.Height()); - } - else - if (Mappings::Spherical == mapping) - { - DecalUpdateCRC(crc, d.VertSweepSta()); - DecalUpdateCRC(crc, d.VertSweepEnd()); - } - } - } - // Look for custom data nodes and for each one, find the parameter node and then iterate over its // children and CRC the properties. For now, we will have to rely on the raw XML. A better solution // would be to have the plug-in that created this XML calculate the CRC itself. - auto it = node.GetChildIterator(); + + const ON_wString custom = L"[CUSTOM] "; + + auto it = decal_node.GetChildIterator(); ON_XMLNode* pChildNode = nullptr; while (nullptr != (pChildNode = it.GetNextChild())) { if (pChildNode->TagName() != ON_RDK_DECAL_CUSTOM) continue; // Not a custom data node. - ON_XMLProperty* prop = pChildNode->GetNamedProperty(ON_RDK_DECAL_CUSTOM_RENDERER); - if (nullptr != prop) - { - // Include the render engine id. - const ON_UUID uuid = prop->GetValue().AsUuid(); - crc = ON_CRC32(crc, sizeof(uuid), &uuid); - } + const ON__UINT32 crc_before_custom_params = crc; // Find the custom parameter node. const ON_XMLNode* pParamNode = pChildNode->GetNamedChild(ON_RDK_DECAL_CUSTOM_PARAMS); @@ -947,22 +968,103 @@ ON__UINT32 ON_Decal::ComputeDecalCRC(ON__UINT32 crc, const ON_XMLNode& node) // { // Iterate over the nodes inside the custom parameter node. const ON_XMLParameters p(*pParamNode); - auto* pIterator = p.NewIterator(); - - ON_wString sParamName; - ON_XMLVariant vParamValue; - while (pIterator->Next(sParamName, vParamValue)) + auto* iterator = p.NewIterator(); + if (nullptr != iterator) { - DecalUpdateCRC(crc, vParamValue); + ON_wString sParamName; + ON_XMLVariant vParamValue; + while (iterator->Next(sParamName, vParamValue)) + { + DecalUpdateCRC(crc, vParamValue ON_DECAL_PROP_NAME(custom + sParamName)); + } + + delete iterator; } - delete pIterator; + if (crc != crc_before_custom_params) + { + // 20th January 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-71351 + // Since the crc has changed, there must be some custom params, so only now do we include the render + // engine id. Prior to this, the render engine id was getting included even when there were no custom + // params. This caused the UI to overlook decals which were programatically created by clients. + const ON_XMLProperty* prop = pChildNode->GetNamedProperty(ON_RDK_DECAL_CUSTOM_RENDERER); + if (nullptr != prop) + { + // Include the render engine id. + const ON_UUID uuid = prop->GetValue().AsUuid(); + DecalUpdateCRC(crc, uuid ON_DECAL_PROP_NAME(custom + L"render_engine_id")); + } + } } } +} - // Make sure it's not zero which would mean 'nil'. - if (0 == crc) - crc--; +ON_DECAL_CRC ON_Decal::ComputeDecalCRC(ON__UINT32 current_remainder, const ON_XMLNode& decal_node) // Static. +{ + // The CRC of a decal is a unique value based on its state. It's created by CRC-ing all the decal properties + // that affect the decal's appearance. We do not include the 'IsTemporary' property in the CRC because whether + // or not a decal is temporary has nothing to do with what it looks like. We do however, include the 'IsVisible' + // property because a decal being visible or invisible actually affects its appearance. Also, the RDK change + // queue relies on the CRC to update the viewport so including the visibility is critical. Furthermore, the + // CRC only includes the properties that are relevant for the decal's mapping type. + + ON_DECAL_CRC crc = current_remainder; + + if (decal_node.TagName() == ON_RDK_DECAL) + { + const ON_DecalNodeReader d(&decal_node); + + DecalUpdateCRC(crc, d.Mapping() ON_DECAL_PROP_NAME(L"mapping")); + DecalUpdateCRC(crc, d.IsVisible() ON_DECAL_PROP_NAME(L"visible")); + DecalUpdateCRC(crc, d.Transparency() ON_DECAL_PROP_NAME(L"transparency")); + DecalUpdateCRC(crc, d.TextureInstanceId() ON_DECAL_PROP_NAME(L"texture_id")); + + const ON_Decal::Mappings mapping = MappingFromString(d.Mapping().AsString()); + + if (Mappings::UV == mapping) + { + DecalUpdateCRC(crc, d.MinU() ON_DECAL_PROP_NAME(L"min_u")); + DecalUpdateCRC(crc, d.MinV() ON_DECAL_PROP_NAME(L"min_v")); + DecalUpdateCRC(crc, d.MaxU() ON_DECAL_PROP_NAME(L"max_u")); + DecalUpdateCRC(crc, d.MaxV() ON_DECAL_PROP_NAME(L"max_v")); + } + else + { + DecalUpdateCRC(crc, d.Origin() ON_DECAL_PROP_NAME(L"origin")); + DecalUpdateCRC(crc, d.VectorUp() ON_DECAL_PROP_NAME(L"up")); + DecalUpdateCRC(crc, d.VectorAcross() ON_DECAL_PROP_NAME(L"across")); + + if ((Mappings::Cylindrical == mapping) || (Mappings::Spherical == mapping)) + { + DecalUpdateCRC(crc, d.MapToInside() ON_DECAL_PROP_NAME(L"map_to_inside")); + DecalUpdateCRC(crc, d.Radius() ON_DECAL_PROP_NAME(L"radius")); + DecalUpdateCRC(crc, d.HorzSweepSta() ON_DECAL_PROP_NAME(L"horz_sweep_sta")); + DecalUpdateCRC(crc, d.HorzSweepEnd() ON_DECAL_PROP_NAME(L"horz_sweep_end")); + + if (Mappings::Cylindrical == mapping) + { + DecalUpdateCRC(crc, d.Height() ON_DECAL_PROP_NAME(L"height")); + } + else + if (Mappings::Spherical == mapping) + { + DecalUpdateCRC(crc, d.VertSweepSta() ON_DECAL_PROP_NAME(L"vert_sweep_sta")); + DecalUpdateCRC(crc, d.VertSweepEnd() ON_DECAL_PROP_NAME(L"vert_sweep_end")); + } + } + else + if (Mappings::Planar == mapping) + { + DecalUpdateCRC(crc, d.Projection() ON_DECAL_PROP_NAME(L"projection")); + } + } + + DecalUpdateCRC_Custom(decal_node, crc); + + // Make sure it's not nil. + if (crc == ON_NIL_DECAL_CRC) + crc = 0xFFFFFFFF; + } return crc; } @@ -1095,8 +1197,21 @@ const ON_DecalCollection& ON_DecalCollection::operator = (const ON_DecalCollecti const ON_SimpleArray& ON_DecalCollection::GetDecalArray(void) const { - if (!m_populated) + // 19th February 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-86089 + // The m_populated flag is an optimization designed to make sure we only populate the array when something + // changes. Unfortunately, in Rhino 8, I forgot to add code to detect when a decal changes externally to this + // class, and the array (which is essentially a cache) becomes invalid. This is fixed in Rhino 9 but the fix + // is too complicated to backport to Rhino 8, so to get around this I'm just going to remove the optimization. + +//if (!m_populated) // Always repopulate the array. { + for (int i = 0; i < m_decals.Count(); i++) + { + delete m_decals[i]; + } + + m_decals.Destroy(); + Populate(); m_populated = true; diff --git a/opennurbs_decals.h b/opennurbs_decals.h index f148cd3e..997af74a 100644 --- a/opennurbs_decals.h +++ b/opennurbs_decals.h @@ -14,12 +14,97 @@ #if !defined(ON_DECALS_INC_) #define ON_DECALS_INC_ +// Comment in this line to enable human-readable decal CRCs. One of the most difficult things about +// diagnosing decal bugs is not being able to get useful information from their CRCs. By enabling +// this feature, the decal CRC will change from being an integer to being a class with debug information +// in it. THIS BREAKS THE SDK SO ONLY USE IT FOR LOCAL DEBUGGING. NEVER CHECK THIS LINE IN WITH IT ENABLED. +//#define HUMAN_READABLE_DECAL_CRC + +#ifndef _DEBUG +#ifdef HUMAN_READABLE_DECAL_CRC +#error "HUMAN_READABLE_DECAL_CRC is defined in release build" +#endif +#endif + +#if (defined _DEBUG) && (defined HUMAN_READABLE_DECAL_CRC) +class ON_HumanReadableDecalCRC +{ +public: + ON_HumanReadableDecalCRC(ON__UINT32 v=0) : _value(v) { } + + void operator = (ON__UINT32 v) { _value = v; } + bool operator == (ON__UINT32 v) const { return _value == v; } + bool operator != (ON__UINT32 v) const { return _value != v; } + + operator ON__UINT32(void) const { return _value; } + + operator const wchar_t*(void) const { return _info1; } + +public: + ON__UINT32 _value = 0; + ON_wString _info1; + ON_wString _info2; +}; +#define ON_DECAL_CRC ON_HumanReadableDecalCRC +#else +#define ON_DECAL_CRC ON__UINT32 +#endif + +#define ON_NIL_DECAL_CRC ON_DECAL_CRC(0) // If a decal CRC is nil, it means 'no decal'. + +// ON_Decal encapsulates a rendering decal which is an image that sticks to the surface of an object +// like a real-life decal does. Decals are identified by their CRC which is a value generated from the +// decal's current state. When a property changes, the CRC will also change. +// +// Decals have a choice of mappings: +// +// - UV: Maps a texture to (u,v) coordinates on an object. +// - Planar: Maps a texture to a rectangle like an ordinary sticker. +// - Spherical: Maps a texture to a spherical object like a label on a ball. +// - Cylindrical: Maps a texture to a cylinder like a label on a can. +// +// They also have a choice of projections: +// +// - Forward: Projects the decal forward onto the object. +// - Backward: Projects the decal backward onto the object. +// - Both: Projects the decal forward and backward onto the object. +// +// Some of the properties are only used by certain mappings: +// +// - UV bounds: UV mapping only. +// - Transparency: All mappings. +// - Origin: All mappings except UV. +// - Up vector: All mappings except UV. +// - Across vector: All mappings except UV. +// - Height: Cylindrical mapping only. +// - Map to inside: Cylindrical and spherical mappings only. +// - Radius: Cylindrical and spherical mappings only. +// - Horizontal sweep: Cylindrical and spherical mappings only. +// - Vertical sweep: Spherical mapping only. +// +// The class stores its data as XML but it is optimized with a built-in cache. As each property is +// requested, it is read from the XML and cached. Thereafter, the cached value is returned and the XML +// for that property is never read again. On writing to a property, the cache is updated and by default +// the XML is also updated. However, it is possible to inhibit the XML update for increased performance. +// See SetCacheOnly() below. + class ON_CLASS ON_Decal { public: + // Construct a decal with all properties set to defaults. ON_Decal(); - ON_Decal(class ON_DecalCollection& coll, ON_XMLNode& node); - ON_Decal(const ON_Decal& d); + + // Construct a decal passing the XML node to be used for its storage. + ON_Decal(ON_XMLNode& node); + + // Construct a decal passing the const XML node to be used for its storage. This decal is read only. + ON_Decal(const ON_XMLNode& node); + + ON_Decal(class ON_DecalCollection& coll, ON_XMLNode& node); // For internal use only. + + // Construct this decal as a copy of another decal. + ON_Decal(const ON_Decal& other); + virtual ~ON_Decal(); virtual const ON_Decal& operator = (const ON_Decal& d); @@ -136,7 +221,7 @@ public: bool GetTextureMapping(ON_TextureMapping& tm) const; // Returns the Decal CRC of the decal. - ON__UINT32 DecalCRC(void) const; + ON_DECAL_CRC DecalCRC(void) const; // Returns the Data CRC of the decal. This is not necessarily the same as the decal CRC // because it allows a starting current remainder. @@ -167,7 +252,9 @@ public: bool SetCustomXML(const ON_UUID& renderEngineId, const ON_XMLNode& custom_param_node); public: // For internal use only. - static ON__UINT32 ComputeDecalCRC(ON__UINT32, const ON_XMLNode&); + static ON_DECAL_CRC ComputeDecalCRC(ON__UINT32, const ON_XMLNode&); + void GetEntireCustomXML(ON_XMLNode&) const; + void AppendCustomXML(const ON_XMLNode&); private: class CImpl; @@ -175,6 +262,6 @@ private: }; // For internal use only. -ON__UINT32 ON_DECL ON_DecalCRCFromNode(const ON_XMLNode& node); +ON_DECAL_CRC ON_DECL ON_DecalCRCFromNode(const ON_XMLNode& node); #endif diff --git a/opennurbs_input_libsdir.h b/opennurbs_input_libsdir.h index 3936cc77..b3ce1579 100644 --- a/opennurbs_input_libsdir.h +++ b/opennurbs_input_libsdir.h @@ -16,6 +16,12 @@ #if !defined(OPENNURBS_INPUT_LIBSDIR_INC_) #define OPENNURBS_INPUT_LIBSDIR_INC_ + + +// RH-86025, RH3DM-179, 2025-02-14, Pierre: +// ON_CMAKE_BUILD should be renamed "ON_NOT_USING_MSVC_LINK_LIB_PRAGMA" +// This whole thing should be reworked so MSVC builds also use build properties, +// instead of the non-portable #pragma comment(lib, "path"). #if defined(ON_COMPILER_MSC) && !defined(OPENNURBS_INPUT_LIBS_DIR) && !defined(ON_CMAKE_BUILD) // This header file insures OPENNURBS_INPUT_LIBS_DIR is defined to be diff --git a/opennurbs_mesh.cpp b/opennurbs_mesh.cpp index d4f5e941..16f3147c 100644 --- a/opennurbs_mesh.cpp +++ b/opennurbs_mesh.cpp @@ -15901,21 +15901,21 @@ ON_Mesh* ON_Mesh::CopyComponents( return CopyComponents(ci_list.Array(), ci_list.UnsignedCount(), destination_mesh); } -bool ON_Mesh::SetSurfaceParamtersFromTextureCoodinates() +bool ON_Mesh::SetSurfaceParametersFromTextureCoodinates(const ON_SimpleArray& TCs) { unsigned int i; const unsigned int vcount = m_V.UnsignedCount(); bool rc; ON_Interval dom; - if (vcount == m_T.UnsignedCount()) + if (vcount == TCs.UnsignedCount()) { dom.Set(0.0, 1.0); m_S.SetCount(0); m_S.Reserve(vcount); for (i = 0; i < vcount; i++) { - ON_2dPoint S = m_T[i]; + ON_2dPoint S = TCs[i]; m_S.Append(S); } rc = true; @@ -16041,6 +16041,12 @@ bool ON_Mesh::SetSurfaceParamtersFromTextureCoodinates() //return true; } +bool ON_Mesh::SetSurfaceParamtersFromTextureCoodinates() +{ + return SetSurfaceParametersFromTextureCoodinates(m_T); +} + + ////////////////////////////////////////////////////////////////////////// // // ON_MeshCache diff --git a/opennurbs_mesh.h b/opennurbs_mesh.h index 0ba4b75a..a749b36f 100644 --- a/opennurbs_mesh.h +++ b/opennurbs_mesh.h @@ -6135,6 +6135,8 @@ The map is an array of length m_F.Count(), ngon_map[] */ bool SetSurfaceParamtersFromTextureCoodinates(); + bool SetSurfaceParametersFromTextureCoodinates(const ON_SimpleArray& TCs); + ///////////////////////////////////////////////////////////////// // Implementation - curvature diff --git a/opennurbs_nurbssurface.cpp b/opennurbs_nurbssurface.cpp index a7aadbb5..306a4c7c 100644 --- a/opennurbs_nurbssurface.cpp +++ b/opennurbs_nurbssurface.cpp @@ -778,60 +778,127 @@ bool ON_NurbsSurface::Read( // NOTE - check legacy I/O code if changed int major_version = 0; int minor_version = 0; - bool rc = file.Read3dmChunkVersion(&major_version,&minor_version); - if (rc && major_version==1) { + while (file.Read3dmChunkVersion(&major_version, &minor_version)) + { + if (1 != major_version) + break; + // common to all 1.x versions - int dim = 0, is_rat = 0, order0 = 0, order1 = 0, cv_count0 = 0, cv_count1 = 0; - int reserved1 = 0, reserved2 = 0; - if (rc) rc = file.ReadInt( &dim ); - if (rc) rc = file.ReadInt( &is_rat ); - if (rc) rc = file.ReadInt( &order0 ); - if (rc) rc = file.ReadInt( &order1 ); - if (rc) rc = file.ReadInt( &cv_count0 ); - if (rc) rc = file.ReadInt( &cv_count1 ); + int dim = 0; + if (false == file.ReadInt(&dim)) + break; + if (dim < 1) + break; + int is_rat = 0; + if (false == file.ReadInt(&is_rat)) + break; - if (rc) rc = file.ReadInt(&reserved1); - if (rc) rc = file.ReadInt(&reserved2); + int order0 = 0; + if (false == file.ReadInt( &order0 )) + break; + if (order0 < 2) + break; + int order1 = 0; + if (false == file.ReadInt( &order1 )) + break; + if (order1 < 2) + break; - if (rc) { - ON_BoundingBox bbox; // read bounding box - may be used in future - rc = file.ReadBoundingBox(bbox); - } + int cv_count0 = 0; + if (false == file.ReadInt( &cv_count0 )) + break; + if (cv_count0 < order0) + break; + int cv_count1 = 0; + if (false == file.ReadInt( &cv_count1 )) + break; + if (cv_count1 < order1) + break; + + // These are sanity checks for overflow. + // Safe fix for RH-83540 + // They prevent attempt to allocate large numbers of knots when + // one of the orders or cv_counts red above is from a corrupt file. + const int expected_knot_count0 = ON_KnotCount(order0, cv_count0); + if (expected_knot_count0 < 2) + break; + const int expected_knot_count1 = ON_KnotCount(order1, cv_count1); + if (expected_knot_count1 < 2) + break; + const int expected_cv_count = cv_count0 * cv_count1; + if (expected_cv_count < 4) + break; + const int expected_cv_capacity = (is_rat != 0 ? (dim + 1) : dim) * expected_cv_count; + if (expected_cv_capacity < 4) + break; + + + int reserved1 = 0; + if (false == file.ReadInt(&reserved1)) + break; + int reserved2 = 0; + if (false == file.ReadInt(&reserved2)) + break; + + ON_BoundingBox ignored_bbox; // read bounding box place holder - may be used in future + if (false == file.ReadBoundingBox(ignored_bbox)) + break; - Create( dim, is_rat, order0, order1, cv_count0, cv_count1 ); - - int count = 0; - if (rc) rc = file.ReadInt(&count); - if (rc && count < 0) - rc = false; - if (rc ) rc = ReserveKnotCapacity(0,count); - if (rc) rc = file.ReadDouble( count, m_knot[0] ); - - count = 0; - if (rc) rc = file.ReadInt(&count); - if (rc && count < 0) - rc = false; - if (rc ) rc = ReserveKnotCapacity(1,count); - if (rc) rc = file.ReadDouble( count, m_knot[1] ); - - count = 0; - if (rc) rc = file.ReadInt(&count); - if (rc && count < 0) - rc = false; + if (false == Create(dim, is_rat, order0, order1, cv_count0, cv_count1)) + break; const int cv_size = CVSize(); - if (rc) rc = ReserveCVCapacity( count*cv_size ); - if (count > 0 && cv_size > 0 && rc ) { - int i, j; - for ( i = 0; i < m_cv_count[0] && rc; i++ ) { - for ( j = 0; j < m_cv_count[1] && rc; j++ ) { - rc = file.ReadDouble( cv_size, CV(i,j) ); - } + if (cv_size < dim) + break; + + int knot_count0 = 0; + if (false == file.ReadInt(&knot_count0)) + break; + if (knot_count0 != expected_knot_count0) + break; + if (false == ReserveKnotCapacity(0, knot_count0)) + break; + if (false == file.ReadDouble(knot_count0, m_knot[0])) + break; + + int knot_count1 = 0; + if (false == file.ReadInt(&knot_count1)) + break; + if (knot_count1 != expected_knot_count1) + break; + if (false == ReserveKnotCapacity(1, knot_count1)) + break; + if (false == file.ReadDouble(knot_count1, m_knot[1])) + break; + + int cv_count = 0; + if (false == file.ReadInt(&cv_count)) + break; + if (cv_count != expected_cv_count) + break; + if (false == ReserveCVCapacity(cv_count * cv_size)) + break; + int i = 0; + for ( i = 0; i < m_cv_count[0]; i++ ) + { + int j = 0; + for ( j = 0; j < m_cv_count[1]; j++ ) + { + if (false == file.ReadDouble(cv_size, CV(i, j))) + break; } + if (j != m_cv_count[1]) + break; } + if (i != m_cv_count[0]) + break; + + // successful read + return true; } - if ( !rc ) - Destroy(); - return rc; + + // Corrupt file + Destroy(); + return false; } ON_Interval ON_NurbsSurface::Domain( int dir ) const diff --git a/opennurbs_public.vcxproj b/opennurbs_public.vcxproj index 99100e11..c0bd7571 100644 --- a/opennurbs_public.vcxproj +++ b/opennurbs_public.vcxproj @@ -626,6 +626,7 @@ + diff --git a/opennurbs_public_version.h b/opennurbs_public_version.h index 71a657bf..73d3bdc9 100644 --- a/opennurbs_public_version.h +++ b/opennurbs_public_version.h @@ -6,7 +6,7 @@ // To update version numbers, edit ..\build\build_dates.msbuild #define RMA_VERSION_MAJOR 8 -#define RMA_VERSION_MINOR 17 +#define RMA_VERSION_MINOR 18 //////////////////////////////////////////////////////////////// // @@ -14,9 +14,9 @@ // first step in each build. // #define RMA_VERSION_YEAR 2025 -#define RMA_VERSION_MONTH 3 -#define RMA_VERSION_DATE 7 -#define RMA_VERSION_HOUR 7 +#define RMA_VERSION_MONTH 4 +#define RMA_VERSION_DATE 8 +#define RMA_VERSION_HOUR 11 #define RMA_VERSION_MINUTE 0 //////////////////////////////////////////////////////////////// @@ -35,8 +35,8 @@ // 3 = build system release build #define RMA_VERSION_BRANCH 0 -#define VERSION_WITH_COMMAS 8,17,25066,7000 -#define VERSION_WITH_PERIODS 8.17.25066.07000 +#define VERSION_WITH_COMMAS 8,18,25098,11000 +#define VERSION_WITH_PERIODS 8.18.25098.11000 #define COPYRIGHT "Copyright (C) 1993-2025, 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 "SR17" -#define RMA_VERSION_NUMBER_SR_WSTRING L"SR17" +#define RMA_VERSION_NUMBER_SR_STRING "SR18" +#define RMA_VERSION_NUMBER_SR_WSTRING L"SR18" -#define RMA_VERSION_WITH_PERIODS_STRING "8.17.25066.07000" -#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.17.25066.07000" +#define RMA_VERSION_WITH_PERIODS_STRING "8.18.25098.11000" +#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.18.25098.11000" diff --git a/opennurbs_subd.h b/opennurbs_subd.h index b8cda2d2..e898af58 100644 --- a/opennurbs_subd.h +++ b/opennurbs_subd.h @@ -3131,7 +3131,7 @@ public: /// Postfix operator ++ sets this to ON_SubDComponentPtr::NextComponent() /// and returns the previous value of this. /// - /// ON_SubDComponentPtr::NextComponent() + /// *this, before increment const ON_SubDComponentPtr operator++(int); @@ -17694,13 +17694,34 @@ public: /* Description: - Increment the iterator. + Prefix increment the iterator. + Returns: + Next vertex. + Remarks: + operator++(void) and NextVertex() behave the same. + In OpenNURBS 8.17 and earlier, this function was incorrectly implemented as + a postfix increment (operator++(int)). This has been corrected in OpenNURBS 8.18. + If you have a plugin compiled without inlining optimizations (e.g. in Debug mode), + operator++(void) will be calling the version in opennurbs.dll distributed + with Rhino that is used to run the plugin. + If you have a plugin compiled with inlining optimizations (e.g. in Release mode), + operator++(void) will behave like the version in opennurbs_subd.h distributed + with the Rhino SDK that was used to compiled the plugin. + */ + const class ON_SubDVertex* operator++() + { + return NextVertex(); + } + + /* + Description: + Postfix increment the iterator. Returns: Current vertex. Remarks: - operator++ and NextVertex() behave differently. + operator++(int) and NextVertex() behave differently. */ - const class ON_SubDVertex* operator++() + const class ON_SubDVertex* operator++(int) { const class ON_SubDVertex* v = m_v_current; NextVertex(); @@ -17739,11 +17760,12 @@ public: /* Description: - Increment the iterator. + Pre-increment the iterator and return the new current vertex. Returns: Next vertex. Remarks: - operator++ and NextVertex() behave differently. + operator++(void) and NextVertex() behave the same. + operator++(int) and NextVertex() behave differently. */ const class ON_SubDVertex* NextVertex() { @@ -17801,6 +17823,41 @@ public: return (m_v_current = m_v_last); } + /* + Description: + Get the iterator's base component in which we are iterating, if it exists. + Returns: + m_component_ptr if it exists, or ON_SubDComponentPtr::Null. + */ + ON_SubDComponentPtr BaseComponentPtr() const + { + return m_component_ptr.m_ptr == 0 ? ON_SubDComponentPtr::Null : m_component_ptr; + } + + /* + Description: + Get the iterator's base edge in which we are iterating, if it exists. + Returns: + m_component_ptr.Edge() if it exists, or nullptr. + */ + ON_SubDEdge* BaseEdge() const + { + if (m_component_ptr.m_ptr == 0) return nullptr; + return m_component_ptr.IsEdge() ? m_component_ptr.Edge() : nullptr; + } + + /* + Description: + Get the iterator's base edge in which we are iterating, if it exists. + Returns: + m_component_ptr.Face() if it exists, or nullptr. + */ + ON_SubDFace* BaseFace() const + { + if (m_component_ptr.m_ptr == 0) return nullptr; + return m_component_ptr.IsFace() ? m_component_ptr.Face() : nullptr; + } + private: void Internal_Init( const ON_SubDRef& subd_ref, @@ -17967,13 +18024,34 @@ public: /* Description: - Increment the iterator. + Prefix increment the iterator. + Returns: + Next edge. + Remarks: + operator++(void) and NextEdge() behave the same. + In OpenNURBS 8.17 and earlier, this function was incorrectly implemented as + a postfix increment (operator++(int)). This has been corrected in OpenNURBS 8.18. + If you have a plugin compiled without inlining optimizations (e.g. in Debug mode), + operator++(void) will be calling the version in opennurbs.dll distributed + with Rhino that is used to run the plugin. + If you have a plugin compiled with inlining optimizations (e.g. in Release mode), + operator++(void) will behave like the version in opennurbs_subd.h distributed + with the Rhino SDK that was used to compiled the plugin. + */ + const class ON_SubDEdge* operator++() + { + return NextEdge(); + } + + /* + Description: + Postfix increment the iterator. Returns: Current edge. Remarks: - operator++ and NextEdge() behave differently. + operator++(int) and NextEdge() behave differently. */ - const class ON_SubDEdge* operator++() + const class ON_SubDEdge* operator++(int) { const class ON_SubDEdge* e = m_e_current; NextEdge(); @@ -18012,11 +18090,12 @@ public: /* Description: - Increment the iterator. + Pre-increment the iterator and return the new current edge. Returns: Next edge. Remarks: - operator++ and NextEdge() behave differently. + operator++(void) and NextEdge() behave the same. + operator++(int) and NextEdge() behave differently. */ const class ON_SubDEdge* NextEdge() { @@ -18074,6 +18153,41 @@ public: return m_e_current = m_e_last; } + /* + Description: + Get the iterator's base component in which we are iterating, if it exists. + Returns: + m_component_ptr if it exists, or ON_SubDComponentPtr::Null. + */ + ON_SubDComponentPtr BaseComponentPtr() const + { + return m_component_ptr.m_ptr == 0 ? ON_SubDComponentPtr::Null : m_component_ptr; + } + + /* + Description: + Get the iterator's base vertex in which we are iterating, if it exists. + Returns: + m_component_ptr.Vertex() if it exists, or nullptr. + */ + ON_SubDVertex* BaseVertex() const + { + if (m_component_ptr.m_ptr == 0) return nullptr; + return m_component_ptr.IsVertex() ? m_component_ptr.Vertex() : nullptr; + } + + /* + Description: + Get the iterator's base edge in which we are iterating, if it exists. + Returns: + m_component_ptr.Face() if it exists, or nullptr. + */ + ON_SubDFace* BaseFace() const + { + if (m_component_ptr.m_ptr == 0) return nullptr; + return m_component_ptr.IsFace() ? m_component_ptr.Face() : nullptr; + } + private: void Internal_Init( const ON_SubDRef& subd_ref, @@ -18240,13 +18354,34 @@ public: /* Description: - Returns the current face and increment the iterator. + Prefix increment the iterator. + Returns: + Next face. + Remarks: + operator++(void) and NextFace() behave the same. + In OpenNURBS 8.17 and earlier, this function was incorrectly implemented as + a postfix increment (operator++(int)). This has been corrected in OpenNURBS 8.18. + If you have a plugin compiled without inlining optimizations (e.g. in Debug mode), + operator++(void) will be calling the version in opennurbs.dll distributed + with Rhino that is used to run the plugin. + If you have a plugin compiled with inlining optimizations (e.g. in Release mode), + operator++(void) will behave like the version in opennurbs_subd.h distributed + with the Rhino SDK that was used to compiled the plugin. + */ + const class ON_SubDFace* operator++() + { + return NextFace(); + } + + /* + Description: + Postfix increment the iterator. Returns: Current face. Remarks: - operator++ and NextFace() behave differently. + operator++(int) and NextFace() behave differently. */ - const class ON_SubDFace* operator++() + const class ON_SubDFace* operator++(int) { const class ON_SubDFace* f = m_face_current; NextFace(); @@ -18286,11 +18421,12 @@ public: /* Description: - Returns the next face and increments the iterator. + Pre-increment the iterator and return the new current face. Returns: Next face. Remarks: - operator++ and NextFace() behave differently. + operator++(void) and NextFace() behave the same. + operator++(int) and NextFace() behave differently. */ const class ON_SubDFace* NextFace() { @@ -18348,6 +18484,41 @@ public: return (m_face_current = m_face_last); } + /* + Description: + Get the iterator's base component in which we are iterating, if it exists. + Returns: + m_component_ptr if it exists, or ON_SubDComponentPtr::Null. + */ + ON_SubDComponentPtr BaseComponentPtr() const + { + return m_component_ptr.m_ptr == 0 ? ON_SubDComponentPtr::Null : m_component_ptr; + } + + /* + Description: + Get the iterator's base vertex in which we are iterating, if it exists. + Returns: + m_component_ptr.Vertex() if it exists, or nullptr. + */ + ON_SubDVertex* BaseVertex() const + { + if (m_component_ptr.m_ptr == 0) return nullptr; + return m_component_ptr.IsVertex() ? m_component_ptr.Vertex() : nullptr; + } + + /* + Description: + Get the iterator's base edge in which we are iterating, if it exists. + Returns: + m_component_ptr.Edge() if it exists, or nullptr. + */ + ON_SubDEdge* BaseEdge() const + { + if (m_component_ptr.m_ptr == 0) return nullptr; + return m_component_ptr.IsEdge() ? m_component_ptr.Edge() : nullptr; + } + private: void Internal_Init( diff --git a/opennurbs_sun.cpp b/opennurbs_sun.cpp index 84fb8c19..e95164e4 100644 --- a/opennurbs_sun.cpp +++ b/opennurbs_sun.cpp @@ -892,6 +892,11 @@ double ON_Sun::CImpl::North(void) const void ON_Sun::CImpl::SetNorth(double north) { + // 28th February 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-81036 + // Only set the north if it actually changes. + if (north == North()) + return; + if (nullptr != _earth_anchor_point) { // Store the north in the earth anchor point. This is more complicated than just setting one value. @@ -938,6 +943,11 @@ double ON_Sun::CImpl::Latitude(void) const void ON_Sun::CImpl::SetLatitude(double lat) { + // 28th February 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-81036 + // Only set the latitude if it actually changes. + if (lat == Latitude()) + return; + if (nullptr != _earth_anchor_point) { // Store the latitude in the earth anchor point. @@ -971,6 +981,11 @@ double ON_Sun::CImpl::Longitude(void) const void ON_Sun::CImpl::SetLongitude(double lon) { + // 28th February 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-81036 + // Only set the longitude if it actually changes. + if (lon == Longitude()) + return; + if (nullptr != _earth_anchor_point) { // Store the longitude in the earth anchor point. @@ -1538,6 +1553,12 @@ void ON_Sun::OnInternalXmlChanged(const ON_Sun* sun) SetLatitude(sun->Latitude()); SetLongitude(sun->Longitude()); } + + // 18th March 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-86536 + // Since the XML has been bulk-overwritten, we need to make sure the sun calculation is done next time + // Azimuth() or Altitude() is called. This bug was introduced by the fix for RH-81036 because that fix + // prevented code which had the side-effect of setting _calc_dirty from being executed. + _impl->_calc_dirty = true; } static const int SunVersion = 1; diff --git a/opennurbs_xml.cpp b/opennurbs_xml.cpp index 20934e66..da9c343b 100644 --- a/opennurbs_xml.cpp +++ b/opennurbs_xml.cpp @@ -2174,6 +2174,13 @@ void ON_XMLNodePrivate::MoveBefore(ON_XMLNode& other) { pBeforeOther->_private->m_next_sibling = &m_node; } + + // 13th February 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-86050 + if (m_parent->_private->m_last_child == &m_node) + { + // 'this' was the tail; redirect the parent's last child. + m_parent->_private->m_last_child = pPrev; + } } void ON_XMLNodePrivate::MoveAfter(ON_XMLNode& other) @@ -2197,6 +2204,13 @@ void ON_XMLNodePrivate::MoveAfter(ON_XMLNode& other) m_parent->_private->m_first_child = m_next_sibling; } + // 13th February 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-86050 + if (m_parent->_private->m_last_child == &m_node) + { + // 'this' was the tail; redirect the parent's last child. + m_parent->_private->m_last_child = pPrev; + } + m_next_sibling = other._private->m_next_sibling; other._private->m_next_sibling = &m_node; @@ -3950,8 +3964,20 @@ const ON_XMLRootNode& ON_XMLUserData::XMLRootForRead(void) const return _private->m_XMLRoot.NodeForRead(); } -ON_XMLRootNode& ON_XMLUserData::XMLRootForWrite(void) const +ON_XMLRootNode& ON_XMLUserData::XMLRootForWrite(void) const // const is a mistake. [SDK_UNFREEZE] { + // 22nd January 2025 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH-67878 + // Per conversation with Dale Lear, this is bad because we are actually going to change the user data while + // it's already attached to the attributes. We're actually expected to delete the old user data and create + // new user data with the changes in it, because otherwise Rhino can't know that it was changed. However, + // Dale suggested the easiest way to fix this is to just bump the copy count, because the optimization in + // CRhinoObject::ModifyAttributes() involving the copy count is really a hack anyway. + + if (m_userdata_copycount > 0) // Zero means we are not even copying user data. + { + const_cast(this)->m_userdata_copycount++; + } + return _private->m_XMLRoot.NodeForWrite(); } diff --git a/opennurbs_xml.h b/opennurbs_xml.h index 58a668b7..f5bd4d76 100644 --- a/opennurbs_xml.h +++ b/opennurbs_xml.h @@ -139,6 +139,8 @@ typedef bool (*ON_XMLRecurseChildrenCallback)(class ON_XMLNode*, void*); // Decals (stored in object attributes user data). +#define ON_RDK_USER_DATA_ROOT L"render-content-manager-data" + #define ON_RDK_DECALS L"decals" #define ON_RDK_DECAL L"decal" diff --git a/opennurbs_zlib.cpp b/opennurbs_zlib.cpp index 2ca0d40a..cbe93598 100644 --- a/opennurbs_zlib.cpp +++ b/opennurbs_zlib.cpp @@ -23,6 +23,13 @@ #include "opennurbs_zlib.h" +// RH-86025, RH3DM-179, 2025-02-14, Pierre: +// We only really need the #pragma comment(lib, "path") to work when we are using +// MSVC and the Microsoft linker, but not defining include dirs in build properties. +// Other compilers do not recognize this pragma and instead use build properties to link to libs. +// ON_CMAKE_BUILD should be renamed "ON_NOT_USING_MSVC_LINK_LIB_PRAGMA" +// This whole thing should be reworked so MSVC builds also use build properties, +// instead of this non-portable pragma. #if defined(ON_COMPILER_MSC) && !defined(ON_CMAKE_BUILD) #if !defined(OPENNURBS_ZLIB_LIB_DIR) @@ -35,9 +42,8 @@ #else // Define OPENNURBS_ZLIB_LIB_DIR to be the directory containing zlib.lib #error You must define OPENNURBS_ZLIB_LIB_DIR -#endif +#endif // defined(OPENNURBS_INPUT_LIBS_DIR) -#endif #if defined(_LIB) && defined(_MT) && !defined(_DLL) @@ -48,9 +54,11 @@ // using Microsoft DLL C-runtime #pragma message ( "Linking with zlib.lib in " OPENNURBS_PP2STR(OPENNURBS_ZLIB_LIB_DIR) ) #pragma comment(lib, "\"" OPENNURBS_ZLIB_LIB_DIR "/" "zlib.lib" "\"") -#endif +#endif // defined(_LIB) && defined(_MT) && !defined(_DLL) -#endif +#endif // !defined(OPENNURBS_ZLIB_LIB_DIR) + +#endif // defined(ON_COMPILER_MSC) && !defined(ON_CMAKE_BUILD) // compressed buffer I/O uses zlib 1.1.3 inflate()/deflate() class ON_CompressorImplementation