Files
opennurbs/opennurbs_brep_io.cpp
2024-02-15 08:00:36 -08:00

1702 lines
41 KiB
C++

//
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
// McNeel & Associates.
//
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
//
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
//
////////////////////////////////////////////////////////////////
#include "opennurbs.h"
#if !defined(ON_COMPILING_OPENNURBS)
// This check is included in all opennurbs source .c and .cpp files to insure
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
// and the opennurbs .h files alter what is declared and how it is declared.
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
#endif
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 auto mesh = file.Save3dmRenderMesh(ON::object_type::brep_object) ? brep->m_F[fi].SharedMesh(ON::render_mesh) : nullptr;
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 auto mesh = file.Save3dmAnalysisMesh(ON::object_type::brep_object) ? brep->m_F[fi].SharedMesh(ON::analysis_mesh) : nullptr;
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 )
{
auto pMesh = ON_Mesh::Cast(obj);
if (nullptr == pMesh)
{
delete obj;
}
else
{
m_F[fi].SetMesh(ON::render_mesh, pMesh);
}
}
}
}
}
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);
if (nullptr != obj)
{
auto pMesh = ON_Mesh::Cast(obj);
if (nullptr == pMesh)
{
delete obj;
}
else
{
m_F[fi].SetMesh(ON::analysis_mesh, pMesh);
}
}
}
}
}
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(&region_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<int> te_index(trim_count);
ON_SimpleArray<int> 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;
if (nullptr != obj)
{
auto pMesh = ON_Mesh::Cast(obj);
if (pMesh)
{
f.SetMesh(ON::render_mesh, pMesh);
}
else
{
delete pMesh;
}
}
}
}
if ( !rc ) {
// delete render mesh geometry
for ( i = 0; i < face_count; i++ )
{
ON_BrepFace& f = m_F[i];
f.DestroyMesh(ON::render_mesh);
}
}
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;
if (nullptr != obj)
{
auto pMesh = ON_Mesh::Cast(obj);
if (pMesh)
{
f.SetMesh(ON::analysis_mesh, pMesh);
}
else
{
delete pMesh;
}
}
}
}
if ( !rc ) {
// delete analysis mesh geometry
for ( i = 0; i < face_count; i++ ) {
ON_BrepFace& f = m_F[i];
f.DestroyMesh(ON::analysis_mesh);
}
}
}
// 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;
}