Files
opennurbs/opennurbs_subd_copy.cpp
Bozo The Builder e7c29061e3 Sync changes from upstream repository
Co-authored-by: Alain <alain@mcneel.com>
Co-authored-by: Andrew Le Bihan <andy@mcneel.com>
Co-authored-by: chuck <chuck@mcneel.com>
Co-authored-by: croudyj <croudyj@gmail.com>
Co-authored-by: Dale Fugier <dale@mcneel.com>
Co-authored-by: Giulio Piacentino <giulio@mcneel.com>
Co-authored-by: Greg Arden <greg@mcneel.com>
Co-authored-by: Jussi Aaltonen <jussi@mcneel.com>
Co-authored-by: kike-garbo <kike@mcneel.com>
Co-authored-by: Steve Baer <steve@mcneel.com>
2022-11-21 14:18:57 -08:00

1215 lines
39 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
#include "opennurbs_subd_data.h"
unsigned int ON_SubDArchiveIdMap::ArchiveIdFromComponentPtr(ON__UINT_PTR ptr)
{
return (unsigned int)(ptr/(ON_SUBD_COMPONENT_FLAGS_MASK+1));
}
const ON_SubDComponentPtr ON_SubDArchiveIdMap::FromVertex(
const ON_SubDVertex* vertex
)
{
ON__UINT_PTR archive_id = (nullptr == vertex) ? 0 : vertex->ArchiveId();
return ON_SubDComponentPtr::Create((const ON_SubDVertex*)(archive_id*(ON_SUBD_COMPONENT_FLAGS_MASK+1)));
}
const ON_SubDComponentPtr ON_SubDArchiveIdMap::FromEdge(
const ON_SubDEdge* edge
)
{
ON__UINT_PTR archive_id = (nullptr == edge) ? 0 : edge->ArchiveId();
return ON_SubDComponentPtr::Create((const ON_SubDEdge*)(archive_id*(ON_SUBD_COMPONENT_FLAGS_MASK+1)));
}
const ON_SubDComponentPtr ON_SubDArchiveIdMap::FromFace(
const ON_SubDFace* face
)
{
ON__UINT_PTR archive_id = (nullptr == face) ? 0 : face->ArchiveId();
return ON_SubDComponentPtr::Create((const ON_SubDFace*)(archive_id*(ON_SUBD_COMPONENT_FLAGS_MASK+1)));
}
const ON_SubDComponentPtr ON_SubDArchiveIdMap::FromVertex(
ON_SubDVertexPtr vertex_ptr
)
{
ON_SubDComponentPtr ptr = FromVertex(vertex_ptr.Vertex());
ptr.m_ptr |= vertex_ptr.VertexDirection();
return ptr;
}
const ON_SubDComponentPtr ON_SubDArchiveIdMap::FromEdge(
ON_SubDEdgePtr edge_ptr
)
{
ON_SubDComponentPtr ptr = FromEdge(edge_ptr.Edge());
ptr.m_ptr |= edge_ptr.EdgeDirection();
return ptr;
}
const ON_SubDComponentPtr ON_SubDArchiveIdMap::FromFace(
ON_SubDFacePtr face_ptr
)
{
ON_SubDComponentPtr ptr = FromFace(face_ptr.Face());
ptr.m_ptr |= face_ptr.FaceDirection();
return ptr;
}
const ON_SubDComponentPtr ON_SubDArchiveIdMap::FromSymmetrySetNext(
ON_SubDComponentPtr::Type component_type,
const ON_SubDComponentBase* component
)
{
if (nullptr == component)
return ON_SubDComponentPtr::Null;
ON_SubDComponentPtr cptr;
switch (component_type)
{
case ON_SubDComponentPtr::Type::Vertex:
cptr = ON_SubDArchiveIdMap::FromVertex(component->m_symmetry_set_next.Vertex());
break;
case ON_SubDComponentPtr::Type::Edge:
cptr = ON_SubDArchiveIdMap::FromEdge(component->m_symmetry_set_next.Edge());
break;
case ON_SubDComponentPtr::Type::Face:
cptr = ON_SubDArchiveIdMap::FromFace(component->m_symmetry_set_next.Face());
break;
case ON_SubDComponentPtr::Type::Unset:
default:
return ON_SubDComponentPtr::Null;
break;
}
return (1 == component->m_symmetry_set_next.ComponentDirection() && component->m_symmetry_set_next.IsNotNull()) ? cptr.SetComponentDirection() : cptr;
}
ON_SubDVertex* ON_SubDArchiveIdMap::CopyVertex(
const ON_SubDVertex* source_vertex,
class ON_SubDimple& subdimple
)
{
if ( nullptr == source_vertex )
return ON_SUBD_RETURN_ERROR(nullptr);
ON_SubDVertex* vertex = subdimple.AllocateVertex(
source_vertex->m_id,
source_vertex->m_vertex_tag,
source_vertex->m_level,
source_vertex->m_P,
source_vertex->m_edge_count,
source_vertex->m_face_count
);
if ( nullptr == vertex )
return ON_SUBD_RETURN_ERROR(nullptr);
const bool bCopyEdgeArray = true;
const bool bCopyFaceArray = true;
const bool bCopyLimitPointList = true;
const bool bCopySymmetrySetNext = true;
vertex->CopyFrom(source_vertex,bCopyEdgeArray,bCopyFaceArray,bCopyLimitPointList, bCopySymmetrySetNext);
// convert vertex->m_edges[] pointers to archive_id values
ON_SubDComponentPtr ptr;
for (unsigned int vei = 0; vei < vertex->m_edge_count; vei++)
{
ptr = ON_SubDArchiveIdMap::FromEdge(vertex->m_edges[vei]);
vertex->m_edges[vei].m_ptr = ptr.m_ptr;
}
// convert vertex->m_faces[] pointers to archive_id values
for (unsigned int vfi = 0; vfi < vertex->m_face_count; vfi++)
{
ptr = ON_SubDArchiveIdMap::FromFace(vertex->m_faces[vfi]);
vertex->m_faces[vfi] = (const ON_SubDFace*)ptr.m_ptr;
}
// convert vertex->m_limit_point[].m_sector_face pointers to archive_id values
for (const ON_SubDSectorSurfacePoint* p = &vertex->m_limit_point; nullptr != p; p = p->m_next_sector_limit_point)
{
ptr = ON_SubDArchiveIdMap::FromFace(p->m_sector_face);
const_cast<ON_SubDSectorSurfacePoint*>(p)->m_sector_face = (const ON_SubDFace*)ptr.m_ptr;
}
// convert symmetry set next pointers to archive_id values
vertex->m_symmetry_set_next = ON_SubDArchiveIdMap::FromSymmetrySetNext(ON_SubDComponentPtr::Type::Vertex, vertex);
return vertex;
}
ON_SubDEdge* ON_SubDArchiveIdMap::CopyEdge(
const ON_SubDEdge* source_edge,
class ON_SubDimple& subdimple
)
{
if ( nullptr == source_edge )
return ON_SUBD_RETURN_ERROR(nullptr);
ON_SubDEdge* edge = subdimple.AllocateEdge(
source_edge->m_id,
source_edge->m_edge_tag,
source_edge->m_level,
source_edge->m_face_count);
if ( nullptr == edge )
return ON_SUBD_RETURN_ERROR(nullptr);
const bool bReverseEdge = false;
const bool bCopyVertexArray = true;
const bool bCopyEdgeArray = true;
const bool bCopySymmetryLoop = true;
edge->CopyFrom(source_edge,bReverseEdge,bCopyVertexArray,bCopyEdgeArray, bCopySymmetryLoop);
// convert edge->m_vertex[] pointers to archive_id values
ON_SubDComponentPtr ptr;
for (unsigned int evi = 0; evi < 2; evi++)
{
ptr = ON_SubDArchiveIdMap::FromVertex(edge->m_vertex[evi]);
edge->m_vertex[evi] = (const ON_SubDVertex*)ptr.m_ptr;
}
// convert edge->m_faces[] pointers to archive_id values
ON_SubDFacePtr* fptr = edge->m_face2;
for (unsigned int efi = 0; efi < edge->m_face_count; efi++, fptr++)
{
if (2 == efi)
fptr = edge->m_facex;
fptr->m_ptr = ON_SubDArchiveIdMap::FromFace(*fptr).m_ptr;
}
// convert symmetry set next pointers to archive_id values
edge->m_symmetry_set_next = ON_SubDArchiveIdMap::FromSymmetrySetNext(ON_SubDComponentPtr::Type::Edge, edge);
return edge;
}
ON_SubDFace* ON_SubDArchiveIdMap::CopyFace(
const ON_SubDFace* source_face,
class ON_SubDimple& subdimple
)
{
if ( nullptr == source_face )
return ON_SUBD_RETURN_ERROR(nullptr);
ON_SubDFace* face = subdimple.AllocateFace( source_face->m_id, source_face->m_level,source_face->m_edge_count, source_face->TexturePointsAreSet());
if ( nullptr == face )
return ON_SUBD_RETURN_ERROR(nullptr);
const bool bCopyEdgeArray = true;
const bool bCopySymmetryLoop = true;
face->CopyFrom(source_face,bCopyEdgeArray, bCopySymmetryLoop);
// convert face->m_edges[] pointers to archive_id values
ON_SubDEdgePtr* eptr = face->m_edge4;
for (unsigned int fei = 0; fei < face->m_edge_count; fei++, eptr++)
{
if (4 == fei)
eptr = face->m_edgex;
eptr->m_ptr = ON_SubDArchiveIdMap::FromEdge(*eptr).m_ptr;
}
// convert symmetry set next pointers to archive_id values
face->m_symmetry_set_next = ON_SubDArchiveIdMap::FromSymmetrySetNext(ON_SubDComponentPtr::Type::Face, face);
return face;
}
bool ON_SubDArchiveIdMap::ConvertArchiveIdToRuntimeVertexPtr(
unsigned int vertex_count,
size_t vertex_capacity,
ON_SubDVertex** vertex
)
{
if ( 0 == vertex_count )
return true;
if ( 0 == vertex_capacity || nullptr == vertex )
return ON_SUBD_RETURN_ERROR(false);
if ( vertex_count > vertex_capacity )
return ON_SUBD_RETURN_ERROR(false);
for (unsigned int i = 0; i < vertex_count; i++)
{
ON__UINT_PTR vptr = (ON__UINT_PTR)(vertex[i]);
vertex[i] = nullptr;
const unsigned int archive_id = ON_SubDArchiveIdMap::ArchiveIdFromComponentPtr(vptr);
// future use // ON__UINT_PTR flags = ON_SUBD_COMPONENT_FLAGS(vptr);
if (0 == archive_id || archive_id < m_archive_id_partition[0] || archive_id >= m_archive_id_partition[1])
{
ON_ERROR("Invalid vertex archive id.");
continue;
}
const ON_SubDComponentPtr* eleptr = ComponentPtrFromArchiveId(archive_id);
if (nullptr == eleptr)
{
ON_ERROR("null element pointer.");
continue;
}
ON_SubDVertex* v = eleptr->Vertex();
if (nullptr == v)
{
ON_ERROR("null vertex pointer.");
continue;
}
if (archive_id != v->ArchiveId())
{
ON_ERROR("archive_id != v->ArchiveId().");
continue;
}
vertex[i] = v;
}
return true;
}
bool ON_SubDArchiveIdMap::ConvertArchiveIdToRuntimeEdgePtr(
unsigned int edge_count,
size_t edgeN_capacity,
ON_SubDEdgePtr* edgeN,
unsigned int edgeX_capacity,
ON_SubDEdgePtr* edgeX
)
{
if ( 0 == edge_count )
return true;
if ( 0 == edgeN_capacity || nullptr == edgeN )
return ON_SUBD_RETURN_ERROR(false);
if ( 0 != edgeX_capacity && nullptr == edgeX )
return ON_SUBD_RETURN_ERROR(false);
if ( edge_count > edgeN_capacity + edgeX_capacity )
return ON_SUBD_RETURN_ERROR(false);
ON_SubDEdgePtr* eptr = edgeN;
for (unsigned int i = 0; i < edge_count; i++, eptr++)
{
if ( i == edgeN_capacity )
eptr = edgeX;
const unsigned int archive_id = ON_SubDArchiveIdMap::ArchiveIdFromComponentPtr(eptr->m_ptr);
ON__UINT_PTR flags = ON_SUBD_COMPONENT_FLAGS(eptr->m_ptr);
eptr->m_ptr = 0;
if (0 == archive_id || archive_id < m_archive_id_partition[1] || archive_id >= m_archive_id_partition[2])
{
ON_ERROR("Invalid edge archive id.");
continue;
}
const ON_SubDComponentPtr* eleptr = ComponentPtrFromArchiveId(archive_id);
if (nullptr == eleptr)
{
ON_ERROR("null element pointer.");
continue;
}
ON_SubDEdge* edge = eleptr->Edge();
if (nullptr == edge)
{
ON_ERROR("null edge pointer.");
continue;
}
if (archive_id != edge->ArchiveId())
{
ON_ERROR("archive_id != edge->ArchiveId().");
continue;
}
*eptr = ON_SubDEdgePtr::Create(edge,ON_SUBD_COMPONENT_DIRECTION(flags));
}
return true;
}
bool ON_SubDArchiveIdMap::ConvertArchiveIdToRuntimeFacePtr(
unsigned int face_count,
size_t faceN_capacity,
ON_SubDFacePtr* faceN,
unsigned int faceX_capacity,
ON_SubDFacePtr* faceX
)
{
if ( 0 == face_count )
return true;
if ( 0 == faceN_capacity || nullptr == faceN )
return ON_SUBD_RETURN_ERROR(false);
if ( 0 != faceX_capacity && nullptr == faceX )
return ON_SUBD_RETURN_ERROR(false);
if ( face_count > faceN_capacity + faceX_capacity )
return ON_SUBD_RETURN_ERROR(false);
ON_SubDFacePtr* fptr = faceN;
for (unsigned int i = 0; i < face_count; i++, fptr++)
{
if ( i == faceN_capacity )
fptr = faceX;
const unsigned int archive_id = ON_SubDArchiveIdMap::ArchiveIdFromComponentPtr(fptr->m_ptr);
ON__UINT_PTR flags = ON_SUBD_COMPONENT_FLAGS(fptr->m_ptr);
fptr->m_ptr = 0;
if (0 == archive_id || archive_id < m_archive_id_partition[2] || archive_id >= m_archive_id_partition[3])
{
ON_ERROR("Invalid face archive id.");
continue;
}
const ON_SubDComponentPtr* eleptr = ComponentPtrFromArchiveId(archive_id);
if (nullptr == eleptr)
{
ON_ERROR("null element pointer.");
continue;
}
ON_SubDFace* face = eleptr->Face();
if (nullptr == face)
{
ON_ERROR("null face pointer.");
continue;
}
if (archive_id != face->ArchiveId())
{
ON_ERROR("archive_id != face->ArchiveId().");
continue;
}
*fptr = ON_SubDFacePtr::Create(face,ON_SUBD_COMPONENT_DIRECTION(flags));
}
return true;
}
bool ON_SubDArchiveIdMap::ConvertArchiveIdToRuntimeSymmetrySetNextPtr(
ON_SubDComponentPtr::Type component_type,
ON_SubDComponentBase* component
)
{
if (nullptr == component)
return false;
const ON_SubDComponentPtr symmetry_set_next = component->m_symmetry_set_next; // symmetry_set_next stores archive id
component->m_symmetry_set_next = ON_SubDComponentPtr::Null;
if (symmetry_set_next.IsNull())
return true;
if (component_type != symmetry_set_next.ComponentType())
return ON_SUBD_RETURN_ERROR(false);
const unsigned archive_id = ON_SubDArchiveIdMap::ArchiveIdFromComponentPtr(symmetry_set_next.m_ptr);
if (archive_id < 1)
return ON_SUBD_RETURN_ERROR(false);
unsigned parition0 = 0;
switch (component_type)
{
case ON_SubDComponentPtr::Type::Unset:
return ON_SUBD_RETURN_ERROR(false);
break;
case ON_SubDComponentPtr::Type::Vertex:
parition0 = 0;
break;
case ON_SubDComponentPtr::Type::Edge:
parition0 = 1;
break;
case ON_SubDComponentPtr::Type::Face:
parition0 = 2;
break;
default:
return ON_SUBD_RETURN_ERROR(false);
break;
}
if(archive_id < m_archive_id_partition[parition0] || archive_id >= m_archive_id_partition[parition0+1])
return ON_SUBD_RETURN_ERROR(false);
const ON_SubDComponentPtr* eleptr = ComponentPtrFromArchiveId(archive_id);
if ( nullptr == eleptr || eleptr->ComponentType() != component_type)
return ON_SUBD_RETURN_ERROR(false);
component->m_symmetry_set_next = (1 == symmetry_set_next.ComponentDirection()) ? eleptr->SetComponentDirection() : eleptr->ClearComponentDirection();
return true;
}
void ON_SubDArchiveIdMap::ValidateArrayCounts(
unsigned short& array_count,
size_t arrayN_capacity,
const void* arrayN,
unsigned short arrayX_capacity,
const void* arrayX
)
{
if (arrayN_capacity >= 0xFFFFU)
{
ON_ERROR("Invalid arrayN_capacity.");
arrayN_capacity = 0xFFFFU;
}
unsigned short arrayN_cap = (unsigned short)arrayN_capacity;
if ( array_count > arrayN_cap + arrayX_capacity
|| (0 == arrayN_cap && 0 != arrayX_capacity)
|| (0 != arrayN_cap && nullptr == arrayN)
|| (0 != arrayX_capacity && nullptr == arrayX)
)
{
ON_ERROR("Invalid array counts.");
if ( nullptr == arrayN )
arrayN_cap = 0;
if ( 0 == arrayN_cap || nullptr == arrayX )
arrayX_capacity = 0;
if (array_count > arrayN_cap + arrayX_capacity )
array_count = arrayN_cap + arrayX_capacity;
}
}
ON_SubDArchiveIdMap::ON_SubDArchiveIdMap()
{
m_fsp.Create(sizeof(ON_SubDComponentPtr),0,0);
m_archive_id_partition[0] = 0;
m_archive_id_partition[1] = 0;
m_archive_id_partition[2] = 0;
m_archive_id_partition[3] = 0;
}
bool ON_SubDArchiveIdMap::Reset()
{
m_fsp.ReturnAll();
m_element_index = ON_UNSET_UINT_INDEX;
m_element_count = 0;
m_archive_id_partition[0] = 0;
m_archive_id_partition[1] = 0;
m_archive_id_partition[2] = 0;
m_archive_id_partition[3] = 0;
return AddComponentPtr(ON_SubDComponentPtr::Null,0);
}
unsigned int ON_SubDArchiveIdMap::Count()
{
return m_element_count;
}
const ON_SubDComponentPtr* ON_SubDArchiveIdMap::First()
{
m_fsp_it.Create(&m_fsp);
m_element_index = 0;
const ON_SubDComponentPtr* p = (const ON_SubDComponentPtr*)m_fsp_it.FirstElement();
if (nullptr != p)
m_element_index++;
return p;
}
const ON_SubDComponentPtr* ON_SubDArchiveIdMap::Next()
{
if ( ON_UNSET_UINT_INDEX == m_element_index)
return First();
const ON_SubDComponentPtr* p = (const ON_SubDComponentPtr*)m_fsp_it.NextElement();
if (nullptr != p)
m_element_index++;
return p;
}
bool ON_SubDArchiveIdMap::Add(const ON_SubDVertex* vertex)
{
return AddComponentPtr(ON_SubDComponentPtr::Create(vertex,0),vertex ? vertex->ArchiveId() : 0);
}
bool ON_SubDArchiveIdMap::Add(const ON_SubDEdge* edge)
{
return AddComponentPtr(ON_SubDComponentPtr::Create(edge,0),edge ? edge->ArchiveId() : 0);
}
bool ON_SubDArchiveIdMap::Add(const ON_SubDFace* face)
{
return AddComponentPtr(ON_SubDComponentPtr::Create(face,0),face ? face->ArchiveId() : 0);
}
class ON_SubDVertex* ON_SubDArchiveIdMap::AddCopy(const class ON_SubDVertex* source_vertex, class ON_SubDimple& subdimple)
{
ON_SubDVertex* vertex = ON_SubDArchiveIdMap::CopyVertex(source_vertex,subdimple);
vertex->SetArchiveId(source_vertex->ArchiveId());
Add(vertex);
return vertex;
}
class ON_SubDEdge* ON_SubDArchiveIdMap::AddCopy(const class ON_SubDEdge* source_edge, class ON_SubDimple& subdimple)
{
ON_SubDEdge* edge = ON_SubDArchiveIdMap::CopyEdge(source_edge,subdimple);
edge->SetArchiveId(source_edge->ArchiveId());
Add(edge);
return edge;
}
class ON_SubDFace* ON_SubDArchiveIdMap::AddCopy(const class ON_SubDFace* source_face, class ON_SubDimple& subdimple)
{
ON_SubDFace* face = ON_SubDArchiveIdMap::CopyFace(source_face,subdimple);
face->SetArchiveId(source_face->ArchiveId());
Add(face);
return face;
}
const ON_SubDComponentPtr* ON_SubDArchiveIdMap::ComponentPtrFromArchiveId(
unsigned int archive_id
) const
{
return (const ON_SubDComponentPtr*)m_fsp.Element(archive_id);
}
bool ON_SubDArchiveIdMap::AddComponentPtr(ON_SubDComponentPtr eptr, unsigned int archive_id)
{
if (m_element_count != archive_id)
{
ON_ERROR("Archive id is not valid and ON_SubD::Read will fail.");
return false;
}
ON_SubDComponentPtr* p = (ON_SubDComponentPtr*)m_fsp.AllocateElement();
*p = eptr;
#if defined(ON_DEBUG)
if (0 != archive_id)
{
const ON_SubDComponentPtr* p1 = (const ON_SubDComponentPtr*)m_fsp.Element(archive_id);
unsigned int archive_id1 = 0;
if (p1 == p)
{
switch (p1->ComponentType())
{
case ON_SubDComponentPtr::Type::Vertex:
archive_id1 = p1->Vertex()->ArchiveId();
break;
case ON_SubDComponentPtr::Type::Edge:
archive_id1 = p1->Edge()->ArchiveId();
break;
case ON_SubDComponentPtr::Type::Face:
archive_id1 = p1->Face()->ArchiveId();
break;
default:
ON_ERROR("invalid element type");
break;
}
}
if (archive_id1 != archive_id)
{
// break here and then see what went wrong
ON_SubDIncrementErrorCount();
m_fsp.Element(archive_id);
m_fsp.Element(archive_id);
}
}
#endif
m_element_count++;
return true;
}
unsigned int ON_SubDArchiveIdMap::ConvertArchiveIdsToRuntimePointers()
{
// Convert archive_id references to runtime pointers.
// The first element is ON_SubDComponentPtr::Null. This is done so the index of the elements
// in element_list[] is equal to the element's archive_id.
const ON_SubDComponentPtr* element = First();
if (nullptr == element || ON_SubDComponentPtr::Type::Unset != element->ComponentType())
return ON_SUBD_RETURN_ERROR(0);
element = Next();
unsigned int archive_id;
for (archive_id = m_archive_id_partition[0]; nullptr != element && archive_id < m_archive_id_partition[1]; archive_id++, element = Next())
{
ON_SubDVertex* v = element->Vertex();
if (nullptr == v)
break;
if (archive_id != v->ArchiveId())
break;
// convert ON_SubDVertex.m_edges[]
ConvertArchiveIdToRuntimeEdgePtr(v->m_edge_count,v->m_edge_capacity,v->m_edges,0,nullptr);
// convert ON_SubDVertex.m_faces[]
ConvertArchiveIdToRuntimeFacePtr(v->m_face_count,v->m_face_capacity,(ON_SubDFacePtr*)v->m_faces,0,nullptr);
for (const ON_SubDSectorSurfacePoint* p = &v->m_limit_point; nullptr != p; p = p->m_next_sector_limit_point)
{
if ( 0 != p->m_sector_face )
ConvertArchiveIdToRuntimeFacePtr(1,1,(ON_SubDFacePtr*)&p->m_sector_face,0,nullptr);
}
// convert v->m_symmetry_set_next to runtime pointer.
ConvertArchiveIdToRuntimeSymmetrySetNextPtr(ON_SubDComponentPtr::Type::Vertex, v);
}
if ( archive_id != m_archive_id_partition[1] )
return ON_SUBD_RETURN_ERROR(0);
for (archive_id = m_archive_id_partition[1]; nullptr != element && archive_id < m_archive_id_partition[2]; archive_id++, element = Next())
{
ON_SubDEdge* e = element->Edge();
if (nullptr == e)
break;
if (archive_id != e->ArchiveId())
break;
// convert ON_SubDEdge.m_vertex[2]
ConvertArchiveIdToRuntimeVertexPtr(2,2,(ON_SubDVertex**)(e->m_vertex));
// convert ON_SubDEdge.m_face2[] and ON_SubDEdge.m_facex[]
ConvertArchiveIdToRuntimeFacePtr(e->m_face_count,sizeof(e->m_face2)/sizeof(e->m_face2[0]),e->m_face2,e->m_facex_capacity,e->m_facex);
// convert e->m_symmetry_set_next to runtime pointer.
ConvertArchiveIdToRuntimeSymmetrySetNextPtr(ON_SubDComponentPtr::Type::Edge, e);
}
if ( archive_id != m_archive_id_partition[2] )
return ON_SUBD_RETURN_ERROR(0);
for (archive_id = m_archive_id_partition[2]; nullptr != element && archive_id < m_archive_id_partition[3]; archive_id++, element = Next())
{
ON_SubDFace* f = element->Face();
if (nullptr == f)
break;
if (archive_id != f->ArchiveId())
break;
// convert ON_SubDFace.m_edge4[] and ON_SubDFace.m_edgex[]
ON_SubDArchiveIdMap::ConvertArchiveIdToRuntimeEdgePtr(f->m_edge_count,sizeof(f->m_edge4)/sizeof(f->m_edge4[0]),f->m_edge4,f->m_edgex_capacity,f->m_edgex);
// convert f->m_symmetry_set_next to runtime pointer.
ConvertArchiveIdToRuntimeSymmetrySetNextPtr(ON_SubDComponentPtr::Type::Face, f);
}
if ( archive_id != m_archive_id_partition[3] )
return ON_SUBD_RETURN_ERROR(0);
return archive_id;
}
void ON_SubD::ShareContentsFrom(ON_SubD& src_subd)
{
if (this == &ON_SubD::Empty || &src_subd == &ON_SubD::Empty)
{
ON_SubDIncrementErrorCount();
}
else if (m_subdimple_sp.get() != src_subd.m_subdimple_sp.get())
{
m_subdimple_sp = src_subd.m_subdimple_sp;
}
}
void ON_SubD::SwapContents(
ON_SubD& a,
ON_SubD& b
)
{
if (&a == &ON_SubD::Empty || &b == &ON_SubD::Empty)
{
ON_SubDIncrementErrorCount();
}
else
{
std::swap(a.m_subdimple_sp, b.m_subdimple_sp);
}
}
ON_SubD::ON_SubD(const ON_SubD& src)
: ON_Geometry(src)
{
this->CopyHelper(src);
}
ON_SubD& ON_SubD::operator=(const ON_SubD& src)
{
if ( this != &src )
{
this->Destroy();
this->CopyHelper(src);
// The next line copies user data
ON_Geometry::operator=(src);
}
return *this;
}
void ON_SubD::CopyHelper(const ON_SubD& src)
{
ON_SubDimple* subdimple = nullptr;
const ON_SubDimple* src_subdimple = src.SubDimple();
if (nullptr != src_subdimple)
{
subdimple = new ON_SubDimple(*src_subdimple);
}
m_subdimple_sp = std::shared_ptr<ON_SubDimple>(subdimple);
if (nullptr != subdimple)
subdimple->SetManagedMeshSubDWeakPointers(m_subdimple_sp);
}
ON__UINT64 ON_SubDimple::GeometryContentSerialNumber() const
{
return m_subd_geometry_content_serial_number;
}
ON__UINT64 ON_SubDimple::RenderContentSerialNumber() const
{
return m_subd_render_content_serial_number;
}
ON__UINT64 ON_SubDimple::ComponentStatusSerialNumber() const
{
return ActiveLevel().ComponentStatusSerialNumber();
}
const ON_AggregateComponentStatusEx ON_SubDimple::AggregateComponentStatus() const
{
return ActiveLevel().AggregateComponentStatus();
}
ON__UINT64 ON_SubDimple::ChangeGeometryContentSerialNumber(
bool bChangePreservesSymmetry
) const
{
// For efficiency, must calculate bUpdateSymmetricObjectGeometry before changing m_subd_geometry_content_serial_number
const bool bUpdateSymmetricObjectGeometry = bChangePreservesSymmetry && m_symmetry.SameSymmetricObjectGeometry(this);
m_subd_geometry_content_serial_number = ON_NextContentSerialNumber();
m_subd_render_content_serial_number = m_subd_geometry_content_serial_number; // changing content automatically changes render content.
if (m_symmetry.IsSet())
{
if (bUpdateSymmetricObjectGeometry)
m_symmetry.SetSymmetricObject(this);
else if (false == m_symmetry.SameSymmetricObjectTopology(this))
m_symmetry.ClearSymmetricObject();
}
return m_subd_geometry_content_serial_number;
}
ON__UINT64 ON_SubDimple::ChangeRenderContentSerialNumber() const
{
m_subd_render_content_serial_number = ON_NextContentSerialNumber();
return m_subd_render_content_serial_number;
}
void ON_SubDimple::SetManagedMeshSubDWeakPointers(
std::shared_ptr<class ON_SubDimple>& subdimple_sp
)
{
// update weak ptrs on limit mesh
const unsigned int level_count = m_levels.UnsignedCount();
for (unsigned level_index = 0; level_index < level_count; level_index++)
{
ON_SubDLevel* level = m_levels[level_index];
if (nullptr == level)
continue;
ON_SubDMeshImpl* surface_mesh_imple = level->m_surface_mesh.SubLimple();
if (nullptr != surface_mesh_imple)
surface_mesh_imple->SetSubDWeakPointer(level->m_face[0], subdimple_sp);
ON_SubDMeshImpl* control_net_mesh_imple = level->m_control_net_mesh.SubLimple();
if (nullptr != control_net_mesh_imple)
control_net_mesh_imple->SetSubDWeakPointer(level->m_face[0], subdimple_sp);
}
}
void ON_SubDMeshImpl::SetSubDWeakPointer(
const ON_SubDFace* subd_first_face,
std::shared_ptr<class ON_SubDimple>& subdimple_sp
)
{
for (;;)
{
const ON_SubDimple* subdimple = subdimple_sp.get();
if (nullptr == subdimple)
break;
if (nullptr == subd_first_face)
break;
if (nullptr == m_first_fragment)
break;
if (m_first_fragment->m_face != subd_first_face)
break;
m_subdimple_wp = subdimple_sp;
return;
}
// It's no longer clear that the subd used to create this limit mesh exist.
ClearFragmentFacePointers(true);
}
ON_SubDimple::ON_SubDimple(const ON_SubDimple& src)
: RuntimeSerialNumber(++ON_SubDimple::Internal_RuntimeSerialNumberGenerator)
{
const bool bCopyComponentStatus = true;
unsigned level_count = src.m_levels.UnsignedCount();
for (/*empty init*/; level_count > 0; level_count--)
{
const ON_SubDLevel* src_level = src.m_levels[level_count - 1];
if (nullptr == src_level)
continue;
if (nullptr == src_level->m_vertex[0])
continue;
if (nullptr == src_level->m_edge[0])
continue;
// it's ok to have subd with just vertices and edges.
//NO//if (nullptr == src_level->m_face[0])
//NO// continue;
break;
}
ON_SubDArchiveIdMap eptrlist;
m_levels.Reserve(level_count);
for (unsigned int level_index = 0; level_index < level_count; level_index++)
{
const ON_SubDLevel* src_level = src.m_levels[level_index];
ON_SubDLevel* level = SubDLevel(level_index,true);
if (nullptr == level)
break;
if (false == level->CopyHelper(src, *src_level, eptrlist, *this, bCopyComponentStatus))
break;
if ( src.m_active_level == src_level )
m_active_level = level;
}
// this ON_SubDimple is an exact copy of src, so they have identical geometry
// and render content.
m_subd_geometry_content_serial_number = src.m_subd_geometry_content_serial_number;
m_subd_render_content_serial_number = src.m_subd_render_content_serial_number;
m_subd_appearance = src.m_subd_appearance;
m_texture_coordinate_type = src.m_texture_coordinate_type;
m_texture_mapping_tag = src.m_texture_mapping_tag;
m_face_packing_id = src.m_face_packing_id;
m_face_packing_topology_hash = src.m_face_packing_topology_hash;
m_face_packing_topology_hash.m_subd_runtime_serial_number
= (src.RuntimeSerialNumber == src.m_face_packing_topology_hash.SubDRuntimeSerialNumber())
? this->RuntimeSerialNumber
: 0;
if (0 == m_face_packing_topology_hash.m_subd_runtime_serial_number)
m_face_packing_topology_hash.m_subd_geometry_content_serial_number = 0;
m_symmetry = src.m_symmetry;
if (
src.RuntimeSerialNumber == src.m_subd_toplology_hash.SubDRuntimeSerialNumber()
&& m_subd_geometry_content_serial_number == src.m_subd_toplology_hash.SubDGeometryContentSerialNumber()
)
{
// src.m_subd_toplology_hash is valid - copy it to this
m_subd_toplology_hash = src.m_subd_toplology_hash;
m_subd_toplology_hash.m_subd_runtime_serial_number = this->RuntimeSerialNumber;
}
if (
src.RuntimeSerialNumber == src.m_subd_toplology_and_edge_creases_hash.SubDRuntimeSerialNumber()
&& m_subd_geometry_content_serial_number == src.m_subd_toplology_and_edge_creases_hash.SubDGeometryContentSerialNumber()
)
{
// src.m_subd_toplology_and_edge_crease_hash is valid - copy it to this
m_subd_toplology_and_edge_creases_hash = src.m_subd_toplology_and_edge_creases_hash;
m_subd_toplology_and_edge_creases_hash.m_subd_runtime_serial_number = this->RuntimeSerialNumber;
}
if (
src.RuntimeSerialNumber == src.m_subd_geometry_hash.SubDRuntimeSerialNumber()
&& m_subd_geometry_content_serial_number == src.m_subd_geometry_hash.SubDGeometryContentSerialNumber()
)
{
// src.m_subd_geometry_hash is valid - copy it to this.
m_subd_geometry_hash = src.m_subd_geometry_hash;
m_subd_geometry_hash.m_subd_runtime_serial_number = this->RuntimeSerialNumber;
}
}
bool ON_SubDLevel::IsEmpty() const
{
return (
nullptr == m_vertex[0]
|| 0U == m_vertex_count
|| this == &ON_SubDLevel::Empty
);
}
int ON_SubDComponentBaseLink::CompareId(ON_SubDComponentBaseLink const*const* lhs, ON_SubDComponentBaseLink const*const* rhs)
{
unsigned int lhs_id = (*lhs)->m_id;
unsigned int rhs_id = (*rhs)->m_id;
if (lhs_id < rhs_id)
return -1;
if (lhs_id > rhs_id)
return 1;
return 0;
}
void ON_SubDLevelComponentIdIterator::Initialize(
bool bLevelLinkedListIncreasingId,
ON_SubDComponentPtr::Type ctype,
const ON_SubDimple& subdimple,
const ON_SubDLevel& level
)
{
m_bLevelLinkedListIncreasingId = false;
m_ctype = ctype;
m_level_index = (unsigned short)level.m_level_index;
m_count = 0;
m_prev_id = 0;
m_first = nullptr;
m_current = nullptr;
switch (ctype)
{
case ON_SubDComponentPtr::Type::Vertex:
m_first = (const ON_SubDComponentBaseLink*)level.m_vertex[0];
break;
case ON_SubDComponentPtr::Type::Edge:
m_first = (const ON_SubDComponentBaseLink*)level.m_edge[0];
break;
case ON_SubDComponentPtr::Type::Face:
m_first = (const ON_SubDComponentBaseLink*)level.m_face[0];
break;
default:
m_first = nullptr;
break;
}
if (nullptr == m_first)
return;
m_bLevelLinkedListIncreasingId = bLevelLinkedListIncreasingId;
if (false == m_bLevelLinkedListIncreasingId)
{
subdimple.InitializeComponentIdIterator(ctype, m_cidit);
}
}
const ON_SubDVertex* ON_SubDLevelComponentIdIterator::FirstVertex()
{
return (ON_SubDComponentPtr::Type::Vertex == m_ctype) ? (const ON_SubDVertex*)InternalFirst() : nullptr;
}
const ON_SubDVertex* ON_SubDLevelComponentIdIterator::NextVertex()
{
return (ON_SubDComponentPtr::Type::Vertex == m_ctype) ? (const ON_SubDVertex*)InternalNext() : nullptr;
}
const ON_SubDEdge* ON_SubDLevelComponentIdIterator::FirstEdge()
{
return (ON_SubDComponentPtr::Type::Edge == m_ctype) ? (const ON_SubDEdge*)InternalFirst() : nullptr;
}
const ON_SubDEdge* ON_SubDLevelComponentIdIterator::NextEdge()
{
return (ON_SubDComponentPtr::Type::Edge == m_ctype) ? (const ON_SubDEdge*)InternalNext() : nullptr;
}
const ON_SubDFace* ON_SubDLevelComponentIdIterator::FirstFace()
{
return (ON_SubDComponentPtr::Type::Face == m_ctype) ? (const ON_SubDFace*)InternalFirst() : nullptr;
}
const ON_SubDFace* ON_SubDLevelComponentIdIterator::NextFace()
{
return (ON_SubDComponentPtr::Type::Face == m_ctype) ? (const ON_SubDFace*)InternalNext() : nullptr;
}
const ON_SubDComponentBase* ON_SubDLevelComponentIdIterator::InternalFirst()
{
m_prev_id = 0;
if (nullptr == m_first)
return nullptr;
m_current = nullptr;
if (m_bLevelLinkedListIncreasingId)
{
m_current = m_first;
}
else
{
for (const ON_SubDComponentBase* c = m_cidit.FirstComponent(); nullptr != c; c = m_cidit.NextComponent())
{
if (m_level_index != c->SubdivisionLevel())
continue;
m_current = (const ON_SubDComponentBaseLink*)c;
break;
}
}
if (nullptr != m_current)
{
if (m_current->m_id <= m_prev_id)
{
// When this happens, searching by component id will be broken in the destination of the SubD copy.
// It is a very serious bug, but we continue so something will get saved to the archive or be created in the copy.
ON_SUBD_ERROR("Iterator is not in order of increasing id.");
}
else
m_prev_id = m_current->m_id;
m_count = 1;
}
return m_current;
}
const ON_SubDComponentBase* ON_SubDLevelComponentIdIterator::InternalNext()
{
if (nullptr == m_first || nullptr == m_current)
return nullptr;
if (m_bLevelLinkedListIncreasingId)
{
m_current = m_current->m_next;
}
else
{
m_current = nullptr;
for (const ON_SubDComponentBase* c = m_cidit.NextComponent(); nullptr != c; c = m_cidit.NextComponent())
{
if (m_level_index != c->SubdivisionLevel())
continue;
m_current = (const ON_SubDComponentBaseLink*)c;
break;
}
}
if (nullptr != m_current)
{
if (m_current->m_id <= m_prev_id)
{
// When this happens, searching by component id will be broken in the destination of the SubD copy.
// It is a very serious bug, but we continue so something will get saved to the archive or be created in the copy.
ON_SUBD_ERROR("Iterator is not in order of increasing id.");
}
else
m_prev_id = m_current->m_id;
++m_count;
}
return m_current;
}
bool ON_SubDLevel::CopyHelper(
const class ON_SubDimple& src_subdimple,
const ON_SubDLevel& src_level,
class ON_SubDArchiveIdMap& archive_id_map,
class ON_SubDimple& dest_subdimple,
bool bCopyComponentStatus
)
{
bool rc = false;
archive_id_map.Reset();
m_surface_mesh.Clear();
m_control_net_mesh.Clear();
for (;;)
{
bool bLevelLinkedListIncreasingId[3] = {};
if ( 0 == src_level.SetArchiveId(src_subdimple, archive_id_map.m_archive_id_partition, bLevelLinkedListIncreasingId) )
break;
unsigned int archive_id = 1;
if ( archive_id != archive_id_map.m_archive_id_partition[0])
break;
// Have to use idit because subd editing (deleting and then adding) can leave the level's linked lists
// with components in an order that is not increasing in id and it is critical that the next three for
// loops iterate the level's components in order of increasing id.
ON_SubDLevelComponentIdIterator src_idit;
// must iterate source vertices in order of increasing id
src_idit.Initialize(bLevelLinkedListIncreasingId[0], ON_SubDComponentPtr::Type::Vertex, src_subdimple, src_level);
for (const ON_SubDVertex* source_vertex = src_idit.FirstVertex(); nullptr != source_vertex; source_vertex = src_idit.NextVertex(), archive_id++)
{
if (archive_id != source_vertex->ArchiveId())
break;
ON_SubDVertex* vertex = archive_id_map.AddCopy(source_vertex,dest_subdimple);
if (nullptr == vertex )
break;
if (archive_id != vertex->ArchiveId())
break;
this->AddVertex(vertex);
if ( bCopyComponentStatus )
vertex->m_status = source_vertex->m_status;
}
if ( archive_id != archive_id_map.m_archive_id_partition[1])
break;
// must iterate source edges in order of increasing id
src_idit.Initialize(bLevelLinkedListIncreasingId[1], ON_SubDComponentPtr::Type::Edge, src_subdimple, src_level);
for (const ON_SubDEdge* source_edge = src_idit.FirstEdge(); nullptr != source_edge; source_edge = src_idit.NextEdge(), archive_id++)
{
if (archive_id != source_edge->ArchiveId())
break;
ON_SubDEdge* edge = archive_id_map.AddCopy(source_edge,dest_subdimple);
if (nullptr == edge )
break;
if (archive_id != edge->ArchiveId())
break;
this->AddEdge(edge);
if ( bCopyComponentStatus )
edge->m_status = source_edge->m_status;
}
if ( archive_id != archive_id_map.m_archive_id_partition[2])
break;
// must iterate source faces in order of increasing id
src_idit.Initialize(bLevelLinkedListIncreasingId[2], ON_SubDComponentPtr::Type::Face, src_subdimple, src_level);
for (const ON_SubDFace* source_face = src_idit.FirstFace(); nullptr != source_face; source_face = src_idit.NextFace(), archive_id++)
{
if (archive_id != source_face->ArchiveId())
break;
ON_SubDFace* face = archive_id_map.AddCopy(source_face,dest_subdimple);
if (nullptr == face )
break;
if (archive_id != face->ArchiveId())
break;
this->AddFace(face);
if ( bCopyComponentStatus )
face->m_status = source_face->m_status;
}
if ( archive_id != archive_id_map.m_archive_id_partition[3])
break;
if (0 == archive_id_map.ConvertArchiveIdsToRuntimePointers())
break;
for (int meshdex = 0; meshdex < 2; meshdex++)
{
ON_SubDMesh* src_mesh = (0==meshdex) ? (&src_level.m_surface_mesh) : (&src_level.m_control_net_mesh);
ON_SubDMesh* this_mesh = (0 == meshdex) ? (&m_surface_mesh) : (&m_control_net_mesh);
if (false == src_mesh->IsEmpty())
{
ON_SubDMesh local_subd_mesh;
local_subd_mesh.CopyFrom(*src_mesh);
for (const ON_SubDMeshFragment* fragment = local_subd_mesh.FirstFragment(); nullptr != fragment; fragment = fragment->m_next_fragment)
{
if (nullptr != fragment->m_face)
{
archive_id = fragment->m_face->ArchiveId();
ON_SubDComponentPtr cptr = ON_SubDArchiveIdMap::FromFace(fragment->m_face);
ON_SubDFacePtr fptr = cptr.FacePtr();
const_cast<ON_SubDMeshFragment*>(fragment)->m_face = nullptr;
if (0 != archive_id)
{
if (archive_id_map.ConvertArchiveIdToRuntimeFacePtr(1, 1, &fptr, 0, nullptr))
{
const_cast<ON_SubDMeshFragment*>(fragment)->m_face = fptr.Face();
if (nullptr != fragment->m_face)
continue;
}
}
}
local_subd_mesh = ON_SubDMesh::Empty;
break;
}
if (false == local_subd_mesh.IsEmpty())
ON_SubDMesh::Swap(*this_mesh, local_subd_mesh);
}
}
this->ClearArchiveId();
this->m_level_index = src_level.m_level_index;
this->m_aggregates = src_level.m_aggregates;
this->m_aggregates.MarkAllAsNotCurrent();
rc = true;
break;
}
archive_id_map.Reset();
src_level.ClearArchiveId();
if ( false == rc )
return ON_SUBD_RETURN_ERROR(false);
return rc;
} // archive_id_map