Changeset View
Changeset View
Standalone View
Standalone View
extern/opennurbs/opennurbs_subd_copy.cpp
- This file was added.
| #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" | |||||
| /* $NoKeywords: $ */ | |||||
| /* | |||||
| // | |||||
| // Copyright (c) 1993-2014 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>. | |||||
| // | |||||
| //////////////////////////////////////////////////////////////// | |||||
| */ | |||||
| unsigned int ON_SubDArchiveIdMap::ArchiveIdFromComponentPtr(ON__UINT_PTR ptr) | |||||
| { | |||||
| return (unsigned int)(ptr/(ON_SUBD_COMPONENT_FLAGS_MASK+1)); | |||||
| } | |||||
| 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))); | |||||
| } | |||||
| 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))); | |||||
| } | |||||
| 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))); | |||||
| } | |||||
| ON_SubDComponentPtr ON_SubDArchiveIdMap::FromVertex( | |||||
| ON_SubDVertexPtr vertex_ptr | |||||
| ) | |||||
| { | |||||
| ON_SubDComponentPtr ptr = FromVertex(vertex_ptr.Vertex()); | |||||
| ptr.m_ptr |= vertex_ptr.VertexDirection(); | |||||
| return ptr; | |||||
| } | |||||
| ON_SubDComponentPtr ON_SubDArchiveIdMap::FromEdge( | |||||
| ON_SubDEdgePtr edge_ptr | |||||
| ) | |||||
| { | |||||
| ON_SubDComponentPtr ptr = FromEdge(edge_ptr.Edge()); | |||||
| ptr.m_ptr |= edge_ptr.EdgeDirection(); | |||||
| return ptr; | |||||
| } | |||||
| ON_SubDComponentPtr ON_SubDArchiveIdMap::FromFace( | |||||
| ON_SubDFacePtr face_ptr | |||||
| ) | |||||
| { | |||||
| ON_SubDComponentPtr ptr = FromFace(face_ptr.Face()); | |||||
| ptr.m_ptr |= face_ptr.FaceDirection(); | |||||
| return ptr; | |||||
| } | |||||
| 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_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; | |||||
| vertex->CopyFrom(source_vertex,bCopyEdgeArray,bCopyFaceArray,bCopyLimitPointList); | |||||
| // 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; | |||||
| } | |||||
| 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_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; | |||||
| edge->CopyFrom(source_edge,bReverseEdge,bCopyVertexArray,bCopyEdgeArray); | |||||
| // 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; | |||||
| } | |||||
| 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_level,source_face->m_edge_count); | |||||
| if ( nullptr == face ) | |||||
| return ON_SUBD_RETURN_ERROR(nullptr); | |||||
| const bool bCopyEdgeArray = true; | |||||
| face->CopyFrom(source_face,bCopyEdgeArray); | |||||
| // 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; | |||||
| } | |||||
| 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; | |||||
| } | |||||
| 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); | |||||
| } | |||||
| } | |||||
| 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); | |||||
| } | |||||
| 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); | |||||
| } | |||||
| 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::ContentSerialNumber() const | |||||
| { | |||||
| return m_subd_content_serial_number; | |||||
| } | |||||
| ON__UINT64 ON_SubDimple::ChangeContentSerialNumber() const | |||||
| { | |||||
| return (m_subd_content_serial_number = ON_NextContentSerialNumber()); | |||||
| } | |||||
| 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; | |||||
| } | |||||
| if (src.m_max_vertex_id > m_max_vertex_id) | |||||
| m_max_vertex_id = src.m_max_vertex_id; | |||||
| if (src.m_max_edge_id > m_max_edge_id) | |||||
| m_max_edge_id = src.m_max_edge_id; | |||||
| if (src.m_max_face_id > m_max_face_id) | |||||
| m_max_face_id = src.m_max_face_id; | |||||
| m_subd_appearance = src.m_subd_appearance; | |||||
| m_texture_domain_type = src.m_texture_domain_type; | |||||
| m_texture_mapping_tag = src.m_texture_mapping_tag; | |||||
| m_symmetry = src.m_symmetry; | |||||
| ChangeContentSerialNumber(); | |||||
| } | |||||
| 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& eptrlist, | |||||
| class ON_SubDimple& dest_subdimple, | |||||
| bool bCopyComponentStatus | |||||
| ) | |||||
| { | |||||
| bool rc = false; | |||||
| eptrlist.Reset(); | |||||
| m_surface_mesh.Clear(); | |||||
| m_control_net_mesh.Clear(); | |||||
| for (;;) | |||||
| { | |||||
| bool bLevelLinkedListIncreasingId[3] = {}; | |||||
| if ( 0 == src_level.SetArchiveId(src_subdimple, eptrlist.m_archive_id_partition, bLevelLinkedListIncreasingId) ) | |||||
| break; | |||||
| unsigned int archive_id = 1; | |||||
| if ( archive_id != eptrlist.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 = eptrlist.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 != eptrlist.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 = eptrlist.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 != eptrlist.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 = eptrlist.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 != eptrlist.m_archive_id_partition[3]) | |||||
| break; | |||||
| if (0 == eptrlist.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 (eptrlist.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; | |||||
| } | |||||
| eptrlist.Reset(); | |||||
| src_level.ClearArchiveId(); | |||||
| if ( false == rc ) | |||||
| return ON_SUBD_RETURN_ERROR(false); | |||||
| return rc; | |||||
| } | |||||