Files
opennurbs/opennurbs_object.cpp
Bozo The Builder f26b1ba26a Sync changes from upstream repository
First publish of public opennurbs from 8.x source
2022-07-28 11:12:21 -07:00

2338 lines
59 KiB
C++

/* $NoKeywords: $ */
/*
//
// Copyright (c) 1993-2012 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
#if defined(OPENNURBS_EXPORTS)
//
//
////////////////////////////////////////////////////////////////////////////////
#endif
unsigned int ON_IsRhinoApplicationId(
ON_UUID id
)
{
if (ON_rhino2_id == id)
return 2;
if (ON_rhino3_id == id)
return 3;
if (ON_rhino4_id == id)
return 4;
if (ON_rhino5_id == id)
return 5;
if (ON_rhino6_id == id)
return 6;
if (ON_rhino7_id == id)
return 7;
if (ON_rhino8_id == id)
return 8;
return 0;
}
unsigned int ON_IsOpennurbsApplicationId(
ON_UUID id
)
{
if (ON_opennurbs4_id == id)
return 4;
if (ON_opennurbs5_id == id)
return 5;
if (ON_opennurbs6_id == id)
return 6;
if (ON_opennurbs7_id == id)
return 7;
return 0;
}
static int ON__isnand(const double* x)
{
const unsigned char* b = (const unsigned char*)x;
static unsigned int b7 = 0;
static unsigned int b6 = 0;
if (0 == b6)
{
// different bytes on
union
{
double x;
unsigned char b[8];
} u; u.x = 2.0; // sign = 0; fraction = 0; exponent = 100 0000 0000 binary
if (0x40 == u.b[7] && 0 == u.b[0]
&& 0 == u.b[1] && 0 == u.b[2] && 0 == u.b[3]
&& 0 == u.b[4] && 0 == u.b[5] && 0 == u.b[6]
)
{
// little endian doubles
b7 = 7;
b6 = 6;
}
else if (0x40 == u.b[0] && 0 == u.b[7]
&& 0 == u.b[1] && 0 == u.b[2] && 0 == u.b[3]
&& 0 == u.b[4] && 0 == u.b[5] && 0 == u.b[6]
)
{
// big endian doubles
b7 = 0;
b6 = 1;
}
else
{
// This sitation is not handled by this algorithm
// and that is a bug in the algorithm.
ON_ERROR("Unexpected bit pattern in double 2.0.");
// assum little endian doubles
b7 = 7;
b6 = 6;
}
}
if (0x7F == (0x7F & b[b7]) && (0xF0 == (0xF0 & b[b6])))
{
// All exponent bits are set
if (0x08 & b[b6])
{
// The most significant fraction bit is set.
// This must be a QNaN
return 2;
}
else
{
// The most significant fraction bit is is clear.
// If any other fraction bits are set, it's an SNaN
if (0 != (0x0F & b[b6]))
return 1;
if (6 == b6)
{
// little endian
return
(0 != b[0] || 0 != b[1] || 0 != b[2] || 0 != b[3] || 0 != b[4] || 0 != b[5])
? 1 // some fraction bit is set
: 0; // all fraction bits are clear.
}
else
{
// big endian
return
(0 != b[2] || 0 != b[3] || 0 != b[4] || 0 != b[5] || 0 != b[6] || 0 != b[7])
? 1 // some fraction bit is set
: 0; // all fraction bits are clear.
}
}
}
return 0; // not a NaN
}
static int ON__isnanf(const float* x)
{
const unsigned char* b = (const unsigned char*)x;
static unsigned int b3 = 0;
static unsigned int b2 = 0;
if (0 == b2)
{
union
{
float x;
unsigned char b[4];
} u;
// different bytes on
u.x = 2.0f; // sign = 0; mantissa = 0; exponent = 1000 0000
if (0x40 == u.b[3] && 0 == u.b[0] && 0 == u.b[1] && 0 == u.b[2])
{
// little endian floats
b3 = 3; b2 = 2;
}
else if (0x40 == u.b[0] && 0 == u.b[3] && 0 == u.b[1] && 0 == u.b[2])
{
// big endian floats
b3 = 0; b2 = 1;
}
else
{
// This sitation is not handled by this algorithm
// and that is a bug in the algorithm.
ON_ERROR("Unexpected bit pattern in float 2.0f.");
// assume little endian floats
b3 = 3; b2 = 2;
}
}
if (0x7F == (0x7F & b[b3]) && (0x80 == (0x80 & b[b2])))
{
// All exponent bits are set
if (0x7F & b[b2])
{
// The most significant fraction bit is set.
// This must be a QNaN
return 2;
}
else
{
// The most significant fraction bit is is clear.
// If any other fraction bits are set, it's an SNaN
if (0 != (0x0F & b[b2]))
return 1;
if (2 == b2)
{
// little endian
return
(0 != b[0] || 0 != b[1])
? 1 // some fraction bit is set
: 0; // all fraction bits are clear.
}
else
{
// big endian
return
(0 != b[2] || 0 != b[3])
? 1 // some fraction bit is set
: 0; // all fraction bits are clear.
}
}
}
return 0; // not a NaN
}
void ON_DBL_SNAN( double* x)
{
union
{
double x;
unsigned char b[8];
} u;
#if defined(ON_LITTLE_ENDIAN)
#define i7 7
#define i6 6
#elif defined(ON_BIG_ENDIAN)
#define i7 0
#define i6 1
#else
unsigned int i7, i6;
u.x = 2.0; // sign = 0; fraction = 0; exponent = 100 0000 0000 binary
if ( 0x40 == u.b[7] && 0 == u.b[0]
&& 0 == u.b[1] && 0 == u.b[2] && 0 == u.b[3]
&& 0 == u.b[4] && 0 == u.b[5] && 0 == u.b[6]
)
{
// little endian doubles
i7 = 7; i6 = 6;
}
else if ( 0x40 == u.b[0] && 0 == u.b[7]
&& 0 == u.b[1] && 0 == u.b[2] && 0 == u.b[3]
&& 0 == u.b[4] && 0 == u.b[5] && 0 == u.b[6]
)
{
// big endian doubles
i7 = 0; i6 = 1;
}
else
{
// this sitation is not handled by this algorithm
// and that is a bug in the algorithm.
ON_ERROR("CPU has unexpected bit pattern in double 2.0.");
i7 = 0;
i6 = 0;
memset(&x,0xFF,sizeof(*x));
return;
}
#endif
// all exponent bits = 1
// fraction bits = 010...0
u.b[i7] = 0x7F; // 0111 1111
u.b[i6] = 0xF4; // 1111 0100
u.b[5] = 0; // 0...
u.b[4] = 0;
u.b[3] = 0;
u.b[2] = 0;
u.b[7-i6] = 0;
u.b[7-i7] = 0;
#if defined(i7)
#undef i7
#undef i6
#endif
// must use memcpy(). On Intel FPU, assignment using x = u.x
// will set x to qnan and invalid op exception occures.
memcpy(x,&u.x,sizeof(*x));
}
void ON_FLT_SNAN( float* x)
{
union
{
float x;
unsigned char b[4];
} u;
#if defined(ON_LITTLE_ENDIAN)
#define i3 3
#define i2 2
#elif defined(ON_BIG_ENDIAN)
#define i3 0
#define i2 1
#else
unsigned int i3, i2;
u.x = 2.0f; // sign = 0; mantissa = 0; exponent = 1000 0000
if ( 0x40 == u.b[3] && 0 == u.b[0] && 0 == u.b[1] && 0 == u.b[2] )
{
// little endian doubles
i3 = 3; i2 = 2;
}
else if ( 0x40 == u.b[0] && 0 == u.b[3] && 0 == u.b[1] && 0 == u.b[2] )
{
// big endian doubles
i3 = 0; i2 = 1;
}
else
{
// this sitation is not handled by this algorithm
// and that is a bug in the algorithm.
ON_ERROR("CPU has unexpected bit pattern in float 2.0f.");
memset(&x,0xFF,sizeof(*x));
return;
}
#endif
// all exponent bits = 1
// fraction bits = 011...1
u.b[i3] = 0x7F; // 0111 1111
u.b[i2] = 0xA0; // 1010 0000
u.b[3-i2] = 0; // 0...
u.b[3-i3] = 0;
#if defined(i3)
#undef i3
#undef i2
#endif
// must use memcpy(). On Intel FPU, assignment using x = u.x
// will set x to qnan and invalid op exception occures.
memcpy(x,&u.x,sizeof(*x));
}
bool ON_IsNaNd(double x)
{
return 0 != ON__isnand(&x);
}
bool ON_IsQNaNd(double x)
{
return 2 == ON__isnand(&x);
}
bool ON_IsSNaNd(double x)
{
return 1 == ON__isnand(&x);
}
bool ON_IsNaNf(float x)
{
return 0 != ON__isnanf(&x);
}
bool ON_IsQNaNf(float x)
{
return 2 == ON__isnanf(&x);
}
bool ON_IsSNaNf(float x)
{
return 1 == ON__isnanf(&x);
}
float ON_FloatFromDouble(
double x
)
{
if (ON_UNSET_VALUE == x)
return ON_UNSET_FLOAT;
if (ON_UNSET_POSITIVE_VALUE == x)
return ON_UNSET_POSITIVE_FLOAT;
return static_cast<float>(x);
}
double ON_DoubleFromFloat(
float x
)
{
if (ON_UNSET_FLOAT == x)
return ON_UNSET_VALUE;
if (ON_UNSET_POSITIVE_FLOAT == x)
return ON_UNSET_POSITIVE_VALUE;
return static_cast<double>(x);
}
bool ON_IsNullPtr(const void* ptr)
{
return (nullptr == ptr);
}
bool ON_IsNullPtr(const ON__UINT_PTR ptr)
{
return (0 == ptr);
}
bool ON_IsNullPtr(const ON__INT_PTR ptr)
{
return (0 == ptr);
}
static void ValidateSizesHelper()
{
static bool bSizedValidated = false;
if ( !bSizedValidated )
{
// Validate int and pointer sizes
bSizedValidated = true;
// These conditional expressions are all constant and should
// all be false. If any are true, then portions of OpenNURBS
// code will fail and probably crash.
#if defined(ON_COMPILER_MSC)
#pragma ON_PRAGMA_WARNING_PUSH
// Disable warning C4127: conditional expression is constant
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4127 )
#endif
if ( ON_SIZEOF_POINTER != sizeof(void*) )
{
ON_ERROR("ON_SIZEOF_POINTER is not correctly defined.");
}
if ( ON_SIZEOF_POINTER != sizeof(ON__INT_PTR) )
{
ON_ERROR("ON_INT_PTR is not correctly defined.");
}
if ( 1 != sizeof(char) )
{
ON_ERROR("OpenNURBS assumes sizeof(char) = 1.");
}
if ( 2 != sizeof(ON__INT16) )
{
ON_ERROR("ON__INT16 is not correctly defined.");
}
if ( 4 != sizeof(ON__INT32) )
{
ON_ERROR("ON__INT32 is not correctly defined.");
}
if ( 8 != sizeof(ON__INT64) )
{
ON_ERROR("ON__INT32 is not correctly defined.");
}
if ( sizeof(int) > sizeof(void*) )
{
ON_ERROR("OpenNURBS assumes sizeof(int) <= sizeof(void*).");
}
if ( 4 != sizeof(float) )
{
ON_ERROR("OpenNURBS assumes sizeof(float) = 4.");
}
if ( 8 != sizeof(double) )
{
ON_ERROR("OpenNURBS assumes sizeof(double) = 8.");
}
#if defined(ON_COMPILER_MSC)
#pragma ON_PRAGMA_WARNING_POP
#endif
}
}
unsigned int ON::LibraryStatus()
{
return ON::m_opennurbs_library_status;
}
void ON::SetLibraryStatus(unsigned int status)
{
ON::m_opennurbs_library_status = status;
}
void ON::Begin()
{
if ( 0 != ON::m_opennurbs_library_status )
return;
ON::m_opennurbs_library_status = 1;
ValidateSizesHelper();
#if !defined(OPENNURBS_EXPORTS)
// Some statically linked library optimizations discard
// object code that is not explicitly referenced.
// By explicitly calling all the ON_Object::Cast overrides,
// we can insure that the class definitions get linked in
// by making a single call to ON::Begin(). These definitions
// are needed for the file reading code to work right.
const ON_Object* p=0;
ON_Object::Cast(p);
ON_3dmObjectAttributes::Cast(p);
ON_Bitmap::Cast(p);
ON_EmbeddedBitmap::Cast(p);
ON_WindowsBitmap::Cast(p);
ON_WindowsBitmapEx::Cast(p);
ON_DimStyle::Cast(p);
ON_DocumentUserStringList::Cast(p);
ON_TextStyle::Cast(p);
ON_Geometry::Cast(p);
ON_Annotation::Cast(p);
ON_Text::Cast(p);
ON_Leader::Cast(p);
ON_Dimension::Cast(p);
ON_DimLinear::Cast(p);
ON_DimAngular::Cast(p);
ON_DimRadial::Cast(p);
ON_DimOrdinate::Cast(p);
ON_Centermark::Cast(p);
ON_Brep::Cast(p);
ON_BrepLoop::Cast(p);
ON_Curve::Cast(p);
ON_ArcCurve::Cast(p);
ON_CurveOnSurface::Cast(p);
ON_CurveProxy::Cast(p);
ON_BrepEdge::Cast(p);
ON_BrepTrim::Cast(p);
ON_LineCurve::Cast(p);
ON_NurbsCurve::Cast(p);
ON_PolyCurve::Cast(p);
ON_PolylineCurve::Cast(p);
ON_DetailView::Cast(p);
ON_Hatch::Cast(p);
ON_InstanceDefinition::Cast(p);
ON_InstanceRef::Cast(p);
ON_Light::Cast(p);
ON_Mesh::Cast(p);
ON_MeshComponentRef::Cast(p);
ON_MorphControl::Cast(p);
ON_NurbsCage::Cast(p);
ON_Point::Cast(p);
ON_BrepVertex::Cast(p);
ON_PointCloud::Cast(p);
ON_PointGrid::Cast(p);
ON_Surface::Cast(p);
ON_Extrusion::Cast(p);
ON_NurbsSurface::Cast(p);
ON_PlaneSurface::Cast(p);
ON_ClippingPlaneSurface::Cast(p);
ON_RevSurface::Cast(p);
ON_SumSurface::Cast(p);
ON_SurfaceProxy::Cast(p);
ON_BrepFace::Cast(p);
ON_OffsetSurface::Cast(p);
ON_TextDot::Cast(p);
ON_Viewport::Cast(p);
ON_Group::Cast(p);
ON_HatchPattern::Cast(p);
ON_HistoryRecord::Cast(p);
ON_Layer::Cast(p);
ON_Linetype::Cast(p);
ON_Material::Cast(p);
ON_Texture::Cast(p);
ON_TextureMapping::Cast(p);
ON_UserData::Cast(p);
ON_UnknownUserData::Cast(p);
ON_UserStringList::Cast(p);
#endif
// Lock and mark all constant system components
ON_ModelComponent::Internal_SystemComponentHelper();
ON::m_opennurbs_library_status = 2;
}
void ON::End()
{
}
int ON_ClassId::CurrentMark()
{
return m_mark0;
}
int ON_ClassId::IncrementMark()
{
m_mark0++;
return m_mark0;
}
int ON_ClassId::Purge( int mark_value )
{
// Fundamental openNURBS class ids have a mark value of 0 and cannot be purged.
int purge_count = 0;
if ( mark_value > 0 ) {
ON_ClassId* prev = 0;
ON_ClassId* next = 0;
ON_ClassId* p;
for ( p = m_p0; p; p = next )
{
next = p->m_pNext;
if ( (0x7FFFFFFF & p->m_mark) == mark_value ) {
purge_count++;
if ( prev )
prev->m_pNext = next;
else
m_p0 = next;
p->m_pNext = 0;
}
else
prev = p;
}
}
return purge_count;
}
const ON_ClassId* ON_ClassId::LastClassId()
{
return m_p1;
}
bool ON_ClassId::PurgeAfter(const ON_ClassId* pClassId)
{
// If you crash in on the p=p->m_pNext iterator in
// the for() loop, it is because somebody incorrectly
// unloaded a dll that contains an ON_OBJECT_IMPLEMENT
// macro.
for (ON_ClassId* p = m_p0; p; p = p->m_pNext)
{
if (pClassId == p)
{
// All class ids after pClassId are assumed to
// be bad.
p->m_pNext = 0;
m_p1 = p;
return true;
}
}
ON_ERROR("ON_ClassId::PurgeAfter pClassId is not active");
return false;
}
//////////////////////////////////////////////////////////////////////////////
static bool g_bDisableDemotion = false;
static void IntToString( int i, char s[7] )
{
// avoid format printing during early start up
int j;
int digit;
char sdig[10];
sdig[0] = '0';
sdig[1] = '1';
sdig[2] = '2';
sdig[3] = '3';
sdig[4] = '4';
sdig[5] = '5';
sdig[6] = '6';
sdig[7] = '7';
sdig[8] = '8';
sdig[9] = '9';
for ( digit = 5; digit > 0; digit-- )
{
j = i%10;
if ( j > 9 || j < 0 )
{
s[digit] = '-';
}
else
{
s[digit] = sdig[j];
}
i /= 10;
}
s[0] = '-';
s[6] = 0;
}
ON_ClassId::ON_ClassId( const char* sClassName,
const char* sBaseClassName,
ON_Object* (*create)(),
const char* sUUID // UUID in registry format from guidgen
)
: m_pNext(0),
m_pBaseClassId(0),
m_create(create),
m_mark(m_mark0),
m_class_id_version(0),
m_f1(0),
m_f2(0),
m_f3(0),
m_f4(0),
m_f5(0),
m_f6(0),
m_f7(0),
m_f8(0)
{
// code compiled on or after opennurbs 200703060 calls this constructor
ConstructorHelper(sClassName,sBaseClassName,sUUID);
m_mark |= 0x80000000; // This bit of m_mark is a flag that indicates
// the new constructor was called.
}
void ON_ClassId::ConstructorHelper( const char* sClassName,
const char* sBaseClassName,
const char* sUUID // UUID in registry format from guidgen
)
{
// Do not initialize "m_class_id_version" or any fields
// after it in this helper. See comments in the constructors
// for more information.
memset( m_sClassName, 0, sizeof(m_sClassName) );
memset( m_sBaseClassName, 0, sizeof(m_sBaseClassName) );
m_uuid = ON_UuidFromString(sUUID);
if ( sClassName ) {
strncpy( m_sClassName, sClassName, sizeof(m_sClassName)-1 );
}
if ( sBaseClassName ) {
strncpy( m_sBaseClassName, sBaseClassName, sizeof(m_sBaseClassName)-1 );
}
m_pBaseClassId = ClassId( m_sBaseClassName );
if ( !m_sClassName[0] ) {
ON_ERROR("ON_ClassId::ON_ClassId() - missing class name");
return;
}
const ON_ClassId* duplicate_class = ClassId( m_sClassName );
// The m_mark0 > 2 test prevents opennurbs and Rhino from
// having two ON_Object derived classes that have the same
// name. Plug-ins are free to use any name.
if ( 0 != duplicate_class && m_mark0 > 2 )
{
char s[7];
int ver;
ON_WARNING("ON_ClassId::ON_ClassId() - class name already in use. Will append number to make it unique.");
for ( ver = 1; ver < 10000 && 0 != duplicate_class; ver++ )
{
IntToString(ver,s);
s[6] = 0;
strncpy( m_sClassName, sClassName, sizeof(m_sClassName)-1 );
strncat( m_sClassName, s, sizeof(m_sClassName)-1 );
duplicate_class = ClassId( m_sClassName );
}
}
if ( 0 != duplicate_class )
{
// Do NOT permit core classes to have duplicate names.
ON_ERROR("ON_ClassId::ON_ClassId() - class name already in use.");
return;
}
if ( m_sClassName[0] != 'O'
|| m_sClassName[1] != 'N'
|| m_sClassName[2] != '_'
|| m_sClassName[3] != 'O'
|| m_sClassName[4] != 'b'
|| m_sClassName[5] != 'j'
|| m_sClassName[6] != 'e'
|| m_sClassName[7] != 'c'
|| m_sClassName[8] != 't'
|| m_sClassName[9] != 0 ) {
if ( !m_sBaseClassName[0] )
{
ON_ERROR("ON_ClassId::ON_ClassId() - missing baseclass name.");
return;
}
}
g_bDisableDemotion = true;
if ( ClassId( m_uuid ) )
{
g_bDisableDemotion = false;
ON_ERROR("ON_ClassId::ON_ClassId() - class uuid already in use.");
return;
}
g_bDisableDemotion = false;
if ( ON_UuidIsNil( m_uuid ) ) {
ON_ERROR("ON_ClassId::ON_ClassId() - class uuid is nill.");
return;
}
// see if any derived classes need to be updated because their static
// members got initialized first
if ( m_sClassName[0] )
{
for ( ON_ClassId* p = m_p0; p; p = p->m_pNext )
{
if (
0 == p->m_pBaseClassId
&& 0 != p->m_sBaseClassName[0]
&& 0 == p->m_sBaseClassName[sizeof(p->m_sBaseClassName)/sizeof(p->m_sBaseClassName[0]) - 1]
)
{
if ( 0 == strcmp( m_sClassName, p->m_sBaseClassName ) )
p->m_pBaseClassId = this;
}
}
}
// Append to the list of class ids
if ( m_p0 && m_p1 )
{
m_p1->m_pNext = this;
m_p1 = this;
}
else
{
// first class id
m_p0 = this;
}
m_p1 = this;
m_p1->m_pNext = 0;
}
ON_ClassId::~ON_ClassId()
{}
static ON_UUID s_most_recent_class_id_create_uuid;
ON_UUID ON_GetMostRecentClassIdCreateUuid()
{
return s_most_recent_class_id_create_uuid;
}
ON_Object* ON_ClassId::Create() const
{
// Save the uuid so that Rhino's .NET SDK
// can create approprate class. The C++
// opennurbs toolkit never uses this value.
s_most_recent_class_id_create_uuid = m_uuid;
return m_create ? m_create() : 0;
}
const ON_ClassId* ON_ClassId::ClassId( const char* sClassName )
{
// static member function
// search list of class ids for one with a matching class name
ON_ClassId* p;
const char* s0;
const char* s1;
if ( !sClassName || !sClassName[0] || sClassName[0] == '0' )
return nullptr;
for(p = m_p0; p; p = p->m_pNext) {
// avoid strcmp() because it crashes on nullptr strings
s0 = sClassName;
s1 = p->m_sClassName;
if ( s0 && s1 && *s0 ) {
while ( *s0 && *s0 == *s1 )
{s0++; s1++;}
if ( !(*s0) && !(*s1) )
break;
}
else {
break;
}
}
return p;
}
const ON_ClassId* ON_ClassId::ClassId( ON_UUID uuid )
{
// static member function
// search list of class ids for one with a matching typecode
const ON_ClassId* p;
for(p = m_p0; p; p = p->m_pNext)
{
if ( !ON_UuidCompare(&p->m_uuid,&uuid) )
break;
}
if ( nullptr == p && false == g_bDisableDemotion)
{
// enable OpenNURBS toolkit to read files that contain old uuids even when
// old class definitions are not loaded.
// 5EAF1119-0B51-11d4-BFFE-0010830122F0 = TL_NurbsCurve
ON_UUID nc0 = {0x5EAF1119,0x0B51,0x11d4,{0xBF,0xFE, 0x00,0x10,0x83,0x01,0x22,0xF0}};
// 76A709D5-1550-11d4-8000-0010830122F0 = old nurbs curve
ON_UUID nc1 = {0x76A709D5,0x1550,0x11d4,{0x80,0x00, 0x00,0x10,0x83,0x01,0x22,0xF0}};
// 4760C817-0BE3-11d4-BFFE-0010830122F0 = TL_NurbsSurface
ON_UUID ns0 = {0x4760C817,0x0BE3,0x11d4,{0xBF,0xFE, 0x00,0x10,0x83,0x01,0x22,0xF0}};
// FA4FD4B5-1613-11d4-8000-0010830122F0 = old nurbs surface
ON_UUID ns1 = {0xFA4FD4B5,0x1613,0x11d4,{0x80,0x00, 0x00,0x10,0x83,0x01,0x22,0xF0}};
// EF638317-154B-11d4-8000-0010830122F0 = old poly curve
ON_UUID pc0 = {0xEF638317,0x154B,0x11d4,{0x80,0x00, 0x00,0x10,0x83,0x01,0x22,0xF0}};
// 0705FDEF-3E2A-11d4-800E-0010830122F0 = old trimmed surface
ON_UUID br0 = {0x0705FDEF,0x3E2A,0x11d4,{0x80,0x0E, 0x00,0x10,0x83,0x01,0x22,0xF0}};
// 2D4CFEDB-3E2A-11d4-800E-0010830122F0 = old b-rep
ON_UUID br1 = {0x2D4CFEDB,0x3E2A,0x11d4,{0x80,0x0E, 0x00,0x10,0x83,0x01,0x22,0xF0}};
// F06FC243-A32A-4608-9DD8-A7D2C4CE2A36 = TL_Brep
ON_UUID br2 = {0xF06FC243,0xA32A,0x4608,{0x9D,0xD8, 0xA7,0xD2,0xC4,0xCE,0x2A,0x36}};
// 0A8401B6-4D34-4b99-8615-1B4E723DC4E5 = TL_RevSurface
ON_UUID revsrf = { 0xa8401b6, 0x4d34, 0x4b99, { 0x86, 0x15, 0x1b, 0x4e, 0x72, 0x3d, 0xc4, 0xe5 } };
// 665F6331-2A66-4cce-81D0-B5EEBD9B5417 = TL_SumSurface
ON_UUID sumsrf = { 0x665f6331, 0x2a66, 0x4cce, { 0x81, 0xd0, 0xb5, 0xee, 0xbd, 0x9b, 0x54, 0x17 } };
if ( !ON_UuidCompare( &uuid, &nc0 ) || !ON_UuidCompare( &uuid, &nc1 ) )
p = &ON_CLASS_RTTI(ON_NurbsCurve);
else if ( !ON_UuidCompare( &uuid, &ns0 ) || !ON_UuidCompare( &uuid, &ns1 ) )
p = &ON_CLASS_RTTI(ON_NurbsSurface);
else if ( !ON_UuidCompare( &uuid, &pc0 ) )
p = &ON_CLASS_RTTI(ON_PolyCurve);
else if ( !ON_UuidCompare( &uuid, &br0 ) || !ON_UuidCompare( &uuid, &br1 ) || !ON_UuidCompare( &uuid, &br2 ) )
p = &ON_CLASS_RTTI(ON_Brep);
else if ( !ON_UuidCompare( &uuid, &revsrf ) )
p = &ON_CLASS_RTTI(ON_RevSurface);
else if ( !ON_UuidCompare( &uuid, &sumsrf ) )
p = &ON_CLASS_RTTI(ON_SumSurface);
else
{
// The p = nullptr line does nothing (p is already nullptr) but, if you're working on
// file reading bugs or other cases that involving rtti bugs, then it's a good
// location for a debugger breakpoint.
p = nullptr;
}
}
return p;
}
class ON__ClassIdDumpNode
{
public:
ON__ClassIdDumpNode();
~ON__ClassIdDumpNode();
const ON_ClassId* m_class_id;
class ON__ClassIdDumpNode* m_parent_node;
int m_depth;
ON_SimpleArray<class ON__ClassIdDumpNode*> m_child_nodes;
int CompareClassUuid( const class ON__ClassIdDumpNode& ) const;
int CompareClassName( const class ON__ClassIdDumpNode& ) const;
bool Dump( int depth, ON_TextLog& text_log );
};
ON__ClassIdDumpNode::ON__ClassIdDumpNode()
{
m_class_id=0;
m_parent_node=0;
m_depth=0;
};
ON__ClassIdDumpNode::~ON__ClassIdDumpNode()
{
}
int ON__ClassIdDumpNode::CompareClassUuid( const class ON__ClassIdDumpNode& other ) const
{
int rc = 0;
const ON_ClassId* a = m_class_id;
const ON_ClassId* b = other.m_class_id;
if ( a != b )
{
if ( 0 == a )
{
rc = -1;
}
else if ( 0 == b )
rc = 1;
else
{
rc = ON_UuidCompare(a->Uuid(),b->Uuid());
if ( 0 == rc )
{
rc = CompareClassName(other);
}
}
}
return rc;
}
int ON__ClassIdDumpNode::CompareClassName( const class ON__ClassIdDumpNode& other ) const
{
int rc = 0;
const ON_ClassId* a = m_class_id;
const ON_ClassId* b = other.m_class_id;
if ( a != b )
{
if ( 0 == a )
{
rc = -1;
}
else if ( 0 == b )
rc = 1;
else
{
const char* a_name = a->ClassName();
const char* b_name = b->ClassName();
if ( 0 == a_name )
{
if ( 0 == b_name )
{
rc = b->Mark() - a->Mark();
if ( 0 == rc )
rc = ON_UuidCompare(a->Uuid(),b->Uuid());
}
else
rc = -1;
}
else if ( 0 == b_name )
{
rc = 1;
}
else
{
rc = on_stricmp(a_name,b_name);
if ( 0 == rc )
{
rc = strcmp(a_name,b_name);
if ( 0 == rc )
{
rc = b->Mark() - a->Mark();
if ( 0 == rc )
rc = ON_UuidCompare(a->Uuid(),b->Uuid());
}
}
}
}
}
return rc;
}
static int ON__ClassIdDumpNode_CompareUuid( const ON__ClassIdDumpNode* a, const ON__ClassIdDumpNode* b )
{
int rc = 0;
if ( 0 == a )
{
rc = (0 == b) ? 0 : -1;
}
else if ( 0 == b )
{
rc = 1;
}
else
{
rc = a->CompareClassUuid(*b);
}
return rc;
}
static int ON__ClassIdDumpNode_CompareName( ON__ClassIdDumpNode *const* a, ON__ClassIdDumpNode *const* b )
{
int rc = 0;
if ( 0 == a )
{
rc = (0 == b) ? 0 : -1;
}
else if ( 0 == b )
{
rc = 1;
}
else
{
rc = (*a)->CompareClassName(*(*b));
}
return rc;
}
bool ON__ClassIdDumpNode::Dump( int depth, ON_TextLog& text_log )
{
bool rc = true;
if ( 0 == m_class_id || m_depth != 0 || depth < 1)
rc = false;
else
{
m_depth = depth;
const char* class_name = m_class_id->ClassName();
if ( 0 == class_name )
{
class_name = "!!ERROR!!";
rc = false;
}
text_log.Print("%s::ClassId: ",m_class_id->ClassName());
text_log.Print( "mark=%d ",m_class_id->Mark() );
text_log.Print( m_class_id->Uuid() );
text_log.Print(" (%08x)\n",m_class_id);
int i, count = m_child_nodes.Count();
if ( count > 0 )
{
// dump children names alphabetically
m_child_nodes.QuickSort( ON__ClassIdDumpNode_CompareName );
text_log.PushIndent();
for ( i = 0; i < count; i++ )
{
ON__ClassIdDumpNode* child_node = m_child_nodes[i];
if ( 0 == child_node )
rc = false;
else
{
if ( !child_node->Dump(depth+1,text_log) )
rc = false;
}
}
text_log.PopIndent();
}
}
return rc;
}
void ON_ClassId::Dump( ON_TextLog& dump )
{
int i, j, count = 0;
const ON_ClassId* p;
for(p = m_p0; p && count < 1000000; p = p->m_pNext)
{
count++;
}
if ( 0 != p )
{
dump.Print("ON_ClassId::m_p0 list is damaged.\n");
}
else
{
ON__ClassIdDumpNode tmp_node;
ON_ClassArray<ON__ClassIdDumpNode> nodes(count);
for(p = m_p0; p; p = p->m_pNext)
{
ON__ClassIdDumpNode& node = nodes.AppendNew();
node.m_class_id = p;
}
// sort nodes by class id's uuid
nodes.QuickSort(ON__ClassIdDumpNode_CompareUuid);
// fill in m_parent_node and m_child_nodes[]
for ( i = 0; i < count; i++ )
{
ON__ClassIdDumpNode& node = nodes[i];
p = node.m_class_id;
if ( 0 != p )
{
tmp_node.m_class_id = p->BaseClass();
j = nodes.BinarySearch(&tmp_node,ON__ClassIdDumpNode_CompareUuid);
if ( j >= 0 && i != j)
{
ON__ClassIdDumpNode& base_node = nodes[j];
node.m_parent_node = &base_node;
base_node.m_child_nodes.Append(&node);
}
}
}
// print class tree
tmp_node.m_class_id = &ON_CLASS_RTTI(ON_Object);
i = nodes.BinarySearch(&tmp_node,ON__ClassIdDumpNode_CompareUuid);
bool rc = false;
if ( i >= 0 )
{
// recursively dump class tree
rc = nodes[i].Dump(1,dump);
for ( i = 0; i < count && rc; i++ )
{
if ( nodes[i].m_depth <= 0 )
rc = false;
}
}
if (!rc)
{
// should never happen
for(p = m_p0; p; p = p->m_pNext)
{
dump.Print("%s::ClassId: ",p->m_sClassName);
dump.Print( "mark=%d ",p->m_mark );
dump.Print( p->m_uuid );
dump.Print(" (%08x)\n",p);
}
}
}
}
const char* ON_ClassId::ClassName() const
{
return m_sClassName;
}
const char* ON_ClassId::BaseClassName() const
{
return m_sBaseClassName;
}
ON_UUID ON_ClassId::Uuid() const
{
return m_uuid;
}
int ON_ClassId::Mark() const
{
return (m_mark & 0x7FFFFFFF);
}
unsigned int ON_ClassId::ClassIdVersion() const
{
return (0 != (m_mark & 0x80000000)) ? m_class_id_version : 0;
}
const ON_ClassId* ON_ClassId::BaseClass() const
{
return m_pBaseClassId;
}
bool ON_ClassId::IsDerivedFrom( const ON_ClassId* pBaseClassId ) const
{
// determine if this is derived from pBaseClassId
bool b = false;
if ( pBaseClassId ) {
const ON_ClassId* p = this;
for(;p;) {
if ( p == pBaseClassId ) {
b = true;
break;
}
p = p->m_pBaseClassId;
}
}
return b;
}
//////////////////////////////////////////////////////////////////////////////
ON_VIRTUAL_OBJECT_IMPLEMENT(ON_Object,0,"60B5DBBD-E660-11d3-BFE4-0010830122F0");
ON_Object::ON_Object() ON_NOEXCEPT
: m_userdata_list(0)
{}
ON_Object::ON_Object(const ON_Object& src)
: m_userdata_list(0)
{
this->CopyUserData(src);
}
ON_Object& ON_Object::operator=(const ON_Object& src)
{
// DO NOT MODIFY this->m_mempool here
if ( this != &src )
{
this->PurgeUserData();
this->CopyUserData(src);
}
return *this;
}
#if defined(ON_HAS_RVALUEREF)
ON_Object::ON_Object( ON_Object&& src ) ON_NOEXCEPT
: m_userdata_list(0)
{
this->MoveUserData(src);
}
ON_Object& ON_Object::operator=( ON_Object&& src )
{
if ( this != &src )
{
this->PurgeUserData();
this->MoveUserData(src);
}
return *this;
}
#endif
ON_Object::~ON_Object()
{
this->PurgeUserData();
}
// DO NOT PUT THIS DECL IN A HEADER FILE.
// THIS FUNCTION IS USED IN SPECIAL CIRCUMSTANCES
// AND IS NOT INTENDED TO BE CALLED.
ON_DECL bool ON__EnableLeakUserData(bool bEnable);
static bool g__bLeakUserData = false;
bool ON__EnableLeakUserData(bool bEnable)
{
bool b = bEnable;
g__bLeakUserData = bEnable ? true : false;
return b;
}
void ON_Object::EmergencyDestroy()
{
m_userdata_list = 0;
}
void ON_Object::PurgeUserData()
{
ON_UserData* p;
ON_UserData* next;
bool bDeleteUserData;
if ( 0 != (next=m_userdata_list) )
{
m_userdata_list = 0;
bDeleteUserData = !g__bLeakUserData;
while( 0 != (p=next) )
{
next = p->m_userdata_next;
p->m_userdata_owner = 0;
p->m_userdata_next = 0;
if ( bDeleteUserData )
delete p;
}
}
}
bool ON_Object::AttachUserData( ON_UserData* p )
{
bool rc = false;
if ( p
&& nullptr == p->m_userdata_owner
&& ON_UuidCompare( &ON_nil_uuid, &p->m_userdata_uuid)
&& nullptr == GetUserData( p->m_userdata_uuid )
) {
if ( p->IsUnknownUserData() ) {
// make sure we have valid user data - the first beta release of Rhino 2.0
// created empty user data.
ON_UnknownUserData* uud = ON_UnknownUserData::Cast(p);
if (uud)
rc = uud->IsValid();
if ( !rc ) {
ON_ERROR("ON_Object::AttachUserData() - attempt to attach invalid UnknownUserData.");
}
}
else
rc = true;
if (rc)
{
p->m_userdata_owner = this;
p->m_userdata_next = m_userdata_list;
m_userdata_list = p;
}
}
return rc;
}
bool ON_Object::DetachUserData( ON_UserData* p )
{
bool rc = false;
if ( p && p->m_userdata_owner == this )
{
ON_UserData* prev = 0;
ON_UserData* ud = m_userdata_list;
while ( ud )
{
if ( ud == p )
{
if ( prev )
prev->m_userdata_next = ud->m_userdata_next;
else
m_userdata_list = ud->m_userdata_next;
ud->m_userdata_owner = 0;
ud->m_userdata_next = 0;
rc = true;
break;
}
prev = ud;
ud = ud->m_userdata_next;
}
}
return rc;
}
ON_UserData* ON_Object::GetUserData( const ON_UUID& userdata_uuid ) const
{
ON_UserData* prev = nullptr;
ON_UserData* p;
for ( p = m_userdata_list; p; prev = p, p = p->m_userdata_next )
{
if ( !ON_UuidCompare( &p->m_userdata_uuid, &userdata_uuid ) )
{
if ( p->IsUnknownUserData() )
{
// See if we can convert this unknown user data into something useful.
// Unknown user data is created when a 3dm archive is read and
// the definition of the specific user data class is not loaded.
// If something is getting around to asking for a specific kind
// of user data, the class definition has probably be dynamically
// loaded.
ON_UnknownUserData* uud = ON_UnknownUserData::Cast(p);
if ( uud ) {
ON_UserData* realp = uud->Convert();
if ( realp )
{
// replace unknown user data with the real thing
if ( prev )
prev->m_userdata_next = realp;
else if ( p == m_userdata_list )
{
// little white lie to attach the "real" user
// data to the object in place of the unknown
// user data.
ON_Object* pNotConst = const_cast<ON_Object*>(this);
pNotConst->m_userdata_list = realp;
realp->m_userdata_owner = pNotConst; // Dale Lear added 22 Jan 2004 to fix I/O bug
}
realp->m_userdata_next = p->m_userdata_next;
p->m_userdata_next = 0;
p->m_userdata_owner = 0;
delete p;
p = realp;
}
}
}
break;
}
}
return p;
}
ON_UserData* ON_Object::FirstUserData() const
{
return m_userdata_list;
}
void ON_Object::TransformUserData( const ON_Xform& x )
{
ON_UserData *p, *next;
for ( p = m_userdata_list; p; p = next ) {
next = p->m_userdata_next;
if ( !p->Transform(x) )
delete p;
}
}
ON_UserData* ON_Object::TransferUserDataItem(
const ON_UserData* source_ud_copy_this,
ON_UserData* source_ud_move_this,
bool bPerformConflictCheck,
ON_Object::UserDataConflictResolution userdata_conflict_resolution
)
{
const ON_UserData* source_ud; // do not initialize so compiler will detect future bugs
if (nullptr != source_ud_move_this)
{
if (nullptr != source_ud_copy_this)
{
ON_ERROR("At most one source_ud pointer can be not null.");
return nullptr;
}
if (nullptr != source_ud_move_this->m_userdata_owner || nullptr != source_ud_move_this->m_userdata_next)
{
ON_ERROR("Cannot move userdata that is attached to another object.");
return nullptr;
}
source_ud = source_ud_move_this;
}
else if ( nullptr != source_ud_copy_this )
{
if (this == source_ud_copy_this->m_userdata_owner)
{
ON_ERROR("source_ud_copy_this is already attached to this object.");
return nullptr;
}
source_ud = source_ud_copy_this;
}
else
{
// nothing to do
return nullptr;
}
if (source_ud->IsUnknownUserData())
{
// make sure we have valid user data - the first beta release of Rhino 2.0
// created empty user data.
const ON_UnknownUserData* uud = ON_UnknownUserData::Cast(source_ud);
if (nullptr == uud && false == uud->IsValid())
{
return nullptr;
}
}
ON_UserData* dest_ud = bPerformConflictCheck ? GetUserData(source_ud->m_userdata_uuid) : nullptr;
bool bDeleteDestinationItem = false;
bool bTransferSourceItem; // no initialization
if (nullptr == dest_ud)
{
bTransferSourceItem = true;
}
else
{
switch (userdata_conflict_resolution)
{
case ON_Object::UserDataConflictResolution::destination_object:
bTransferSourceItem = false;
break;
case ON_Object::UserDataConflictResolution::source_object:
bTransferSourceItem = true;
break;
case ON_Object::UserDataConflictResolution::source_copycount_gt:
bTransferSourceItem = (source_ud->m_userdata_copycount > dest_ud->m_userdata_copycount);
break;
case ON_Object::UserDataConflictResolution::source_copycount_ge:
bTransferSourceItem = (source_ud->m_userdata_copycount >= dest_ud->m_userdata_copycount);
break;
case ON_Object::UserDataConflictResolution::destination_copycount_gt:
bTransferSourceItem = (dest_ud->m_userdata_copycount > source_ud->m_userdata_copycount);
break;
case ON_Object::UserDataConflictResolution::destination_copycount_ge:
bTransferSourceItem = (dest_ud->m_userdata_copycount >= source_ud->m_userdata_copycount);
break;
case ON_Object::UserDataConflictResolution::delete_item:
bTransferSourceItem = false;
bDeleteDestinationItem = true;
break;
default:
bTransferSourceItem = false;
break;
}
}
if (false == bTransferSourceItem)
{
if (bDeleteDestinationItem && nullptr != dest_ud)
{
delete dest_ud;
}
return nullptr;
}
if (nullptr != source_ud_copy_this)
{
ON_Object* p = source_ud_copy_this->Duplicate();
if ( nullptr == p )
return nullptr;
source_ud_move_this = ON_UserData::Cast(p);
if (nullptr == source_ud_move_this)
{
delete p;
return nullptr;
}
source_ud_move_this->m_userdata_owner = nullptr;
}
if (nullptr == source_ud_move_this)
{
ON_ERROR("Bug in the code above.");
return nullptr;
}
if (nullptr != dest_ud)
{
delete dest_ud;
}
source_ud_move_this->m_userdata_owner = this;
source_ud_move_this->m_userdata_next = m_userdata_list;
m_userdata_list = source_ud_move_this;
return m_userdata_list;
};
unsigned int ON_Object::CopyUserData(
const ON_Object& source_object,
ON_UUID source_userdata_item_id,
ON_Object::UserDataConflictResolution userdata_conflict_resolution
)
{
unsigned int copied_item_count = 0;
if (this == &source_object)
return copied_item_count;
const bool bPerformConflictCheck = (nullptr != m_userdata_list);
const bool bIgnoreUserDataItemId = (ON_nil_uuid == source_userdata_item_id);
for (const ON_UserData* source_ud = source_object.m_userdata_list; nullptr != source_ud; source_ud = source_ud->m_userdata_next)
{
if (source_ud->m_userdata_copycount <= 0)
continue;
if (bIgnoreUserDataItemId || source_ud->m_userdata_uuid == source_userdata_item_id)
{
if (nullptr != TransferUserDataItem(source_ud, nullptr, bPerformConflictCheck, userdata_conflict_resolution))
copied_item_count++;
}
}
return copied_item_count;
}
unsigned int ON_Object::MoveUserData(
ON_Object& source_object,
ON_UUID source_userdata_item_id,
ON_Object::UserDataConflictResolution userdata_conflict_resolution,
bool bDeleteAllSourceItems)
{
unsigned int moved_item_count = 0;
const bool bIgnoreUserDataItemId = (ON_nil_uuid == source_userdata_item_id);
if ( nullptr == m_userdata_list && bIgnoreUserDataItemId )
{
// quick and simple when the "this" doesn't
// have any user data.
if ( nullptr != source_object.m_userdata_list )
{
m_userdata_list = source_object.m_userdata_list;
source_object.m_userdata_list = nullptr;
for (ON_UserData* dest_ud = m_userdata_list; nullptr != dest_ud; dest_ud = dest_ud->m_userdata_next)
{
dest_ud->m_userdata_owner = this;
moved_item_count++;
}
}
}
else
{
// Carefully move userdata an item at a time from source_object to "this"
const bool bPerformConflictCheck = true;
ON_UserData* source_ud_next = source_object.m_userdata_list;
source_object.m_userdata_list = nullptr;
ON_UserData* source_object_userdata_last = nullptr;
for ( ON_UserData* source_ud = source_ud_next; nullptr != source_ud; source_ud = source_ud_next)
{
source_ud_next = source_ud->m_userdata_next;
source_ud->m_userdata_next = nullptr;
source_ud->m_userdata_owner = nullptr;
if (bIgnoreUserDataItemId || source_ud->m_userdata_uuid == source_userdata_item_id)
{
if (TransferUserDataItem(nullptr, source_ud, bPerformConflictCheck, userdata_conflict_resolution))
{
moved_item_count++;
continue;
}
}
// The transfer did not occur. Resolve state of orphaned source_ud.
if (nullptr != source_ud->m_userdata_owner || nullptr != source_ud->m_userdata_next)
{
ON_ERROR("There is a serious bug in this code.");
continue;
}
if (bDeleteAllSourceItems)
{
// delete the orphan
delete source_ud;
}
else
{
// reattach the orphan to source_object
source_ud->m_userdata_owner = &source_object;
if (nullptr == source_object.m_userdata_list)
{
source_object.m_userdata_list = source_ud;
}
else if (nullptr != source_object_userdata_last)
{
source_object_userdata_last->m_userdata_next = source_ud;
}
source_object_userdata_last = source_ud;
}
}
}
return moved_item_count;
}
void ON_Object::CopyUserData( const ON_Object& src )
{
CopyUserData(src,ON_nil_uuid,ON_Object::UserDataConflictResolution::destination_object);
}
void ON_Object::MoveUserData( ON_Object& src )
{
MoveUserData(src,ON_nil_uuid,ON_Object::UserDataConflictResolution::destination_object,true);
}
bool ON_Object::UpdateReferencedComponents(
const class ON_ComponentManifest& source_manifest,
const class ON_ComponentManifest& destination_manifest,
const class ON_ManifestMap& manifest_map
)
{
return true;
}
void ON_Object::MemoryRelocate()
{
// When the memory location of an ON_Object changes,
// the back-pointers on its user data need to be updated.
ON_UserData* ud;
for ( ud = m_userdata_list; ud; ud = ud->m_userdata_next )
{
ud->m_userdata_owner = this;
}
}
bool ON_Object::IsKindOf( const ON_ClassId* pBaseClassId ) const
{
bool b = false;
const ON_ClassId* p = ClassId();
if ( p )
b = p->IsDerivedFrom( pBaseClassId );
return b;
}
ON::object_type ON_Object::ObjectType() const
{
// virtual function that is generally overridden
return ON::unknown_object_type;
}
ON_UUID ON_Object::ModelObjectId() const
{
return ON_nil_uuid;
}
ON_UUID ON_Light::ModelObjectId() const
{
return m_light_id;
}
unsigned int ON_Object::SizeOf() const
{
unsigned int sz = sizeof(*this);
const ON_UserData* ud = m_userdata_list;
while ( ud )
{
sz += ud->SizeOf();
ud = ud->m_userdata_next;
}
return sz;
}
ON__UINT32 ON_Object::DataCRC(ON__UINT32 current_remainder) const
{
// do not include user data.
return current_remainder;
}
bool ON_Object::IsValid(ON_TextLog* text_log) const
{
return true;
}
bool ON_Object::ThisIsNullptr(
bool bSilentError
) const
{
// CLang warns that these tests may be ommitted because in "well-defined C++ code"
// they are always false.
//
// Earth to CLang:
// This tool to find code that is not well formed, alert us to that fact,
// but not potentiall not crash so our loyal customers don't loose their work.
//
// return (this == nullptr);
// return ( nullptr == this );
if (0 != ((ON__UINT_PTR)this))
return false;
if (false == bSilentError)
ON_ERROR("this is nullptr.");
return true;
}
bool ON_Object::IsCorrupt(
bool bRepair,
bool bSilentError,
class ON_TextLog* text_log
) const
{
bool rc = true;
if (false == ThisIsNullptr(bSilentError) )
{
switch (ObjectType())
{
case ON::object_type::brep_object:
{
const ON_Brep* brep = ON_Brep::Cast(this);
if (brep)
rc = brep->ON_Brep::IsCorrupt(bRepair, bSilentError, text_log);
else if ( false == bSilentError )
ON_ERROR("ON_Brep::Cast(this) failed.");
}
break;
case ON::object_type::mesh_object:
{
const ON_Mesh* mesh = ON_Mesh::Cast(this);
if (mesh)
rc = mesh->ON_Mesh::IsCorrupt(bRepair, bSilentError, text_log);
else if ( false == bSilentError )
ON_ERROR("ON_Mesh::Cast(this) failed.");
}
break;
default:
rc = false;
break;
}
}
return rc;
}
void ON_Object::Dump( ON_TextLog& dump ) const
{
const ON_ClassId* p = ClassId();
if ( p )
{
const char* class_name = p->ClassName();
if ( 0 == class_name )
class_name = "unknown";
dump.Print("class name: %s\n",class_name);
dump.Print("class uuid: ");
dump.Print(p->Uuid());
dump.Print("\n");
}
else
{
dump.Print("ON_Object::ClassId() FAILED\n");
}
}
bool ON_Object::Write(
ON_BinaryArchive&
) const
{
// default Write() does nothing.
return false;
// object derived from ON_Object should have a Write() that looks
// something like
/*
bool rc = file.Write3dmChunkVersion(1,0);
if (rc) {
// TODO
}
return rc;
*/
}
bool ON_Object::Read(
ON_BinaryArchive&
)
{
// default Read() does nothing.
return false;
// object derived from ON_Object should have a Read() that looks
// something like
/*
int major_version = 0;
int minor_version = 0;
bool rc = file.Read3dmChunkVersion(&major_version,&minor_version);
if (rc && major_version==1) {
// common to all 1.x versions
// TODO
}
return rc;
*/
}
void ON_Object::DestroyRuntimeCache( bool bDelete )
{
}
void ON_Curve::DestroyRuntimeCache( bool bDelete )
{
}
void ON_CurveProxy::DestroyRuntimeCache( bool bDelete )
{
ON_Curve::DestroyRuntimeCache(bDelete);
if ( 0 != m_real_curve && m_real_curve != this )
{
ON_Curve* curve = const_cast<ON_Curve*>(m_real_curve);
if ( 0 != curve )
curve->DestroyRuntimeCache( bDelete );
}
}
void ON_Surface::DestroyRuntimeCache( bool bDelete )
{
}
void ON_SurfaceProxy::DestroyRuntimeCache( bool bDelete )
{
ON_Surface::DestroyRuntimeCache( bDelete );
if ( 0 != m_surface && m_surface != this )
{
ON_Surface* surface = const_cast<ON_Surface*>(m_surface);
if ( 0 != surface )
surface->DestroyRuntimeCache( bDelete );
}
}
void ON_Brep::DestroyRuntimeCache( bool bDelete )
{
int i, count;
count = m_C2.Count();
for ( i = 0; i < count; i++ )
{
if ( m_C2[i] )
m_C2[i]->DestroyRuntimeCache(bDelete);
}
count = m_C3.Count();
for ( i = 0; i < count; i++ )
{
if ( m_C3[i] )
m_C3[i]->DestroyRuntimeCache(bDelete);
}
count = m_S.Count();
for ( i = 0; i < count; i++ )
{
if ( m_S[i] )
m_S[i]->DestroyRuntimeCache(bDelete);
}
count = m_T.Count();
for ( i = 0; i < count; i++ )
{
m_T[i].DestroyRuntimeCache(bDelete);
}
count = m_E.Count();
for ( i = 0; i < count; i++ )
{
m_E[i].DestroyRuntimeCache(bDelete);
}
count = m_F.Count();
for ( i = 0; i < count; i++ )
{
m_F[i].DestroyRuntimeCache(bDelete);
}
// 15 August 2003 Dale Lear:
// I added the line to destroy the face's m_bbox.
// Since m_bbox is private, it will be recalculated
// when it is needed. (We hope.) The fact the face
// m_bbox is private and recalculated as needed makes
// it different than the m_pbox info on trims and loops.
m_bbox.Destroy();
}
template <class T> class ON_ArrayIterator
{
public:
ON_ArrayIterator() = default;
~ON_ArrayIterator() = default;
ON_ArrayIterator(const ON_ArrayIterator<T>&) = default;
ON_ArrayIterator& operator=(const ON_ArrayIterator<T>&) = default;
ON_ArrayIterator(
T* first,
size_t count
)
{
m_first = (count > 0) ? first : nullptr;
m_last = (nullptr != m_first) ? (m_first+(count-1)) : nullptr;
m_current = m_first;
}
ON_ArrayIterator(
T* first,
T* last
)
{
m_first = (nullptr != first && first <= last) ? first : nullptr;
m_last = (nullptr != m_first) ? last : nullptr;
m_current = m_first;
}
ON_ArrayIterator(
ON_SimpleArray < T >& a
)
{
unsigned int count = a.UnsignedCount();
T* first = a.Array();
m_first = (count > 0) ? first : nullptr;
m_last = (nullptr != m_first) ? (m_first+(count-1)) : nullptr;
m_current = m_first;
}
ON_ArrayIterator(
ON_ClassArray < T >& a
)
{
unsigned int count = a.UnsignedCount();
T* first = a.Array();
m_first = (count > 0) ? first : nullptr;
m_last = (nullptr != m_first) ? (m_first+(count-1)) : nullptr;
m_current = m_first;
}
ON_ArrayIterator(
ON_ObjectArray < T >& a
)
{
unsigned int count = a.UnsignedCount();
T* first = a.Array();
m_first = (count > 0) ? first : nullptr;
m_last = (nullptr != m_first) ? (m_first+(count-1)) : nullptr;
m_current = m_first;
}
T* First()
{
m_current = m_first;
return m_first;
}
T* Next()
{
if (m_current < m_last)
m_current++;
else
m_current = nullptr;
return m_current;
}
T* Current() const
{
return m_current;
}
size_t Count() const
{
return (m_last - m_first);
}
private:
T* m_first = nullptr;
T* m_last = nullptr;
T* m_current = nullptr;
};
//virtual
unsigned int ON_Brep::ClearComponentStates(
ON_ComponentStatus states_to_clear
) const
{
if (states_to_clear.IsClear())
return 0U;
m_aggregate_status = ON_AggregateComponentStatus::NotCurrent;
unsigned int rc = 0;
ON_ArrayIterator< const ON_BrepVertex > vit( m_V.Array(), m_V.UnsignedCount() );
for ( const ON_BrepVertex* p = vit.First(); nullptr != p; p = vit.Next())
{
rc += p->m_status.ClearStates(states_to_clear);
}
ON_ArrayIterator< const ON_BrepEdge > eit( m_E.Array(), m_E.UnsignedCount() );
for ( const ON_BrepEdge* p = eit.First(); nullptr != p; p = eit.Next())
{
rc += p->m_status.ClearStates(states_to_clear);
}
ON_ArrayIterator< const ON_BrepTrim > tit( m_T.Array(), m_T.UnsignedCount() );
for ( const ON_BrepTrim* p = tit.First(); nullptr != p; p = tit.Next())
{
rc += p->m_status.ClearStates(states_to_clear);
}
ON_ArrayIterator< const ON_BrepLoop > lit( m_L.Array(), m_L.UnsignedCount() );
for ( const ON_BrepLoop* p = lit.First(); nullptr != p; p = lit.Next())
{
rc += p->m_status.ClearStates(states_to_clear);
}
ON_ArrayIterator< const ON_BrepFace > fit( m_F.Array(), m_F.UnsignedCount() );
for ( const ON_BrepFace* p = fit.First(); nullptr != p; p = fit.Next())
{
rc += p->m_status.ClearStates(states_to_clear);
}
return rc;
}
//virtual
unsigned int ON_Brep::GetComponentsWithSetStates(
ON_ComponentStatus states_filter,
bool bAllEqualStates,
ON_SimpleArray< ON_COMPONENT_INDEX >& components
) const
{
components.SetCount(0);
if (states_filter.IsClear())
return 0;
ON_AggregateComponentStatus acs = AggregateComponentStatus();
ON_ComponentStatus as = acs.AggregateStatus();
if (bAllEqualStates)
{
if ( false == as.AllEqualStates(states_filter, states_filter) )
return 0;
}
else
{
if ( false == as.SomeEqualStates(states_filter, states_filter) )
return 0;
}
unsigned int c = 0;
if ( states_filter.IsSelected() && c < m_aggregate_status.SelectedCount() )
c = m_aggregate_status.SelectedCount();
if ( states_filter.IsHighlighted() && c < m_aggregate_status.HighlightedCount() )
c = m_aggregate_status.HighlightedCount();
if ( states_filter.IsHidden() && c < m_aggregate_status.HiddenCount() )
c = m_aggregate_status.HiddenCount();
if ( states_filter.IsLocked() && c < m_aggregate_status.LockedCount() )
c = m_aggregate_status.LockedCount();
if ( states_filter.IsDamaged() && c < m_aggregate_status.DamagedCount() )
c = m_aggregate_status.DamagedCount();
if ( states_filter.IsSelected() && c < m_aggregate_status.SelectedCount() )
c = m_aggregate_status.SelectedCount();
components.Reserve(c);
ON_ArrayIterator< const ON_BrepVertex > vit( m_V.Array(), m_V.UnsignedCount() );
for ( const ON_BrepVertex* p = vit.First(); nullptr != p; p = vit.Next())
{
if (bAllEqualStates ? p->m_status.AllEqualStates(states_filter, states_filter) : p->m_status.SomeEqualStates(states_filter, states_filter))
components.Append(p->ComponentIndex());
}
ON_ArrayIterator< const ON_BrepEdge > eit( m_E.Array(), m_E.UnsignedCount() );
for ( const ON_BrepEdge* p = eit.First(); nullptr != p; p = eit.Next())
{
if (bAllEqualStates ? p->m_status.AllEqualStates(states_filter, states_filter) : p->m_status.SomeEqualStates(states_filter, states_filter))
components.Append(p->ComponentIndex());
}
ON_ArrayIterator< const ON_BrepTrim > tit( m_T.Array(), m_T.UnsignedCount() );
for ( const ON_BrepTrim* p = tit.First(); nullptr != p; p = tit.Next())
{
if (bAllEqualStates ? p->m_status.AllEqualStates(states_filter, states_filter) : p->m_status.SomeEqualStates(states_filter, states_filter))
components.Append(p->ComponentIndex());
}
ON_ArrayIterator< const ON_BrepLoop > lit( m_L.Array(), m_L.UnsignedCount() );
for ( const ON_BrepLoop* p = lit.First(); nullptr != p; p = lit.Next())
{
if (bAllEqualStates ? p->m_status.AllEqualStates(states_filter, states_filter) : p->m_status.SomeEqualStates(states_filter, states_filter))
components.Append(p->ComponentIndex());
}
ON_ArrayIterator< const ON_BrepFace > fit( m_F.Array(), m_F.UnsignedCount() );
for ( const ON_BrepFace* p = fit.First(); nullptr != p; p = fit.Next())
{
if (bAllEqualStates ? p->m_status.AllEqualStates(states_filter, states_filter) : p->m_status.SomeEqualStates(states_filter, states_filter))
components.Append(p->ComponentIndex());
}
return components.UnsignedCount();
}
static ON_ComponentStatus* BrepComponentStatus(
const ON_Brep& brep,
ON_COMPONENT_INDEX component_index
)
{
if (component_index.m_index >= 0)
{
switch (component_index.m_type)
{
case ON_COMPONENT_INDEX::TYPE::brep_vertex:
if ( component_index.m_index < brep.m_V.Count() )
return &brep.m_V[component_index.m_index].m_status;
break;
case ON_COMPONENT_INDEX::TYPE::brep_edge:
if ( component_index.m_index < brep.m_E.Count() )
return &brep.m_E[component_index.m_index].m_status;
break;
case ON_COMPONENT_INDEX::TYPE::brep_trim:
if ( component_index.m_index < brep.m_T.Count() )
return &brep.m_T[component_index.m_index].m_status;
break;
case ON_COMPONENT_INDEX::TYPE::brep_loop:
if ( component_index.m_index < brep.m_L.Count() )
return &brep.m_L[component_index.m_index].m_status;
break;
case ON_COMPONENT_INDEX::TYPE::brep_face:
if ( component_index.m_index < brep.m_F.Count() )
return &brep.m_F[component_index.m_index].m_status;
break;
}
}
return nullptr;
}
//virtual
unsigned int ON_Brep::SetComponentStates(
ON_COMPONENT_INDEX component_index,
ON_ComponentStatus states_to_set
) const
{
ON_ComponentStatus* s = BrepComponentStatus(*this,component_index);
return
(nullptr == s)
? 0U
: s->SetStates(states_to_set);
}
//virtual
unsigned int ON_Brep::ClearComponentStates(
ON_COMPONENT_INDEX component_index,
ON_ComponentStatus states_to_clear
) const
{
ON_ComponentStatus* s = BrepComponentStatus(*this,component_index);
return
(nullptr == s)
? 0U
: s->ClearStates(states_to_clear);
}
//virtual
unsigned int ON_Brep::SetComponentStatus(
ON_COMPONENT_INDEX component_index,
ON_ComponentStatus status_to_copy
) const
{
ON_ComponentStatus* s = BrepComponentStatus(*this,component_index);
return
(nullptr == s)
? 0U
: s->SetStatus(status_to_copy);
}
//virtual
ON_AggregateComponentStatus ON_Brep::AggregateComponentStatus() const
{
if (false == m_aggregate_status.IsCurrent())
{
if (m_V.UnsignedCount() == 0 )
return ON_AggregateComponentStatus::Empty;
ON_AggregateComponentStatus a = ON_AggregateComponentStatus::Empty;
ON_ArrayIterator< const ON_BrepVertex > vit( m_V.Array(), m_V.UnsignedCount() );
for ( const ON_BrepVertex* p = vit.First(); nullptr != p; p = vit.Next())
{
a.Add(p->m_status);
}
ON_ArrayIterator< const ON_BrepEdge > eit( m_E.Array(), m_E.UnsignedCount() );
for ( const ON_BrepEdge* p = eit.First(); nullptr != p; p = eit.Next())
{
a.Add(p->m_status);
}
ON_ArrayIterator< const ON_BrepTrim > tit( m_T.Array(), m_T.UnsignedCount() );
for ( const ON_BrepTrim* p = tit.First(); nullptr != p; p = tit.Next())
{
a.Add(p->m_status);
}
ON_ArrayIterator< const ON_BrepLoop > lit( m_L.Array(), m_L.UnsignedCount() );
for ( const ON_BrepLoop* p = lit.First(); nullptr != p; p = lit.Next())
{
a.Add(p->m_status);
}
ON_ArrayIterator< const ON_BrepFace > fit( m_F.Array(), m_F.UnsignedCount() );
for ( const ON_BrepFace* p = fit.First(); nullptr != p; p = fit.Next())
{
a.Add(p->m_status);
}
m_aggregate_status = a;
}
return m_aggregate_status;
}
//virtual
void ON_Brep::MarkAggregateComponentStatusAsNotCurrent() const
{
this->m_aggregate_status.MarkAsNotCurrent();
}