mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 19:46:08 +08:00
4076 lines
111 KiB
C++
4076 lines
111 KiB
C++
//
|
|
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include "opennurbs.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
ON_OBJECT_IMPLEMENT(ON_ModelComponent,ON_Object,"CF37CFB5-8E6F-435F-98FE-D20FA9E7DB6F");
|
|
|
|
|
|
bool ON_ModelComponent::IsValid(
|
|
ON_TextLog* text_log
|
|
) const
|
|
{
|
|
return ( m_runtime_serial_number > 0 );
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::ComponentTypeToString(
|
|
ON_ModelComponent::Type component_type
|
|
)
|
|
{
|
|
switch (component_type)
|
|
{
|
|
case ON_ModelComponent::Type::Unset:
|
|
return ON_wString("Unset");
|
|
case ON_ModelComponent::Type::ModelGeometry:
|
|
return ON_wString("ModelGeometry");
|
|
case ON_ModelComponent::Type::Image:
|
|
return ON_wString("EmbeddedFile");
|
|
case ON_ModelComponent::Type::LinePattern:
|
|
return ON_wString("LinePattern");
|
|
case ON_ModelComponent::Type::Layer:
|
|
return ON_wString("Layer");
|
|
case ON_ModelComponent::Type::Group:
|
|
return ON_wString("Group");
|
|
case ON_ModelComponent::Type::TextStyle:
|
|
return ON_wString("TextStyle");
|
|
case ON_ModelComponent::Type::DimStyle:
|
|
return ON_wString("AnnotationStyle");
|
|
case ON_ModelComponent::Type::HatchPattern:
|
|
return ON_wString("HatchPattern");
|
|
case ON_ModelComponent::Type::InstanceDefinition:
|
|
return ON_wString("InstanceDefinition");
|
|
case ON_ModelComponent::Type::HistoryRecord:
|
|
return ON_wString("HistoryRecord");
|
|
case ON_ModelComponent::Type::TextureMapping:
|
|
return ON_wString("TextureMapping");
|
|
case ON_ModelComponent::Type::Material:
|
|
return ON_wString("RenderMaterial");
|
|
case ON_ModelComponent::Type::RenderLight:
|
|
return ON_wString("RenderLight");
|
|
case ON_ModelComponent::Type::RenderContent:
|
|
return ON_wString("RenderContent");
|
|
case ON_ModelComponent::Type::EmbeddedFile:
|
|
return ON_wString("EmbeddedFile");
|
|
case ON_ModelComponent::Type::SectionStyle:
|
|
return ON_wString("SectionStyle");
|
|
case ON_ModelComponent::Type::ObsoleteValue:
|
|
return ON_wString("ObsoleteValue");
|
|
case ON_ModelComponent::Type::Mixed:
|
|
return ON_wString("Mixed");
|
|
default:
|
|
ON_ERROR("invalid m_component_type value");
|
|
}
|
|
|
|
return ON_wString::EmptyString;
|
|
}
|
|
|
|
ON_ModelComponentTypeIterator::ON_ModelComponentTypeIterator() ON_NOEXCEPT
|
|
{
|
|
const size_t types_capacity = sizeof(m_types)/sizeof(m_types[0]);
|
|
for (size_t k = 0; k < types_capacity; k++)
|
|
m_types[k] = ON_ModelComponent::Type::Unset;
|
|
}
|
|
|
|
ON_ModelComponentTypeIterator::ON_ModelComponentTypeIterator(
|
|
size_t type_count,
|
|
const ON_ModelComponent::Type* types
|
|
) ON_NOEXCEPT
|
|
{
|
|
const size_t types_capacity = sizeof(m_types)/sizeof(m_types[0]);
|
|
m_type_count
|
|
= (nullptr != types && type_count > 0)
|
|
? (int)((type_count < types_capacity) ? type_count : types_capacity)
|
|
: 0;
|
|
memset(m_types, 0, sizeof(m_types));
|
|
for (int i = 0; i < m_type_count; i++)
|
|
m_types[i] = types[i];
|
|
for (size_t k = (size_t)m_type_count; k < types_capacity; k++)
|
|
m_types[k] = ON_ModelComponent::Type::Unset;
|
|
}
|
|
|
|
unsigned int ON_ModelComponentTypeIterator::TypeCount() const
|
|
{
|
|
return (unsigned int)m_type_count;
|
|
}
|
|
|
|
ON_ModelComponent::Type ON_ModelComponentTypeIterator::FirstType()
|
|
{
|
|
m_current_index = ON_UNSET_INT_INDEX;
|
|
return NextType();
|
|
}
|
|
|
|
ON_ModelComponent::Type ON_ModelComponentTypeIterator::LastType()
|
|
{
|
|
m_current_index = ON_UNSET_INT_INDEX;
|
|
return PreviousType();
|
|
}
|
|
|
|
ON_ModelComponent::Type ON_ModelComponentTypeIterator::NextType()
|
|
{
|
|
if (m_type_count > 0)
|
|
{
|
|
if (ON_UNSET_INT_INDEX == m_current_index)
|
|
m_current_index = 0;
|
|
else if (m_current_index < m_type_count)
|
|
m_current_index++;
|
|
}
|
|
return CurrentType();
|
|
}
|
|
|
|
ON_ModelComponent::Type ON_ModelComponentTypeIterator::PreviousType()
|
|
{
|
|
if (m_type_count > 0)
|
|
{
|
|
if (ON_UNSET_INT_INDEX == m_current_index)
|
|
m_current_index = m_type_count-1;
|
|
else if (m_current_index >= 0)
|
|
m_current_index--;
|
|
}
|
|
return CurrentType();
|
|
}
|
|
|
|
ON_ModelComponent::Type ON_ModelComponentTypeIterator::CurrentType() const
|
|
{
|
|
return (m_current_index >= 0 && m_current_index < m_type_count) ? m_types[m_current_index] : ON_ModelComponent::Type::Unset;
|
|
}
|
|
|
|
void ON_ModelComponent::Dump(
|
|
ON_TextLog& text_log
|
|
) const
|
|
{
|
|
const char* sUnset = "unset";
|
|
if (false == text_log.IsTextHash())
|
|
{
|
|
// m_runtime_serial_number depends on how many components have
|
|
// been contructed before this one. It must be suppressed when
|
|
// calculating content hash values from text logs.
|
|
text_log.Print("Model component %llu\n", m_runtime_serial_number);
|
|
}
|
|
text_log.PushIndent();
|
|
|
|
// model serial number CRhinoDoc::RuntimeSerialNumber()
|
|
text_log.Print("Model serial number = ");
|
|
if (ModelSerialNumberIsSet())
|
|
{
|
|
const unsigned int model_sn = ModelSerialNumber();
|
|
text_log.Print("%u", model_sn);
|
|
text_log.PrintNewLine();
|
|
// worksession reference model
|
|
const unsigned int reference_model_sn = ReferenceModelSerialNumber();
|
|
if (reference_model_sn > 0)
|
|
{
|
|
text_log.Print("Reference model = %u\n", reference_model_sn);
|
|
}
|
|
// linked instance defintion model
|
|
const unsigned int idef_model_sn = InstanceDefinitionModelSerialNumber();
|
|
if (idef_model_sn > 0)
|
|
{
|
|
text_log.Print("Instance definition = %u\n", idef_model_sn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
text_log.Print(sUnset);
|
|
text_log.PrintNewLine();
|
|
}
|
|
|
|
text_log.Print("Type = ");
|
|
if (this->ComponentTypeIsSet())
|
|
{
|
|
text_log.Print(ON_ModelComponent::ComponentTypeToString(m_component_type));
|
|
}
|
|
else
|
|
{
|
|
text_log.Print(sUnset);
|
|
}
|
|
text_log.PrintNewLine();
|
|
|
|
text_log.Print("Id = ");
|
|
if (IdIsSet())
|
|
text_log.Print(Id());
|
|
else
|
|
text_log.Print(sUnset);
|
|
text_log.PrintNewLine();
|
|
|
|
|
|
text_log.Print("Index = ");
|
|
if (IndexIsSet())
|
|
text_log.Print("%d", Index());
|
|
else
|
|
text_log.Print(sUnset);
|
|
text_log.PrintNewLine();
|
|
|
|
text_log.Print("Name = ");
|
|
if (NameIsSet())
|
|
text_log.Print(L"%ls", static_cast<const wchar_t*>(m_component_name));
|
|
else
|
|
text_log.Print(sUnset);
|
|
text_log.PrintNewLine();
|
|
|
|
const ON__UINT64 content_version_number = ContentVersionNumber();
|
|
if (0 != content_version_number && false == text_log.IsTextHash())
|
|
{
|
|
// content_version_number values vary depending on how
|
|
// the actual content was specified, even if the final content
|
|
// is identical. It must must be suppressed when calculating
|
|
// content hash values from text logs.
|
|
|
|
// Use PRIu64 to portably print 64-bit unsigned int in decimal format.
|
|
text_log.Print("Content version number = %" PRIu64 "\n",content_version_number);
|
|
}
|
|
|
|
text_log.PopIndent();
|
|
}
|
|
|
|
void ON_ModelComponentReference::Dump(
|
|
ON_TextLog& text_log
|
|
) const
|
|
{
|
|
const ON_ModelComponent* model_component = ModelComponent();
|
|
if ( nullptr == model_component )
|
|
text_log.Print("Empty ON_ModelComponentReference\n");
|
|
else
|
|
model_component->Dump(text_log);
|
|
}
|
|
|
|
unsigned int ON_ModelComponent::SizeOf() const
|
|
{
|
|
return (unsigned int)((sizeof(*this) - sizeof(ON_Object)) + ON_Object::SizeOf());
|
|
}
|
|
|
|
ON__UINT32 ON_ModelComponent::DataCRC(
|
|
ON__UINT32 current_remainder
|
|
) const
|
|
{
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_locked_status), &m_locked_status);
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_set_status), &m_set_status);
|
|
if (ModelSerialNumberIsSet())
|
|
{
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_model_serial_number), &m_model_serial_number);
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_reference_model_serial_number), &m_reference_model_serial_number);
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_linked_idef_serial_number), &m_linked_idef_serial_number);
|
|
}
|
|
if (IdIsSet())
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_component_id), &m_component_id);
|
|
if (ComponentTypeIsSet())
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_component_type), &m_component_type);
|
|
if (IndexIsSet())
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(m_component_index), &m_component_index);
|
|
if (NameIsSet())
|
|
{
|
|
ON_NameHash name_hash = NameHash();
|
|
current_remainder = ON_CRC32(current_remainder, sizeof(name_hash), &name_hash);
|
|
}
|
|
return current_remainder;
|
|
}
|
|
|
|
ON_UUID ON_ModelComponent::ModelObjectId() const
|
|
{
|
|
return Id();
|
|
}
|
|
|
|
static ON__UINT64 ON_ModelComponentContentVersionNumberOne(
|
|
ON__UINT64 runtime_serial_number
|
|
)
|
|
{
|
|
// make it unlikely for classes created sequentually to have the same content version numbers.
|
|
ON__UINT64 s = ON_CRC32(0, sizeof(runtime_serial_number), &runtime_serial_number );
|
|
return (runtime_serial_number*0x100000000ULL | s);
|
|
}
|
|
|
|
ON_ModelComponent::ON_ModelComponent
|
|
(
|
|
ON__UINT64 runtime_serial_number
|
|
) ON_NOEXCEPT
|
|
: m_runtime_serial_number(runtime_serial_number)
|
|
, m_content_version_number(ON_ModelComponentContentVersionNumberOne(m_runtime_serial_number))
|
|
{}
|
|
|
|
ON_ModelComponent::ON_ModelComponent() ON_NOEXCEPT
|
|
: m_runtime_serial_number(++ON_ModelComponent::Internal_RuntimeSerialNumberGenerator)
|
|
, m_content_version_number(ON_ModelComponentContentVersionNumberOne(m_runtime_serial_number))
|
|
{}
|
|
|
|
static const ON_ModelComponent Unset;
|
|
|
|
ON_ModelComponent::Type ON_ModelComponent::ComponentTypeFromUnsigned(
|
|
unsigned int component_type_as_unsigned
|
|
)
|
|
{
|
|
switch (component_type_as_unsigned)
|
|
{
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::Unset);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::Image);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::TextureMapping);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::Material);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::LinePattern);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::Layer);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::Group);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::TextStyle);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::DimStyle);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::RenderLight);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::HatchPattern);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::InstanceDefinition);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::ModelGeometry);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::HistoryRecord);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::RenderContent);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::EmbeddedFile);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::ObsoleteValue);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::SectionStyle);
|
|
ON_ENUM_FROM_UNSIGNED_CASE(ON_ModelComponent::Type::Mixed);
|
|
}
|
|
|
|
ON_ERROR("component_type_as_unsigned has invalid value.");
|
|
return ON_ModelComponent::Type::Unset;
|
|
}
|
|
|
|
bool ON_ModelComponent::WriteModelComponentAttributes(
|
|
class ON_BinaryArchive& archive,
|
|
unsigned int attributes_filter
|
|
) const
|
|
{
|
|
const int major_version = 1;
|
|
const int minor_version = 0;
|
|
if (!archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,major_version,minor_version))
|
|
return false;
|
|
bool rc = false;
|
|
|
|
for (;;)
|
|
{
|
|
unsigned int bit;
|
|
bit = ON_ModelComponent::Attributes::IdAttribute & attributes_filter;
|
|
const bool bWriteId = (0 != bit && IdIsSet());
|
|
|
|
bit = ON_ModelComponent::Attributes::ParentIdAttribute & attributes_filter;
|
|
const bool bWriteParentId = (0 != bit && ParentIdIsSet());
|
|
|
|
bit = ON_ModelComponent::Attributes::IndexAttribute & attributes_filter;
|
|
const bool bWriteIndex = (0 != bit && IndexIsSet());
|
|
|
|
bit = ON_ModelComponent::Attributes::NameAttribute & attributes_filter;
|
|
const bool bWriteName = (0 != bit && NameIsSet());
|
|
|
|
bit = ON_ModelComponent::Attributes::ComponentStatusAttribute & attributes_filter;
|
|
const bool bWriteComponentStatus = (0 != bit && ModelComponentStatusIsSet());
|
|
|
|
ON__UINT32 write_bits = 0U;
|
|
if ( bWriteId )
|
|
write_bits |= 0x01U;
|
|
if ( bWriteParentId )
|
|
write_bits |= 0x02U;
|
|
if ( bWriteIndex )
|
|
write_bits |= 0x04U;
|
|
if ( bWriteName )
|
|
write_bits |= 0x08U;
|
|
if ( bWriteComponentStatus )
|
|
write_bits |= 0x10U;
|
|
|
|
if (!archive.WriteInt(write_bits))
|
|
break;
|
|
|
|
if (bWriteId)
|
|
{
|
|
if (!archive.WriteUuid(Id()))
|
|
break;
|
|
}
|
|
|
|
if (bWriteParentId)
|
|
{
|
|
if (!archive.WriteUuid(ParentId()))
|
|
break;
|
|
}
|
|
|
|
if (bWriteIndex)
|
|
{
|
|
if (!archive.Write3dmReferencedComponentIndex(*this))
|
|
break;
|
|
}
|
|
|
|
|
|
if (bWriteName)
|
|
{
|
|
if (!archive.WriteString(Name()))
|
|
break;
|
|
}
|
|
|
|
if (bWriteComponentStatus)
|
|
{
|
|
const ON_ComponentStatus component_status = ModelComponentStatus();
|
|
|
|
const ON__UINT32 locked_bit = 0x01;
|
|
const ON__UINT32 hidden_bit = 0x02;
|
|
// Additional states can be saved if that is reasonable.
|
|
|
|
const ON__UINT32 mask
|
|
= locked_bit
|
|
| hidden_bit;
|
|
ON__UINT32 value = 0U;
|
|
if ( component_status.IsLocked() )
|
|
value |= locked_bit;
|
|
if ( component_status.IsHidden() )
|
|
value |= hidden_bit;
|
|
if (!archive.WriteInt(mask))
|
|
break;
|
|
if (!archive.WriteInt(value))
|
|
break;
|
|
}
|
|
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if (!archive.EndWrite3dmChunk())
|
|
rc = false;
|
|
return rc;
|
|
}
|
|
|
|
bool ON_ModelComponent::ReadModelComponentAttributes(
|
|
class ON_BinaryArchive& archive
|
|
)
|
|
{
|
|
int major_version = 10;
|
|
int minor_version = 0;
|
|
if (!archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version))
|
|
return false;
|
|
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
if ( 1 != major_version)
|
|
break;
|
|
|
|
ON__UINT32 write_bits = 0U;
|
|
if (!archive.ReadInt(&write_bits))
|
|
break;
|
|
|
|
const bool bReadId = (0 != (write_bits & 0x01U));
|
|
const bool bReadParentId (0 != (write_bits & 0x02U));
|
|
const bool bReadIndex (0 != (write_bits & 0x04U));
|
|
const bool bReadName (0 != (write_bits & 0x08U));
|
|
const bool bReadComponentStatus = (0 != (write_bits & 0x10U));
|
|
|
|
if (bReadId)
|
|
{
|
|
ON_UUID id = Id();
|
|
if (!archive.ReadUuid(id))
|
|
break;
|
|
SetId(id);
|
|
}
|
|
|
|
if (bReadParentId)
|
|
{
|
|
ON_UUID parent_id = ParentId();
|
|
if (!archive.ReadUuid(parent_id))
|
|
break;
|
|
SetParentId(parent_id);
|
|
}
|
|
|
|
if (bReadIndex)
|
|
{
|
|
int component_index = Index();
|
|
if (!archive.ReadInt(&component_index))
|
|
break;
|
|
SetIndex(component_index);
|
|
}
|
|
|
|
|
|
if (bReadName)
|
|
{
|
|
ON_wString name;
|
|
if (!archive.ReadString(name))
|
|
break;
|
|
SetName(name);
|
|
}
|
|
|
|
if (bReadComponentStatus)
|
|
{
|
|
ON__UINT32 mask = 0U;
|
|
if (!archive.ReadInt(&mask))
|
|
break;
|
|
ON__UINT32 value = 0U;
|
|
if (!archive.ReadInt(&value))
|
|
break;
|
|
|
|
const ON__UINT32 locked_bit = 0x01;
|
|
const ON__UINT32 hidden_bit = 0x02;
|
|
// Additional states can be saved if that is reasonable.
|
|
|
|
const ON_ComponentStatus component_status0 = ModelComponentStatus();
|
|
ON_ComponentStatus component_status = component_status0;
|
|
if (0 != (mask & locked_bit))
|
|
{
|
|
const bool bIsLocked = (0 != (value & locked_bit));
|
|
component_status.SetLockedState(bIsLocked);
|
|
}
|
|
if (0 != (mask & hidden_bit))
|
|
{
|
|
const bool bIsHidden = (0 != (value & hidden_bit));
|
|
component_status.SetHiddenState(bIsHidden);
|
|
}
|
|
|
|
if ( component_status != component_status0 )
|
|
SetModelComponentStatus(component_status);
|
|
}
|
|
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if (!archive.EndRead3dmChunk())
|
|
rc = false;
|
|
return rc;
|
|
}
|
|
|
|
|
|
unsigned int ON_ModelComponent::CopyFrom(
|
|
const ON_ModelComponent& src,
|
|
unsigned int attributes_filter
|
|
)
|
|
{
|
|
unsigned int rc = 0;
|
|
unsigned int bit;
|
|
bool b;
|
|
|
|
// Erase unused bits.
|
|
attributes_filter &= ON_ModelComponent::Attributes::AllAttributes;
|
|
|
|
// Cannot set locked attributes.
|
|
bit = m_locked_status;
|
|
attributes_filter &= ~bit;
|
|
|
|
if ( 0 == attributes_filter )
|
|
return rc; // nothing to change
|
|
|
|
bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute & attributes_filter;
|
|
if (0 != bit)
|
|
{
|
|
b = (src.ModelSerialNumberIsSet())
|
|
? SetModelSerialNumber(src.ModelSerialNumber(),src.ReferenceModelSerialNumber(),src.InstanceDefinitionModelSerialNumber())
|
|
: ClearModelSerialNumber();
|
|
if (b)
|
|
rc |= bit;
|
|
}
|
|
|
|
// component type must be set before parent id
|
|
bit = ON_ModelComponent::Attributes::TypeAttribute & attributes_filter;
|
|
if (0 != bit)
|
|
{
|
|
b = (src.ComponentTypeIsSet())
|
|
? SetComponentType(src.ComponentType())
|
|
: ClearComponentType();
|
|
if (b)
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IdAttribute & attributes_filter;
|
|
if (0 != bit)
|
|
{
|
|
b = (src.IdIsSet())
|
|
? SetId(src.Id())
|
|
: ClearId();
|
|
if (b)
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::ParentIdAttribute & attributes_filter;
|
|
if (0 != bit)
|
|
{
|
|
b = (src.ParentIdIsSet())
|
|
? SetParentId(src.ParentId())
|
|
: ClearParentId();
|
|
if (b)
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IndexAttribute & attributes_filter;
|
|
if (0 != bit)
|
|
{
|
|
b = (src.IndexIsSet())
|
|
? SetIndex(src.Index())
|
|
: ClearIndex();
|
|
if (b)
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::NameAttribute & attributes_filter;
|
|
if (0 != bit)
|
|
{
|
|
b = (src.NameIsSet())
|
|
? SetName(src.Name())
|
|
: ClearName();
|
|
if (b)
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::ComponentStatusAttribute & attributes_filter;
|
|
if (0 != bit)
|
|
{
|
|
b = (src.ModelComponentStatusIsSet())
|
|
? SetModelComponentStatus(src.ModelComponentStatus())
|
|
: ClearModelComponentStatus();
|
|
if (b)
|
|
rc |= bit;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
ON_ModelComponent::ON_ModelComponent(const ON_ModelComponent& src)
|
|
: ON_Object(src)
|
|
, m_runtime_serial_number(++ON_ModelComponent::Internal_RuntimeSerialNumberGenerator)
|
|
, m_content_version_number(ON_ModelComponentContentVersionNumberOne(m_runtime_serial_number))
|
|
{
|
|
CopyFrom(src,ON_ModelComponent::Attributes::AllAttributes);
|
|
|
|
// The Type attribute is a special case. Locking it in the copy
|
|
// constructor allows the model components that are derived from
|
|
// ON_ModelComponent to use the default copy constructor.
|
|
const unsigned int bit = ON_ModelComponent::Attributes::TypeAttribute;
|
|
if (0 != (bit & m_set_status)
|
|
&& ON_ModelComponent::ComponentTypeIsValid(m_component_type)
|
|
&& src.ComponentTypeIsLocked()
|
|
)
|
|
m_locked_status |= bit;
|
|
}
|
|
|
|
ON_ModelComponent& ON_ModelComponent::operator=(const ON_ModelComponent& src)
|
|
{
|
|
if (this != &src)
|
|
{
|
|
// copy user data
|
|
ON_Object::operator=(src);
|
|
|
|
// copy ON_ModelComponent fields
|
|
CopyFrom(src,ON_ModelComponent::Attributes::AllAttributes);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ON_ModelComponent::ON_ModelComponent(
|
|
ON_ModelComponent::Type component_type,
|
|
const ON_ModelComponent& src
|
|
) ON_NOEXCEPT
|
|
: ON_Object(src)
|
|
, m_runtime_serial_number(++ON_ModelComponent::Internal_RuntimeSerialNumberGenerator)
|
|
, m_content_version_number(ON_ModelComponentContentVersionNumberOne(m_runtime_serial_number))
|
|
, m_component_type(component_type)
|
|
{
|
|
if (ON_ModelComponent::Type::Unset != m_component_type)
|
|
{
|
|
// set and lock m_component_type
|
|
m_set_status = ON_ModelComponent::Attributes::TypeAttribute;
|
|
m_locked_status = ON_ModelComponent::Attributes::TypeAttribute;
|
|
}
|
|
CopyFrom(src,ON_ModelComponent::Attributes::AllAttributes);
|
|
}
|
|
|
|
|
|
ON_ModelComponent::ON_ModelComponent(
|
|
ON_ModelComponent::Type component_type
|
|
) ON_NOEXCEPT
|
|
: m_runtime_serial_number(++ON_ModelComponent::Internal_RuntimeSerialNumberGenerator)
|
|
, m_content_version_number(ON_ModelComponentContentVersionNumberOne(m_runtime_serial_number))
|
|
, m_component_type(component_type)
|
|
{
|
|
if (ON_ModelComponent::Type::Unset != m_component_type)
|
|
{
|
|
m_locked_status = ON_ModelComponent::Attributes::TypeAttribute;
|
|
m_set_status = ON_ModelComponent::Attributes::TypeAttribute;
|
|
}
|
|
}
|
|
|
|
ON__UINT64 ON_ModelComponent::NextRuntimeSerialNumber()
|
|
{
|
|
const ON__UINT64 last_runtime_serial_number(ON_ModelComponent::Internal_RuntimeSerialNumberGenerator);
|
|
return (last_runtime_serial_number + 1);
|
|
}
|
|
|
|
ON__UINT64 ON_ModelComponent::RuntimeSerialNumber() const
|
|
{
|
|
return m_runtime_serial_number;
|
|
}
|
|
|
|
ON__UINT64 ON_ModelComponent::ContentVersionNumber() const
|
|
{
|
|
return m_content_version_number;
|
|
}
|
|
|
|
void ON_ModelComponent::IncrementContentVersionNumber() const
|
|
{
|
|
m_content_version_number++;
|
|
}
|
|
|
|
bool ON_ModelComponent::EraseIdentification(
|
|
bool bIgnoreLocks
|
|
)
|
|
{
|
|
if (false == bIgnoreLocks)
|
|
{
|
|
if (IdIsLocked() && !(ON_ModelComponent::Unset.Id() == m_component_id))
|
|
{
|
|
ON_ERROR("Cannot erase id.");
|
|
return false;
|
|
}
|
|
if (ParentIdIsLocked() && !(ON_ModelComponent::Unset.Id() == m_component_parent_id))
|
|
{
|
|
ON_ERROR("Cannot erase parent id.");
|
|
return false;
|
|
}
|
|
if (NameIsLocked() && ON_ModelComponent::Unset.Name() != m_component_name)
|
|
{
|
|
ON_ERROR("Cannot erase name.");
|
|
return false;
|
|
}
|
|
if (IndexIsLocked() && ON_ModelComponent::Unset.Index() != m_component_index)
|
|
{
|
|
ON_ERROR("Cannot erase index.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
m_component_id = ON_ModelComponent::Unset.Id();
|
|
m_component_parent_id = ON_ModelComponent::Unset.Id();
|
|
m_component_index = ON_ModelComponent::Unset.Index();
|
|
m_component_name = ON_ModelComponent::Unset.Name();
|
|
m_component_name_hash = ON_ModelComponent::Unset.NameHash();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ON_ModelComponent::IsSystemComponent() const
|
|
{
|
|
return (
|
|
0 == m_content_version_number
|
|
&& 0 != (ON_ModelComponent::Attributes::SystemComponentAttribute & m_locked_status)
|
|
);
|
|
}
|
|
|
|
bool ON_ModelComponent::SetAsSystemComponent()
|
|
{
|
|
return Internal_SetAsSystemComponent(false);
|
|
}
|
|
|
|
bool ON_ModelComponent::SetAsUnsetSystemComponent()
|
|
{
|
|
return Internal_SetAsSystemComponent(true);
|
|
}
|
|
|
|
bool ON_ModelComponent::Internal_SetAsSystemComponent(
|
|
bool bUnsetSystemComponent
|
|
)
|
|
{
|
|
if (m_locked_status == 0xFFFFU)
|
|
{
|
|
ON_ERROR("component is already a system component.");
|
|
return true;
|
|
}
|
|
|
|
const bool bIndexRequired = ON_ModelComponent::IndexRequired(m_component_type);
|
|
const bool bUniqueNameRequired = ON_ModelComponent::UniqueNameRequired(m_component_type);
|
|
const bool bUniqueNameIncludesParent = ON_ModelComponent::UniqueNameIncludesParent(m_component_type);
|
|
|
|
for (;;)
|
|
{
|
|
if (ParentIdIsNotNil())
|
|
break;
|
|
|
|
if (bUniqueNameIncludesParent != ParentIdIsSet())
|
|
break;
|
|
|
|
if (IdIsNil())
|
|
{
|
|
if (!bUnsetSystemComponent)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (bUnsetSystemComponent)
|
|
break;
|
|
}
|
|
|
|
if ( bIndexRequired && false == bUnsetSystemComponent )
|
|
{
|
|
if (false == IndexIsSet())
|
|
break;
|
|
if (Index() >= 0)
|
|
break;
|
|
if (Index() <= ON_UNSET_INT_INDEX)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (IndexIsSet())
|
|
break;
|
|
}
|
|
|
|
if ( ON_ModelComponent::m_component_status != m_component_status )
|
|
break;
|
|
|
|
if (bUniqueNameRequired && false == bUnsetSystemComponent)
|
|
{
|
|
if (false == NameIsNotEmpty())
|
|
break;
|
|
if (false == NameHash().IsValidAndNotEmpty())
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (NameIsSet())
|
|
return false;
|
|
if (false == NameHash().IsEmptyNameHash())
|
|
break;
|
|
}
|
|
|
|
m_locked_status = 0xFFFFU;
|
|
m_content_version_number = 0;
|
|
return true;
|
|
}
|
|
|
|
ON_ERROR("Invalid settings for a system component.");
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Model Serial Number interface
|
|
//
|
|
|
|
unsigned int ON_ModelComponent::ModelSerialNumber() const
|
|
{
|
|
return m_model_serial_number;
|
|
}
|
|
|
|
unsigned int ON_ModelComponent::ReferenceModelSerialNumber() const
|
|
{
|
|
return m_reference_model_serial_number;
|
|
}
|
|
|
|
unsigned int ON_ModelComponent::InstanceDefinitionModelSerialNumber() const
|
|
{
|
|
return m_linked_idef_serial_number;
|
|
}
|
|
|
|
bool ON_ModelComponent::SetModelSerialNumber(
|
|
unsigned int model_serial_number
|
|
)
|
|
{
|
|
return SetModelSerialNumber(
|
|
model_serial_number,
|
|
ON_ModelComponent::Unset.ReferenceModelSerialNumber(),
|
|
ON_ModelComponent::Unset.InstanceDefinitionModelSerialNumber()
|
|
);
|
|
}
|
|
|
|
bool ON_ModelComponent::SetModelSerialNumber(
|
|
unsigned int model_serial_number,
|
|
unsigned int reference_model_serial_number,
|
|
unsigned int instance_definition_model_serial_number
|
|
)
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute;
|
|
if (0 != (bit & m_locked_status))
|
|
return false;
|
|
|
|
m_model_serial_number = model_serial_number;
|
|
m_reference_model_serial_number = reference_model_serial_number;
|
|
m_linked_idef_serial_number = instance_definition_model_serial_number;
|
|
m_set_status |= bit;
|
|
return true;
|
|
|
|
}
|
|
|
|
bool ON_ModelComponent::ClearModelSerialNumber()
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute;
|
|
return (bit == ClearModelComponentAttributes(bit));
|
|
}
|
|
|
|
void ON_ModelComponent::LockModelSerialNumber()
|
|
{
|
|
m_locked_status |= ON_ModelComponent::Attributes::ModelSerialNumberAttribute;
|
|
}
|
|
|
|
bool ON_ModelComponent::ModelSerialNumberIsLocked() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute;
|
|
return (0 != (bit & m_locked_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::ModelSerialNumberIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::IsReferenceComponent() const
|
|
{
|
|
return (0 != m_reference_model_serial_number || 0 != m_linked_idef_serial_number);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Name interface
|
|
//
|
|
//
|
|
|
|
const wchar_t* ON_ModelComponent::GetName(
|
|
ON_wString& component_name
|
|
) const
|
|
{
|
|
component_name = static_cast<const wchar_t*>(m_component_name);
|
|
return static_cast<const wchar_t*>(component_name);
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::Name() const
|
|
{
|
|
return NameIsSet() ? m_component_name : ON_wString::EmptyString;
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::DeletedName() const
|
|
{
|
|
return DeletedNameIsSet() ? m_component_name : ON_wString::EmptyString;
|
|
}
|
|
|
|
const wchar_t* ON_ModelComponent::NameAsPointer() const
|
|
{
|
|
return NameIsSet() ? m_component_name : ON_wString::EmptyString;
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::RemoveAllReferencePrefixDelimiters(
|
|
const wchar_t* name
|
|
)
|
|
{
|
|
if ( nullptr == name || 0 == name[0] )
|
|
return ON_wString::EmptyString;
|
|
|
|
ON_wString local(name);
|
|
local.Replace(ON_ModelComponent::ReferencePrefixDelimiter, nullptr);
|
|
|
|
return local.IsNotEmpty() ? local : ON_wString::EmptyString;
|
|
}
|
|
|
|
static const ON_wString Internal_RemoveTrailingNameToken(
|
|
const wchar_t* name,
|
|
const ON_wString& token
|
|
)
|
|
{
|
|
if ( nullptr == name || 0 == name[0] || token.IsEmpty() )
|
|
return ON_wString::EmptyString;
|
|
|
|
ON_wString local(name);
|
|
|
|
wchar_t* s0 = local.Array();
|
|
if (nullptr == s0)
|
|
return ON_wString::EmptyString;
|
|
|
|
// remove any reference name delimiters
|
|
const unsigned int d_length = token.Length();
|
|
const unsigned int local_length = (unsigned int)local.Length();
|
|
if (local_length < d_length )
|
|
return local;
|
|
|
|
if (ON_wString::EqualOrdinal(s0 + (local_length - d_length), token, false))
|
|
{
|
|
local.SetLength((local_length - d_length));
|
|
}
|
|
|
|
return local;
|
|
}
|
|
|
|
|
|
|
|
const ON_wString ON_ModelComponent::RemoveTrailingReferencePrefixDelimiter(
|
|
const wchar_t* name
|
|
)
|
|
{
|
|
return Internal_RemoveTrailingNameToken(name, ON_ModelComponent::ReferencePrefixDelimiter);
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::RemoveTrailingReferencePrefixSeparator(
|
|
const wchar_t* name
|
|
)
|
|
{
|
|
return Internal_RemoveTrailingNameToken(name, ON_ModelComponent::ReferencePrefixSeparator);
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::RemoveTrailingNamePathSeparator(
|
|
const wchar_t* name
|
|
)
|
|
{
|
|
return Internal_RemoveTrailingNameToken(name, ON_ModelComponent::NamePathSeparator);
|
|
}
|
|
|
|
//const ON_wString ON_ModelComponent::WorksessionReferenceNamePrefix(
|
|
// const wchar_t* reference_prefix,
|
|
// bool bAppendReferenceNamePrefixDelimiter
|
|
//)
|
|
//{
|
|
// ON_wString s(reference_prefix);
|
|
//
|
|
// for (;;)
|
|
// {
|
|
// const int length0 = s.Length();
|
|
// s.TrimLeftAndRight();
|
|
// s.TrimLeftAndRight(L"[]");
|
|
// const int length1 = s.Length();
|
|
// if (length1 <= 0 || length1 >= length0)
|
|
// break;
|
|
// }
|
|
//
|
|
// if (s.IsEmpty())
|
|
// return ON_wString::EmptyString;
|
|
//
|
|
// ON_wString worksession_prefix = L"[ ";
|
|
// worksession_prefix += s;
|
|
// worksession_prefix += L" ]";
|
|
// return worksession_prefix;
|
|
//}
|
|
|
|
static const wchar_t* InternalStringBeginsWithToken(
|
|
const wchar_t* str,
|
|
const wchar_t* token
|
|
)
|
|
{
|
|
if (nullptr == str || nullptr == token || 0 == token[0])
|
|
return nullptr;
|
|
while (*str == *token && 0 != *token)
|
|
{
|
|
str++;
|
|
token++;
|
|
}
|
|
return (0 == *token) ? str : nullptr;
|
|
}
|
|
|
|
const wchar_t* ON_ModelComponent::IsReferencePrefixDelimiter(
|
|
const wchar_t* s
|
|
)
|
|
{
|
|
return InternalStringBeginsWithToken(s, ON_ModelComponent::ReferencePrefixDelimiter);
|
|
}
|
|
|
|
const wchar_t* ON_ModelComponent::IsReferencePrefixSeparator(
|
|
const wchar_t* s
|
|
)
|
|
{
|
|
return InternalStringBeginsWithToken(s, ON_ModelComponent::ReferencePrefixSeparator);
|
|
}
|
|
|
|
const wchar_t* ON_ModelComponent::IsNamePathSeparator(
|
|
const wchar_t* s
|
|
)
|
|
{
|
|
return InternalStringBeginsWithToken(s, ON_ModelComponent::NamePathSeparator);
|
|
}
|
|
|
|
void ON_ModelComponent::SplitName(
|
|
const wchar_t* name,
|
|
ON_wString& reference_prefix,
|
|
ON_wString& name_parent,
|
|
ON_wString& name_leaf
|
|
)
|
|
{
|
|
ON_wString local(name);
|
|
wchar_t* str = local.Array();
|
|
wchar_t* tail = str + local.Length();
|
|
|
|
reference_prefix = ON_wString::EmptyString;
|
|
name_parent = ON_wString::EmptyString;
|
|
name_leaf = ON_wString::EmptyString;
|
|
if (nullptr == str || 0 == str[0])
|
|
return;
|
|
|
|
bool bHaveReference = false;
|
|
bool bHaveLeaf = false;
|
|
while (tail > str)
|
|
{
|
|
tail--;
|
|
|
|
if (false == bHaveLeaf)
|
|
{
|
|
const wchar_t* s = ON_ModelComponent::IsNamePathSeparator(tail);
|
|
if (nullptr != s)
|
|
{
|
|
bHaveLeaf = true;
|
|
name_leaf = s;
|
|
*tail = 0;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (false == bHaveReference)
|
|
{
|
|
const wchar_t* s = ON_ModelComponent::IsReferencePrefixDelimiter(tail);
|
|
if (nullptr != s)
|
|
{
|
|
bHaveReference = true;
|
|
if (false == bHaveLeaf)
|
|
{
|
|
bHaveLeaf = true;
|
|
name_leaf = s;
|
|
}
|
|
else
|
|
{
|
|
name_parent = s;
|
|
}
|
|
*tail = 0;
|
|
reference_prefix = ON_ModelComponent::RemoveAllReferencePrefixDelimiters(str);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (false == bHaveReference)
|
|
{
|
|
if (false == bHaveLeaf)
|
|
name_leaf = name;
|
|
else
|
|
name_parent = str;
|
|
}
|
|
|
|
reference_prefix.TrimLeftAndRight();
|
|
name_parent.TrimLeftAndRight();
|
|
name_leaf.TrimLeftAndRight();
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::NameReferencePrefix(const wchar_t * name)
|
|
{
|
|
if (nullptr == name || 0 == name[0])
|
|
return ON_wString::EmptyString;
|
|
const wchar_t* tail = name;
|
|
while (0 != *tail)
|
|
tail++;
|
|
|
|
while (tail > name)
|
|
{
|
|
tail--;
|
|
const wchar_t* s = ON_ModelComponent::IsReferencePrefixDelimiter(tail);
|
|
if (nullptr != s)
|
|
{
|
|
ON_wString name_reference = name;
|
|
name_reference.SetLength(tail - name);
|
|
name_reference = ON_ModelComponent::RemoveAllReferencePrefixDelimiters(name_reference);
|
|
name_reference.TrimLeftAndRight();
|
|
return name_reference;
|
|
}
|
|
}
|
|
|
|
return ON_wString::EmptyString;
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::NameParent(
|
|
const wchar_t * name,
|
|
bool bIncludeReference
|
|
)
|
|
{
|
|
if (nullptr == name || 0 == name[0])
|
|
return ON_wString::EmptyString;
|
|
|
|
if (false == bIncludeReference)
|
|
{
|
|
ON_wString name_reference;
|
|
ON_wString name_parent;
|
|
ON_wString name_leaf;
|
|
SplitName(name, name_reference, name_parent, name_leaf);
|
|
return name_parent;
|
|
}
|
|
|
|
const wchar_t* tail = name;
|
|
while (0 != *tail)
|
|
tail++;
|
|
|
|
while (tail > name)
|
|
{
|
|
tail--;
|
|
const wchar_t* s = ON_ModelComponent::IsNamePathSeparator(tail);
|
|
if (nullptr != s)
|
|
{
|
|
ON_wString name_parent = name;
|
|
name_parent.SetLength(tail - name);
|
|
name_parent.TrimLeftAndRight();
|
|
if (bIncludeReference)
|
|
return name_parent;
|
|
}
|
|
}
|
|
|
|
return ON_wString::EmptyString;
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::NameLeaf(
|
|
const wchar_t* name
|
|
)
|
|
{
|
|
if (nullptr == name || 0 == name[0])
|
|
return ON_wString::EmptyString;
|
|
const wchar_t* tail = name;
|
|
while (0 != *tail)
|
|
tail++;
|
|
|
|
while( tail > name )
|
|
{
|
|
tail--;
|
|
|
|
const wchar_t* s = ON_ModelComponent::IsNamePathSeparator(tail);
|
|
if ( nullptr == s )
|
|
s = ON_ModelComponent::IsReferencePrefixDelimiter(tail);
|
|
if (nullptr != s)
|
|
{
|
|
ON_wString name_leaf = s;
|
|
name_leaf.TrimLeftAndRight();
|
|
return name_leaf; // can be empty when name ends in a delimiter or separator or spaces
|
|
}
|
|
}
|
|
|
|
ON_wString name_leaf = name;
|
|
name_leaf.TrimLeftAndRight();
|
|
|
|
return name_leaf;
|
|
}
|
|
|
|
const ON_wString ON_ModelComponent::RemoveReferencePrefix(const wchar_t * name)
|
|
{
|
|
if (nullptr == name || 0 == name[0])
|
|
return ON_wString::EmptyString;
|
|
const wchar_t* tail = name;
|
|
while (0 != *tail)
|
|
tail++;
|
|
|
|
while (tail > name)
|
|
{
|
|
tail--;
|
|
const wchar_t* s = ON_ModelComponent::IsReferencePrefixDelimiter(tail);
|
|
if (nullptr != s)
|
|
{
|
|
ON_wString name_no_reference = s;
|
|
name_no_reference.TrimLeftAndRight();
|
|
return name_no_reference;
|
|
}
|
|
}
|
|
|
|
ON_wString name_no_reference(name);
|
|
name_no_reference.TrimLeftAndRight();
|
|
return name_no_reference;
|
|
}
|
|
|
|
|
|
const ON_NameHash& ON_ModelComponent::Internal_NameHash() const
|
|
{
|
|
if (m_component_name_hash.IsEmptyNameHash() && m_component_name.IsNotEmpty())
|
|
{
|
|
// lazy evaulation because SHA-1 calculation takes appreciable time
|
|
|
|
// For components whose names are in a tree structure, like layers,
|
|
// the parent id must be included.
|
|
// For all other components, the parent id must be ignored.
|
|
const ON_UUID name_parent_id
|
|
= ON_ModelComponent::UniqueNameIncludesParent(m_component_type)
|
|
? m_component_parent_id
|
|
: ON_nil_uuid;
|
|
const bool bIgnoreCase = ON_ModelComponent::UniqueNameIgnoresCase(m_component_type);
|
|
m_component_name_hash = ON_NameHash::Create(name_parent_id,m_component_name,bIgnoreCase);
|
|
}
|
|
return m_component_name_hash;
|
|
}
|
|
|
|
const ON_NameHash& ON_ModelComponent::NameHash() const
|
|
{
|
|
return NameIsSet() ? Internal_NameHash() : ON_NameHash::EmptyNameHash;
|
|
}
|
|
|
|
const ON_NameHash ON_ModelComponent::NewNameHash(
|
|
const wchar_t* new_name
|
|
) const
|
|
{
|
|
ON_wString local_buffer(new_name);
|
|
local_buffer.TrimLeftAndRight();
|
|
if (local_buffer.IsNotEmpty() && false == ON_ModelComponent::IsValidComponentName(local_buffer))
|
|
{
|
|
return ON_NameHash::UnsetNameHash;
|
|
}
|
|
|
|
const ON_UUID name_parent_id
|
|
= ON_ModelComponent::UniqueNameIncludesParent(ComponentType())
|
|
? Id()
|
|
: ON_nil_uuid;
|
|
return ON_NameHash::Create(name_parent_id, local_buffer);
|
|
}
|
|
|
|
const ON_NameHash& ON_ModelComponent::DeletedNameHash() const
|
|
{
|
|
return DeletedNameIsSet() ? Internal_NameHash() : ON_NameHash::EmptyNameHash;
|
|
}
|
|
|
|
bool ON_ModelComponent::NameIsEmpty() const
|
|
{
|
|
// should return true when the name is not set.
|
|
return NameIsSet() ? m_component_name.IsEmpty() : true;
|
|
}
|
|
|
|
bool ON_ModelComponent::NameIsNotEmpty() const
|
|
{
|
|
return NameIsSet() ? m_component_name.IsNotEmpty() : false;
|
|
}
|
|
|
|
bool ON_ModelComponent::ChangeName(
|
|
const wchar_t* new_name,
|
|
class ON_ComponentManifest* manifest
|
|
)
|
|
{
|
|
const ON_ModelComponent::Type component_type = ComponentType();
|
|
|
|
if (nullptr != manifest)
|
|
{
|
|
if (manifest->ItemFromId(component_type, Id()).IsUnset())
|
|
{
|
|
ON_ERROR("component is not in the manifest.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const bool bUniqueNameRequired = ON_ModelComponent::UniqueNameRequired(component_type);
|
|
ON_wString local_name(new_name);
|
|
local_name.TrimLeftAndRight();
|
|
new_name = local_name;
|
|
const ON_UUID name_parent_id
|
|
= ON_ModelComponent::UniqueNameIncludesParent(component_type)
|
|
? ParentId()
|
|
: ON_nil_uuid;
|
|
const ON_NameHash new_name_hash = ON_NameHash::Create(name_parent_id,new_name);
|
|
if (local_name.IsEmpty() )
|
|
{
|
|
if (bUniqueNameRequired)
|
|
{
|
|
ON_ERROR("This component cannot have an empty name.");
|
|
return false;
|
|
}
|
|
}
|
|
else if (ON_ModelComponent::IsValidComponentName(new_name))
|
|
{
|
|
ON_ERROR("Invalid component name.");
|
|
return false;
|
|
}
|
|
else if (bUniqueNameRequired && nullptr != manifest )
|
|
{
|
|
if (manifest->ItemFromNameHash(component_type, new_name_hash).IsValid())
|
|
{
|
|
// name is already being used.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (
|
|
nullptr != manifest
|
|
&& manifest->ChangeComponentName(Id(), component_type, ParentId(), new_name).IsUnset()
|
|
)
|
|
{
|
|
ON_ERROR("Unable to update manifest.");
|
|
return false;
|
|
}
|
|
|
|
const bool rc
|
|
= (local_name.IsEmpty())
|
|
? ClearName()
|
|
: SetName(new_name);
|
|
|
|
if (false == rc)
|
|
{
|
|
ON_ERROR("Unable to change component name.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_ModelComponent::SetName(
|
|
const wchar_t* component_name
|
|
)
|
|
{
|
|
ON_wString local_buffer(component_name);
|
|
local_buffer.TrimLeftAndRight();
|
|
|
|
const unsigned int bit = ON_ModelComponent::Attributes::NameAttribute;
|
|
if (0 != (bit & m_locked_status))
|
|
return false;
|
|
|
|
if (local_buffer.IsNotEmpty() && false == ON_ModelComponent::IsValidComponentName(local_buffer))
|
|
{
|
|
ON_ERROR("Invalid component_name parameter.");
|
|
return false;
|
|
}
|
|
|
|
const bool bContentChange = (false == NameIsSet() || false == m_component_name.EqualOrdinal(local_buffer,false));
|
|
|
|
m_component_name = local_buffer;
|
|
|
|
// lazy evaluation is used to set m_component_name_hash
|
|
m_component_name_hash = ON_NameHash::EmptyNameHash;
|
|
|
|
m_set_status |= bit;
|
|
m_set_status &= ~(ON_ModelComponent::Attributes::DeletedNameAttribute);
|
|
|
|
if ( bContentChange )
|
|
IncrementContentVersionNumber();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_ModelComponent::SetLocalizedSystemComponentName(
|
|
const wchar_t* system_component_localized_name
|
|
)
|
|
{
|
|
if (false == IsSystemComponent())
|
|
{
|
|
ON_ERROR("not a system component.");
|
|
return false;
|
|
}
|
|
if (NameIsLocked())
|
|
{
|
|
ON_ERROR("name cannot be changed.");
|
|
return false;
|
|
}
|
|
ON_wString local_buffer(system_component_localized_name);
|
|
local_buffer.TrimLeftAndRight();
|
|
system_component_localized_name = local_buffer;
|
|
if (nullptr == system_component_localized_name || 0 == system_component_localized_name[0])
|
|
{
|
|
ON_ERROR("system_component_localized_name cannot be empty.");
|
|
return false;
|
|
}
|
|
const ON_NameHash name_hash = ON_NameHash::Create(ParentId(),system_component_localized_name);
|
|
if (false == name_hash.IsValidAndNotEmpty())
|
|
{
|
|
ON_ERROR("system_component_localized_name is not valid.");
|
|
return false;
|
|
}
|
|
|
|
m_component_name = local_buffer;
|
|
m_component_name_hash = name_hash;
|
|
return SetAsSystemComponent();
|
|
}
|
|
|
|
bool ON_ModelComponent::ClearName()
|
|
{
|
|
const unsigned int bit = (ON_ModelComponent::Attributes::NameAttribute | ON_ModelComponent::Attributes::DeletedNameAttribute);
|
|
return (bit == ClearModelComponentAttributes(bit));
|
|
}
|
|
|
|
void ON_ModelComponent::LockName()
|
|
{
|
|
m_locked_status |= ON_ModelComponent::Attributes::NameAttribute;
|
|
|
|
// If name is deleted, erase it.
|
|
m_set_status &= ~(ON_ModelComponent::Attributes::DeletedNameAttribute);
|
|
if (0 == (ON_ModelComponent::Attributes::NameAttribute & m_set_status))
|
|
{
|
|
m_component_name_hash = ON_NameHash::EmptyNameHash;
|
|
m_component_name = ON_wString::EmptyString;
|
|
}
|
|
}
|
|
|
|
void ON_ModelComponent::LockAllSettingsExceptName()
|
|
{
|
|
const unsigned int name_bit = ON_ModelComponent::Attributes::NameAttribute;
|
|
unsigned int mask = ~name_bit;
|
|
mask &= ON_ModelComponent::Attributes::AllAttributes;
|
|
m_locked_status |= mask;
|
|
}
|
|
|
|
bool ON_ModelComponent::NameIsLocked() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::NameAttribute;
|
|
return (0 != (bit & m_locked_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::NameIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::NameAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::DeletedNameIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::DeletedNameAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::DeleteName()
|
|
{
|
|
if ( NameIsLocked() )
|
|
return false; // cannot modify a locked name.
|
|
|
|
if ( false == NameIsSet() )
|
|
return false; // nothing to delete.
|
|
|
|
const ON__UINT16 name_bit = (ON__UINT16)ON_ModelComponent::Attributes::NameAttribute;
|
|
const ON__UINT16 deleted_name_bit = (ON__UINT16)ON_ModelComponent::Attributes::DeletedNameAttribute;
|
|
m_set_status &= ~(name_bit | deleted_name_bit);
|
|
|
|
// do this for all m_component_name contents including empty names.
|
|
// There is a difference between name being "unset" and name being "set to empty".
|
|
//
|
|
// name is now "deleted"
|
|
m_set_status |= deleted_name_bit;
|
|
IncrementContentVersionNumber();
|
|
|
|
return DeletedNameIsSet();
|
|
}
|
|
|
|
bool ON_ModelComponent::UndeleteName()
|
|
{
|
|
if ( NameIsLocked() )
|
|
return false; // cannot modify a locked name.
|
|
|
|
if ( false == DeletedNameIsSet() )
|
|
return false; // nothing to delete.
|
|
|
|
const ON__UINT16 name_bit = (ON__UINT16)ON_ModelComponent::Attributes::NameAttribute;
|
|
const ON__UINT16 deleted_name_bit = (ON__UINT16)ON_ModelComponent::Attributes::DeletedNameAttribute;
|
|
m_set_status &= ~(name_bit | deleted_name_bit);
|
|
|
|
// do this for all m_component_name contents including empty names.
|
|
// There is a difference between name being "unset" and name being "set to empty".
|
|
//
|
|
// name is now "undeleted"
|
|
m_set_status |= name_bit;
|
|
IncrementContentVersionNumber();
|
|
|
|
return NameIsSet();
|
|
}
|
|
|
|
int ON_ModelComponent::CompareName(
|
|
const wchar_t* other_name
|
|
) const
|
|
{
|
|
return CompareName(ParentId(), other_name );
|
|
}
|
|
|
|
int ON_ModelComponent::CompareName(
|
|
const ON_UUID& other_parent_id,
|
|
const wchar_t* other_name
|
|
) const
|
|
{
|
|
int rc
|
|
= (ON_ModelComponent::UniqueNameIncludesParent(m_component_type) && NameIsSet())
|
|
? ON_UuidCompare(m_component_parent_id, other_parent_id)
|
|
: 0;
|
|
return
|
|
(0 != rc)
|
|
? rc
|
|
: ON_wString::CompareAttributeName(Name(), other_name);
|
|
}
|
|
|
|
int ON_ModelComponent::CompareId(
|
|
const ON_ModelComponent& a,
|
|
const ON_ModelComponent& b
|
|
)
|
|
{
|
|
return ON_UuidCompare(a.m_component_id, b.m_component_id);
|
|
}
|
|
|
|
int ON_ModelComponent::CompareNameAndId(
|
|
const ON_ModelComponent& a,
|
|
const ON_ModelComponent& b
|
|
)
|
|
{
|
|
int rc = ON_ModelComponent::CompareName(a, b);
|
|
if (0 == rc)
|
|
rc = ON_ModelComponent::CompareId(a, b);
|
|
return rc;
|
|
}
|
|
|
|
int ON_ModelComponent::CompareIdAndName(
|
|
const ON_ModelComponent& a,
|
|
const ON_ModelComponent& b
|
|
)
|
|
{
|
|
int rc = ON_ModelComponent::CompareId(a, b);
|
|
if (0 == rc)
|
|
rc = ON_ModelComponent::CompareName(a, b);
|
|
return rc;
|
|
}
|
|
|
|
|
|
int ON_ModelComponent::CompareName(
|
|
const ON_ModelComponent& a,
|
|
const ON_ModelComponent& b
|
|
)
|
|
{
|
|
const ON_UUID a_parent_id
|
|
= ON_ModelComponent::UniqueNameIncludesParent(a.m_component_type) && a.NameIsSet()
|
|
? a.ParentId()
|
|
: ON_nil_uuid;
|
|
const ON_UUID b_parent_id
|
|
= ON_ModelComponent::UniqueNameIncludesParent(b.m_component_type) && b.NameIsSet()
|
|
? b.ParentId()
|
|
: ON_nil_uuid;
|
|
|
|
int rc = ON_UuidCompare(a_parent_id,b_parent_id);
|
|
|
|
return
|
|
(0 != rc)
|
|
? rc
|
|
: ON_wString::CompareAttributeName(a.m_component_name,b.m_component_name);
|
|
}
|
|
|
|
int ON_ModelComponent::CompareNameExact(
|
|
const wchar_t* other_name
|
|
) const
|
|
{
|
|
return CompareNameExact(ParentId(),other_name);
|
|
}
|
|
|
|
int ON_ModelComponent::CompareNameExact(
|
|
const ON_UUID& other_parent_id,
|
|
const wchar_t* other_name
|
|
) const
|
|
{
|
|
int rc = ON_ModelComponent::CompareName(other_parent_id,other_name);
|
|
return
|
|
(0 != rc)
|
|
? rc
|
|
: ON_wString::CompareOrdinal(m_component_name,other_name,false);
|
|
}
|
|
|
|
int ON_ModelComponent::CompareNameExact(
|
|
const ON_ModelComponent& a,
|
|
const ON_ModelComponent& b
|
|
)
|
|
{
|
|
int rc = ON_ModelComponent::CompareName(a,b);
|
|
return
|
|
(0 != rc)
|
|
? rc
|
|
: ON_wString::CompareOrdinal(a.m_component_name,b.m_component_name,false);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Type interface
|
|
//
|
|
|
|
ON_ModelComponent::Type ON_ModelComponent::ComponentType() const
|
|
{
|
|
return m_component_type;
|
|
}
|
|
|
|
bool ON_ModelComponent::SetComponentType(
|
|
ON_ModelComponent::Type component_type
|
|
)
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::TypeAttribute;
|
|
if (0 != (bit & m_locked_status))
|
|
return false;
|
|
|
|
const bool bContentChange = (m_component_type != component_type);
|
|
|
|
m_component_type = component_type;
|
|
m_set_status |= bit;
|
|
|
|
if ( bContentChange )
|
|
IncrementContentVersionNumber();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_ModelComponent::ClearComponentType()
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::TypeAttribute;
|
|
return (bit == ClearModelComponentAttributes(bit));
|
|
}
|
|
|
|
void ON_ModelComponent::LockComponentType()
|
|
{
|
|
m_locked_status |= ON_ModelComponent::Attributes::TypeAttribute;
|
|
}
|
|
|
|
bool ON_ModelComponent::ComponentTypeIsLocked() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::TypeAttribute;
|
|
return (0 != (bit & m_locked_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::ComponentTypeIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::TypeAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::ComponentTypeIsValid(
|
|
ON_ModelComponent::Type component_type
|
|
)
|
|
{
|
|
return (
|
|
ON_ModelComponent::ComponentTypeFromUnsigned(static_cast<unsigned int>(component_type)) == component_type
|
|
&& ON_ModelComponent::Type::Unset != component_type
|
|
);
|
|
}
|
|
|
|
bool ON_ModelComponent::ComponentTypeIsValidAndNotMixed(
|
|
ON_ModelComponent::Type component_type
|
|
)
|
|
{
|
|
return
|
|
ON_ModelComponent::ComponentTypeIsValid(component_type)
|
|
&& ON_ModelComponent::Type::Mixed != component_type;
|
|
}
|
|
|
|
bool ON_ModelComponent::IsValidComponentName(
|
|
const ON_wString& candidate_component_name
|
|
)
|
|
{
|
|
return ON_ModelComponent::IsValidComponentName(
|
|
(size_t)candidate_component_name.Length(),
|
|
static_cast<const wchar_t*>(candidate_component_name)
|
|
);
|
|
|
|
}
|
|
|
|
bool ON_ModelComponent::IsValidComponentName(
|
|
size_t length,
|
|
const wchar_t* candidate_component_name
|
|
)
|
|
{
|
|
return
|
|
(length > 0
|
|
&& length <= 2147483645
|
|
&& length == (size_t)ON_wString::Length(candidate_component_name,length+1)
|
|
&& ON_ModelComponent::IsValidComponentName(candidate_component_name)
|
|
);
|
|
}
|
|
|
|
|
|
|
|
bool ON_ModelComponent::IsValidComponentName(
|
|
const class ON_ComponentManifest& model_manfest,
|
|
const ON_ModelComponent& model_component,
|
|
bool bPermitReferencePrefix,
|
|
ON_wString& valid_name
|
|
)
|
|
{
|
|
valid_name = ON_wString::EmptyString;
|
|
const ON_ModelComponent::Type model_component_type = model_component.ComponentType();
|
|
|
|
const ON_wString original_name = model_component.Name();
|
|
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
if (false == ON_ModelComponent::IsValidComponentName(original_name))
|
|
{
|
|
break;
|
|
}
|
|
|
|
const bool bUniqueNameRequired = ON_ModelComponent::UniqueNameRequired(model_component_type);
|
|
if (bPermitReferencePrefix && false == bUniqueNameRequired)
|
|
{
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
const class ON_ComponentManifestItem& item
|
|
= (bUniqueNameRequired)
|
|
? model_manfest.ItemFromName(&model_component)
|
|
: ON_ComponentManifestItem::UnsetItem;
|
|
|
|
const bool bItemFromNameIsOK
|
|
= (item.ComponentRuntimeSerialNumber() == model_component.RuntimeSerialNumber())
|
|
|| item.IsUnset()
|
|
|| item.IsSystemComponent()
|
|
;
|
|
|
|
if ( bItemFromNameIsOK && bPermitReferencePrefix)
|
|
{
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
ON_wString ref;
|
|
ON_wString parent;
|
|
ON_wString leaf;
|
|
ON_ModelComponent::SplitName(
|
|
original_name,
|
|
ref,
|
|
parent,
|
|
leaf
|
|
);
|
|
if (bItemFromNameIsOK && ref.IsEmpty())
|
|
{
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if (false == ON_ModelComponent::IsValidComponentName(leaf))
|
|
break;
|
|
|
|
const class ON_ComponentManifestItem& leaf_item
|
|
= (bUniqueNameRequired)
|
|
? model_manfest.ItemFromName(model_component_type,model_component.ParentId(),leaf)
|
|
: ON_ComponentManifestItem::UnsetItem;
|
|
|
|
if (leaf_item.IsUnset() || leaf_item.IsSystemComponent())
|
|
{
|
|
valid_name = leaf;
|
|
break;
|
|
}
|
|
|
|
valid_name = model_manfest.UnusedName(
|
|
model_component.ComponentType(),
|
|
model_component.ParentId(),
|
|
leaf,
|
|
nullptr,
|
|
nullptr,
|
|
0,
|
|
nullptr
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
if (rc)
|
|
{
|
|
valid_name = original_name;
|
|
}
|
|
else if (valid_name.IsEmpty())
|
|
{
|
|
valid_name = model_manfest.UnusedName(
|
|
model_component_type,
|
|
model_component.ParentId(),
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
0,
|
|
nullptr
|
|
);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static bool Internal_IsValidComponentNameCodePoint(ON__UINT32 unicode_code_point)
|
|
{
|
|
return
|
|
unicode_code_point >= ON_UnicodeCodePoint::ON_Space
|
|
&& 0 != ON_IsValidUnicodeCodePoint(unicode_code_point)
|
|
&& 0 == ON_IsUnicodeC1ControlCodePoint(unicode_code_point)
|
|
;
|
|
}
|
|
|
|
bool ON_ModelComponent::IsValidComponentNameFirstCodePoint(
|
|
ON__UINT32 unicode_code_point
|
|
)
|
|
{
|
|
return
|
|
Internal_IsValidComponentNameCodePoint(unicode_code_point)
|
|
&& 0 == ON_IsUnicodeSpaceCodePoint(unicode_code_point)
|
|
&& unicode_code_point != '('
|
|
&& unicode_code_point != ')'
|
|
&& unicode_code_point != '['
|
|
&& unicode_code_point != ']'
|
|
&& unicode_code_point != '{'
|
|
&& unicode_code_point != '}';
|
|
}
|
|
|
|
bool ON_ModelComponent::IsValidComponentNameFirstCodePoint(
|
|
int length,
|
|
const wchar_t* candidate_component_name
|
|
)
|
|
{
|
|
if (nullptr == candidate_component_name || 0 == candidate_component_name[0])
|
|
return false;
|
|
|
|
if (length < 0)
|
|
{
|
|
for (length = 0; 0 != candidate_component_name[length]; length++)
|
|
{
|
|
if (length > 8)
|
|
break; // 8 elements is plenty for all possible wchar_t encodings.
|
|
}
|
|
}
|
|
|
|
ON_UnicodeErrorParameters e = ON_UnicodeErrorParameters::FailOnErrors;
|
|
e.m_error_code_point = 0;
|
|
ON__UINT32 unicode_code_point = 0;
|
|
ON_DecodeWideChar(candidate_component_name, length, &e, &unicode_code_point);
|
|
return ON_ModelComponent::IsValidComponentNameFirstCodePoint(unicode_code_point);
|
|
}
|
|
|
|
bool ON_ModelComponent::IsValidComponentName(
|
|
const wchar_t* candidate_component_name
|
|
)
|
|
{
|
|
const bool bPermitInternalSpaces = true;
|
|
|
|
|
|
if (nullptr == candidate_component_name || 0 == candidate_component_name[0])
|
|
return false;
|
|
|
|
// the first character in a component name cannot be a bracket, space or below
|
|
const ON__UINT32 c2[2] = { (ON__UINT32)(candidate_component_name[0]), (ON__UINT32)(candidate_component_name[1]) };
|
|
const ON__UINT32 first_code_point
|
|
= ON_IsValidUTF32Value(c2[0])
|
|
? c2[0]
|
|
: (ON_IsValidUTF16SurrogatePair(c2[0], c2[1]) ? ON_DecodeUTF16SurrogatePair(c2[0], c2[1],0): 0)
|
|
;
|
|
bool rc = IsValidComponentNameFirstCodePoint(first_code_point);
|
|
|
|
bool bLastCharWasSpace = false;
|
|
for ( const wchar_t* name = candidate_component_name; 0 != *name && rc; name++ )
|
|
{
|
|
const ON__UINT32 c = (ON__UINT32)(name[0]);
|
|
if (0 == Internal_IsValidComponentNameCodePoint(c))
|
|
{
|
|
if (ON_IsValidUTF16SurrogatePair(c, (ON__UINT32)(name[1])))
|
|
{
|
|
// all code points that come from surrogate pairs are permitted
|
|
bLastCharWasSpace = false;
|
|
name++;
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
if (ON_IsUnicodeSpaceCodePoint(c))
|
|
{
|
|
rc = bPermitInternalSpaces;
|
|
bLastCharWasSpace = true;
|
|
}
|
|
else
|
|
bLastCharWasSpace = false;
|
|
}
|
|
|
|
return (rc && !bLastCharWasSpace) ? true : false;
|
|
}
|
|
|
|
bool ON_ModelComponent::IndexRequired(ON_ModelComponent::Type component_type)
|
|
{
|
|
switch (component_type)
|
|
{
|
|
case ON_ModelComponent::Type::Image:
|
|
case ON_ModelComponent::Type::TextureMapping:
|
|
case ON_ModelComponent::Type::RenderContent: // }
|
|
case ON_ModelComponent::Type::EmbeddedFile: // } JohnC: I have no idea how to decide what to return.
|
|
case ON_ModelComponent::Type::ObsoleteValue: // }
|
|
case ON_ModelComponent::Type::Material: // ON_Layer references render material by index
|
|
case ON_ModelComponent::Type::LinePattern: // ON_Layer references line pattern by index
|
|
case ON_ModelComponent::Type::Layer:
|
|
case ON_ModelComponent::Type::Group:
|
|
case ON_ModelComponent::Type::TextStyle:
|
|
case ON_ModelComponent::Type::DimStyle:
|
|
case ON_ModelComponent::Type::RenderLight:
|
|
case ON_ModelComponent::Type::HatchPattern:
|
|
case ON_ModelComponent::Type::InstanceDefinition:
|
|
case ON_ModelComponent::Type::SectionStyle:
|
|
return true;
|
|
|
|
case ON_ModelComponent::Type::ModelGeometry:
|
|
case ON_ModelComponent::Type::HistoryRecord:
|
|
return false;
|
|
|
|
default:
|
|
ON_ERROR("Invalid component_type parameter.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ON_ModelComponent::UniqueNameIncludesParent(ON_ModelComponent::Type component_type)
|
|
{
|
|
// [Giulio] If this table is changed, then also RhinoCommon documentation in
|
|
// Rhino.DocObjects.ModelComponent.FindName() / FindNameHash() will require appropriate tweaks.
|
|
|
|
switch (component_type)
|
|
{
|
|
case ON_ModelComponent::Type::Layer:
|
|
return true;
|
|
|
|
case ON_ModelComponent::Type::Image:
|
|
case ON_ModelComponent::Type::TextureMapping:
|
|
case ON_ModelComponent::Type::Material:
|
|
case ON_ModelComponent::Type::RenderContent: // JohnC: TODO: Giulio's tweak above. Left for the wrapping phase.
|
|
case ON_ModelComponent::Type::EmbeddedFile: // JohnC: TODO: Giulio's tweak above. Left for the wrapping phase.
|
|
case ON_ModelComponent::Type::LinePattern:
|
|
case ON_ModelComponent::Type::Group:
|
|
case ON_ModelComponent::Type::TextStyle:
|
|
case ON_ModelComponent::Type::DimStyle:
|
|
case ON_ModelComponent::Type::RenderLight:
|
|
case ON_ModelComponent::Type::HatchPattern:
|
|
case ON_ModelComponent::Type::InstanceDefinition:
|
|
case ON_ModelComponent::Type::ModelGeometry:
|
|
case ON_ModelComponent::Type::HistoryRecord:
|
|
case ON_ModelComponent::Type::SectionStyle:
|
|
return false;
|
|
|
|
default:
|
|
ON_ERROR("Invalid component_type parameter.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ON_ModelComponent::UniqueNameRequired(ON_ModelComponent::Type component_type)
|
|
{
|
|
// [Giulio] If this table is changed, then also
|
|
// Rhino.DocObjects.ModelComponent.ModelComponentTypeRequiresUniqueName()
|
|
// will need the same tweak.
|
|
|
|
switch (component_type)
|
|
{
|
|
case ON_ModelComponent::Type::LinePattern:
|
|
case ON_ModelComponent::Type::Layer:
|
|
case ON_ModelComponent::Type::Group:
|
|
case ON_ModelComponent::Type::TextStyle:
|
|
case ON_ModelComponent::Type::DimStyle:
|
|
case ON_ModelComponent::Type::HatchPattern:
|
|
case ON_ModelComponent::Type::InstanceDefinition:
|
|
case ON_ModelComponent::Type::EmbeddedFile:
|
|
case ON_ModelComponent::Type::SectionStyle:
|
|
return true;
|
|
|
|
case ON_ModelComponent::Type::Image:
|
|
case ON_ModelComponent::Type::TextureMapping:
|
|
case ON_ModelComponent::Type::Material:
|
|
case ON_ModelComponent::Type::RenderContent: // JohnC: TODO: Giulio's tweak above. Left for the wrapping phase.
|
|
case ON_ModelComponent::Type::RenderLight:
|
|
case ON_ModelComponent::Type::ModelGeometry:
|
|
case ON_ModelComponent::Type::HistoryRecord:
|
|
return false;
|
|
|
|
default:
|
|
ON_ERROR("Invalid component_type parameter.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ON_ModelComponent::UniqueNameIgnoresCase(ON_ModelComponent::Type component_type)
|
|
{
|
|
// This function must return true for components like ON_Material that do not require a unique name.
|
|
return (
|
|
// NO // ON_ModelComponent::UniqueNameRequired(component_type) &&
|
|
ON_ModelComponent::Type::Group != component_type
|
|
);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Id interface
|
|
//
|
|
bool ON_ModelComponent::SetIdentification(
|
|
const class ON_ComponentManifestItem& manifest_item,
|
|
const wchar_t* manifest_name,
|
|
bool bSetId,
|
|
bool bSetParentId,
|
|
bool bSetName,
|
|
bool bSetIndex
|
|
)
|
|
{
|
|
bool rc = true;
|
|
|
|
if (bSetId && false == (manifest_item.Id() == Id()))
|
|
{
|
|
if (false == SetId(manifest_item.Id()))
|
|
{
|
|
ON_ERROR("id cannot be set");
|
|
rc = false;
|
|
}
|
|
}
|
|
|
|
const ON_UUID parent_id
|
|
= bSetParentId
|
|
? manifest_item.NameHash().ParentId()
|
|
: ON_nil_uuid;
|
|
|
|
if (bSetParentId && false == (parent_id == ParentId()))
|
|
{
|
|
if (false == SetParentId(parent_id))
|
|
{
|
|
ON_ERROR("parent id cannot be set");
|
|
rc = false;
|
|
}
|
|
}
|
|
|
|
if (bSetName && NameHash() != manifest_item.NameHash())
|
|
{
|
|
if ( manifest_item.NameHash() != ON_NameHash::Create(manifest_item.NameHash().ParentId(),manifest_name) )
|
|
{
|
|
ON_ERROR("manifest_name parameter is not valid.");
|
|
rc = false;
|
|
}
|
|
else if (false == SetName(manifest_name) )
|
|
{
|
|
ON_ERROR("name cannot be set");
|
|
rc = false;
|
|
}
|
|
}
|
|
|
|
if (bSetIndex && Index() != manifest_item.Index() )
|
|
{
|
|
if (false == SetIndex(manifest_item.Index()))
|
|
{
|
|
ON_ERROR("index cannot be set");
|
|
rc = false;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Id interface
|
|
//
|
|
|
|
const ON_UUID& ON_ModelComponent::Id() const
|
|
{
|
|
return m_component_id;
|
|
}
|
|
|
|
bool ON_ModelComponent::IdIsNil() const
|
|
{
|
|
return (ON_nil_uuid == m_component_id);
|
|
}
|
|
|
|
bool ON_ModelComponent::IdIsNotNil() const
|
|
{
|
|
return !(ON_nil_uuid == m_component_id);
|
|
}
|
|
|
|
bool ON_ModelComponent::SetId(
|
|
const ON_UUID& component_id
|
|
)
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IdAttribute;
|
|
if (0 != (bit & m_locked_status))
|
|
return false;
|
|
|
|
const bool bContentChange = (false == (m_component_id == component_id));
|
|
m_component_id = component_id;
|
|
m_set_status |= bit;
|
|
if ( bContentChange )
|
|
IncrementContentVersionNumber();
|
|
|
|
return true;
|
|
}
|
|
|
|
const ON_UUID& ON_ModelComponent::IfIdIsNilSetId()
|
|
{
|
|
return
|
|
( ON_nil_uuid == m_component_id)
|
|
? SetId()
|
|
: m_component_id;
|
|
}
|
|
|
|
const ON_UUID& ON_ModelComponent::SetId()
|
|
{
|
|
if (false == IdIsLocked())
|
|
{
|
|
SetId(ON_CreateId());
|
|
return m_component_id;
|
|
}
|
|
return ON_nil_uuid;
|
|
}
|
|
|
|
const ON_UUID& ON_ModelComponent::SetAndLockId()
|
|
{
|
|
const ON_UUID& new_id = SetId();
|
|
if (!(ON_nil_uuid == new_id))
|
|
LockId();
|
|
return new_id;
|
|
}
|
|
|
|
bool ON_ModelComponent::ClearId()
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IdAttribute;
|
|
return (bit == ClearModelComponentAttributes(bit));
|
|
}
|
|
|
|
void ON_ModelComponent::LockId()
|
|
{
|
|
m_locked_status |= ON_ModelComponent::Attributes::IdAttribute;
|
|
}
|
|
|
|
bool ON_ModelComponent::IdIsLocked() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IdAttribute;
|
|
return (0 != (bit & m_locked_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::IdIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IdAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Component Status interface
|
|
//
|
|
//
|
|
|
|
ON_ComponentStatus ON_ModelComponent::ModelComponentStatus() const
|
|
{
|
|
return m_component_status;
|
|
}
|
|
|
|
bool ON_ModelComponent::SetModelComponentStatus(
|
|
ON_ComponentStatus component_status
|
|
)
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ComponentStatusAttribute;
|
|
if (0 != (bit & m_locked_status))
|
|
return false;
|
|
|
|
const bool bContentChange = (m_component_status != component_status);
|
|
|
|
m_component_status = component_status;
|
|
m_set_status |= bit;
|
|
|
|
if ( bContentChange )
|
|
IncrementContentVersionNumber();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_ModelComponent::ClearModelComponentStatus()
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ComponentStatusAttribute;
|
|
return (bit == ClearModelComponentAttributes(bit));
|
|
}
|
|
|
|
void ON_ModelComponent::LockModelComponentStatus()
|
|
{
|
|
m_locked_status |= ON_ModelComponent::Attributes::ComponentStatusAttribute;
|
|
}
|
|
|
|
bool ON_ModelComponent::ModelComponentStatusIsLocked() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ComponentStatusAttribute;
|
|
return (0 != (bit & m_locked_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::ModelComponentStatusIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ComponentStatusAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::IsDeleted() const
|
|
{
|
|
return m_component_status.IsDeleted();
|
|
}
|
|
|
|
bool ON_ModelComponent::SetDeletedModelComponentState(
|
|
bool bDeleted,
|
|
ON_ComponentManifest* manifest
|
|
)
|
|
{
|
|
bDeleted = bDeleted ? true : false; // inusre exact "true"
|
|
ON_ComponentStatus component_status = ModelComponentStatus();
|
|
if (bDeleted == component_status.IsDeleted())
|
|
{
|
|
// nothing to change
|
|
ON_ERROR("model_component deleted status = bDeleted");
|
|
}
|
|
else
|
|
{
|
|
component_status.SetDeletedState(bDeleted);
|
|
if (false == SetModelComponentStatus(component_status))
|
|
{
|
|
ON_ERROR("cannot change component deleted state.");
|
|
}
|
|
}
|
|
|
|
const ON_ComponentManifestItem& manifest_item
|
|
= (nullptr != manifest)
|
|
? ((bDeleted || ON_nil_uuid == m_component_id) ? manifest->ItemFromComponentRuntimeSerialNumber(m_runtime_serial_number) : manifest->ItemFromId(m_component_id))
|
|
: ON_ComponentManifestItem::UnsetItem;
|
|
|
|
const bool bComponentInManifest
|
|
= nullptr != manifest
|
|
&& manifest_item.Id() == m_component_id
|
|
&& (false == bDeleted || manifest_item.ComponentRuntimeSerialNumber() == this->m_runtime_serial_number);
|
|
|
|
if (nullptr != manifest && false == bComponentInManifest )
|
|
{
|
|
ON_ERROR("component is not in manifest.");
|
|
}
|
|
|
|
if (bDeleted)
|
|
{
|
|
// delete component name
|
|
if (DeletedNameIsSet())
|
|
{
|
|
ON_ERROR("component name is already deleted");
|
|
}
|
|
else if (NameIsSet())
|
|
{
|
|
if (false == DeleteName())
|
|
{
|
|
ON_ERROR("component name cannot be deleted.");
|
|
}
|
|
}
|
|
|
|
if (bComponentInManifest)
|
|
{
|
|
// delete manifest item
|
|
if (manifest_item.IsDeleted())
|
|
{
|
|
ON_ERROR("manifest item deleted status is already true.");
|
|
}
|
|
else
|
|
{
|
|
const ON_ComponentManifestItem& deleted_manifest_item = manifest->DeleteComponent(m_runtime_serial_number);
|
|
if (false == deleted_manifest_item.IsDeleted())
|
|
{
|
|
ON_ERROR("unable to change manifest item deleted status to true.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// undelete component name
|
|
ON_wString candidate_name;
|
|
if (NameIsSet())
|
|
{
|
|
ON_ERROR("model_component name is already set");
|
|
candidate_name = Name();
|
|
}
|
|
else if (DeletedNameIsSet())
|
|
{
|
|
candidate_name = DeletedName();
|
|
if (false == UndeleteName())
|
|
{
|
|
ON_ERROR("cannot model_component deleted name cannot be restored.");
|
|
}
|
|
}
|
|
|
|
if (bComponentInManifest)
|
|
{
|
|
// undelete manifest item
|
|
if (false == manifest_item.IsDeleted())
|
|
{
|
|
ON_ERROR("doc_manifest item deleted status is already false.");
|
|
}
|
|
else
|
|
{
|
|
// When an component is being replaced, it is common for the old an new component
|
|
// to have the same id but different RuntimeSerialNumber() values.
|
|
ON_wString assigned_name;
|
|
const ON_ComponentManifestItem& undeleted_manifest_item = manifest->UndeleteComponentAndChangeRuntimeSerialNumber(
|
|
Id(),
|
|
ParentId(),
|
|
RuntimeSerialNumber(),
|
|
candidate_name,
|
|
assigned_name
|
|
);
|
|
if (false != undeleted_manifest_item.IsDeleted())
|
|
{
|
|
ON_ERROR("unable to change manifest item deleted status to false.");
|
|
}
|
|
SetName(assigned_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (bDeleted == IsDeleted());
|
|
}
|
|
|
|
bool ON_ModelComponent::IsLocked() const
|
|
{
|
|
return m_component_status.IsLocked();
|
|
}
|
|
|
|
void ON_ModelComponent::SetLockedModelComponentState(
|
|
bool bLockedState
|
|
)
|
|
{
|
|
ON_ComponentStatus component_status = ModelComponentStatus();
|
|
if (bLockedState != component_status.IsLocked())
|
|
{
|
|
component_status.SetLockedState(bLockedState);
|
|
if (false == SetModelComponentStatus(component_status))
|
|
{
|
|
ON_ERROR("cannot change component locked state.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool ON_ModelComponent::IsHidden() const
|
|
{
|
|
return m_component_status.IsHidden();
|
|
}
|
|
|
|
void ON_ModelComponent::SetHiddenModelComponentState(
|
|
bool bHiddenState
|
|
)
|
|
{
|
|
ON_ComponentStatus component_status = ModelComponentStatus();
|
|
if (bHiddenState != component_status.IsHidden())
|
|
{
|
|
component_status.SetHiddenState(bHiddenState);
|
|
if (false == SetModelComponentStatus(component_status))
|
|
{
|
|
ON_ERROR("cannot change component hidden state.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Index interface
|
|
//
|
|
// The component index is intended to be unique among components with identical
|
|
// types in the context of a model.
|
|
//
|
|
|
|
int ON_ModelComponent::Index() const
|
|
{
|
|
return m_component_index;
|
|
}
|
|
|
|
int ON_ModelComponent::Index(
|
|
int unset_index_value
|
|
) const
|
|
{
|
|
return IndexIsSet() ? m_component_index : unset_index_value;
|
|
}
|
|
|
|
bool ON_ModelComponent::SetIndex(
|
|
int component_index
|
|
)
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IndexAttribute;
|
|
if (0 != (bit & m_locked_status))
|
|
return false;
|
|
|
|
const bool bContentChange = (m_component_index != component_index);
|
|
|
|
m_component_index = component_index;
|
|
m_set_status |= bit;
|
|
|
|
if ( bContentChange )
|
|
IncrementContentVersionNumber();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_ModelComponent::ClearIndex()
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IndexAttribute;
|
|
return (bit == ClearModelComponentAttributes(bit));
|
|
}
|
|
|
|
void ON_ModelComponent::LockIndex()
|
|
{
|
|
m_locked_status |= ON_ModelComponent::Attributes::IndexAttribute;
|
|
}
|
|
|
|
bool ON_ModelComponent::IndexIsLocked() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IndexAttribute;
|
|
return (0 != (bit & m_locked_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::IndexIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::IndexAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ParentId interface
|
|
//
|
|
// The component parent_id is intended to be unique among components with identical
|
|
// types in the context of a model.
|
|
//
|
|
|
|
const ON_UUID& ON_ModelComponent::ParentId() const
|
|
{
|
|
return m_component_parent_id;
|
|
}
|
|
|
|
bool ON_ModelComponent::ParentIdIsNil() const
|
|
{
|
|
return (ON_nil_uuid == m_component_parent_id);
|
|
}
|
|
|
|
bool ON_ModelComponent::ParentIdIsNotNil() const
|
|
{
|
|
return (!(ON_nil_uuid == m_component_parent_id));
|
|
}
|
|
|
|
|
|
bool ON_ModelComponent::SetParentId(
|
|
const ON_UUID& component_parent_id
|
|
)
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ParentIdAttribute;
|
|
if (0 != (bit & m_locked_status))
|
|
return false;
|
|
|
|
const bool bContentChange = (m_component_parent_id != component_parent_id);
|
|
|
|
m_component_parent_id = component_parent_id;
|
|
m_set_status |= bit;
|
|
|
|
if (bContentChange)
|
|
{
|
|
if (ON_ModelComponent::UniqueNameIncludesParent(m_component_type))
|
|
{
|
|
// The name hash includes the parent id for this type of component (like layers).
|
|
// Lazy evaluation is used to set m_component_name_hash.
|
|
m_component_name_hash = ON_NameHash::EmptyNameHash;
|
|
}
|
|
IncrementContentVersionNumber();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_ModelComponent::ClearParentId()
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ParentIdAttribute;
|
|
return (bit == ClearModelComponentAttributes(bit));
|
|
}
|
|
|
|
void ON_ModelComponent::LockParentId()
|
|
{
|
|
m_locked_status |= ON_ModelComponent::Attributes::ParentIdAttribute;
|
|
}
|
|
|
|
bool ON_ModelComponent::ParentIdIsLocked() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ParentIdAttribute;
|
|
return (0 != (bit & m_locked_status));
|
|
}
|
|
|
|
bool ON_ModelComponent::ParentIdIsSet() const
|
|
{
|
|
const unsigned int bit = ON_ModelComponent::Attributes::ParentIdAttribute;
|
|
return (0 != (bit & m_set_status));
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// General attributes interface
|
|
//
|
|
//
|
|
|
|
unsigned int ON_ModelComponent::ClearModelComponentAttributes(
|
|
unsigned int attributes_filter
|
|
)
|
|
{
|
|
const unsigned int locked_status = (unsigned int)m_locked_status;
|
|
unsigned int rc = 0;
|
|
unsigned int bit;
|
|
|
|
// Cannot modify locked attributes.
|
|
attributes_filter &= ~locked_status;
|
|
|
|
const unsigned int set_status0 = m_set_status;
|
|
|
|
bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
m_model_serial_number = ON_ModelComponent::Unset.m_model_serial_number;
|
|
m_reference_model_serial_number = ON_ModelComponent::Unset.m_reference_model_serial_number;
|
|
m_linked_idef_serial_number = ON_ModelComponent::Unset.m_linked_idef_serial_number;
|
|
m_set_status &= ~bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IdAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
m_component_id = ON_ModelComponent::Unset.m_component_id;
|
|
m_set_status ^= bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::ParentIdAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
m_component_parent_id = ON_ModelComponent::Unset.m_component_id;
|
|
m_set_status &= ~bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::TypeAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
m_component_type = ON_ModelComponent::Unset.m_component_type;
|
|
m_set_status &= ~bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::ComponentStatusAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
m_component_status = ON_ModelComponent::Unset.m_component_status;
|
|
m_set_status &= ~bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IndexAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
m_component_index = ON_ModelComponent::Unset.m_component_index;
|
|
m_set_status &= ~bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::NameAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
if (0 == (m_set_status & ON_ModelComponent::Attributes::DeletedNameAttribute))
|
|
{
|
|
m_component_name = ON_wString::EmptyString;
|
|
m_component_name_hash = ON_NameHash::EmptyNameHash;
|
|
}
|
|
m_set_status &= ~bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::DeletedNameAttribute & attributes_filter;
|
|
if ( 0 != bit )
|
|
{
|
|
if (0 == (m_set_status & ON_ModelComponent::Attributes::NameAttribute))
|
|
{
|
|
m_component_name = ON_wString::EmptyString;
|
|
m_component_name_hash = ON_NameHash::EmptyNameHash;
|
|
}
|
|
m_set_status &= ~bit;
|
|
rc |= bit;
|
|
}
|
|
|
|
if ( set_status0 != m_set_status )
|
|
IncrementContentVersionNumber();
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_BinaryArchive::ReadModelComponentAttributes(
|
|
ON_ModelComponent& model_component,
|
|
unsigned int* attributes_filter
|
|
)
|
|
{
|
|
unsigned int read_bits = 0;
|
|
if ( nullptr != attributes_filter )
|
|
*attributes_filter = read_bits;
|
|
|
|
if (m_SetModelComponentSerialNumbers)
|
|
{
|
|
model_component.SetModelSerialNumber(
|
|
this->m_model_serial_number,
|
|
this->m_reference_model_serial_number,
|
|
this->m_instance_definition_model_serial_number
|
|
);
|
|
}
|
|
|
|
int major_version = 0;
|
|
int minor_version = 0;
|
|
if (false == BeginRead3dmChunk(TCODE_MODEL_ATTRIBUTES_CHUNK,&major_version,&minor_version))
|
|
return false;
|
|
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
if ( 1 != major_version )
|
|
break;
|
|
|
|
unsigned int bit;
|
|
unsigned char read_status;
|
|
|
|
bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute;
|
|
read_status = 0;
|
|
if (!ReadChar(&read_status))
|
|
break;
|
|
if (2 == read_status)
|
|
model_component.ClearModelSerialNumber();
|
|
else if (1 == read_status)
|
|
{
|
|
unsigned int model_serial_number = 0;
|
|
unsigned int reference_model_serial_number = 0;
|
|
unsigned int instance_definition_model_serial_number = 0;
|
|
if ( !ReadInt(&model_serial_number) )
|
|
break;
|
|
if ( !ReadInt(&reference_model_serial_number) )
|
|
break;
|
|
if ( !ReadInt(&instance_definition_model_serial_number) )
|
|
break;
|
|
model_component.SetModelSerialNumber(
|
|
model_serial_number,
|
|
reference_model_serial_number,
|
|
instance_definition_model_serial_number
|
|
);
|
|
read_bits |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IdAttribute;
|
|
read_status = 0;
|
|
if (!ReadChar(&read_status))
|
|
break;
|
|
if (2 == read_status)
|
|
{
|
|
model_component.ClearId();
|
|
}
|
|
else if (1 == read_status)
|
|
{
|
|
ON_UUID component_id = ON_nil_uuid;
|
|
if ( !ReadUuid(component_id) )
|
|
break;
|
|
model_component.SetId(component_id);
|
|
read_bits |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::TypeAttribute;
|
|
read_status = 0;
|
|
if (!ReadChar(&read_status))
|
|
break;
|
|
if (2 == read_status)
|
|
model_component.ClearComponentType();
|
|
else if (1 == read_status)
|
|
{
|
|
unsigned int component_type_as_unsigned = 0;
|
|
if ( !ReadInt(&component_type_as_unsigned) )
|
|
break;
|
|
model_component.SetComponentType(ON_ModelComponent::ComponentTypeFromUnsigned(component_type_as_unsigned));
|
|
read_bits |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IndexAttribute;
|
|
read_status = 0;
|
|
if (!ReadChar(&read_status))
|
|
break;
|
|
if (2 == read_status)
|
|
model_component.ClearIndex();
|
|
else if (1 == read_status)
|
|
{
|
|
int component_index = 0;
|
|
if ( !ReadInt(&component_index) )
|
|
break;
|
|
model_component.SetIndex(component_index);
|
|
read_bits |= bit;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::NameAttribute;
|
|
read_status = 0;
|
|
if (!ReadChar(&read_status))
|
|
break;
|
|
if (2 == read_status)
|
|
model_component.ClearName();
|
|
else if (1 == read_status)
|
|
{
|
|
ON_wString component_name;
|
|
if ( !ReadString(component_name) )
|
|
break;
|
|
model_component.SetName(static_cast<const wchar_t*>(component_name));
|
|
read_bits |= bit;
|
|
}
|
|
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if ( nullptr != attributes_filter)
|
|
*attributes_filter = read_bits;
|
|
|
|
if (false == EndRead3dmChunk())
|
|
rc = false;
|
|
|
|
return rc;
|
|
}
|
|
|
|
class ON_ModelComponentOverrideStackElement
|
|
{
|
|
public:
|
|
ON_ModelComponentOverrideStackElement(
|
|
const ON_ModelComponent& original_model_component,
|
|
const ON_ModelComponent& model_component_override
|
|
)
|
|
: m_original_model_component(original_model_component)
|
|
, m_model_component_override(model_component_override)
|
|
{}
|
|
~ON_ModelComponentOverrideStackElement() = default;
|
|
|
|
const ON_ModelComponent& m_original_model_component;
|
|
const ON_ModelComponent& m_model_component_override;
|
|
ON_ModelComponentOverrideStackElement* m_next = nullptr;
|
|
|
|
private:
|
|
ON_ModelComponentOverrideStackElement(const ON_ModelComponentOverrideStackElement&) = delete;
|
|
ON_ModelComponentOverrideStackElement& operator=(const ON_ModelComponentOverrideStackElement&) = delete;
|
|
};
|
|
|
|
bool ON_BinaryArchive::WriteModelComponentAttributes(
|
|
const class ON_ModelComponent& model_component,
|
|
unsigned int attributes_filter
|
|
)
|
|
{
|
|
if (false == BeginWrite3dmChunk(TCODE_MODEL_ATTRIBUTES_CHUNK,1,0))
|
|
return false;
|
|
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
unsigned int bit = ON_ModelComponent::Attributes::ModelSerialNumberAttribute & attributes_filter;
|
|
unsigned char write_status = (0 != bit) ? 1 : 0;
|
|
if ( 0 != write_status && false == model_component.ModelSerialNumberIsSet() )
|
|
write_status = 2;
|
|
if (!WriteChar(write_status))
|
|
break;
|
|
if (1 == write_status )
|
|
{
|
|
const unsigned int model_serial_number = model_component.ModelSerialNumber();
|
|
const unsigned int reference_model_serial_number = model_component.ReferenceModelSerialNumber();
|
|
const unsigned int instance_definition_model_serial_number = model_component.InstanceDefinitionModelSerialNumber();
|
|
if ( !WriteInt(model_serial_number) )
|
|
break;
|
|
if ( !WriteInt(reference_model_serial_number) )
|
|
break;
|
|
if ( !WriteInt(instance_definition_model_serial_number) )
|
|
break;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IdAttribute & attributes_filter;
|
|
write_status = (0 != bit) ? 1 : 0;
|
|
if ( 0 != write_status && false == model_component.IdIsSet() )
|
|
write_status = 2;
|
|
if (!WriteChar(write_status))
|
|
break;
|
|
if (1 == write_status )
|
|
{
|
|
ON_UUID component_id = model_component.Id();
|
|
if ( !WriteUuid(component_id) )
|
|
break;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::TypeAttribute & attributes_filter;
|
|
write_status = (0 != bit) ? 1 : 0;
|
|
if ( 0 != write_status && false == model_component.ComponentTypeIsSet() )
|
|
write_status = 2;
|
|
if (!WriteChar(write_status))
|
|
break;
|
|
if (1 == write_status )
|
|
{
|
|
unsigned int component_type_as_unsigned = static_cast<unsigned int>(model_component.ComponentType());
|
|
if ( !WriteInt(component_type_as_unsigned) )
|
|
break;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::IndexAttribute & attributes_filter;
|
|
write_status = (0 != bit) ? 1 : 0;
|
|
if ( 0 != write_status && false == model_component.IndexIsSet() )
|
|
write_status = 2;
|
|
if (!WriteChar(write_status))
|
|
break;
|
|
if (1 == write_status )
|
|
{
|
|
if ( !Write3dmReferencedComponentIndex( model_component ) )
|
|
break;
|
|
}
|
|
|
|
bit = ON_ModelComponent::Attributes::NameAttribute & attributes_filter;
|
|
write_status = (0 != bit) ? 1 : 0;
|
|
if ( 0 != write_status && false == model_component.NameIsSet() )
|
|
write_status = 2;
|
|
if (!WriteChar(write_status))
|
|
break;
|
|
if (1 == write_status )
|
|
{
|
|
if (false == this->WriteModelComponentName(model_component) )
|
|
break;
|
|
}
|
|
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if (false == EndWrite3dmChunk())
|
|
rc = false;
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_BinaryArchive::Write3dmReferencedComponentIndex(
|
|
const ON_ModelComponent& model_component
|
|
)
|
|
{
|
|
if (ReferencedComponentIndexMapping())
|
|
{
|
|
// During writing, the m_manifest member stores
|
|
// the model id and index as the "Component" values and
|
|
// the archive id and index as the "Manifest" values.
|
|
const ON_UUID component_id = model_component.Id();
|
|
return
|
|
(ON_nil_uuid == component_id)
|
|
? Write3dmReferencedComponentIndex(model_component.ComponentType(), model_component.Index())
|
|
: Write3dmReferencedComponentIndex(model_component.ComponentType(), component_id);
|
|
}
|
|
|
|
// no component mapping.
|
|
return WriteInt(model_component.Index());
|
|
}
|
|
|
|
bool ON_BinaryArchive::Read3dmReferencedComponentIndexArray(
|
|
ON_ModelComponent::Type component_type,
|
|
ON_SimpleArray<int>& component_index_array
|
|
)
|
|
{
|
|
if (!ReadArray(component_index_array))
|
|
return false;
|
|
if (false == ReferencedComponentIndexMapping())
|
|
return true; // true means continue reading
|
|
|
|
int count = 0;
|
|
for (int i = 0; i < component_index_array.Count(); i++)
|
|
{
|
|
int archive_index = component_index_array[i];
|
|
if (ON_ModelComponent::Type::TextStyle == component_type
|
|
&& archive_index >= 0
|
|
&& archive_index < m_text_style_to_dim_style_archive_index_map.Count()
|
|
)
|
|
{
|
|
const ON_2dex ts_to_ds = m_text_style_to_dim_style_archive_index_map[archive_index];
|
|
if (archive_index == ts_to_ds.i && ts_to_ds.j >= 0)
|
|
{
|
|
archive_index = ts_to_ds.j;
|
|
component_type = ON_ModelComponent::Type::DimStyle;
|
|
}
|
|
}
|
|
int component_index = archive_index;
|
|
component_index_array[i] = 0;
|
|
const ON_ManifestMapItem& map_item = ManifestMap().MapItemFromSourceIndex(component_type, archive_index);
|
|
if (false == map_item.SourceAndDestinationAreSet() || ON_UNSET_INT_INDEX == map_item.DestinationIndex())
|
|
{
|
|
ON_ERROR("Unable to update component reference index.");
|
|
continue;
|
|
}
|
|
component_index = map_item.DestinationIndex();
|
|
component_index_array[count++] = component_index;
|
|
}
|
|
component_index_array.SetCount(count);
|
|
|
|
return true; // true means continue reading
|
|
}
|
|
|
|
bool ON_BinaryArchive::Read3dmReferencedComponentIndex(
|
|
ON_ModelComponent::Type component_type,
|
|
int* component_index
|
|
)
|
|
{
|
|
if (nullptr != component_index)
|
|
*component_index = ON_UNSET_INT_INDEX;
|
|
|
|
int archive_component_index = ON_UNSET_INT_INDEX;
|
|
if (!ReadInt(&archive_component_index))
|
|
return false;
|
|
|
|
if (archive_component_index < 0 || false == ReferencedComponentIndexMapping() )
|
|
{
|
|
// system component with a persistent negative index
|
|
if (nullptr != component_index)
|
|
*component_index = archive_component_index;
|
|
return true;
|
|
}
|
|
|
|
int updated_component_index = archive_component_index;
|
|
|
|
if (ON_ModelComponent::Type::TextStyle == component_type)
|
|
{
|
|
component_type = ON_ModelComponent::Type::DimStyle;
|
|
const int archive_text_style_index = archive_component_index;
|
|
archive_component_index = ON_UNSET_INT_INDEX;
|
|
if (archive_text_style_index >= 0
|
|
&& archive_text_style_index < m_text_style_to_dim_style_archive_index_map.Count()
|
|
)
|
|
{
|
|
const ON_2dex ts_to_ds = m_text_style_to_dim_style_archive_index_map[archive_text_style_index];
|
|
if (archive_text_style_index == ts_to_ds.i && ts_to_ds.j >= 0)
|
|
{
|
|
archive_component_index = ts_to_ds.j;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ON_ModelComponent::Type::DimStyle == component_type)
|
|
{
|
|
if (this->Archive3dmVersion() <= 50)
|
|
{
|
|
if (nullptr != component_index)
|
|
*component_index = archive_component_index;
|
|
|
|
return true;
|
|
}
|
|
const int archive_dim_style_index = archive_component_index;
|
|
if (archive_dim_style_index >= 0
|
|
&& archive_dim_style_index < m_archive_dim_style_table.Count()
|
|
)
|
|
{
|
|
const ON_DimStyle* archive_dim_style = m_archive_dim_style_table[archive_dim_style_index];
|
|
if (nullptr != archive_dim_style)
|
|
{
|
|
if (archive_dim_style->ParentIdIsNotNil())
|
|
{
|
|
// override dimstyle - not in manifests or dimstyle table.
|
|
if (nullptr != component_index)
|
|
*component_index = archive_component_index;
|
|
|
|
return true;
|
|
}
|
|
|
|
const ON_ComponentManifestItem& item = m_manifest.ItemFromId(ON_ModelComponent::Type::DimStyle,archive_dim_style->Id());
|
|
if ( item.Id() == archive_dim_style->Id() )
|
|
{
|
|
archive_component_index = item.Index();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const ON_ManifestMapItem& map_item = m_manifest_map.MapItemFromSourceIndex(component_type,archive_component_index);
|
|
if (map_item.SourceAndDestinationAreSet() && ON_UNSET_INT_INDEX != map_item.DestinationIndex())
|
|
{
|
|
updated_component_index = map_item.DestinationIndex();
|
|
}
|
|
else
|
|
{
|
|
ON_ERROR("Unable to update component index.");
|
|
|
|
// Get something that might work when possible
|
|
switch (component_type)
|
|
{
|
|
case ON_ModelComponent::Type::Image:
|
|
break;
|
|
case ON_ModelComponent::Type::TextureMapping:
|
|
break;
|
|
case ON_ModelComponent::Type::Material:
|
|
updated_component_index = ON_Material::Default.Index();
|
|
break;
|
|
case ON_ModelComponent::Type::LinePattern:
|
|
updated_component_index = ON_Linetype::Continuous.Index();
|
|
break;
|
|
case ON_ModelComponent::Type::Layer:
|
|
break;
|
|
case ON_ModelComponent::Type::Group:
|
|
break;
|
|
|
|
case ON_ModelComponent::Type::TextStyle:
|
|
case ON_ModelComponent::Type::DimStyle:
|
|
if (nullptr != m_archive_current_dim_style)
|
|
{
|
|
const ON_ManifestMapItem& archive_current_dim_style_map_item = m_manifest_map.MapItemFromSourceIndex(ON_ModelComponent::Type::DimStyle,m_archive_current_dim_style->Index());
|
|
if (archive_current_dim_style_map_item.SourceAndDestinationAreSet()
|
|
&& ON_UNSET_INT_INDEX != archive_current_dim_style_map_item.DestinationIndex()
|
|
)
|
|
{
|
|
updated_component_index = archive_current_dim_style_map_item.DestinationIndex();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ON_ModelComponent::Type::RenderLight:
|
|
break;
|
|
case ON_ModelComponent::Type::HatchPattern:
|
|
break;
|
|
case ON_ModelComponent::Type::InstanceDefinition:
|
|
break;
|
|
case ON_ModelComponent::Type::ModelGeometry:
|
|
break;
|
|
case ON_ModelComponent::Type::HistoryRecord:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nullptr != component_index)
|
|
*component_index = updated_component_index;
|
|
|
|
return true; // true indicates the read worked, even if the component index cannot be updated.
|
|
}
|
|
|
|
bool ON_BinaryArchive::Write3dmReferencedComponentIndex(
|
|
ON_ModelComponent::Type component_type,
|
|
int model_index
|
|
)
|
|
{
|
|
// When writing 3dm archives, the model index needs to be converted
|
|
// to an archive index. This function is used when the model component
|
|
// id is not known (for example, when writing ON_Layer material and
|
|
// line pattern indexes.
|
|
int archive_index = model_index;
|
|
|
|
if (model_index >= 0)
|
|
{
|
|
if (ON_ModelComponent::Type::TextStyle == component_type)
|
|
{
|
|
// In version 6, August 2016, text style information was moved to ON_DimStyle.
|
|
//
|
|
// In order to write files that can be read by earlier versions of Rhino,
|
|
// a text style table that is parallel to the dimstyle table is saved in the 3d archive.
|
|
|
|
if (ON_3dmArchiveTableType::dimension_style_table == m_3dm_active_table)
|
|
{
|
|
// The text style index of a dimstyle is being written. This is needed
|
|
// so V5 and V6 Rhino WIPs built before August 2016 will be able to read
|
|
// the file.
|
|
const int text_style_count = m_manifest.ActiveComponentCount(ON_ModelComponent::Type::TextStyle);
|
|
const int dim_style_count = m_manifest.ActiveComponentCount(ON_ModelComponent::Type::DimStyle);
|
|
if (dim_style_count > 0 && dim_style_count <= text_style_count)
|
|
archive_index = dim_style_count - 1;
|
|
else if (text_style_count > 0)
|
|
archive_index = 0;
|
|
else
|
|
archive_index = -1;
|
|
return WriteInt(archive_index);
|
|
}
|
|
|
|
if (ON_3dmArchiveTableType::text_style_table != m_3dm_active_table)
|
|
{
|
|
// We are finished writing the text style and dim style tables.
|
|
// There is a parallel set of text styles and dimension styles.
|
|
// To get the right index in the archive for older versions of Rhino, change the component type to dimstyle.
|
|
component_type = ON_ModelComponent::Type::DimStyle;
|
|
}
|
|
}
|
|
|
|
if ( ReferencedComponentIndexMapping() )
|
|
{
|
|
const ON_ManifestMapItem& map_item = ManifestMap().MapItemFromSourceIndex(component_type, model_index);
|
|
if (
|
|
component_type == map_item.ComponentType()
|
|
&& ON_UNSET_INT_INDEX != map_item.DestinationIndex()
|
|
)
|
|
{
|
|
archive_index = map_item.DestinationIndex();
|
|
}
|
|
else
|
|
{
|
|
ON_ERROR("unable to convert model index to archive index.");
|
|
archive_index = model_index;
|
|
}
|
|
}
|
|
}
|
|
return WriteInt(archive_index);
|
|
}
|
|
|
|
bool ON_BinaryArchive::Write3dmReferencedComponentIndex(
|
|
ON_ModelComponent::Type component_type,
|
|
ON_UUID model_id
|
|
)
|
|
{
|
|
// When writing 3dm archives, the model index needs to be converted
|
|
// to an archive index. This function is used when the model component
|
|
// id is known.
|
|
int archive_index = ON_UNSET_INT_INDEX;
|
|
if (ON_nil_uuid == model_id)
|
|
{
|
|
ON_ERROR("model_id is nil.");
|
|
}
|
|
else
|
|
{
|
|
const ON_ManifestMapItem& map_item = ManifestMap().MapItemFromSourceId(model_id);
|
|
if (component_type != map_item.ComponentType()
|
|
|| false == map_item.SourceIsSet()
|
|
)
|
|
{
|
|
ON_ERROR("model_id not in arcive manifest map.");
|
|
}
|
|
else if (false == ReferencedComponentIndexMapping())
|
|
{
|
|
// component reference mapping is disabled (rare)
|
|
archive_index = map_item.SourceIndex();
|
|
}
|
|
else
|
|
{
|
|
// adjust component reference to use the index in the archive (common)
|
|
if (ON_UNSET_INT_INDEX != map_item.DestinationIndex())
|
|
{
|
|
archive_index = map_item.DestinationIndex();
|
|
}
|
|
else
|
|
{
|
|
ON_ERROR("Unable to get archive component reference index.");
|
|
}
|
|
}
|
|
}
|
|
return WriteInt(archive_index);
|
|
}
|
|
|
|
bool ON_BinaryArchive::ReferencedComponentIndexMapping() const
|
|
{
|
|
return m_bReferencedComponentIndexMapping;
|
|
}
|
|
|
|
void ON_BinaryArchive::SetReferencedComponentIndexMapping(
|
|
bool bEnableReferencedComponentIndexMapping
|
|
)
|
|
{
|
|
const bool b = bEnableReferencedComponentIndexMapping ? true : false;
|
|
if (b != m_bReferencedComponentIndexMapping)
|
|
m_bReferencedComponentIndexMapping = b;
|
|
}
|
|
|
|
bool ON_BinaryArchive::Write3dmReferencedComponentId(
|
|
ON_ModelComponent::Type component_type,
|
|
ON_UUID model_component_id
|
|
)
|
|
{
|
|
return WriteUuid(model_component_id);
|
|
}
|
|
|
|
bool ON_BinaryArchive::Write3dmReferencedComponentId(
|
|
const ON_ModelComponent& model_component
|
|
)
|
|
{
|
|
return WriteUuid(model_component.Id());
|
|
}
|
|
|
|
bool ON_BinaryArchive::Read3dmReferencedComponentId(
|
|
ON_ModelComponent::Type component_type,
|
|
ON_UUID* component_id
|
|
)
|
|
{
|
|
ON_UUID id = ON_nil_uuid;
|
|
const bool rc = ReadUuid(id);
|
|
|
|
ON_UUID default_id = ON_nil_uuid;
|
|
|
|
bool bConvertToModelId = true;
|
|
switch (component_type)
|
|
{
|
|
case ON_ModelComponent::Type::Unset:
|
|
bConvertToModelId = false;
|
|
break;
|
|
case ON_ModelComponent::Type::Image:
|
|
break;
|
|
case ON_ModelComponent::Type::TextureMapping:
|
|
break;
|
|
case ON_ModelComponent::Type::Material:
|
|
break;
|
|
case ON_ModelComponent::Type::RenderContent: // JohnC: I have no idea what to do here.
|
|
break;
|
|
case ON_ModelComponent::Type::EmbeddedFile: // JohnC: I have no idea what to do here.
|
|
break;
|
|
case ON_ModelComponent::Type::LinePattern:
|
|
break;
|
|
case ON_ModelComponent::Type::Layer:
|
|
break;
|
|
case ON_ModelComponent::Type::Group:
|
|
break;
|
|
case ON_ModelComponent::Type::TextStyle:
|
|
break;
|
|
case ON_ModelComponent::Type::DimStyle:
|
|
default_id = this->ArchiveCurrentDimStyleId();
|
|
break;
|
|
case ON_ModelComponent::Type::RenderLight:
|
|
break;
|
|
case ON_ModelComponent::Type::HatchPattern:
|
|
break;
|
|
case ON_ModelComponent::Type::InstanceDefinition:
|
|
break;
|
|
case ON_ModelComponent::Type::ModelGeometry:
|
|
break;
|
|
case ON_ModelComponent::Type::HistoryRecord:
|
|
break;
|
|
case ON_ModelComponent::Type::Mixed:
|
|
bConvertToModelId = false;
|
|
break;
|
|
default:
|
|
bConvertToModelId = false;
|
|
break;
|
|
}
|
|
|
|
if (false == rc || ON_nil_uuid == id )
|
|
{
|
|
id = default_id;
|
|
}
|
|
else if ( ON_nil_uuid != id && bConvertToModelId )
|
|
{
|
|
const ON_ComponentManifestItem& item = this->Manifest().ItemFromId(component_type, id);
|
|
if (component_type == item.ComponentType() && item.Id() == id )
|
|
{
|
|
// expected ...
|
|
const ON_ManifestMapItem& map_item = this->ManifestMap().MapItemFromSourceId(id);
|
|
if (component_type == map_item.ComponentType()
|
|
&& map_item.SourceId() == id
|
|
&& ON_nil_uuid != map_item.DestinationId()
|
|
)
|
|
{
|
|
// ... everything is as it should be. Assign id used in model.
|
|
id = map_item.DestinationId();
|
|
}
|
|
// else
|
|
// {
|
|
// Either the id was unchanged or the reading code failed
|
|
// to set as (source,destination) pair in the manifest map.
|
|
// It's not an error condition.
|
|
// }
|
|
}
|
|
else
|
|
{
|
|
// complicated situations
|
|
switch (component_type)
|
|
{
|
|
case ON_ModelComponent::Type::Unset:
|
|
break;
|
|
case ON_ModelComponent::Type::Image:
|
|
break;
|
|
case ON_ModelComponent::Type::TextureMapping:
|
|
break;
|
|
case ON_ModelComponent::Type::Material:
|
|
break;
|
|
case ON_ModelComponent::Type::LinePattern:
|
|
break;
|
|
case ON_ModelComponent::Type::Layer:
|
|
break;
|
|
case ON_ModelComponent::Type::Group:
|
|
break;
|
|
case ON_ModelComponent::Type::TextStyle:
|
|
break;
|
|
case ON_ModelComponent::Type::DimStyle:
|
|
if (ON_ModelComponent::Type::DimStyle != item.ComponentType()
|
|
&& ON_DimStyle::SystemDimstyleFromId(id).Id() != id
|
|
)
|
|
{
|
|
const unsigned int fixed_version = ON_VersionNumberConstruct(6, 0, 2017, 1, 15, 0);
|
|
const unsigned int archive_version = this->ArchiveOpenNURBSVersion();
|
|
if (archive_version >= fixed_version)
|
|
{
|
|
// Should not happen
|
|
ON_ERROR("dimstyle id not in archive.");
|
|
}
|
|
id = default_id;
|
|
}
|
|
break;
|
|
case ON_ModelComponent::Type::RenderLight:
|
|
break;
|
|
case ON_ModelComponent::Type::HatchPattern:
|
|
break;
|
|
case ON_ModelComponent::Type::InstanceDefinition:
|
|
break;
|
|
case ON_ModelComponent::Type::ModelGeometry:
|
|
break;
|
|
case ON_ModelComponent::Type::HistoryRecord:
|
|
break;
|
|
case ON_ModelComponent::Type::Mixed:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nullptr != component_id)
|
|
*component_id = id;
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_BinaryArchive::ReferencedComponentIdMapping() const
|
|
{
|
|
return m_bReferencedComponentIdMapping;
|
|
}
|
|
|
|
void ON_BinaryArchive::SetReferencedComponentIdMapping(
|
|
bool bEnableReferenceComponentIdMapping
|
|
)
|
|
{
|
|
m_bReferencedComponentIdMapping
|
|
= bEnableReferenceComponentIdMapping
|
|
? true
|
|
: false;
|
|
}
|
|
|
|
const ON_ComponentManifest& ON_BinaryArchive::Manifest() const
|
|
{
|
|
return m_manifest;
|
|
}
|
|
|
|
const ON_ManifestMap& ON_BinaryArchive::ManifestMap() const
|
|
{
|
|
return m_manifest_map;
|
|
}
|
|
|
|
bool ON_BinaryArchive::UpdateManifestMapItemDestination(
|
|
const class ON_ManifestMapItem& map_item
|
|
)
|
|
{
|
|
if (ON::archive_mode::read3dm != this->Mode())
|
|
{
|
|
ON_ERROR("archive mode != ON::archive_mode::read3dm");
|
|
return false;
|
|
}
|
|
if (map_item.SourceIsUnset())
|
|
{
|
|
ON_ERROR("map_item source information is not set.");
|
|
return false;
|
|
}
|
|
|
|
const bool bIgnoreSourceIndex = (ON_ModelComponent::Type::Group == map_item.ComponentType());
|
|
|
|
return m_manifest_map.UpdatetMapItemDestination(map_item, bIgnoreSourceIndex);
|
|
}
|
|
|
|
|
|
bool ON_BinaryArchive::Internal_Write3dmUpdateManifest(
|
|
const ON_ModelComponent& model_component
|
|
)
|
|
{
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
const ON_ComponentManifestItem& manifest_item = m_manifest.AddComponentToManifest(model_component, false, nullptr);
|
|
if (manifest_item.IsUnset())
|
|
break;
|
|
ON_ManifestMapItem map_item;
|
|
if (!map_item.SetSourceIdentification(&model_component))
|
|
break;
|
|
if (!map_item.SetDestinationIdentification(&manifest_item))
|
|
break;
|
|
|
|
rc = m_manifest_map.AddMapItem(map_item);
|
|
break;
|
|
}
|
|
if (!rc)
|
|
{
|
|
ON_ERROR("Unable to update archive manifest and map.");
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_BinaryArchive::Internal_Write3dmLightOrGeometryUpdateManifest(
|
|
ON_ModelComponent::Type component_type,
|
|
ON_UUID component_id,
|
|
int component_index,
|
|
const ON_wString& component_name
|
|
)
|
|
{
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
const ON__UINT64 no_serial_number_yet = 0;
|
|
const ON_NameHash component_name_hash = ON_NameHash::Create(ON_nil_uuid, component_name);
|
|
const ON_ComponentManifestItem& manifest_item = m_manifest.AddComponentToManifest(component_type, no_serial_number_yet, component_id, component_name_hash);
|
|
if (manifest_item.IsUnset())
|
|
break;
|
|
|
|
if (ON_ModelComponent::IndexRequired(component_type))
|
|
{
|
|
if (component_index < 0)
|
|
{
|
|
ON_ERROR("component_index should have value >= 0");
|
|
component_index = manifest_item.Index();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ON_UNSET_INT_INDEX != component_index)
|
|
{
|
|
ON_ERROR("component_index should have value ON_UNSET_INT_INDEX");
|
|
component_index = ON_UNSET_INT_INDEX;
|
|
}
|
|
}
|
|
|
|
ON_ManifestMapItem map_item;
|
|
if (!map_item.SetSourceIdentification(component_type, component_id, component_index))
|
|
break;
|
|
if (!map_item.SetDestinationIdentification(&manifest_item))
|
|
break;
|
|
|
|
rc = m_manifest_map.AddMapItem(map_item);
|
|
break;
|
|
}
|
|
if (!rc)
|
|
{
|
|
ON_ERROR("Unable to update archive manifest and map.");
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_BinaryArchive::Internal_Read3dmUpdateManifest(
|
|
ON_ModelComponent& model_component
|
|
)
|
|
{
|
|
const bool bResolveIdAndNameCollisions = true;
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
const ON_ComponentManifestItem& item_from_id
|
|
= model_component.IdIsNotNil()
|
|
? m_manifest.ItemFromId(model_component.Id())
|
|
: ON_ComponentManifestItem::UnsetItem;
|
|
|
|
const ON_ComponentManifestItem& item_from_name
|
|
= ( model_component.NameIsNotEmpty() && ON_ModelComponent::UniqueNameRequired(model_component.ComponentType()) )
|
|
? m_manifest.ItemFromName(&model_component)
|
|
: ON_ComponentManifestItem::UnsetItem;
|
|
|
|
if (item_from_id.IsValid())
|
|
{
|
|
// id conflict - this is bad
|
|
ON_WARNING("id conflict - 3dm file is not valid.");
|
|
if (item_from_id.ComponentType() == model_component.ComponentType())
|
|
{
|
|
// duplicate components - first one wins and no remapping the id
|
|
model_component.ClearId();
|
|
model_component.SetId(); // generates new id
|
|
}
|
|
}
|
|
|
|
if (item_from_name.IsValid() && false == item_from_name.IsSystemComponent() )
|
|
{
|
|
// name conflict but not id conflict - still bad
|
|
// first name wins - no remapping
|
|
if (false == item_from_id.IsValid())
|
|
{
|
|
// one warning is enough
|
|
ON_WARNING("name conflict - 3dm file is not valid.");
|
|
}
|
|
model_component.SetName(m_manifest.UnusedName(model_component));
|
|
}
|
|
|
|
const bool bIndexRequired = ON_ModelComponent::IndexRequired(model_component.ComponentType());
|
|
const int archive_index = model_component.Index();
|
|
|
|
ON_wString assigned_name;
|
|
const ON_ComponentManifestItem& manifest_item = m_manifest.AddComponentToManifest(model_component, bResolveIdAndNameCollisions, &assigned_name);
|
|
if (manifest_item.IsUnset())
|
|
break;
|
|
if (bResolveIdAndNameCollisions && manifest_item.IsValid())
|
|
{
|
|
if (manifest_item.Id() != model_component.Id())
|
|
{
|
|
ON_WARNING("new id assigned to model component.");
|
|
model_component.SetId(manifest_item.Id());
|
|
}
|
|
if (false == ON_wString::EqualOrdinal(model_component.Name(),assigned_name,false))
|
|
{
|
|
ON_WARNING("new name assigned to model component.");
|
|
model_component.SetName(assigned_name);
|
|
}
|
|
|
|
// In damaged files, the index values are a mess.
|
|
// Fix them here.
|
|
const int manifest_index = manifest_item.Index();
|
|
const int assigned_index
|
|
= bIndexRequired
|
|
? (manifest_index >= 0 ? manifest_index : archive_index)
|
|
: ON_UNSET_INT_INDEX;
|
|
|
|
if (assigned_index != archive_index)
|
|
{
|
|
if (bIndexRequired) // This is a good location for a debugger breakpoint when debugging file reading index issues.
|
|
model_component.SetIndex(manifest_item.Index());
|
|
else
|
|
model_component.ClearIndex();
|
|
}
|
|
}
|
|
|
|
ON_ComponentManifestItem source_item(manifest_item);
|
|
if (ON_ModelComponent::Type::Group == model_component.ComponentType()
|
|
&& archive_index >= 0
|
|
&& manifest_item.Index() >= 0
|
|
&& archive_index != manifest_item.Index()
|
|
)
|
|
{
|
|
// group index values are not always the zero based index of the
|
|
// group element's location in the archive.
|
|
source_item.SetIndex(archive_index);
|
|
}
|
|
|
|
ON_ManifestMapItem map_item;
|
|
// Rhino will update destination identification if it changes when added to the model.
|
|
if (!map_item.SetSourceIdentification(&source_item))
|
|
break;
|
|
if (!map_item.SetDestinationIdentification(&model_component))
|
|
break;
|
|
rc = m_manifest_map.AddMapItem(map_item);
|
|
break;
|
|
}
|
|
if (!rc)
|
|
{
|
|
ON_ERROR("Unable to update archive manifest and map.");
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_BinaryArchive::Internal_Read3dmLightOrGeometryUpdateManifest(
|
|
ON_ModelComponent::Type component_type,
|
|
ON_UUID component_id,
|
|
int component_index,
|
|
const ON_wString& component_name
|
|
)
|
|
{
|
|
bool rc = false;
|
|
for (;;)
|
|
{
|
|
const ON__UINT64 no_serial_number_yet = 0;
|
|
const ON_NameHash component_name_hash = ON_NameHash::Create(ON_nil_uuid, component_name);
|
|
const ON_ComponentManifestItem& manifest_item = m_manifest.AddComponentToManifest(component_type, no_serial_number_yet, component_id, component_name_hash);
|
|
if (manifest_item.IsUnset())
|
|
break;
|
|
|
|
if (ON_ModelComponent::IndexRequired(component_type))
|
|
{
|
|
if (component_index < 0)
|
|
{
|
|
ON_ERROR("component_index should have value >= 0");
|
|
component_index = manifest_item.Index();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ON_UNSET_INT_INDEX != component_index)
|
|
{
|
|
ON_ERROR("component_index should have value ON_UNSET_INT_INDEX");
|
|
component_index = ON_UNSET_INT_INDEX;
|
|
}
|
|
}
|
|
|
|
ON_ManifestMapItem map_item;
|
|
// Rhino will update destination if it changes id or index
|
|
if (!map_item.SetDestinationIdentification(component_type, component_id, component_index))
|
|
break;
|
|
if (!map_item.SetSourceIdentification(&manifest_item))
|
|
break;
|
|
|
|
rc = m_manifest_map.AddMapItem(map_item);
|
|
break;
|
|
}
|
|
if (!rc)
|
|
{
|
|
ON_ERROR("Unable to update archive manifest and map.");
|
|
}
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
bool ON_BinaryArchive::AddManifestMapItem(
|
|
const class ON_ManifestMapItem& map_item
|
|
)
|
|
{
|
|
if (false == map_item.SourceAndDestinationAreSet() )
|
|
{
|
|
ON_ERROR("map_item source and destination are not set.");
|
|
return false;
|
|
}
|
|
const bool bIndexRequired = ON_ModelComponent::IndexRequired(map_item.ComponentType());
|
|
if (bIndexRequired && map_item.SourceIndex() < 0)
|
|
{
|
|
ON_ERROR("map_item.m_source_component_index is not set.");
|
|
return false;
|
|
}
|
|
switch (Mode())
|
|
{
|
|
case ON::archive_mode::read3dm:
|
|
{
|
|
const ON_ComponentManifestItem& archive_item_from_id = m_manifest.ItemFromId(map_item.SourceId());
|
|
if (
|
|
map_item.ComponentType() != archive_item_from_id.ComponentType()
|
|
|| map_item.SourceId() != archive_item_from_id.Id()
|
|
|| map_item.SourceIndex() != archive_item_from_id.Index()
|
|
)
|
|
{
|
|
ON_ERROR("map_item.m_source_component_id is not in the archive manifest.");
|
|
return false;
|
|
}
|
|
if (bIndexRequired)
|
|
{
|
|
const ON_ComponentManifestItem& archive_item_from_index = m_manifest.ItemFromIndex(map_item.ComponentType(), map_item.SourceIndex());
|
|
if (
|
|
map_item.ComponentType() != archive_item_from_index.ComponentType()
|
|
|| map_item.SourceId() != archive_item_from_index.Id()
|
|
|| map_item.SourceIndex() != archive_item_from_index.Index()
|
|
)
|
|
{
|
|
ON_ERROR("map_item.m_source_component_index is not in the archive manifest.");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ON::archive_mode::write3dm:
|
|
{
|
|
const ON_ComponentManifestItem& archive_item_from_id = m_manifest.ItemFromId(map_item.DestinationId());
|
|
if (
|
|
map_item.ComponentType() != archive_item_from_id.ComponentType()
|
|
|| map_item.DestinationId() != archive_item_from_id.Id()
|
|
|| map_item.DestinationIndex() != archive_item_from_id.Index()
|
|
)
|
|
{
|
|
ON_ERROR("map_item.m_destination_component_id is not in the archive manifest.");
|
|
return false;
|
|
}
|
|
if (bIndexRequired)
|
|
{
|
|
const ON_ComponentManifestItem& archive_item_from_index = m_manifest.ItemFromIndex(map_item.ComponentType(), map_item.DestinationIndex());
|
|
if (
|
|
map_item.ComponentType() != archive_item_from_index.ComponentType()
|
|
|| map_item.DestinationId() != archive_item_from_index.Id()
|
|
|| map_item.DestinationIndex() != archive_item_from_index.Index()
|
|
)
|
|
{
|
|
ON_ERROR("map_item.m_destination_component_index is not in the archive manifest.");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!m_manifest_map.AddMapItem(map_item))
|
|
{
|
|
ON_ERROR("m_manifest_map.AddMapItem(map_item) failed.");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentWeakReference::ON_ModelComponentWeakReference() ON_NOEXCEPT
|
|
{}
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentWeakReference::~ON_ModelComponentWeakReference()
|
|
{}
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentWeakReference::ON_ModelComponentWeakReference(const ON_ModelComponentWeakReference& src) ON_NOEXCEPT
|
|
: m_wp(src.m_wp)
|
|
{}
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentWeakReference& ON_ModelComponentWeakReference::operator=(const ON_ModelComponentWeakReference& src)
|
|
{
|
|
if ( this != &src)
|
|
m_wp = src.m_wp;
|
|
return *this;
|
|
}
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
ON_ModelComponentWeakReference::ON_ModelComponentWeakReference( ON_ModelComponentWeakReference&& src ) ON_NOEXCEPT
|
|
: m_wp(std::move(src.m_wp))
|
|
{}
|
|
|
|
ON_ModelComponentWeakReference& ON_ModelComponentWeakReference::operator=(ON_ModelComponentWeakReference&& src)
|
|
{
|
|
if ( this != &src )
|
|
{
|
|
m_wp.reset();
|
|
m_wp = std::move(src.m_wp);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
#endif
|
|
|
|
ON_ModelComponentWeakReference::ON_ModelComponentWeakReference(const ON_ModelComponentReference& src) ON_NOEXCEPT
|
|
: m_wp(src.m_sp)
|
|
{}
|
|
|
|
ON_ModelComponentWeakReference& ON_ModelComponentWeakReference::operator=(const ON_ModelComponentReference& src)
|
|
{
|
|
m_wp = src.m_sp;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentReference::ON_ModelComponentReference() ON_NOEXCEPT
|
|
{}
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentReference::~ON_ModelComponentReference()
|
|
{}
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentReference::ON_ModelComponentReference(const ON_ModelComponentReference& src) ON_NOEXCEPT
|
|
: m_sp(src.m_sp)
|
|
{}
|
|
|
|
// Explicit implementation to insure m_sp is completely managed in the openurbs DLL.
|
|
ON_ModelComponentReference& ON_ModelComponentReference::operator=(const ON_ModelComponentReference& src)
|
|
{
|
|
if ( this != &src)
|
|
m_sp = src.m_sp;
|
|
return *this;
|
|
}
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
ON_ModelComponentReference::ON_ModelComponentReference( ON_ModelComponentReference&& src ) ON_NOEXCEPT
|
|
: m_sp(std::move(src.m_sp))
|
|
{}
|
|
|
|
ON_ModelComponentReference& ON_ModelComponentReference::operator=(ON_ModelComponentReference&& src)
|
|
{
|
|
if ( this != &src )
|
|
{
|
|
m_sp.reset();
|
|
m_sp = std::move(src.m_sp);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
#endif
|
|
|
|
ON_ModelComponentReference::ON_ModelComponentReference(const ON_ModelComponentWeakReference& src) ON_NOEXCEPT
|
|
: m_sp(src.m_wp.lock())
|
|
{
|
|
// NOTE WELL:
|
|
// std::shared_ptr<T>(std::weak_ptr<T>) throws an exception when weak_ptr is empty.
|
|
// std::shared_ptr<T>(std::weak_ptr<T>.lock()) constructs and empty shared_ptr when weak_ptr is empty.
|
|
}
|
|
|
|
|
|
ON_ModelComponentReference& ON_ModelComponentReference::operator=(const ON_ModelComponentWeakReference& src)
|
|
{
|
|
m_sp = src.m_wp.lock();
|
|
return *this;
|
|
}
|
|
|
|
|
|
ON_ModelComponentReference::ON_ModelComponentReference(
|
|
std::shared_ptr<ON_ModelComponent>& sp
|
|
) ON_NOEXCEPT
|
|
: m_sp(sp)
|
|
{}
|
|
|
|
ON_ModelComponentReference& ON_ModelComponentReference::operator=(std::shared_ptr<ON_ModelComponent>& sp)
|
|
{
|
|
m_sp = sp;
|
|
return *this;
|
|
}
|
|
|
|
ON_ModelComponentReference ON_ModelComponentReference::CreateConstantSystemComponentReference(
|
|
const class ON_ModelComponent& system_model_component
|
|
) ON_NOEXCEPT
|
|
{
|
|
if ( system_model_component.IsSystemComponent())
|
|
return CreateForExperts(const_cast<ON_ModelComponent*>(&system_model_component),false);
|
|
|
|
ON_ERROR("Invalid system_model_component parameter.");
|
|
return ON_ModelComponentReference::Empty;
|
|
}
|
|
|
|
|
|
ON_ModelComponentReference ON_ModelComponentReference::CreateForExperts(
|
|
class ON_ModelComponent* model_component,
|
|
bool bManagedComponentReference
|
|
) ON_NOEXCEPT
|
|
{
|
|
if ( nullptr == model_component )
|
|
return ON_ModelComponentReference::Empty;
|
|
if (bManagedComponentReference && model_component->IsSystemComponent())
|
|
{
|
|
// If you get this error, you have const cast a system component
|
|
// and there will be a hard to diagnose crash when the the
|
|
// last shared pointer attempts to delete the constant system component.
|
|
//
|
|
// You should be using ON_ModelComponentReference::CreateConstantSystemComponentReference.
|
|
ON_ERROR("The future attempt to delete model_component will crash the application.");
|
|
return ON_ModelComponentReference::Empty;
|
|
}
|
|
ON_ModelComponentReference r;
|
|
r.m_sp
|
|
= bManagedComponentReference
|
|
? ON_MANAGED_SHARED_PTR(ON_ModelComponent,model_component) // default calls delete model_component
|
|
: ON_UNMANAGED_SHARED_PTR(ON_ModelComponent,model_component);
|
|
return r;
|
|
}
|
|
|
|
const class ON_ModelComponent* ON_ModelComponentReference::ModelComponent() const ON_NOEXCEPT
|
|
{
|
|
return m_sp.get();
|
|
}
|
|
|
|
class ON_ModelComponent* ON_ModelComponentReference::ExclusiveModelComponent() const ON_NOEXCEPT
|
|
{
|
|
return
|
|
(1 == m_sp.use_count())
|
|
? m_sp.get()
|
|
: nullptr;
|
|
}
|
|
|
|
ON__UINT64 ON_ModelComponentReference::ModelComponentRuntimeSerialNumber() const ON_NOEXCEPT
|
|
{
|
|
const ON_ModelComponent* model_component = m_sp.get();
|
|
return (nullptr != model_component) ? model_component->RuntimeSerialNumber() : 0;
|
|
}
|
|
|
|
const ON_UUID ON_ModelComponentReference::ModelComponentId() const ON_NOEXCEPT
|
|
{
|
|
const ON_ModelComponent* model_component = m_sp.get();
|
|
return (nullptr != model_component) ? model_component->Id() : ON_nil_uuid;
|
|
}
|
|
|
|
int ON_ModelComponentReference::ModelComponentIndex() const ON_NOEXCEPT
|
|
{
|
|
const ON_ModelComponent* model_component = m_sp.get();
|
|
return (nullptr != model_component) ? model_component->Index() : ON_UNSET_INT_INDEX;
|
|
}
|
|
|
|
const ON_NameHash ON_ModelComponentReference::ModelComponentNameHash() const ON_NOEXCEPT
|
|
{
|
|
const ON_ModelComponent* model_component = m_sp.get();
|
|
return (nullptr != model_component) ? model_component->NameHash() : ON_NameHash::UnsetNameHash;
|
|
}
|
|
|
|
bool ON_ModelComponentReference::IsEmpty() const ON_NOEXCEPT
|
|
{
|
|
return (nullptr == m_sp.get());
|
|
}
|
|
|
|
unsigned int ON_ModelComponentReference::ReferenceCount() const ON_NOEXCEPT
|
|
{
|
|
return (unsigned int)(m_sp.use_count());
|
|
}
|
|
|
|
ON_ModelComponentContentMark::ON_ModelComponentContentMark(
|
|
const ON_ModelComponent& model_component
|
|
)
|
|
{
|
|
Set(model_component);
|
|
}
|
|
|
|
ON_ModelComponentContentMark::ON_ModelComponentContentMark(
|
|
const ON_ModelComponent* model_component
|
|
)
|
|
{
|
|
Set(model_component);
|
|
}
|
|
|
|
void ON_ModelComponentContentMark::Set(
|
|
const class ON_ModelComponent& model_component
|
|
)
|
|
{
|
|
m_component_id = model_component.Id();
|
|
m_component_serial_number = model_component.RuntimeSerialNumber();
|
|
m_component_content_version_number = model_component.ContentVersionNumber();
|
|
m_component_type = model_component.ComponentType();
|
|
}
|
|
|
|
void ON_ModelComponentContentMark::Set(
|
|
const class ON_ModelComponent* model_component
|
|
)
|
|
{
|
|
if (nullptr == model_component)
|
|
*this = ON_ModelComponentContentMark::Unset;
|
|
else
|
|
Set(*model_component);
|
|
}
|
|
|
|
bool ON_ModelComponentContentMark::EqualContent(
|
|
const class ON_ModelComponent& model_component
|
|
) const
|
|
{
|
|
const ON_ModelComponentContentMark rhs(model_component);
|
|
return EqualContent(*this, rhs);
|
|
}
|
|
|
|
bool ON_ModelComponentContentMark::EqualContent(
|
|
const class ON_ModelComponent* model_component
|
|
) const
|
|
{
|
|
const ON_ModelComponentContentMark rhs(model_component);
|
|
return EqualContent(*this, rhs);
|
|
}
|
|
|
|
bool ON_ModelComponentContentMark::EqualContent(
|
|
const ON_ModelComponentContentMark& lhs,
|
|
const ON_ModelComponentContentMark& rhs
|
|
)
|
|
{
|
|
return
|
|
lhs.m_component_serial_number == rhs.m_component_serial_number
|
|
&& lhs.m_component_content_version_number == rhs.m_component_content_version_number
|
|
&& lhs.m_component_id == rhs.m_component_id
|
|
&& lhs.m_component_type == rhs.m_component_type
|
|
;
|
|
}
|
|
|
|
bool operator==(
|
|
const ON_ModelComponentContentMark& lhs,
|
|
const ON_ModelComponentContentMark& rhs
|
|
)
|
|
{
|
|
return ON_ModelComponentContentMark::EqualContent(lhs, rhs);
|
|
}
|
|
|
|
bool operator!=(
|
|
const ON_ModelComponentContentMark& lhs,
|
|
const ON_ModelComponentContentMark& rhs
|
|
)
|
|
{
|
|
return ON_ModelComponentContentMark::EqualContent(lhs, rhs) ? false : true;
|
|
}
|
|
|
|
ON_UUID ON_ModelComponentContentMark::ComponentId() const
|
|
{
|
|
return m_component_id;
|
|
}
|
|
|
|
ON__UINT64 ON_ModelComponentContentMark::ComponentRuntimeSerialNumber() const
|
|
{
|
|
return m_component_serial_number;
|
|
}
|
|
|
|
ON__UINT64 ON_ModelComponentContentMark::ComponentContentVersionNumber() const
|
|
{
|
|
return m_component_content_version_number;
|
|
}
|
|
|
|
ON_ModelComponent::Type ON_ModelComponentContentMark::ComponentType() const
|
|
{
|
|
return m_component_type;
|
|
}
|
|
|
|
bool ON_ModelComponentContentMark::IsSet() const
|
|
{
|
|
return (0 != m_component_serial_number);
|
|
}
|
|
|
|
bool ON_ModelComponentContentMark::IsUnset() const
|
|
{
|
|
return (0 == m_component_serial_number);
|
|
}
|