/* $NoKeywords: $ */ /* // // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// */ #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 bool ON_BrepVertex::Write( ON_BinaryArchive& file ) const { bool rc = file.WriteInt( m_vertex_index ); if ( rc ) rc = file.WritePoint( point ); if ( rc ) rc = file.WriteArray( m_ei ); if ( rc ) rc = file.WriteDouble( m_tolerance ); return rc; } bool ON_BrepVertex::Read( ON_BinaryArchive& file ) { bool rc = file.ReadInt( &m_vertex_index ); if ( rc ) rc = file.ReadPoint( point ); if ( rc ) rc = file.ReadArray( m_ei ); if ( rc ) rc = file.ReadDouble( &m_tolerance ); return rc; } bool ON_BrepEdge::Write( ON_BinaryArchive& file ) const { bool rc = file.WriteInt( m_edge_index ); if (rc) rc = file.WriteInt( m_c3i ); int i = ProxyCurveIsReversed() ? 1 : 0; if (rc) rc = file.WriteInt( i ); if (rc) rc = file.WriteInterval( ProxyCurveDomain() ); if (rc) rc = file.WriteInt( 2, m_vi ); if (rc) rc = file.WriteArray( m_ti ); if (rc) rc = file.WriteDouble( m_tolerance ); if ( file.Archive3dmVersion() >= 3 ) { // added in opennurbs version 200206180 if (rc) rc = file.WriteInterval( Domain() ); } return rc; } bool ON_BrepEdge::Read( ON_BinaryArchive& file ) { int bReversed = false; ON_Interval proxy_domain; bool rc = file.ReadInt( &m_edge_index ); if (rc) rc = file.ReadInt( &m_c3i ); if (rc) rc = file.ReadInt( &bReversed ); if (rc) rc = file.ReadInterval( proxy_domain ); if (rc) rc = file.ReadInt( 2, m_vi ); if (rc) rc = file.ReadArray( m_ti ); if (rc) rc = file.ReadDouble( &m_tolerance ); ON_Interval domain = proxy_domain; if ( file.Archive3dmVersion() >= 3 && file.ArchiveOpenNURBSVersion() >= 200206180 ) { if (rc) { rc = file.ReadInterval(domain); if ( !rc) domain = proxy_domain; } } SetProxyCurve( nullptr, proxy_domain ); if ( bReversed ) ON_CurveProxy::Reverse(); SetDomain(domain); return rc; } bool ON_BrepTrim::Write( ON_BinaryArchive& file ) const { ON_3dPoint P(0.0,0.0,0.0); bool rc = file.WriteInt( m_trim_index ); int i; if ( rc ) rc = file.WriteInt( m_c2i ); if ( rc ) rc = file.WriteInterval( ProxyCurveDomain() ); if ( rc ) rc = file.WriteInt( m_ei ); if ( rc ) rc = file.WriteInt( 2, m_vi ); if ( rc ) rc = file.WriteInt( m_bRev3d ); i = m_type; if ( rc ) rc = file.WriteInt( i ); i = m_iso; if ( rc ) rc = file.WriteInt( i ); if ( rc ) rc = file.WriteInt( m_li ); if ( rc ) rc = file.WriteDouble( 2, m_tolerance ); if ( file.Archive3dmVersion() < 3 ) { if ( rc ) rc = file.WritePoint( P ); // m_P[0] ); if ( rc ) rc = file.WritePoint( P ); // m_P[1] ); } else { // trim proxy curve information added in version 200206180 if (rc ) rc = file.WriteInterval( Domain() ); unsigned char b[24]; memset(b,0,sizeof(b)); b[0] = ProxyCurveIsReversed() ? 1 : 0; if (rc) rc = file.WriteChar(8,b); b[0] = 0; if (rc) rc = file.WriteChar(24,b); } if ( rc ) rc = file.WriteDouble( m__legacy_2d_tol ); if ( rc ) rc = file.WriteDouble( m__legacy_3d_tol ); return rc; } bool ON_BrepTrim::Read( ON_BinaryArchive& file ) { ON_3dPoint P[2]; int i; bool rc = file.ReadInt( &m_trim_index ); if ( rc ) rc = file.ReadInt( &m_c2i ); if ( rc ) { ON_Interval d; rc = file.ReadInterval( d ); if (rc) { SetProxyCurveDomain(d); SetDomain(d); } } if ( rc ) rc = file.ReadInt( &m_ei ); if ( rc ) rc = file.ReadInt( 2, m_vi ); if ( rc ) { i = m_bRev3d; rc = file.ReadInt( &i ); if (rc) m_bRev3d = (i!=0); } i = unknown; if ( rc ) rc = file.ReadInt( &i ); switch (i) { case unknown: m_type = unknown; break; case boundary: m_type = boundary; break; case mated: m_type = mated; break; case seam: m_type = seam; break; case singular: m_type = singular; break; } i = ON_Surface::not_iso; if ( rc ) rc = file.ReadInt( &i ); switch(i) { case ON_Surface::not_iso: m_iso = ON_Surface::not_iso; break; case ON_Surface::x_iso: m_iso = ON_Surface::x_iso; break; case ON_Surface::y_iso: m_iso = ON_Surface::y_iso; break; case ON_Surface::W_iso: m_iso = ON_Surface::W_iso; break; case ON_Surface::S_iso: m_iso = ON_Surface::S_iso; break; case ON_Surface::E_iso: m_iso = ON_Surface::E_iso; break; case ON_Surface::N_iso: m_iso = ON_Surface::N_iso; break; } if ( rc ) rc = file.ReadInt( &m_li ); if ( rc ) rc = file.ReadDouble( 2, m_tolerance ); if ( file.Archive3dmVersion() >= 3 && file.ArchiveOpenNURBSVersion() >= 200206180 ) { // read trim proxy curve information added in version 200206180 ON_Interval d = ProxyCurveDomain(); if (rc ) { rc = file.ReadInterval( d ); if ( !rc ) d = ProxyCurveDomain(); } unsigned char b[24]; memset(b,0,sizeof(b)); bool bProxyCurveIsReversed = false; if (rc) { rc = file.ReadChar(8,b); if (rc && b[0] == 1 ) bProxyCurveIsReversed = true; } if (rc) rc = file.ReadChar(24,b); if ( bProxyCurveIsReversed ) ON_CurveProxy::Reverse(); SetDomain(d); } else { if ( rc ) rc = file.ReadPoint( P[0] ); //m_P[0] ); if ( rc ) rc = file.ReadPoint( P[1] ); //m_P[1] ); } if ( rc ) rc = file.ReadDouble( &m__legacy_2d_tol ); if ( rc ) rc = file.ReadDouble( &m__legacy_3d_tol ); return rc; } bool ON_BrepLoop::Write( ON_BinaryArchive& file ) const { int i; bool rc = file.WriteInt( m_loop_index ); if (rc) rc = file.WriteArray( m_ti ); i = m_type; if (rc) rc = file.WriteInt( i ); if (rc) rc = file.WriteInt( m_fi ); return rc; } bool ON_BrepLoop::Read( ON_BinaryArchive& file ) { int i; bool rc = file.ReadInt( & m_loop_index ); if (rc) rc = file.ReadArray( m_ti ); i = unknown; if (rc) rc = file.ReadInt( &i ); switch(i) { case unknown: m_type = unknown; break; case outer: m_type = outer; break; case inner: m_type = inner; break; case slit: m_type = slit; break; } if (rc) rc = file.ReadInt( &m_fi ); return rc; } bool ON_BrepFace::Write( ON_BinaryArchive& file ) const { bool rc = file.WriteInt( m_face_index ); if ( rc ) rc = file.WriteArray( m_li ); if ( rc ) rc = file.WriteInt( m_si ); if ( rc ) rc = file.WriteInt( m_bRev ); if ( rc ) rc = file.WriteInt( m_face_material_channel ); return rc; } bool ON_BrepFace::Read( ON_BinaryArchive& file ) { int i; bool rc = file.ReadInt( &m_face_index ); if ( rc ) rc = file.ReadArray( m_li ); if ( rc ) rc = file.ReadInt( &m_si ); if ( rc ) { i = m_bRev; rc = file.ReadInt( &i ); if ( rc ) m_bRev = (i!=0); } if ( rc ) { rc = file.ReadInt( &m_face_material_channel ); if ( m_face_material_channel < 0 ) m_face_material_channel = 0; } return rc; } bool ON_BrepVertexArray::Read( ON_BinaryArchive& file ) { Empty(); ON__UINT32 tcode = 0; ON__INT64 length_TCODE_ANONYMOUS_CHUNK = 0; int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmBigChunk( &tcode, &length_TCODE_ANONYMOUS_CHUNK ); if (rc) { if (tcode != TCODE_ANONYMOUS_CHUNK) rc = false; if (rc) rc = file.Read3dmChunkVersion(&major_version,&minor_version); if (rc) { if ( major_version==1 ) { if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc ; i++ ) { ON_BrepVertex& vertex = AppendNew(); rc = vertex.Read(file)?true:false; } } else { rc = 0; } } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepVertexArray::Write( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if (rc) { rc = file.Write3dmChunkVersion(1,0); const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { if (rc) rc = m_a[i].Write(file); } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_BrepEdgeArray::Read( ON_BinaryArchive& file ) { Empty(); ON__UINT32 tcode = 0; ON__INT64 length_TCODE_ANONYMOUS_CHUNK = 0; int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmBigChunk( &tcode, &length_TCODE_ANONYMOUS_CHUNK ); if (rc) { if (tcode != TCODE_ANONYMOUS_CHUNK) rc = false; if (rc) rc = file.Read3dmChunkVersion(&major_version,&minor_version); if (rc) { if ( major_version==1 ) { if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc ; i++ ) { ON_BrepEdge& edge = AppendNew(); rc = edge.Read(file) ? true : false; } } else { rc = 0; } } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepEdgeArray::Write( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if (rc) { rc = file.Write3dmChunkVersion(1,0); const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { if (rc) rc = m_a[i].Write(file); } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_BrepTrimArray::Read( ON_BinaryArchive& file ) { Empty(); ON__UINT32 tcode = 0; ON__INT64 length_TCODE_ANONYMOUS_CHUNK = 0; int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmBigChunk( &tcode, &length_TCODE_ANONYMOUS_CHUNK ); if (rc) { if (tcode != TCODE_ANONYMOUS_CHUNK) rc = false; if (rc) rc = file.Read3dmChunkVersion(&major_version,&minor_version); if (rc) { if ( major_version==1 ) { if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc ; i++ ) { ON_BrepTrim& trim = AppendNew(); rc = trim.Read(file)?true:false; if ( rc ) { if ( trim.m_trim_index != m_count-1 ) { // 28 May 2013 Dale Lear // Fix http://mcneel.myjetbrains.com/youtrack/issue/RH-18299 // Fix bogus index values to prevent crashes. ON_ERROR("Invalid value of m_trim_index"); trim.m_trim_index = m_count-1; } } } } else { rc = 0; } } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepTrimArray::Write( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if (rc) { rc = file.Write3dmChunkVersion(1,0); const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { if (rc) rc = m_a[i].Write(file); } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_BrepLoopArray::Read( ON_BinaryArchive& file ) { Empty(); ON__UINT32 tcode = 0; ON__INT64 length_TCODE_ANONYMOUS_CHUNK = 0; int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmBigChunk( &tcode, &length_TCODE_ANONYMOUS_CHUNK ); if (rc) { if (tcode != TCODE_ANONYMOUS_CHUNK) rc = false; if (rc) rc = file.Read3dmChunkVersion(&major_version,&minor_version); if (rc) { if ( major_version==1 ) { if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc ; i++ ) { ON_BrepLoop& loop = AppendNew(); rc = loop.Read(file) ? true : false; } } else { rc = 0; } } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepLoopArray::Write( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if (rc) { rc = file.Write3dmChunkVersion(1,0); const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { if (rc) rc = m_a[i].Write(file); } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_BrepFaceArray::Read( ON_BinaryArchive& file ) { Empty(); ON__UINT32 tcode = 0; ON__INT64 length_TCODE_ANONYMOUS_CHUNK = 0; int count = 0; int i; int major_version = 0; int minor_version = 0; bool rc = file.BeginRead3dmBigChunk( &tcode, &length_TCODE_ANONYMOUS_CHUNK ); if (rc) { if (tcode != TCODE_ANONYMOUS_CHUNK) rc = false; if (rc) rc = file.Read3dmChunkVersion(&major_version,&minor_version); if (rc) { if ( major_version==1 ) { if (rc) rc = file.ReadInt(&count); SetCapacity(count); for ( i = 0; i < count && rc ; i++ ) { ON_BrepFace& face = AppendNew(); rc = face.Read(file)?true:false; } if ( minor_version >= 1 ) { // chunk version 1.1 and later has face uuids for ( i = 0; i < count && rc; i++ ) { rc = file.ReadUuid( m_a[i].m_face_uuid ); } if (rc && minor_version >= 2) { // chunk version 1.2 and later has per face colors bool bHavePerFaceColors = false; rc = file.ReadBool(&bHavePerFaceColors); if (rc && bHavePerFaceColors) { for (i = 0; rc && i < count; i++) { ON_Color per_face_color = ON_Color::UnsetColor; rc = file.ReadColor(per_face_color); if (rc && ON_Color::UnsetColor != per_face_color) m_a[i].SetPerFaceColor(per_face_color); } } } } } else { rc = 0; } } if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BrepFaceArray::Write( ON_BinaryArchive& file ) const { int i; bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if (rc) { // 1.1 added m_face_uuid // 1.2 added m_per_face_color const int minor_version = file.Archive3dmVersion() >= 70 ? 2 : 1; rc = file.Write3dmChunkVersion(1, minor_version); // chunk version 1.0 and later const int count = Count(); if (rc) rc = file.WriteInt( count ); for ( i = 0; rc && i < count; i++ ) { if (rc) rc = m_a[i].Write(file); } // chunk version 1.1 and later for ( i = 0; rc && i < count; i++ ) { rc = file.WriteUuid( m_a[i].m_face_uuid ); } if (rc && minor_version >= 2) { // 1.2 added optional per face colors bool bHavePerFaceColors = false; for (i = 0; rc && i < count; i++) { if (ON_Color::UnsetColor != m_a[i].PerFaceColor()) { bHavePerFaceColors = true; break; } } rc = file.WriteBool(bHavePerFaceColors); if (rc && bHavePerFaceColors) { for (i = 0; rc && i < count; i++) rc = file.WriteColor(m_a[i].PerFaceColor()); } } if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_Brep::Write( ON_BinaryArchive& file ) const { const ON_Brep* brep = this; ON_Brep* v2brep = 0; //bool rc = file.Write3dmChunkVersion(3,0); // serialization version //bool rc = file.Write3dmChunkVersion(3,1); // added meshes int minor_version = (file.Archive3dmVersion() <= 50) ? 2 : 3 // August 9, 2016 m_region_topology added to V6 files. ; bool rc = file.Write3dmChunkVersion(3,minor_version); // added m_is_solid // 2d curves if (rc) rc = brep->m_C2.Write(file); // 3d curves if (rc) rc = brep->m_C3.Write(file); // untrimmed surfaces if (rc) rc = brep->m_S.Write(file); // vertices if (rc) rc = brep->m_V.Write(file); // edges if (rc) rc = brep->m_E.Write(file); // trims if (rc) rc = brep->m_T.Write(file); // loops if (rc) rc = brep->m_L.Write(file); // faces if (rc) rc = brep->m_F.Write(file); // bounding box if (rc) rc = file.WritePoint( brep->m_bbox.m_min ); if (rc) rc = file.WritePoint( brep->m_bbox.m_max ); // end of chunk version 3.0 if (rc) { // added for chunk version 3.1 const int face_count = brep->m_F.Count(); int fi; unsigned char b; // write render meshes rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if ( rc ) { for ( fi = 0; rc && fi < face_count; fi++ ) { const ON_Mesh* mesh = file.Save3dmRenderMesh(ON::object_type::brep_object) ? brep->m_F[fi].m_render_mesh : 0; b = mesh ? 1 : 0; rc = file.WriteChar(b); if (rc && mesh) { rc = file.WriteObject(*mesh); } } if ( !file.EndWrite3dmChunk() ) { rc = false; } } // write analysis meshes if (rc) rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if ( rc ) { for ( fi = 0; rc && fi < face_count; fi++ ) { const ON_Mesh* mesh = file.Save3dmAnalysisMesh(ON::object_type::brep_object) ? brep->m_F[fi].m_analysis_mesh : 0; b = mesh ? 1 : 0; rc = file.WriteChar(b); if (rc && mesh) { rc = file.WriteObject(*mesh); } } if ( !file.EndWrite3dmChunk() ) rc = false; } } // end of chunk version 3.1 if (rc) { // use value of "this" m_is_solid to avoid expensive // calculation on the v2brep if ( !file.WriteInt( m_is_solid ) ) rc = false; } // end of chunk version 3.2 if (rc) { const bool bWriteRegionTopology = (nullptr != m_region_topology) && (m_F.UnsignedCount() > 0) && (m_region_topology->m_FS.UnsignedCount() == 2 * m_F.UnsignedCount()); if (minor_version <= 2) { if (bWriteRegionTopology && minor_version == 2 && 50 == file.Archive3dmVersion()) Internal_AttachV5RegionTopologyAsUserData(file); } else if (minor_version >= 3) { // begin chunk verson 3.3 // region topology chunk added if (!file.BeginWrite3dmAnonymousChunk(1)) return false; rc = false; for (;;) { if (!file.WriteBool(bWriteRegionTopology)) break; if (bWriteRegionTopology) { if (!m_region_topology->Write(file)) break; } rc = true; break; } if (!file.EndWrite3dmChunk()) rc = false; // end chunk version 3.3 } } if ( 0 != v2brep ) delete v2brep; return rc; } static void ReadFillInMissingBoxes( ON_Brep& brep ) { // older files did not save bounding box information int ti, li, lti, trim_count, loop_count; const ON_Curve* c2; trim_count = brep.m_T.Count(); loop_count = brep.m_L.Count(); for ( ti = 0; ti < trim_count; ti++ ) { ON_BrepTrim& trim = brep.m_T[ti]; if ( !trim.m_pbox.IsValid() ) { c2 = trim.TrimCurveOf(); if ( c2 ) trim.m_pbox = c2->BoundingBox(); } } for ( li = 0; li < loop_count; li++ ) { ON_BrepLoop& loop = brep.m_L[li]; if ( !loop.m_pbox.IsValid() ) { for ( lti = 0; lti < loop.m_ti.Count(); lti++ ) { ti = loop.m_ti[lti]; if ( ti >= 0 && ti < trim_count ) loop.m_pbox.Union( brep.m_T[ti].m_pbox ); } } } } static const ON_BoundingBox Internal_BestBoundingBox( const ON_BoundingBox archive_bbox, const ON_BoundingBox new_bbox ) { if (false == new_bbox.IsNotEmpty()) return archive_bbox; // don't have a new bbox if (false == archive_bbox.IsValid()) return new_bbox; if (archive_bbox.Includes(new_bbox, false)) return new_bbox; // The best code currently available calculated new_box. // I should be good enough. If it is different // from archive then you need to understand WHY it is different // and fix the problem at the source - not mask it at read time. return new_bbox; // <- Good place to debug bbox reading bugs } bool ON_Brep::Read( ON_BinaryArchive& file ) { int i; int C2_count = 0; int C3_count = 0; int S_count = 0; int major_version = 0; int minor_version = 0; bool rc = file.Read3dmChunkVersion( &major_version, &minor_version ); if ( rc && major_version == 2 ) { rc = ReadOld200(file,minor_version); // legacy trimmed face } else if ( rc && major_version == 3 ) { // 2d curves if (rc) rc = m_C2.Read(file); C2_count = m_C2.Count(); // 3d curves if (rc) rc = m_C3.Read(file); C3_count = m_C3.Count(); // untrimmed surfaces if (rc) rc = m_S.Read(file); S_count = m_S.Count(); // vertices if (rc) rc = m_V.Read(file); // edges if (rc) { rc = m_E.Read(file); if (rc) { for ( i = 0; i < m_E.Count(); i++ ) { ON_BrepEdge& e = m_E[i]; e.m_brep = this; if ( e.m_c3i >= 0 && e.m_c3i < C3_count ) { bool bProxyCurveIsReversed = e.ProxyCurveIsReversed(); ON_Interval pdom = e.ProxyCurveDomain(); ON_Interval edom = e.Domain(); e.SetProxyCurve( m_C3[e.m_c3i], pdom ); if ( bProxyCurveIsReversed ) e.ON_CurveProxy::Reverse(); e.SetDomain(edom); } } } } // trims if (rc) { rc = m_T.Read(file); if (rc) { for ( i = 0; i < m_T.Count(); i++ ) { ON_BrepTrim& trim = m_T[i]; trim.m_brep = this; if ( trim.m_c2i >= 0 && trim.m_c2i < C2_count ) { bool bProxyCurveIsReversed = trim.ProxyCurveIsReversed(); ON_Interval pdom = trim.ProxyCurveDomain(); ON_Interval tdom = trim.Domain(); trim.SetProxyCurve( m_C2[trim.m_c2i], pdom ); if ( bProxyCurveIsReversed ) trim.ON_CurveProxy::Reverse(); trim.SetDomain(tdom); } } } } // loops if (rc) { rc = m_L.Read(file); if ( rc ) { for ( i = 0; i < m_L.Count(); i++ ) { m_L[i].m_brep = this; } } } // faces if (rc) { rc = m_F.Read(file); if (rc) { for ( i = 0; i < m_F.Count(); i++ ) { ON_BrepFace& f = m_F[i]; f.m_brep = this; if ( f.m_si >= 0 && f.m_si < S_count ) f.SetProxySurface(m_S[f.m_si]); } } } // bounding box if (rc) rc = file.ReadPoint( m_bbox.m_min ); if (rc) rc = file.ReadPoint( m_bbox.m_max ); // fill in missing information ReadFillInMissingBoxes(*this); // end of chunk version 3.0 if (rc && minor_version >= 1 ) { // added for chunk version 3.1 ON_Object* obj; ON__UINT32 tcode = 0; ON__INT64 length_TCODE_ANONYMOUS_CHUNK = 0; int fi; unsigned char b; const int face_count = m_F.Count(); // read render meshes tcode = 0; length_TCODE_ANONYMOUS_CHUNK = 0; rc = file.BeginRead3dmBigChunk( &tcode, &length_TCODE_ANONYMOUS_CHUNK ); if ( rc ) { if ( tcode != TCODE_ANONYMOUS_CHUNK ) rc = false; else { for ( fi = 0; rc && fi < face_count; fi++ ) { rc = file.ReadChar(&b); if (rc && b) { obj = 0; rc = file.ReadObject(&obj); if ( 0 != obj ) { m_F[fi].m_render_mesh = ON_Mesh::Cast(obj); if ( !m_F[fi].m_render_mesh ) delete obj; } } } } if ( !file.EndRead3dmChunk() ) rc = false; } if (rc) { // read analysis meshes tcode = 0; length_TCODE_ANONYMOUS_CHUNK = 0; rc = file.BeginRead3dmBigChunk( &tcode, &length_TCODE_ANONYMOUS_CHUNK ); if ( rc ) { if ( tcode != TCODE_ANONYMOUS_CHUNK ) rc = false; else { for ( fi = 0; rc && fi < face_count; fi++ ) { rc = file.ReadChar(&b); if (rc && b) { rc = file.ReadObject(&obj); m_F[fi].m_analysis_mesh = ON_Mesh::Cast(obj); if ( !m_F[fi].m_analysis_mesh ) delete obj; } } } if ( !file.EndRead3dmChunk() ) rc = false; } } } if ( rc && minor_version >= 2 ) { rc = file.ReadInt( &m_is_solid ); if ( m_is_solid < 0 || m_is_solid >= 3 ) m_is_solid = 0; if (rc && minor_version >= 3) { // begin chunk verson 3.3 // region topology chunk added int region_topology_chunk_version = 0; if (!file.BeginRead3dmAnonymousChunk(®ion_topology_chunk_version)) rc = false; else { bool rc1 = false; for (;;) { if (region_topology_chunk_version < 1) break; bool bReadRegionTopology = false; if (!file.ReadBool(&bReadRegionTopology)) break; if (bReadRegionTopology) { m_region_topology = new ON_BrepRegionTopology(); if (!m_region_topology->Read(file)) { delete m_region_topology; m_region_topology = nullptr; break; } } rc1 = true; break; } if (!file.EndRead3dmChunk()) rc1 = false; if (false == rc1) rc = false; } } } } if ( file.ArchiveOpenNURBSVersion() < 20021002 ) { m_is_solid = 0; } // GBA 3-Sept-20 RH-60112 // In V6 and earlier bounding boxes of faces were bounding box of underlying surface. // This can result in enourmous boxes which mess up make2d // In V7 bounding boxes use the trim pbox resulting in resonable boxes. ////if (file.Archive3dmVersion() < 70 || file.ArchiveOpenNURBSVersion() < 2382395020) ////{ //// if (!m_bbox.IsEmpty()) //// { //// ON_BoundingBox orig_box = m_bbox; //// ClearBoundingBox(); //// BoundingBox(); // compute bounding box //// m_bbox.Intersection(orig_box); //// } ////} // Dale Lear https://mcneel.myjetbrains.com/youtrack/issue/RH-64277 // The test used to fix RH-60112 was not adequate and now the set of // active v7 3dm files has lots of cases with breps that have // oversized bounding boxes by the new standard avter Greg's RH-60112 changes. // We have already started writing V8 files and those versions of V8 // have been used by some of our Discourse early adopters. // At this point, I'm going to assume a bounding box read from a V7 or V8 file // can be too big. By the time V9 rolls around, the boxes should be cleaned up. if (file.Archive3dmVersion() < 90 && m_bbox.IsNotEmpty() ) { const ON_BoundingBox archive_brep_bbox = m_bbox; ON_BoundingBox new_brep_bbox = ON_BoundingBox::EmptyBoundingBox; const unsigned int face_count = m_F.UnsignedCount(); for (unsigned fi = 0; fi < face_count; ++fi) { ON_BrepFace& f = this->m_F[fi]; const ON_BoundingBox archive_face_bbox = f.m_bbox; ON_BoundingBox new_face_bbox = f.InternalFaceBoundingBox(false, false); f.m_bbox = Internal_BestBoundingBox(archive_face_bbox, new_face_bbox); new_brep_bbox.Union(f.m_bbox); } m_bbox = Internal_BestBoundingBox(archive_brep_bbox, new_brep_bbox); } return rc; } bool ON_Brep::ReadOld200( ON_BinaryArchive& file, int minor_version ) { bool rc = true; // read legacy trimmed surface collection from Rhino 2.0 int face_count = 0; int edge_count = 0; int loop_count = 0; int trim_count = 0; int outer_flag = 0; ON_BoundingBox bnd_2d_bbox; int i, fi, fbi, fbcnt, bti, btcnt, twin_index; int ftype_flag, btype_flag, gcon_flag, mono_flag; char b; if (rc) rc = file.ReadInt( &face_count ); if (rc) rc = file.ReadInt( &edge_count ); if (rc) rc = file.ReadInt( &loop_count ); if (rc) rc = file.ReadInt( &trim_count ); if ( face_count < 1 || edge_count < 1 || loop_count < 1 || trim_count < 1 ) rc = false; if (rc) rc = file.ReadInt( &outer_flag ); if (rc) rc = file.ReadPoint( m_bbox.m_min ); if (rc) rc = file.ReadPoint( m_bbox.m_max ); // 2d curves m_C2.Reserve(trim_count); for ( i = 0; rc && i < trim_count; i++ ) { ON_PolyCurve* curve = new ON_PolyCurve(); rc = curve->Read( file )?true:false; if ( curve->Count() == 1 ) { m_C2.Append( curve->HarvestSegment(0) ); delete curve; } else m_C2.Append( curve ); } const int c2_count = m_C2.Count(); // 3d curves m_C3.Reserve(edge_count); for ( i = 0; rc && i < edge_count; i++ ) { ON_PolyCurve* curve = new ON_PolyCurve(); rc = curve->Read( file )?true:false; if ( curve->Count() == 1 ) { m_C3.Append( curve->HarvestSegment(0) ); delete curve; } else m_C3.Append( curve ); } const int c3_count = m_C3.Count(); // make a new edge for each 3d curve m_E.Reserve(c3_count); for ( i = 0; i < c3_count && rc; i++ ) { NewEdge(i); } // 3d surfaces m_S.Reserve(face_count); for ( i = 0; rc && i < face_count; i++ ) { ON_NurbsSurface* surface = new ON_NurbsSurface(); rc = surface->Read( file )?true:false; m_S.Append( surface ); } ON_SimpleArray te_index(trim_count); ON_SimpleArray te_twin_index(trim_count); m_F.Reserve(face_count); m_L.Reserve(loop_count); m_T.Reserve(trim_count); for ( fi = 0; rc && fi < face_count; fi++ ) { ftype_flag = 0; fbcnt = 0; ON_BrepFace& f = NewFace(fi); if (rc) rc = file.ReadInt( &i ); // legacy face index if (rc) rc = file.ReadInt( &i ); // OBSOLETE f.m_material_index int k = f.m_bRev; if (rc) rc = file.ReadInt( &k ); if (rc) f.m_bRev = (k!=0); if (rc) rc = file.ReadInt( &ftype_flag ); if (rc) rc = file.ReadPoint( f.m_bbox.m_min ); if (rc) rc = file.ReadPoint( f.m_bbox.m_max ); if (rc) rc = file.ReadInt( &fbcnt); if (fbcnt < 1 ) rc = false; for ( fbi = 0; rc && fbi < fbcnt; fbi++ ) { btype_flag = 0; ON_BrepLoop::TYPE looptype = ON_BrepLoop::unknown; if (rc) rc = file.ReadInt( &i ); // legacy loop index if (rc) rc = file.ReadInt( &btype_flag ); switch (btype_flag) { case 0: looptype = ON_BrepLoop::outer; break; case 1: looptype = ON_BrepLoop::inner; break; case -1: looptype = ON_BrepLoop::slit; break; default: looptype = ON_BrepLoop::unknown; break; } if (rc) rc = file.ReadDouble( 2, &bnd_2d_bbox.m_min.x ); if (rc) rc = file.ReadDouble( 2, &bnd_2d_bbox.m_max.x ); btcnt = 0; if (rc) rc = file.ReadInt( &btcnt ); if (btcnt < 1 ) rc = false; ON_BrepLoop& bnd = NewLoop(looptype,f); for ( bti = 0; rc && bti < btcnt; bti++ ) { ON_BrepTrim& trim = NewTrim(false,bnd,m_T.Count()); te_index.Append(trim.m_trim_index); if (rc) rc = file.ReadInt( &i ); // legacy trim index if ( trim.m_trim_index != i ) { ON_ERROR("ON_Brep::ReadOld200 - trim.m_trim_index out of synch."); //rc = false; //break; } if (rc) rc = file.ReadInt( &twin_index ); te_twin_index.Append(twin_index); b = 0; if (rc) rc = file.ReadChar( &b ); // true if legacy trim managed 3d edge if (rc) rc = file.ReadInt( &trim.m_ei ); if ( trim.m_ei < 0 || trim.m_ei >= c3_count ) { trim.m_ei = -1; if (b) { ON_ERROR("ON_Brep::ReadOld201 - trim.m_ei out of range."); rc = false; break; } } if ( trim.m_trim_index >= 0 && trim.m_trim_index < c2_count ) trim.m_c2i = trim.m_trim_index; else { ON_ERROR("ON_Brep::ReadOld200 - trim.m_trim_index out of range."); rc = false; trim.m_c2i = -1; break; } int bRev3d_as_int = trim.m_bRev3d; if (rc) rc = file.ReadInt(&bRev3d_as_int); if (rc) trim.m_bRev3d = (bRev3d_as_int!=0); if (rc) rc = file.ReadInt(&gcon_flag); if (rc) rc = file.ReadInt(&mono_flag); if (rc) rc = file.ReadDouble(&trim.m__legacy_3d_tol); if (rc) rc = file.ReadDouble(&trim.m__legacy_2d_tol); } } } // finish hooking trims to edges if (rc) { int trim_index; for ( i = 0; i < trim_count; i++ ) { trim_index = te_index[i]; if ( trim_index >= 0 && trim_index < m_T.Count() ) continue; twin_index = te_twin_index[i]; if ( twin_index >= 0 && twin_index < m_T.Count() ) continue; ON_BrepTrim& trim1 = m_T[trim_index]; ON_BrepTrim& trim2 = m_T[twin_index]; if ( trim1.m_ei >= 0 && trim1.m_ei < c2_count && trim2.m_ei < 0 ) trim2.m_ei = trim1.m_ei; else if ( trim2.m_ei >= 0 && trim2.m_ei < c2_count && trim1.m_ei < 0 ) trim1.m_ei = trim2.m_ei; } for ( i = 0; i < m_T.Count(); i++ ) { ON_BrepTrim& trim = m_T[i]; ON_Curve* tcurve = m_C2[trim.m_c2i]; trim.SetProxyCurve( tcurve ); if ( trim.m_ei >= 0 && trim.m_ei < c3_count ) m_E[trim.m_ei].m_ti.Append(trim.m_trim_index); } // finish setting flags SetTrimIsoFlags(); SetTrimTypeFlags(); // create 3d vertex information SetVertices(); // set tols from values in file SetTolsFromLegacyValues(); } else { Destroy(); } if (rc) { // 3d render mesh geometry ON_Object* obj; for ( i = 0; rc && i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; file.ReadChar(&b); if (b) { obj = 0; rc = (file.ReadObject(&obj)==1)?true:false; f.m_render_mesh = ON_Mesh::Cast(obj); if ( !f.m_render_mesh ) delete obj; } } if ( !rc ) { // delete render mesh geometry for ( i = 0; i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; if ( f.m_render_mesh ) { delete f.m_render_mesh; f.m_render_mesh = 0; } } } if (rc && minor_version >= 1) { // 3d analysis mesh geometry for ( i = 0; rc && i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; file.ReadChar(&b); if (b) { obj = 0; rc = file.ReadObject(&obj)?true:false; f.m_analysis_mesh = ON_Mesh::Cast(obj); if ( !f.m_analysis_mesh ) delete obj; } } if ( !rc ) { // delete analysis mesh geometry for ( i = 0; i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; if ( f.m_analysis_mesh ) { delete f.m_analysis_mesh; f.m_analysis_mesh = 0; } } } } // fill in missing information ReadFillInMissingBoxes(*this); if (!rc ) { ON_ERROR("ON_Brep::ReadOld201() - trouble reading render/analysis meshes"); rc = true; } } // 22 April 2003: // Use outer_flag to set m_is_solid for closed solids // with outward pointing normals. if ( 1 == outer_flag && IsSolid() ) m_is_solid = 1; return rc; } bool ON_Brep::ReadOld100( ON_BinaryArchive& file ) { // b-rep was written by old Rhino I/O tookit int sz, i; // 2d curve geometry file.ReadInt( &sz ); if ( sz < 1 ) { return false; } m_C2.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_C2.Append( Read100_BrepCurve( file ) ); } // 3d curve geomery file.ReadInt( &sz ); if ( sz < 1 ) { return false; } m_C3.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_C3.Append( Read100_BrepCurve( file ) ); } // surface geometry file.ReadInt( &sz ); if ( sz < 1 ) { return false; } m_S.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_S.Append( Read100_BrepSurface( file ) ); } /* CRhinoChunk* pChunk; CRhinoNurbsSurface* pSurface; const int typecode, length; for ( i = 0; i < sz; i++ ) { file.ReadInt( &typecode ); if ( typecode == TCODE_RHINO_OBJECT_NURBS_SURFACE && length > 0 ) { pSurface = (CRhinoNurbsSurface*)pChunk; } m_S.Append( pSurface ); } */ // read topology // vertices file.ReadInt( &sz ); m_V.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_V.AppendNew(); m_V[i].Read(file); } // edges file.ReadInt( &sz ); m_E.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_E.AppendNew(); m_E[i].Read(file); } // trims file.ReadInt( &sz ); m_T.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_T.AppendNew(); m_T[i].Read(file); } // loops file.ReadInt( &sz ); m_L.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_L.AppendNew(); m_L[i].Read(file); } // faces file.ReadInt( &sz ); m_F.Reserve(sz); for ( i = 0; i < sz; i++ ) { m_F.AppendNew(); m_F[i].Read(file); } // bounding box file.ReadPoint( m_bbox.m_min ); file.ReadPoint( m_bbox.m_max ); // fill in missing information ReadFillInMissingBoxes(*this); return true; } bool ON_Brep::ReadOld101( ON_BinaryArchive& file ) { ON_Object* pO = nullptr; ON_Curve* pC = nullptr; ON_Surface* pS = nullptr; int i, count; // 2d curves file.ReadInt( &count ); m_C2.Reserve(count); for ( i = 0; i < count; i++ ) { pO = nullptr; file.ReadObject( &pO ); pC = ON_Curve::Cast(pO); if ( !pC ) delete pO; // ERROR! m_C2.Append( pC ); pC = nullptr; pO = nullptr; } // 3d curves file.ReadInt( &count ); m_C3.Reserve(count); for ( i = 0; i < count; i++ ) { pO = nullptr; file.ReadObject( &pO ); pC = ON_Curve::Cast(pO); if ( !pC ) delete pO; // ERROR! m_C3.Append( pC ); pC = nullptr; pO = nullptr; } // untrimmed surfaces file.ReadInt( &count ); m_S.Reserve(count); for ( i = 0; i < count; i++ ) { pO = nullptr; file.ReadObject( &pO ); pS = ON_Surface::Cast(pO); if ( !pS ) delete pO; // ERROR! m_S.Append( pS ); pS = nullptr; pO = nullptr; } // vertices file.ReadInt( &count ); m_V.Reserve(count); m_V.SetCount(count); for ( i = 0; i < count; i++ ) { m_V[i].Read(file); } // edges file.ReadInt( &count ); m_E.Reserve(count); m_E.SetCount(count); for ( i = 0; i < count; i++ ) { ON_BrepEdge& edge = m_E[i]; edge.Read(file); edge.SetProxyCurve( edge.m_c3i >= 0 ? m_C3[edge.m_c3i] : 0 ); edge.m_brep = this; } // trims file.ReadInt( &count ); m_T.Reserve(count); m_T.SetCount(count); for ( i = 0; i < count; i++ ) { m_T[i].Read(file); ON_BrepTrim& trim = m_T[i]; trim.SetProxyCurve( trim.m_c2i >= 0 ? m_C2[trim.m_c2i] : 0 ); trim.m_brep = this; } // loops file.ReadInt( &count ); m_L.Reserve(count); m_L.SetCount(count); for ( i = 0; i < count; i++ ) { m_L[i].Read(file); m_L[i].m_brep = this; } // faces file.ReadInt( &count ); m_F.Reserve(count); m_F.SetCount(count); for ( i = 0; i < count; i++ ) { ON_BrepFace& face = m_F[i]; face.Read(file); face.SetProxySurface(face.m_si >= 0 ? m_S[face.m_si] : 0); face.m_brep = this; } // bounding box file.ReadPoint( m_bbox.m_min ); file.ReadPoint( m_bbox.m_max ); // fill in missing information ReadFillInMissingBoxes(*this); return true; } ON_Curve* ON_Brep::Read100_BrepCurve( ON_BinaryArchive& ) const { // TODO - look at old Rhino I/O tookit code and read b-rep curves return nullptr; } ON_Surface* ON_Brep::Read100_BrepSurface( ON_BinaryArchive& ) const { // TODO - look at old Rhino I/O tookit code and read b-rep surfaces return nullptr; }