// // 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 . // //////////////////////////////////////////////////////////////// #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 class ON_V5_BrepRegionTopologyUserData : public ON_UserData { ON_OBJECT_DECLARE(ON_V5_BrepRegionTopologyUserData); public: ON_V5_BrepRegionTopologyUserData(); ~ON_V5_BrepRegionTopologyUserData(); ON_V5_BrepRegionTopologyUserData(const ON_V5_BrepRegionTopologyUserData&); ON_V5_BrepRegionTopologyUserData& operator=(const ON_V5_BrepRegionTopologyUserData&); bool Archive() const override; bool DeleteAfterWrite( const class ON_BinaryArchive& archive, const class ON_Object* parent_object ) const override; bool DeleteAfterRead( const class ON_BinaryArchive& archive, class ON_Object* parent_object ) const override; bool Write(ON_BinaryArchive& binary_archive) const override; bool Read(ON_BinaryArchive& binary_archive) override; bool GetDescription( ON_wString& description ) override; const ON_BrepRegionTopology* m_write_region_topology_ptr = nullptr; mutable ON_BrepRegionTopology* m_read_region_topology_ptr = nullptr; }; ON_OBJECT_IMPLEMENT(ON_V5_BrepRegionTopologyUserData,ON_UserData,"7FE23D63-E536-43f1-98E2-C807A2625AFF"); ON_V5_BrepRegionTopologyUserData::ON_V5_BrepRegionTopologyUserData() { m_userdata_copycount = 1; m_userdata_uuid = ON_CLASS_ID(ON_V5_BrepRegionTopologyUserData); m_application_uuid = ON_opennurbs4_id; } ON_V5_BrepRegionTopologyUserData::~ON_V5_BrepRegionTopologyUserData() { m_write_region_topology_ptr = nullptr; if (nullptr != m_read_region_topology_ptr) { delete m_read_region_topology_ptr; m_read_region_topology_ptr = nullptr; } } ON_V5_BrepRegionTopologyUserData::ON_V5_BrepRegionTopologyUserData( const ON_V5_BrepRegionTopologyUserData& src ) : ON_UserData(src) { // copy constructor is never called. //m_userdata_uuid = ON_CLASS_ID(ON_V5_BrepRegionTopologyUserData); //m_application_uuid = ON_opennurbs4_id; } ON_V5_BrepRegionTopologyUserData& ON_V5_BrepRegionTopologyUserData::operator=(const ON_V5_BrepRegionTopologyUserData& src) { // operator= is never called. //if ( this != &src ) //{ // ON_UserData::operator=(src); // m_region_topology = src.m_region_topology; //} return *this; } bool ON_V5_BrepRegionTopologyUserData::Archive() const { return true; } bool ON_V5_BrepRegionTopologyUserData::DeleteAfterWrite( const class ON_BinaryArchive&, //archive, const class ON_Object* //parent_object ) const { return true; } bool ON_V5_BrepRegionTopologyUserData::DeleteAfterRead( const class ON_BinaryArchive& archive, class ON_Object* parent_object ) const { const ON_Brep* brep = ON_Brep::Cast(parent_object); if (nullptr != brep && nullptr == brep->m_region_topology) { brep->m_region_topology = m_read_region_topology_ptr; m_read_region_topology_ptr = nullptr; } return true; } bool ON_BrepRegionTopology::Transform( const ON_Xform& xform) { // Transforming the bbox makes it grow too large under repeated // rotations. So, we will destroy it here and reset it below. //m_bbox.Transform(xform); int i, j; const int region_count = m_R.Count(); const int faceside_count = m_FS.Count(); if ( nullptr != m_brep ) { const int face_count = m_brep->m_F.Count(); for (i = 0; i < region_count; i++ ) { ON_BrepRegion& r = m_R[i]; r.m_bbox.Destroy(); for ( j = 0; j < r.m_fsi.Count(); j++ ) { int fsi = r.m_fsi[j]; if ( fsi >= 0 && fsi < faceside_count ) { int fi = m_FS[fsi].m_fi; if ( fi >= 0 && fi < face_count ) { r.m_bbox.Union(m_brep->m_F[fi].BoundingBox()); } } } } } for ( i = 0; i < faceside_count; i++ ) m_FS[i].TransformUserData(xform); for ( i = 0; i < region_count; i++ ) m_R[i].TransformUserData(xform); return true; } bool ON_V5_BrepRegionTopologyUserData::Write(ON_BinaryArchive& binary_archive) const { // m_write_region_topology_ptr is never nullptr when this fuction is called return (nullptr == m_write_region_topology_ptr) ? false : m_write_region_topology_ptr->Write(binary_archive) ; } bool ON_V5_BrepRegionTopologyUserData::Read(ON_BinaryArchive& binary_archive) { m_read_region_topology_ptr = new ON_BrepRegionTopology(); m_read_region_topology_ptr->m_brep = ON_Brep::Cast(Owner()); return m_read_region_topology_ptr->Read(binary_archive); } bool ON_V5_BrepRegionTopologyUserData::GetDescription( ON_wString& description ) { description=L"V5 Brep Region Topology userdata"; return true; } void ON_Brep::Internal_AttachV5RegionTopologyAsUserData( ON_BinaryArchive& archive ) const { if ( archive.Archive3dmVersion() != 50 ) return; const bool bWriteRegionTopology = (nullptr != m_region_topology) && (m_F.UnsignedCount() > 0) && (m_region_topology->m_FS.UnsignedCount() == 2 * m_F.UnsignedCount()); if ( false == bWriteRegionTopology ) return; ON_V5_BrepRegionTopologyUserData* ud = new ON_V5_BrepRegionTopologyUserData(); ud->m_write_region_topology_ptr = m_region_topology; const_cast(this)->AttachUserData(ud); } ON_OBJECT_IMPLEMENT_NO_COPYCTOR(ON_BrepFaceSide,ON_Object,"30930370-0D5B-4ee4-8083-BD635C7398A4"); bool ON_BrepFaceSide::IsValid( ON_TextLog* text_log ) const { return true; } ON_BrepFaceSide::ON_BrepFaceSide() { m_faceside_index = -1; m_ri = -1; m_fi = -1; m_srf_dir = 0; m_rtop = 0; memset(&m_faceside_user,0,sizeof(m_faceside_user)); } ON_BrepFaceSide::~ON_BrepFaceSide() { } ON_BrepFaceSide& ON_BrepFaceSide::operator=(const ON_BrepFaceSide& src) { if ( this != &src) { // do not copy m_brep pointer m_faceside_user = src.m_faceside_user; m_faceside_index = src.m_faceside_index; m_ri = src.m_ri; m_fi = src.m_fi; m_srf_dir = src.m_srf_dir; ON_Object::operator=(src); } return *this; } bool ON_BrepFaceSide::Write(ON_BinaryArchive& file) const { bool rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if ( !rc ) return false; for(;;) { rc = file.WriteInt( m_faceside_index ); if (!rc) break; rc = file.WriteInt( m_ri ); if (!rc) break; rc = file.WriteInt( m_fi ); if (!rc) break; rc = file.WriteInt( m_srf_dir ); if (!rc) break; break; } if (!file.EndWrite3dmChunk()) rc = false; return rc; } bool ON_BrepFaceSide::Read(ON_BinaryArchive& file) { int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; for(;;) { rc = (1==major_version); if (!rc) break; rc = file.ReadInt( &m_faceside_index ); if (!rc) break; rc = file.ReadInt( &m_ri ); if (!rc) break; rc = file.ReadInt( &m_fi ); if (!rc) break; rc = file.ReadInt( &m_srf_dir ); if (!rc) break; break; } if (!file.EndRead3dmChunk()) rc = false; return rc; } const ON_Brep* ON_BrepFaceSide::Brep() const { return m_rtop ? m_rtop->Brep() : nullptr; } const ON_BrepRegionTopology* ON_BrepFaceSide::RegionTopology() const { return m_rtop; } const ON_BrepRegion* ON_BrepFaceSide::Region() const { ON_BrepRegion* region = 0; if ( m_rtop && m_ri >= 0 && m_ri < m_rtop->m_R.Count() ) { region = &m_rtop->m_R[m_ri]; //region = const_cast(&m_rtop->m_R[m_ri]); } return region; } const ON_BrepFace* ON_BrepFaceSide::Face() const { const ON_BrepFace* face = 0; if ( m_rtop && m_fi >= 0 ) { const ON_Brep* brep = m_rtop->Brep(); if ( brep && m_fi < brep->m_F.Count() ) { face = &brep->m_F[m_fi]; } } return face; } int ON_BrepFaceSide::SurfaceNormalDirection() const { return m_srf_dir; } ON_OBJECT_IMPLEMENT_NO_COPYCTOR(ON_BrepRegion,ON_Object,"CA7A0092-7EE6-4f99-B9D2-E1D6AA798AA1"); bool ON_BrepRegion::IsValid( ON_TextLog* text_log ) const { return true; } ON_BrepRegion::ON_BrepRegion() { m_region_index = -1; m_type = -1; m_rtop = 0; memset(&m_region_user,0,sizeof(m_region_user)); } ON_BrepRegion::~ON_BrepRegion() { } ON_BrepRegion& ON_BrepRegion::operator=(const ON_BrepRegion& src) { if ( this != &src ) { // do not copy m_brep pointer m_region_user = src.m_region_user; m_region_index = src.m_region_index; m_fsi = src.m_fsi; m_type = src.m_type; m_bbox = src.m_bbox; ON_Object::operator=(src); } return *this; } bool ON_BrepRegion::Write(ON_BinaryArchive& file) const { bool rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if ( !rc ) return false; for(;;) { rc = file.WriteInt( m_region_index ); if (!rc) break; rc = file.WriteInt( m_type ); if (!rc) break; rc = file.WriteArray( m_fsi ); if (!rc) break; rc = file.WriteBoundingBox( m_bbox ); if (!rc) break; break; } if (!file.EndWrite3dmChunk()) rc = false; return rc; } bool ON_BrepRegion::Read(ON_BinaryArchive& file) { int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; for(;;) { rc = (1==major_version); if (!rc) break; rc = file.ReadInt( &m_region_index ); if (!rc) break; rc = file.ReadInt( &m_type ); if (!rc) break; rc = file.ReadArray( m_fsi ); if (!rc) break; rc = file.ReadBoundingBox( m_bbox ); if (!rc) break; break; } if (!file.EndRead3dmChunk()) rc = false; return rc; } const ON_Brep* ON_BrepRegion::Brep() const { return m_rtop ? m_rtop->Brep() : nullptr; } ON_BrepRegionTopology* ON_BrepRegion::RegionTopology() const { return m_rtop; } ON_BrepFaceSide* ON_BrepRegion::FaceSide(int rfsi) const { ON_BrepFaceSide* faceside = 0; if ( m_rtop && rfsi >= 0 && rfsi < m_fsi.Count() ) { int fsi = m_fsi[rfsi]; if ( fsi >= 0 && fsi < m_rtop->m_FS.Count() ) { faceside = &m_rtop->m_FS[fsi]; } } return faceside; } bool ON_BrepRegion::IsFinite() const { return (1 == m_type); } const ON_BoundingBox& ON_BrepRegion::BoundingBox() const { return m_bbox; } ON_BrepFaceSideArray::ON_BrepFaceSideArray() { } ON_BrepFaceSideArray::~ON_BrepFaceSideArray() { } bool ON_BrepFaceSideArray::Read( ON_BinaryArchive& file ) { return (file.Archive3dmVersion() < 60) ? Internal_ReadV5(file) : Internal_ReadV6(file); } bool ON_BrepFaceSideArray::Internal_ReadV5( ON_BinaryArchive& file ) { Empty(); int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmChunk( TCODE_ANONYMOUS_CHUNK, &major_version, &minor_version ); if (rc) { for(;;) { rc = (1 == major_version); if (!rc) break; if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc; i++ ) { ON_BrepFaceSide& faceside = AppendNew(); rc = faceside.Read(file)?true:false; } break; } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepFaceSideArray::Internal_ReadV6( ON_BinaryArchive& file ) { Empty(); int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmChunk( TCODE_ANONYMOUS_CHUNK, &major_version, &minor_version ); if (rc) { for(;;) { rc = (1 == major_version); if (!rc) break; if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc; i++ ) { ON_BrepFaceSide& faceside = AppendNew(); rc = file.ReadObject(faceside)?true:false; } break; } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepFaceSideArray::Write( ON_BinaryArchive& file ) const { return (file.Archive3dmVersion() < 60) ? Internal_WriteV5(file) : Internal_WriteV6(file); } bool ON_BrepFaceSideArray::Internal_WriteV5( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 1, 0 ); if (rc) { const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { rc = m_a[i].Write(file)?true:false; } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_BrepFaceSideArray::Internal_WriteV6( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 1, 0 ); if (rc) { const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { rc = file.WriteObject(m_a[i])?true:false; } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } unsigned int ON_BrepFaceSideArray::SizeOf() const { unsigned int sz = SizeOfArray(); for ( int i = 0; i < m_count; i++ ) sz += (m_a[i].SizeOf() - ((unsigned int)sizeof(ON_BrepFaceSide))); return sz; } ON_BrepRegionArray::ON_BrepRegionArray() { } ON_BrepRegionArray::~ON_BrepRegionArray() { } bool ON_BrepRegionArray::Read( ON_BinaryArchive& file ) { return (file.Archive3dmVersion() < 60) ? Internal_ReadV5(file) : Internal_ReadV6(file); } bool ON_BrepRegionArray::Internal_ReadV5( ON_BinaryArchive& file ) { Empty(); int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmChunk( TCODE_ANONYMOUS_CHUNK, &major_version, &minor_version ); if (rc) { for(;;) { rc = (1 == major_version); if (!rc) break; if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc ; i++ ) { ON_BrepRegion& region = AppendNew(); rc = region.Read(file)?true:false; } break; } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepRegionArray::Internal_ReadV6( ON_BinaryArchive& file ) { Empty(); int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmChunk( TCODE_ANONYMOUS_CHUNK, &major_version, &minor_version ); if (rc) { for(;;) { rc = (1 == major_version); if (!rc) break; if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc ; i++ ) { ON_BrepRegion& region = AppendNew(); rc = file.ReadObject(region)?true:false; } break; } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepRegionArray::Write( ON_BinaryArchive& file ) const { return (file.Archive3dmVersion() < 60) ? Internal_WriteV5(file) : Internal_WriteV6(file); } bool ON_BrepRegionArray::Internal_WriteV5( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 1, 0 ); if (rc) { const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { rc = m_a[i].Write(file)?true:false; } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_BrepRegionArray::Internal_WriteV6( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 1, 0 ); if (rc) { const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { rc = file.WriteObject(m_a[i])?true:false; } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } unsigned int ON_BrepRegionArray::SizeOf() const { unsigned int sz = SizeOfArray(); for ( int i = 0; i < m_count; i++ ) sz += (m_a[i].SizeOf() - ((unsigned int)sizeof(ON_BrepRegion))); return sz; } ON_BrepRegionTopology::ON_BrepRegionTopology() { } ON_BrepRegionTopology::~ON_BrepRegionTopology() { } ON_BrepRegionTopology::ON_BrepRegionTopology(const ON_BrepRegionTopology& src) { int i; // do not copy m_brep m_brep = 0; m_FS = src.m_FS; m_R = src.m_R; for (i = 0; i < m_FS.Count(); i++ ) m_FS[i].m_rtop = this; for (i = 0; i < m_R.Count(); i++ ) m_R[i].m_rtop = this; } ON_BrepRegionTopology& ON_BrepRegionTopology::operator=(const ON_BrepRegionTopology& src) { if ( this != &src ) { // do not copy m_brep m_FS = src.m_FS; m_R = src.m_R; int i; for (i = 0; i < m_FS.Count(); i++ ) m_FS[i].m_rtop = this; for (i = 0; i < m_R.Count(); i++ ) m_R[i].m_rtop = this; } return *this; } bool ON_BrepRegionTopology::IsValid( ON_TextLog* text_log) const { #define PRINT_MSG(s) if (text_log) text_log->Print(s) #define PRINT_MSG1(s,a1) if (text_log) text_log->Print(s,a1) #define PRINT_MSG2(s,a1,a2) if (text_log) text_log->Print(s,a1,a2) #define PRINT_MSG3(s,a1,a2,a3) if (text_log) text_log->Print(s,a1,a2,a3) int infinite_region_index = -1; int rfs_count = 0; int ri, fsi; if ( !m_brep ) { PRINT_MSG("ON_BrepRegionTopology::m_brep is nullptr\n"); return false; } const int faceside_count = m_FS.Count(); if ( faceside_count != 2*m_brep->m_F.Count() ) { PRINT_MSG("ON_BrepRegionTopology::m_FS.Count() != 2*m_brep->m_F.Count()\n"); return false; } int void_regionside_count = 0; for ( fsi = 0; fsi < faceside_count; fsi++ ) { const ON_BrepFaceSide& fs = m_FS[fsi]; const int fi = fsi/2; const int srf_dir = (fsi%2) ? -1 : 1; if ( fs.m_rtop != this ) { PRINT_MSG1("ON_BrepRegionTopology::m_FS[%d].m_rtop != this\n",fsi); return false; } if ( fi != fs.m_fi ) { PRINT_MSG3("ON_BrepRegionTopology::m_FS[%d].m_fi = %d != %d\n",fsi,fs.m_fi,fi); return false; } if ( fs.m_srf_dir != srf_dir ) { PRINT_MSG3("ON_BrepRegionTopology::m_FS[%d].m_srf_dir = %d != %d\n",fsi,fs.m_srf_dir,srf_dir); return false; } if ( -1 == fs.m_ri ) { void_regionside_count++; } } const int region_count = m_R.Count(); if ( region_count <= 0 ) { PRINT_MSG("ON_BrepRegionTopology::m_R.Count() <= 0\n"); return false; } for ( ri = 0; ri < region_count; ri++ ) { const ON_BrepRegion& region = m_R[ri]; if ( region.m_rtop != this ) { PRINT_MSG1("ON_BrepRegionTopology::m_R[%d].m_rtop != this\n",ri); return false; } if ( region.m_type < 0 ) { PRINT_MSG("ON_BrepRegionTopology::m_R[%d].m_type < 0\n"); return false; } if ( region.m_type > 1 ) { PRINT_MSG("ON_BrepRegionTopology::m_R[%d].m_type > 1\n"); return false; } if ( 0 == region.m_type ) { if ( infinite_region_index >= 0 ) { PRINT_MSG2("ON_BrepRegionTopology::m_R[%d and %d].m_type = 0\n",infinite_region_index,ri); return false; } infinite_region_index = ri; } if ( region.m_fsi.Count() <= 0 ) { PRINT_MSG1("ON_BrepRegionTopology::m_R[%d].m_fsi.Count() <= 0\n",ri); return false; } for ( int rfsi = 0; rfsi < region.m_fsi.Count(); rfsi++ ) { fsi = region.m_fsi[rfsi]; if ( fsi < 0 || fsi >= faceside_count) { PRINT_MSG2("ON_BrepRegionTopology::m_R[%d].m_fsi[%d] is out of range\n",ri,rfsi); return false; } const ON_BrepFaceSide& faceside = m_FS[fsi]; if ( faceside.m_ri != ri ) { PRINT_MSG3("ON_BrepRegionTopology::m_FS[m_R[%d].m_fsi[%d]].m_ri != %d\n",ri,rfsi,ri); return false; } for ( int j = rfsi+1; j < region.m_fsi.Count(); j++ ) { if ( fsi == region.m_fsi[j] ) { PRINT_MSG3("ON_BrepRegionTopology::m_R[%d].m_fsi[%d and %d]] are duplicates\n",ri,rfsi,j); return false; } } rfs_count++; } } if ( faceside_count != rfs_count+void_regionside_count ) { PRINT_MSG2("Sum of ON_BrepRegionTopology::m_R[%d].m_fsi.Count() = %d != m_FS.Count()\n",ri,rfs_count); return false; } if ( infinite_region_index < 0 ) { PRINT_MSG("ON_BrepRegionTopology::m_R[] has no infinte region\n"); return false; } #undef PRINT_MSG #undef PRINT_MSG1 #undef PRINT_MSG2 #undef PRINT_MSG3 return true; } const ON_Brep* ON_BrepRegionTopology::Brep() const { return m_brep; } bool ON_BrepRegionTopology::Read( ON_BinaryArchive& file ) { int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; for(;;) { rc = (1 == major_version); if (!rc) break; rc = m_FS.Read(file); for ( i = 0; i < m_FS.Count(); i++ ) m_FS[i].m_rtop = this; if (!rc) break; rc = m_R.Read(file); for ( i = 0; i < m_R.Count(); i++ ) m_R[i].m_rtop = this; if (!rc) break; break; } if ( !file.EndRead3dmChunk() ) rc = false; return rc; } bool ON_BrepRegionTopology::Write( ON_BinaryArchive& file) const { bool rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if (!rc) return false; for(;;) { rc = m_FS.Write(file); if (!rc) break; rc = m_R.Write(file); if (!rc) break; break; } if ( !file.EndWrite3dmChunk() ) rc = false; return rc; } unsigned int ON_BrepRegionTopology::SizeOf() const { return m_FS.SizeOf() + m_R.SizeOf(); } class ON_BrepRegionTopology* ON_Brep::Internal_RegionTopologyPointer( const class ON_Brep* brep, bool bValidateFaceCount ) { if (nullptr != brep && nullptr != brep->m_region_topology) { if (bValidateFaceCount && brep->m_region_topology->m_FS.UnsignedCount() != 2 * brep->m_F.UnsignedCount()) { delete brep->m_region_topology; brep->m_region_topology = nullptr; } return brep->m_region_topology; } return nullptr; } ON_BrepFaceSide* ON_BrepFace::FaceSide(int dir) const { ON_BrepFaceSide* faceside = 0; const ON_BrepRegionTopology* rtop = ON_Brep::Internal_RegionTopologyPointer(m_brep, true); if ( rtop ) { if ( m_face_index >= 0 && m_face_index < m_brep->m_F.Count() ) { int fsi = 2*m_face_index + ((dir<1)?1:0); faceside = const_cast(&rtop->m_FS[fsi]); if ( m_face_index != faceside->m_fi || dir != faceside->m_srf_dir ) faceside = 0; } } return faceside; } bool ON_Brep::HasRegionTopology() const { return (nullptr != m_region_topology); } const ON_BrepRegionTopology& ON_Brep::RegionTopology() const { bool bCreate = false; if ( nullptr == m_region_topology ) { bCreate = true; m_region_topology = new ON_BrepRegionTopology(); } else { bCreate = (m_region_topology->m_FS.UnsignedCount() != 2 * m_F.UnsignedCount()); } if (bCreate ) { } return *m_region_topology; } void ON_Brep::DestroyRegionTopology() { if (nullptr != m_region_topology) { delete m_region_topology; m_region_topology = nullptr; } } void ON_Brep::MemoryRelocate() { int i, count; // The call to the base class MemoryRelocate() takes care of // updating user data back-pointers. ON_Geometry::MemoryRelocate(); // When the memory location of an ON_Brep changes, // the m_brep backpointers on its pieces need to be updated. count = m_E.Count(); for ( i = 0; i < count; i++ ) { m_E[i].m_brep = this; } count = m_T.Count(); for ( i = 0; i < count; i++ ) { m_T[i].m_brep = this; } count = m_L.Count(); for ( i = 0; i < count; i++ ) { m_L[i].m_brep = this; } count = m_F.Count(); for ( i = 0; i < count; i++ ) { m_F[i].m_brep = this; } if ( m_region_topology ) { m_region_topology->m_brep = this; } } ON_Brep* ON_Brep::SubBrep( int subfi_count, const int* subfi, ON_Brep* sub_brep ) const { class LeakStopper : public ON_Workspace { // If an error occures during construction, // this class cleans up sub_brep in an // appropriate fashion. public: LeakStopper() {m_p=0;m_sub_brep=0;} ~LeakStopper() {if (m_p) delete m_p; else if (m_sub_brep) m_sub_brep->Destroy();} ON_Brep* m_p; // ON_Brep::SubBrep allocated sub_brep ON_Brep* m_sub_brep; // user's sub_brep argument }; LeakStopper leak_stopper; if ( sub_brep ) sub_brep->Destroy(); if ( subfi_count <= 0 || 0 == subfi ) return 0; if ( subfi_count > m_F.Count() ) return 0; // validate indices in extract_fi[] and // make sure there are no duplicates. int fi, fli, lti, i, j; int Lcount = 0; int Tcount = 0; int Ecount = 0; int Vcount = 0; int maxfi = -1; int minfi = m_F.Count(); int* Emap = leak_stopper.GetIntMemory(m_E.Count()); memset(Emap,0,m_E.Count()*sizeof(Emap[0])); int* Vmap = leak_stopper.GetIntMemory(m_V.Count()); memset(Vmap,0,m_V.Count()*sizeof(Vmap[0])); for ( i = 0; i < subfi_count; i++ ) { fi = subfi[i]; if ( fi < 0 || fi >= m_F.Count() ) { ON_ERROR("ON_Brep::SubBrep sub_fi[] has invalid indices"); return 0; } if ( fi > maxfi ) maxfi = fi; else if ( fi < minfi ) minfi = fi; else { for ( j = 0; j < i; j++ ) { if ( subfi[j] == fi ) { ON_ERROR("ON_Brep::SubBrep sub_fi[] has duplicate indices"); return 0; } } } const ON_BrepFace& face = m_F[fi]; for ( fli = 0; fli < face.m_li.Count(); fli++ ) { const ON_BrepLoop* loop = face.Loop(fli); if ( !loop || this != loop->Brep() ) return 0; Lcount++; for ( lti = 0; lti < loop->m_ti.Count(); lti++ ) { const ON_BrepTrim* trim = loop->Trim(lti); if ( !trim || this != trim->Brep() ) return 0; Tcount++; if ( trim->m_vi[0] < 0 || trim->m_vi[0] >= m_V.Count() ) return 0; if ( trim->m_vi[1] < 0 || trim->m_vi[1] >= m_V.Count() ) return 0; if ( 0 == Vmap[trim->m_vi[0]] ) { Vmap[trim->m_vi[0]] = 1; Vcount++; } if ( 0 == Vmap[trim->m_vi[1]] ) { Vmap[trim->m_vi[1]] = 1; Vcount++; } if ( ON_BrepTrim::singular == trim->m_type || ON_BrepTrim::ptonsrf == trim->m_type) // March 29, 2010 Lowell - Allow ptonsrf { if ( trim->m_ei >= 0 || trim->m_vi[0] != trim->m_vi[1] ) return 0; } else if ( trim->m_ei >= 0 ) { const ON_BrepEdge* edge = trim->Edge(); if ( 0 == edge || this != edge->Brep() ) return 0; if ( 0 == Emap[trim->m_ei] ) { Emap[trim->m_ei] = 1; Ecount++; // edge's vertices should already be mapped. if ( 0 == Vmap[edge->m_vi[0]] ) return 0; if ( 0 == Vmap[edge->m_vi[1]] ) return 0; } } else { return 0; } } } } if ( !sub_brep ) { sub_brep = ON_Brep::New(); leak_stopper.m_p = sub_brep; } else { leak_stopper.m_sub_brep = sub_brep; } sub_brep->m_F.Reserve(subfi_count); sub_brep->m_L.Reserve(Lcount); sub_brep->m_T.Reserve(Tcount); sub_brep->m_E.Reserve(Ecount); sub_brep->m_V.Reserve(Vcount); sub_brep->m_S.Reserve(subfi_count); sub_brep->m_C2.Reserve(Tcount); sub_brep->m_C3.Reserve(Ecount); // build sub_brep vertices for ( i = 0; i < m_V.Count(); i++ ) { if ( Vmap[i] ) { const ON_BrepVertex& vertex = m_V[i]; ON_BrepVertex& sub_vertex = sub_brep->NewVertex(vertex.point,vertex.m_tolerance); Vmap[i] = sub_vertex.m_vertex_index; sub_vertex.CopyUserData(vertex); // March 29, 2010 Lowell - Copy user fields memcpy(&sub_vertex.m_vertex_user, &vertex.m_vertex_user, sizeof(sub_vertex.m_vertex_user)); } else Vmap[i] = -1; } // build sub_brep edges for ( i = 0; i < m_E.Count(); i++ ) { if ( Emap[i] ) { const ON_BrepEdge& edge = m_E[i]; if ( Vmap[edge.m_vi[0]] < 0 ) return 0; if ( Vmap[edge.m_vi[1]] < 0 ) return 0; ON_Curve* c3 = edge.DuplicateCurve(); if ( 0 == c3 ) return 0; sub_brep->m_C3.Append(c3); ON_BrepVertex& sub_v0 = sub_brep->m_V[Vmap[edge.m_vi[0]]]; ON_BrepVertex& sub_v1 = sub_brep->m_V[Vmap[edge.m_vi[1]]]; ON_BrepEdge& sub_edge = sub_brep->NewEdge(sub_v0,sub_v1,sub_brep->m_C3.Count()-1,0,edge.m_tolerance); Emap[i] = sub_edge.m_edge_index; sub_edge.CopyUserData(edge); // March 29, 2010 Lowell - Copy user fields memcpy(&sub_edge.m_edge_user, &edge.m_edge_user, sizeof(sub_edge.m_edge_user)); } else Emap[i] = -1; } bool bHaveBBox = m_bbox.IsValid(); ON_BoundingBox sub_bbox; for ( i = 0; i < subfi_count; i++ ) { const ON_BrepFace& face = m_F[subfi[i]]; ON_Surface* srf = face.DuplicateSurface(); if (!srf) return 0; sub_brep->m_S.Append(srf); ON_BrepFace& sub_face = sub_brep->NewFace(sub_brep->m_S.Count()-1); sub_face.CopyUserData(face); sub_face.m_bRev = face.m_bRev; sub_face.m_face_material_channel = face.m_face_material_channel; sub_face.m_face_uuid = face.m_face_uuid; sub_face.m_bbox = face.m_bbox; sub_face.m_domain[0] = face.m_domain[0]; sub_face.m_domain[1] = face.m_domain[1]; // March 29, 2010 Lowell - Copy user fields memcpy(&sub_face.m_face_user, &face.m_face_user, sizeof(sub_face.m_face_user)); if ( bHaveBBox ) { if ( sub_face.m_bbox.IsValid() ) sub_bbox.Union(sub_face.m_bbox); else { bHaveBBox = false; sub_bbox.Destroy(); } } for ( fli = 0; fli < face.m_li.Count(); fli++ ) { const ON_BrepLoop& loop = m_L[face.m_li[fli]]; ON_BrepLoop& sub_loop = sub_brep->NewLoop(loop.m_type,sub_face); sub_loop.CopyUserData(loop); sub_loop.m_pbox = loop.m_pbox; // April 19, 2010 Lowell - Copy user fields memcpy(&sub_loop.m_loop_user, &loop.m_loop_user, sizeof(sub_loop.m_loop_user)); for ( lti = 0; lti < loop.m_ti.Count(); lti++ ) { const ON_BrepTrim& trim = m_T[loop.m_ti[lti]]; if ( Vmap[trim.m_vi[0]] < 0 || Vmap[trim.m_vi[1]] < 0 ) return 0; if ( trim.m_ei >= 0 && Emap[trim.m_ei] < 0 ) return 0; if(trim.m_c2i >= 0) { ON_Curve* c2 = trim.DuplicateCurve(); if ( !c2 ) return 0; sub_brep->m_C2.Append(c2); } else if(trim.m_type != ON_BrepTrim::ptonsrf) return 0; if ( trim.m_ei >= 0 ) { ON_BrepEdge& sub_edge = sub_brep->m_E[Emap[trim.m_ei]]; sub_brep->NewTrim(sub_edge,trim.m_bRev3d,sub_loop,sub_brep->m_C2.Count()-1); } else if ( ON_BrepTrim::singular == trim.m_type ) { ON_BrepVertex& sub_vertex = sub_brep->m_V[Vmap[trim.m_vi[0]]]; sub_brep->NewSingularTrim(sub_vertex,sub_loop,trim.m_iso,sub_brep->m_C2.Count()-1); } // March 29, 2010 Lowell - copy ptonsrf type else if ( ON_BrepTrim::ptonsrf == trim.m_type) { ON_BrepTrim& sub_trim = sub_brep->NewTrim(false, sub_loop, -1); sub_trim.m_type = ON_BrepTrim::ptonsrf; ON_BrepVertex& sub_vertex = sub_brep->m_V[Vmap[trim.m_vi[0]]]; sub_trim.m_vi[0] = sub_trim.m_vi[1] = sub_vertex.m_vertex_index; } else { return 0; } ON_BrepTrim& sub_trim = sub_brep->m_T[sub_brep->m_T.Count()-1]; sub_trim.CopyUserData(trim); sub_trim.m__legacy_2d_tol = trim.m__legacy_2d_tol; sub_trim.m__legacy_3d_tol = trim.m__legacy_3d_tol; sub_trim.m__legacy_flags = trim.m__legacy_flags; sub_trim.m_tolerance[0] = trim.m_tolerance[0]; sub_trim.m_tolerance[1] = trim.m_tolerance[1]; sub_trim.m_pbox = trim.m_pbox; sub_trim.m_iso = trim.m_iso; // April 19, 2010 Lowell - Copy user fields memcpy(&sub_trim.m_trim_user, &trim.m_trim_user, sizeof(sub_trim.m_trim_user)); // Since we are extracting a subset of the original brep, // some mated edges could turn into boundary edges. The // call to NewTrim() above will correctly handle setting // and updating sub_trims that came from mated trims. if ( ON_BrepTrim::mated != trim.m_type ) sub_trim.m_type = trim.m_type; } } } if ( !bHaveBBox || !sub_bbox.IsValid() ) sub_brep->BoundingBox(); else sub_brep->m_bbox = sub_bbox; // return subbrep after disabling the leak stopper leak_stopper.m_p = 0; leak_stopper.m_sub_brep = 0; return sub_brep; } ON_Brep* ON_BrepRegion::RegionBoundaryBrep( ON_Brep* brep ) const { ON_Workspace ws; if ( 0 == m_rtop ) return 0; const ON_Brep* rtop_brep = m_rtop->Brep(); if ( rtop_brep == brep || 0 == rtop_brep || rtop_brep->m_F.Count() <= 0 || m_fsi.Count() <= 0 ) return 0; ON_SimpleArray FS(m_fsi.Count()); ON_SimpleArray subfi(m_fsi.Count()); int rfsi, i; for ( rfsi = 0; rfsi < m_fsi.Count(); rfsi++ ) { const ON_BrepFaceSide* fs = FaceSide(rfsi); if ( 0 == fs || fs->m_fi < 0 || fs->m_fi >= rtop_brep->m_F.Count() ) return 0; for ( i = 0; i < FS.Count(); i++ ) { if ( fs->m_fi == FS[i]->m_fi ) break; } if ( i < FS.Count() ) continue; FS.Append(fs); subfi.Append(fs->m_fi); } brep = rtop_brep->SubBrep(subfi.Count(),subfi.Array(),brep); if ( !brep ) return 0; if ( brep->m_F.Count() != FS.Count() ) return 0; for ( i = 0; i < FS.Count(); i++ ) { ON_BrepFace& face = brep->m_F[i]; face.m_bRev = ( FS[i]->m_srf_dir < 0 ); } bool bIsOriented = false; bool bHasBoundary = true; if ( brep->IsManifold(&bIsOriented,&bHasBoundary) ) { if ( bIsOriented && !bHasBoundary ) { if ( 1 == m_type ) brep->m_is_solid = 2; else if ( 0 == m_type ) brep->m_is_solid = 1; } } return brep; }