Files
opennurbs/opennurbs_polyedgecurve.cpp
2024-08-22 01:43:04 -07:00

856 lines
21 KiB
C++

#include "opennurbs.h"
#if !defined(ON_COMPILING_OPENNURBS)
// This check is included in all opennurbs source .c and .cpp files to insure
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
// and the opennurbs .h files alter what is declared and how it is declared.
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
#endif
#include "opennurbs_polyedgecurve.h"
ON_OBJECT_IMPLEMENT(ON_PolyEdgeSegment,ON_CurveProxy,"42F47A87-5B1B-4e31-AB87-4639D78325D6");
ON_PolyEdgeSegment::ON_PolyEdgeSegment()
{
Init();
}
ON_PolyEdgeSegment::~ON_PolyEdgeSegment()
{
Init();
}
void ON_PolyEdgeSegment::Init()
{
m_component_index.UnSet();
m_object_id = ON_nil_uuid;
m_brep = 0;
m_trim = 0;
m_edge = 0;
m_face = 0;
m_surface = 0;
m_edge_domain = ON_Interval::EmptyInterval;
m_trim_domain = ON_Interval::EmptyInterval;
ON_CurveProxy::SetProxyCurve(0);
ClearEvalCacheHelper();
}
bool ON_PolyEdgeSegment::Create(
const ON_BrepTrim* trim,
const ON_UUID& object_id
)
{
Init();
if ( !trim )
return false;
if ( trim->m_ei >= 0 )
return false;
const ON_Brep* brep = trim->Brep();
if ( !brep )
return false;
const ON_BrepEdge* edge = trim->Edge();
if ( !edge )
return false;
const ON_Curve* c3 = edge->EdgeCurveOf();
if ( !c3 )
return false;
m_brep = brep;
m_trim = trim;
m_edge = edge;
m_face = trim->Face();
if ( m_face )
m_surface = m_face->SurfaceOf();
m_edge_domain = m_edge->Domain();
m_trim_domain = m_trim->Domain();
ON_CurveProxy::SetProxyCurve(
c3,
edge->ProxyCurveDomain()
);
if ( m_edge->ProxyCurveIsReversed() )
ON_CurveProxy::Reverse();
ON_CurveProxy::SetDomain( m_edge_domain[0], m_edge_domain[1] );
m_component_index = trim->ComponentIndex();
m_object_id = object_id;
return true;
}
bool ON_PolyEdgeSegment::ReversedEdgeDir() const
{
bool rc = false;
if ( m_edge )
{
rc = m_edge->ProxyCurveIsReversed() != ON_CurveProxy::ProxyCurveIsReversed();
}
return rc;
}
bool ON_PolyEdgeSegment::ReversedTrimDir() const
{
bool rc = false;
if ( m_trim && m_edge )
{
rc = ReversedEdgeDir();
if ( m_trim->m_bRev3d )
rc = !rc;
}
return rc;
}
bool ON_PolyEdgeSegment::Create(
const ON_Curve* curve,
const ON_UUID& object_id
)
{
//bool rc = false;
Init();
if ( !curve )
return false;
const ON_BrepEdge* edge = ON_BrepEdge::Cast(curve);
if ( edge )
{
const ON_Brep* brep = edge->Brep();
if ( !brep )
return false;
const ON_Curve* c3 = edge->EdgeCurveOf();
if ( !c3 )
return false;
m_edge = edge;
m_brep = brep;
m_component_index = edge->ComponentIndex();
m_edge_domain = m_edge->Domain();
m_trim_domain = m_trim->Domain();
ON_CurveProxy::SetProxyCurve(
c3,
edge->ProxyCurveDomain()
);
if ( m_edge->ProxyCurveIsReversed() )
ON_CurveProxy::Reverse();
ON_CurveProxy::SetDomain( m_edge_domain[0], m_edge_domain[1] );
}
else
{
ON_CurveProxy::SetProxyCurve(const_cast<ON_Curve*>(curve));
}
m_object_id = object_id;
return true;
}
const ON_BrepEdge* ON_PolyEdgeSegment::BrepEdge() const
{
return m_edge;
}
const ON_BrepTrim* ON_PolyEdgeSegment::BrepTrim() const
{
return m_trim;
}
const ON_Brep* ON_PolyEdgeSegment::Brep() const
{
return m_brep;
}
const ON_BrepFace* ON_PolyEdgeSegment::BrepFace() const
{
return m_face;
}
const ON_Surface* ON_PolyEdgeSegment::Surface() const
{
return m_surface;
}
ON_Surface::ISO ON_PolyEdgeSegment::IsoType() const
{
return m_trim ? m_trim->m_iso : ON_Surface::not_iso;
}
ON_Interval ON_PolyEdgeSegment::EdgeDomain() const
{
return m_edge_domain;
}
ON_Interval ON_PolyEdgeSegment::TrimDomain() const
{
return m_trim_domain;
}
void ON_PolyEdgeSegment::ClearEvalCacheHelper()
{
m_t = ON_UNSET_VALUE;
m_edge_t = ON_UNSET_VALUE;
m_trim_t = ON_UNSET_VALUE;
m_srf_uv[0] = ON_UNSET_VALUE;
m_srf_uv[1] = ON_UNSET_VALUE;
m_trim_hint = 0;
m_edge_hint = 0;
m_evsrf_hint[0] = 0;
m_evsrf_hint[1] = 0;
m_evsrf_uv[0] = ON_UNSET_VALUE;
m_evsrf_uv[1] = ON_UNSET_VALUE;
m_evsrf_pt = ON_3dPoint::UnsetPoint;
}
double ON_PolyEdgeSegment::EdgeParameter(double t) const
{
double edge_t = ON_UNSET_VALUE;
if ( m_edge )
{
if ( m_t == t && m_edge_t != ON_UNSET_VALUE )
edge_t = m_edge_t;
else
{
ON_PolyEdgeSegment* p = const_cast<ON_PolyEdgeSegment*>(this);
if ( t != m_t )
{
p->m_t = t;
p->m_trim_t = ON_UNSET_VALUE;
p->m_srf_uv[0] = ON_UNSET_VALUE;
p->m_srf_uv[1] = ON_UNSET_VALUE;
}
ON_Interval d = Domain();
bool bReversedEdgeDir = ReversedEdgeDir();
if ( bReversedEdgeDir || m_edge_domain != d )
{
double s = d.NormalizedParameterAt(t);
if ( bReversedEdgeDir )
s = 1.0 - s;
edge_t = m_edge_domain.ParameterAt(s);
}
else
edge_t = t;
p->m_edge_t = edge_t;
}
}
return edge_t;
}
ON_OBJECT_IMPLEMENT(ON_PolyEdgeCurve,ON_PolyCurve,"39FF3DD3-FE0F-4807-9D59-185F0D73C0E4");
ON_PolyEdgeCurve::ON_PolyEdgeCurve()
{
}
ON_PolyEdgeCurve::~ON_PolyEdgeCurve()
{
}
bool ON_PolyEdgeCurve::SetStartPoint( ON_3dPoint start_point )
{
return ON_Curve::SetStartPoint(start_point); // cannot change edges
}
bool ON_PolyEdgeCurve::SetEndPoint( ON_3dPoint end_point )
{
return ON_Curve::SetEndPoint(end_point); // cannot change edges
}
bool ON_PolyEdgeCurve::ChangeClosedCurveSeam( double t )
{
//int saved_is_closed_helper = m_is_closed_helper;
if ( SegmentCount() == 1 )
{
// A ON_PolyEdgeSegment cannot have its start/end
// changed. Split it into two segments and let
// ON_PolyCurve::ChangeClosedCurveSeam() do the work.
if ( !IsClosed() )
return false;
ON_Interval crvd = Domain();
double s = crvd.NormalizedParameterAt(t);
if ( s <= ON_SQRT_EPSILON || s >= (1.0 - ON_SQRT_EPSILON) )
{
s = fmod(s,1.0);
if ( s < 0.0 )
s += 1.0;
if ( fabs(s) <= ON_SQRT_EPSILON || fabs(1.0-s) <= ON_SQRT_EPSILON )
{
// split parameter is at start/end of this segment
if ( t != crvd[0] )
{
DestroyRuntimeCache();
SetDomain(t,t+crvd.Length() );
//m_is_closed_helper = saved_is_closed_helper;
}
return true;
}
return false;
}
ON_PolyEdgeSegment* left_seg = SegmentCurve(0);
if ( 0 == left_seg )
return false;
DestroyRuntimeCache();
ON_Curve* left = left_seg;
ON_Curve* right = 0;
double segt = SegmentCurveParameter(t);
if ( !left_seg->Split(segt,left,right) )
return false;
SetDomain(crvd[0],t);
ON_PolyEdgeSegment* right_seg = ON_PolyEdgeSegment::Cast(right);
if ( 0 == right_seg )
return false;
Append(right_seg);
double st[3];
st[0] = crvd[0];
st[1] = t;
st[2] = crvd[1];
SetParameterization( st );
}
// ON_PolyCurve::ChangeClosedCurveSeam works fine on
// two or more segments.
bool rc = ON_PolyCurve::ChangeClosedCurveSeam(t);
//if ( saved_is_closed_helper )
// m_is_closed_helper = saved_is_closed_helper;
return rc;
}
bool ON_PolyEdgeCurve::PrependAndMatch(ON_Curve*)
{
return false; // cannot change edges
}
bool ON_PolyEdgeCurve::AppendAndMatch(ON_Curve*)
{
return false; // cannot change edges
}
ON_Curve* ON_PolyEdgeSegment::DuplicateCurve() const
{
return ON_CurveProxy::DuplicateCurve();
// 21 December 2004 Dale Lear
// This is wrong. I did it some time ago as a quick
// fix for one of Lowell's early uses of CRhinoPolyEdges
// however, this will cause lots of crashes now that
// all commands have to deal with polyedges and the code
// in those commands assumes that DuplicateCurve() returns
// a valid stand-alone curve. If you end up here and
// wish this code still worked the old way, please get
// in touch with Dale Lear and we'll find a way to get
// your code to work.
// NO // ON_PolyEdgeSegment* dup = Duplicate();
// NO // return dup;
}
ON_Curve* ON_PolyEdgeCurve::DuplicateCurve() const
{
return ON_PolyCurve::DuplicateCurve();
// 21 December 2004 Dale Lear
// The code below is wrong. I wrote it some time ago as a quick
// fix for one of Lowell's early uses of CRhinoPolyEdges
// however, this will cause lots of crashes now that
// all commands have to deal with polyedges and the code
// in those commands assumes that DuplicateCurve() returns
// a valid stand-alone curve. If you end up here and
// wish this code still worked the old way, please get
// in touch with Dale Lear and we'll find a way to get
// your code to work.
// NO // int cnt = Count();
// NO // ON_SimpleArray<double> t(cnt+1);
// NO // ON_PolyEdgeCurve* dup_crv = new ON_PolyEdgeCurve();
// NO //
// NO // t.Append(Domain()[0]);
// NO //
// NO // for( int i=0; i<cnt; i++)
// NO // {
// NO // const ON_Curve* seg = SegmentCurve(i);
// NO // if ( seg )
// NO // {
// NO // t.Append(SegmentDomain(i)[1]);
// NO // dup_crv->ON_PolyCurve::Append( seg->DuplicateCurve() );
// NO // }
// NO // }
// NO //
// NO // if( cnt > 0 && cnt+1 == t.Count() )
// NO // {
// NO // dup_crv->SetParameterization( t.Array() );
// NO // }
// NO //
// NO // dup_crv->m_ev_srf_tan_mode = m_ev_srf_tan_mode;
// NO // dup_crv->m_is_closed_helper = m_is_closed_helper;
// NO //
// NO // return dup_crv;
}
bool ON_PolyEdgeSegment::IsClosed(void) const
{
bool rc = ON_CurveProxy::IsClosed();
if ( !rc
&& m_edge
&& m_edge->m_vi[0] == m_edge->m_vi[1]
&& m_edge->ProxyCurve() == ProxyCurve()
&& m_edge->ProxyCurveDomain() == ProxyCurveDomain()
&& 0 != ProxyCurve()
&& ProxyCurve()->Domain() == ProxyCurveDomain()
)
{
rc = m_edge->IsClosed();
}
return rc;
}
// 7-1-03 lw added override to unset cached closed flag
// when a segment is removed
bool ON_PolyEdgeCurve::Remove( int segment_index )
{
bool rc = ON_PolyCurve::Remove( segment_index);
//if( rc)
// m_is_closed_helper = 0; // Cached closed flag...
return rc;
}
bool ON_PolyEdgeCurve::Remove( )
{
return Remove(Count()-1);
}
bool ON_PolyEdgeCurve::IsClosed(void) const
{
bool rc = ON_PolyCurve::IsClosed();
if ( !rc && SegmentCount() > 1 )
{
// Since the segments that make up a ON_PolyEdgeCurve
// cannot have their ends matched (because the curves
// belong to objects already in the rhino model),
// the IsClosed() test has to tolerate larger gaps
// in brep topology.
//
// If the start and end segments are edges that belong
// to the same brep, then they "join" if and only if
// they share a vertex.
const ON_PolyEdgeSegment* seg0 = SegmentCurve(0);
const ON_PolyEdgeSegment* seg1 = SegmentCurve(SegmentCount()-1);
const ON_BrepEdge* edge0 = seg0->BrepEdge();
const ON_BrepEdge* edge1 = seg1->BrepEdge();
if ( edge0 && edge1 && edge0->Brep() == edge1->Brep() )
{
// check for topological closure
//
// Do NOT add a test for sloppy geometric closure here.
// If the edges are in the same brep and they don't
// meet topologically, then there is something in the
// brep that is separating the edges.
int evi0 = seg0->ReversedEdgeDir() ? 1 : 0;
int evi1 = seg1->ReversedEdgeDir() ? 0 : 1;
double et0 = seg0->EdgeParameter(seg0->Domain()[0]);
double et1 = seg1->EdgeParameter(seg1->Domain()[1]);
if ( et0 != ON_UNSET_VALUE && et1 != ON_UNSET_VALUE )
{
ON_Interval edom0 = edge0->Domain();
ON_Interval edom1 = edge1->Domain();
if ( et0 == edom0[evi0] && et1 == edom1[evi1] )
{
// The polyedge starts at the (evi0?end:start) of edge0
// and ends at the (ev1?end:start) of edge1.
if ( edge0->m_vi[evi0] == edge1->m_vi[evi1] )
{
// the polyedge start/ends at a common vertex
rc = true;
}
}
else if ( edge0 == edge1
&& fabs(et0-et1) <= ON_ZERO_TOLERANCE
&& edom0.Includes(et0,true)
&& edom1.Includes(et1,true)
)
{
// The start/end of the polyedge is an interior point
// of a single edge. (This happens when the "seam" gets
// adjusted to be inside of an edge.) It is unlikely that
// ON_PolyCurve::IsClosed() would return false in this
// case, but this check should keep everybody happy.
rc = true;
}
}
}
}
return rc;
}
bool ON_PolyEdgeCurve::Create( const ON_BrepTrim* trim, const ON_UUID& object_id )
{
bool rc = false;
Destroy();
//m_is_closed_helper = 0;
if ( trim )
{
ON_PolyEdgeSegment* segment = new ON_PolyEdgeSegment();
rc = segment->Create(trim,object_id);
if (rc )
Append(segment);
else
delete segment;
}
return rc;
}
bool ON_PolyEdgeCurve::Create( const ON_Curve* curve, const ON_UUID& object_id )
{
bool rc = false;
Destroy();
//m_is_closed_helper = 0;
if ( curve )
{
ON_PolyEdgeSegment* segment = new ON_PolyEdgeSegment();
rc = segment->Create(curve,object_id);
if (rc )
Append(segment);
else
delete segment;
}
return rc;
}
int ON_PolyEdgeCurve::SegmentCount() const
{
return ON_PolyCurve::Count();
}
ON_PolyEdgeSegment* ON_PolyEdgeCurve::SegmentCurve(
int segment_index
) const
{
return ON_PolyEdgeSegment::Cast(ON_PolyCurve::SegmentCurve(segment_index));
}
ON_PolyEdgeSegment* ON_PolyEdgeCurve::operator[](int segment_index) const
{
return SegmentCurve(segment_index);
}
void ON_PolyEdgeCurve::DestroyRuntimeCache( bool bDelete )
{
//m_is_closed_helper = 0;
ON_PolyCurve::DestroyRuntimeCache(bDelete);
}
void ON_PolyEdgeSegment::DestroyRuntimeCache( bool bDelete )
{
ClearEvalCacheHelper();
ON_CurveProxy::DestroyRuntimeCache(bDelete);
}
bool ON_PolyEdgeCurve::Prepend( ON_PolyEdgeSegment* new_segment )
{
DestroyRuntimeCache();
bool rc = false;
if ( new_segment )
{
if ( Count() > 0 )
{
// keep segment domains in synch with polycurve domain
// so that parameter bookkeeping is easy.
ON_Interval cdom = Domain();
ON_Interval sdom = new_segment->Domain();
if ( sdom[1] != cdom[0] )
{
sdom[0] = cdom[0] - sdom.Length();
sdom[1] = cdom[0];
new_segment->SetDomain(sdom[0],sdom[1]);
}
}
rc = ON_PolyCurve::Prepend(new_segment);
}
return rc;
}
bool ON_PolyEdgeCurve::Append( ON_PolyEdgeSegment* new_segment )
{
DestroyRuntimeCache();
bool rc = false;
if ( new_segment )
{
//m_is_closed_helper = 0;
if ( Count() > 0 )
{
// keep segment domains in synch with polycurve domain
// so that parameter bookkeeping is easy.
ON_Interval cdom = Domain();
ON_Interval sdom = new_segment->Domain();
if ( sdom[0] != cdom[1] )
{
sdom[1] = cdom[1] + sdom.Length();
sdom[0] = cdom[1];
new_segment->SetDomain(sdom[0],sdom[1]);
}
}
rc = ON_PolyCurve::Append(new_segment);
}
return rc;
}
bool ON_PolyEdgeCurve::Insert(
int segment_index,
ON_PolyEdgeSegment* new_segment
)
{
DestroyRuntimeCache();
bool rc = false;
if ( segment_index > 0 )
{
//m_is_closed_helper = 0;
rc = ON_PolyCurve::Insert(segment_index,new_segment);
if ( rc )
{
int i;
for ( i = segment_index; i < Count(); i++ )
{
ON_PolyEdgeSegment* seg = SegmentCurve(i);
ON_Interval d = SegmentDomain(i);
seg->SetDomain(d[0],d[1]);
}
}
}
else if ( segment_index == 0 )
rc = Prepend(new_segment);
return rc;
}
const ON_BrepEdge* ON_PolyEdgeCurve::EdgeAt(double t) const
{
ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
return seg ? seg->BrepEdge() : 0;
}
const ON_BrepTrim* ON_PolyEdgeCurve::TrimAt(double t) const
{
ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
return seg ? seg->BrepTrim() : 0;
}
const ON_Brep* ON_PolyEdgeCurve::BrepAt(double t) const
{
ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
return seg ? seg->Brep() : 0;
}
const ON_BrepFace* ON_PolyEdgeCurve::FaceAt(double t) const
{
ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
return seg ? seg->BrepFace() : 0;
}
const ON_Surface* ON_PolyEdgeCurve::SurfaceAt(double t) const
{
ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
return seg ? seg->Surface() : 0;
}
ON_Surface::ISO ON_PolyEdgeCurve::IsoType( double t) const
{
ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
return seg ? seg->IsoType() : ON_Surface::not_iso;
}
double ON_PolyEdgeCurve::EdgeParameter(double t) const
{
double edge_t = ON_UNSET_VALUE;
int segment_index = SegmentIndex(t);
ON_PolyEdgeSegment* seg = SegmentCurve( segment_index );
if ( seg )
{
ON_Interval pdom = SegmentDomain(segment_index);
ON_Interval sdom = seg->Domain();
if ( sdom != pdom )
{
double s = pdom.NormalizedParameterAt(t);
t = sdom.ParameterAt(s);
}
edge_t = seg->EdgeParameter(t);
}
return edge_t;
}
// Test if there are any surface edges in the polyedge
bool ON_PolyEdgeCurve::ContainsAnyEdges() const
{
int i, count = SegmentCount();
for( i = 0; i < count; i++)
{
ON_PolyEdgeSegment* segment = SegmentCurve(i);
if( 0 != segment && nullptr != segment->BrepEdge())
{
return true;
}
}
return false;
}
// Test if all segments of the polyedge are surface edges
bool ON_PolyEdgeCurve::ContainsAllEdges() const
{
int i, count = SegmentCount();
for( i = 0; i < count; i++)
{
ON_PolyEdgeSegment* segment = SegmentCurve(i);
if( nullptr == segment || nullptr == segment->BrepEdge())
{
return false;
}
}
return true;
}
int ON_PolyEdgeCurve::FindEdge( const ON_BrepEdge* edge) const
{
int rc = -1;
if ( 0 != edge )
{
int i, count = SegmentCount();
for( i = 0; i < count; i++)
{
ON_PolyEdgeSegment* segment = SegmentCurve(i);
if ( 0 != segment && edge == segment->BrepEdge() )
{
rc = i;
break;
}
}
}
return rc;
}
int ON_PolyEdgeCurve::FindTrim( const ON_BrepTrim* trim) const
{
int rc = -1;
if ( 0 != trim )
{
int i, count = SegmentCount();
for( i = 0; i < count; i++)
{
ON_PolyEdgeSegment* segment = SegmentCurve(i);
if ( 0 != segment && trim == segment->BrepTrim() )
{
rc = i;
break;
}
}
}
return rc;
}
int ON_PolyEdgeCurve::FindCurve( const ON_Curve* curve) const
{
int rc = -1;
if ( 0 != curve )
{
int i, count = SegmentCount();
for( i = 0; i < count; i++)
{
ON_PolyEdgeSegment* segment = SegmentCurve(i);
if ( 0 != segment
&& (curve == segment || curve == segment->ProxyCurve() || curve == segment->BrepEdge()) )
{
rc = i;
break;
}
}
}
return rc;
}
bool ON_PolyEdgeSegment::Write( ON_BinaryArchive& archive ) const
{
bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
if (!rc)
return false;
for(;;)
{
rc = archive.WriteUuid(m_object_id);
if (!rc) break;
rc = archive.WriteComponentIndex(m_component_index);
if (!rc) break;
rc = archive.WriteInterval(m_edge_domain);
if (!rc) break;
rc = archive.WriteInterval(m_trim_domain);
if (!rc) break;
bool b = ON_CurveProxy::ProxyCurveIsReversed();
rc = archive.WriteBool(b);
if (!rc) break;
rc = archive.WriteInterval(ON_CurveProxy::Domain());
if (!rc) break;
rc = archive.WriteInterval(ON_CurveProxy::ProxyCurveDomain());
if (!rc) break;
break;
}
if ( !archive.EndWrite3dmChunk() )
rc = false;
return rc;
}
bool ON_PolyEdgeSegment::Read( ON_BinaryArchive& archive )
{
Init();
int major_version = 0;
int minor_version = 0;
bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
if (!rc)
return false;
for(;;)
{
rc = (1 == major_version);
if ( !rc )
break;
rc = archive.ReadUuid(m_object_id);
if (!rc) break;
rc = archive.ReadComponentIndex(m_component_index);
if (!rc) break;
rc = archive.ReadInterval(m_edge_domain);
if (!rc) break;
rc = archive.ReadInterval(m_trim_domain);
if (!rc) break;
// Read ON_ProxyCurve values we need
bool bReversed = false;
rc = archive.ReadBool(&bReversed);
if (!rc) break;
ON_Interval this_domain;
rc = archive.ReadInterval(this_domain);
if (!rc) break;
ON_Interval real_curve_domain;
rc = archive.ReadInterval(real_curve_domain);
if (!rc) break;
if ( bReversed)
ON_CurveProxy::Reverse();
ON_CurveProxy::SetDomain(this_domain);
ON_CurveProxy::SetProxyCurveDomain(real_curve_domain);
break;
}
if ( !archive.EndRead3dmChunk() )
rc = false;
return rc;
}