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

2937 lines
68 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
ON_OBJECT_IMPLEMENT(ON_NurbsCage,ON_Geometry,"06936AFB-3D3C-41ac-BF70-C9319FA480A1");
ON_OBJECT_IMPLEMENT(ON_MorphControl,ON_Geometry,"D379E6D8-7C31-4407-A913-E3B7040D034A");
bool ON_NurbsCage::Read(ON_BinaryArchive& archive)
{
Destroy();
int major_version = 0;
int minor_version = 0;
bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
if ( rc )
{
while(rc)
{
if ( major_version != 1 )
{
ON_ERROR("ON_NurbsCage::Read - old code unable to read new version of chunk");
rc = false;
break;
}
int dim=0;
int order0=0,order1=0,order2=0;
int cv_count0=0,cv_count1=0,cv_count2=0;
int is_rat=0;
rc = archive.ReadInt(&dim);
if (!rc)
break;
if (dim < 1 || dim > 10000)
{
ON_ERROR("ON_NurbsCage::Read - invalid dim");
rc=false;
break;
}
rc = archive.ReadInt(&is_rat);
if (!rc)
break;
if (is_rat != 0 && is_rat != 1)
{
ON_ERROR("ON_NurbsCage::Read - invalid is_rat");
rc=false;
break;
}
rc = archive.ReadInt(&order0);
if (!rc)
break;
if ( order0 < 2 || order0 > 10000 )
{
ON_ERROR("ON_NurbsCage::Read - invalid order0");
rc=false;
break;
}
rc = archive.ReadInt(&order1);
if (!rc)
break;
if ( order1 < 2 || order1 > 10000 )
{
ON_ERROR("ON_NurbsCage::Read - invalid order1");
rc=false;
break;
}
rc = archive.ReadInt(&order2);
if (!rc)
break;
if ( order2 < 2 || order2 > 10000 )
{
ON_ERROR("ON_NurbsCage::Read - invalid order2");
rc=false;
break;
}
rc = archive.ReadInt(&cv_count0);
if (!rc)
break;
if ( cv_count0 < order0 || cv_count0 > 100000 )
{
ON_ERROR("ON_NurbsCage::Read - invalid cv_count0");
rc=false;
break;
}
rc = archive.ReadInt(&cv_count1);
if (!rc)
break;
if ( cv_count1 < order1 || cv_count1 > 100000 )
{
ON_ERROR("ON_NurbsCage::Read - invalid cv_count1");
rc=false;
break;
}
rc = archive.ReadInt(&cv_count2);
if (!rc)
break;
if ( cv_count2 < order2 || cv_count2 > 100000 )
{
ON_ERROR("ON_NurbsCage::Read - invalid cv_count2");
rc=false;
break;
}
rc = Create(dim,is_rat==1,order0,order1,order2,cv_count0,cv_count1,cv_count2);
if (!rc)
break;
if (rc)
rc = archive.ReadDouble(KnotCount(0),m_knot[0]);
if (rc)
rc = archive.ReadDouble(KnotCount(1),m_knot[1]);
if (rc)
rc = archive.ReadDouble(KnotCount(2),m_knot[2]);
int i,j,k;
const int cv_dim = m_is_rat?(m_dim+1):m_dim;
for(i = 0; i < cv_count0 && rc; i++)
{
for(j = 0; j < cv_count1 && rc; j++)
{
for ( k = 0; k < cv_count2 && rc; k++)
{
rc = archive.ReadDouble(cv_dim,CV(i,j,k));
}
}
}
break;
}
if ( !archive.EndRead3dmChunk() )
{
rc = false;
}
}
return rc;
}
bool ON_NurbsCage::Write(ON_BinaryArchive& archive) const
{
bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
if (rc)
{
rc = archive.WriteInt(m_dim);
if(rc)
rc = archive.WriteInt(m_is_rat);
if (rc)
rc = archive.WriteInt(m_order[0]);
if (rc)
rc = archive.WriteInt(m_order[1]);
if (rc)
rc = archive.WriteInt(m_order[2]);
if (rc)
rc = archive.WriteInt(m_cv_count[0]);
if (rc)
rc = archive.WriteInt(m_cv_count[1]);
if (rc)
rc = archive.WriteInt(m_cv_count[2]);
if (rc)
rc = archive.WriteDouble(KnotCount(0),m_knot[0]);
if (rc)
rc = archive.WriteDouble(KnotCount(1),m_knot[1]);
if (rc)
rc = archive.WriteDouble(KnotCount(2),m_knot[2]);
int i,j,k;
const int cv_dim = m_is_rat?(m_dim+1):m_dim;
double* bogus_cv = (double*)alloca(cv_dim*sizeof(*bogus_cv));
for ( i = 0; i < cv_dim; i++ )
bogus_cv[i] = ON_UNSET_VALUE;
for(i = 0; i < m_cv_count[0] && rc; i++)
{
for(j = 0; j < m_cv_count[1] && rc; j++)
{
for ( k = 0; k < m_cv_count[2] && rc; k++)
{
const double* cv = CV(i,j,k);
if ( !cv )
cv = bogus_cv;
rc = archive.WriteDouble(cv_dim,cv);
}
}
}
if ( !archive.EndWrite3dmChunk() )
{
rc = false;
}
}
return rc;
}
ON_NurbsCage::ON_NurbsCage()
: m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
{
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
m_cv_count[0] = 0;
m_cv_count[1] = 0;
m_cv_count[2] = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_knot[0] = 0;
m_knot[1] = 0;
m_knot[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
}
ON_NurbsCage::ON_NurbsCage( int dim, bool is_rat,
int order0,
int order1,
int order2,
int cv_count0,
int cv_count1,
int cv_count2
)
: m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
{
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
m_cv_count[0] = 0;
m_cv_count[1] = 0;
m_cv_count[2] = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_knot[0] = 0;
m_knot[1] = 0;
m_knot[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
Create( dim, is_rat, order0, order1, order2, cv_count0, cv_count1, cv_count2 );
}
ON_NurbsCage::ON_NurbsCage( const ON_BoundingBox& bbox,
int order0, int order1, int order2,
int cv_count0, int cv_count1, int cv_count2
)
: m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
{
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
m_cv_count[0] = 0;
m_cv_count[1] = 0;
m_cv_count[2] = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_knot[0] = 0;
m_knot[1] = 0;
m_knot[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
Create(bbox,order0,order1,order2, cv_count0, cv_count1, cv_count2);
}
bool ON_NurbsCage::IsParallelogram(double tolerance) const
{
int i,j,k;
double r,s,t;
double x,y,z,dist;
ON_Interval d[3];
ON_3dPoint P, X, Y, Z, Q, B;
bool rc = IsValid()?true:false;
for ( i = 0; i < 3 && rc; i++ )
{
d[i] = Domain(i);
rc = ( d[i][0] == m_knot[i][0]
&& d[i][1] == m_knot[i][m_cv_count[i]+m_order[i]-3]
);
}
if (rc)
{
GetCV(0,0,0,P);
GetCV(m_cv_count[0]-1,0,0,X);
GetCV(0,m_cv_count[1]-1,0,Y);
GetCV(0,0,m_cv_count[2]-1,Z);
if ( tolerance < ON_ZERO_TOLERANCE )
tolerance = ON_ZERO_TOLERANCE;
for ( i = 0; i < m_cv_count[0]; i++ )
{
r = ON_GrevilleAbcissa(m_order[0],m_knot[0]+i);
x = d[0].NormalizedParameterAt(r);
for ( j = 0; j < m_cv_count[1]; j++ )
{
s = ON_GrevilleAbcissa(m_order[1],m_knot[1]+j);
y = d[1].NormalizedParameterAt(s);
for ( k = 0; k < m_cv_count[2]; k++ )
{
t = ON_GrevilleAbcissa(m_order[2],m_knot[2]+k);
z = d[2].NormalizedParameterAt(t);
Evaluate(r,s,t,0,3,&Q.x);
B = (1.0-x-y-z)*P + x*X + y*Y + z*Z;
dist = B.DistanceTo(Q);
if ( dist > tolerance )
return false;
}
}
}
}
return rc;
}
ON_NurbsCage::ON_NurbsCage( const ON_3dPoint* box_corners,
int order0, int order1, int order2,
int cv_count0, int cv_count1, int cv_count2
)
: m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
{
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
m_cv_count[0] = 0;
m_cv_count[1] = 0;
m_cv_count[2] = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_knot[0] = 0;
m_knot[1] = 0;
m_knot[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
Create(box_corners,order0,order1,order2, cv_count0, cv_count1, cv_count2);
}
ON_NurbsCage::ON_NurbsCage( const ON_BezierCage& src )
: m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
{
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
m_cv_count[0] = 0;
m_cv_count[1] = 0;
m_cv_count[2] = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_knot[0] = 0;
m_knot[1] = 0;
m_knot[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
*this = src;
}
ON_NurbsCage::~ON_NurbsCage()
{
Destroy();
}
int ON_NurbsCage::KnotCount(int dir) const
{
return (dir>=0 && dir<=2) ? ON_KnotCount(m_order[dir],m_cv_count[dir]) : 0;
}
double ON_NurbsCage::GrevilleAbcissa(
int dir, // dir
int gindex // index (0 <= index < CVCount(dir)
) const
{
return (dir >= 0 && dir <= 2)
? ON_GrevilleAbcissa( m_order[dir], m_knot[dir] + gindex )
: ON_UNSET_VALUE;
}
bool ON_NurbsCage::MakeDeformable()
{
return true;
}
bool ON_NurbsCage::IsDeformable() const
{
return true;
}
bool ON_NurbsCage::GetTightBoundingBox( ON_BoundingBox& tight_bbox,bool bGrowBox,const ON_Xform* xform) const
{
if ( bGrowBox && !tight_bbox.IsValid() )
{
bGrowBox = false;
}
if ( !bGrowBox )
{
tight_bbox.Destroy();
}
if( xform && !xform->IsIdentity() )
{
ON_3dPoint P;
int i,j,k;
for ( i = 0; i < m_cv_count[0]; i++ )
{
for ( j = 0; j < m_cv_count[1]; j++ )
{
for ( k = 0; k < m_cv_count[2]; k++ )
{
GetCV(i,j,k,P);
P = (*xform)*P;
if ( tight_bbox.Set(P,bGrowBox) )
{
bGrowBox = true;
}
}
}
}
}
else
{
if ( GetBoundingBox(tight_bbox,bGrowBox?true:false) )
bGrowBox = true;
}
return bGrowBox?true:false;
}
int ON_NurbsCage::CVCount() const
{
return CVCount(0)*CVCount(1)*CVCount(2);
}
int ON_NurbsCage::CVCount(int dir) const
{
return (dir>=0&&dir<=2) ? m_cv_count[dir] : 0;
}
void ON_NurbsCage::DestroyRuntimeCache(bool bDelete)
{
ON_Geometry::DestroyRuntimeCache(bDelete);
}
ON::object_type ON_NurbsCage::ObjectType() const
{
return ON::cage_object;
}
ON_NurbsCage& ON_NurbsCage::operator=( const ON_BezierCage& src )
{
if ( Create(src.m_dim,src.m_is_rat,
src.m_order[0],src.m_order[1],src.m_order[2],
src.m_order[0],src.m_order[1],src.m_order[2]) )
{
int i,j,k;
for ( i = 0; i < m_cv_count[0]; i++ )
{
for ( j = 0; j < m_cv_count[1]; j++ )
{
for ( k = 0; k < m_cv_count[2]; k++ )
{
SetCV(i,j,k,ON::intrinsic_point_style,src.CV(i,j,k));
}
}
}
}
return *this;
}
unsigned int ON_NurbsCage::SizeOf() const
{
unsigned int sz = ON_Geometry::SizeOf();
sz += (sizeof(*this) - sizeof(ON_Geometry));
sz += (KnotCount(0) + KnotCount(1) + KnotCount(2) + CVSize()*CVCount())*sizeof(double);
return sz;
}
ON__UINT32 ON_NurbsCage::DataCRC(ON__UINT32 current_remainder) const
{
current_remainder = ON_CRC32(current_remainder,sizeof(m_dim),&m_dim);
current_remainder = ON_CRC32(current_remainder,sizeof(m_is_rat),&m_is_rat);
current_remainder = ON_CRC32(current_remainder,3*sizeof(m_order[0]),&m_order[0]);
current_remainder = ON_CRC32(current_remainder,3*sizeof(m_cv_count[0]),&m_cv_count[0]);
if ( m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2] > 0
&& m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0
&& m_cv )
{
size_t sizeof_cv = CVSize()*sizeof(m_cv[0]);
const double* cv = m_cv;
int i, j, k;
for ( i = 0; i < m_cv_count[0]; i++ )
{
for ( j = 0; j < m_cv_count[1]; j++ )
{
cv = CV(i,j,0);
for (k = 0; k < m_cv_count[2]; k++ )
{
current_remainder = ON_CRC32(current_remainder,sizeof_cv,cv);
cv += m_cv_stride[2];
}
}
}
}
current_remainder = ON_CRC32(current_remainder,KnotCount(0)*sizeof(m_knot[0][0]),m_knot[0]);
current_remainder = ON_CRC32(current_remainder,KnotCount(1)*sizeof(m_knot[1][0]),m_knot[1]);
current_remainder = ON_CRC32(current_remainder,KnotCount(2)*sizeof(m_knot[2][0]),m_knot[2]);
return current_remainder;
}
ON_NurbsCage::ON_NurbsCage(const ON_NurbsCage& src)
: ON_Geometry(src),
m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
{
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
m_cv_count[0] = 0;
m_cv_count[1] = 0;
m_cv_count[2] = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_knot[0] = 0;
m_knot[1] = 0;
m_knot[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
*this = src;
}
ON_NurbsCage& ON_NurbsCage::operator=(const ON_NurbsCage& src)
{
if ( this != &src )
{
ON_Geometry::operator=(src);
if ( Create( src.m_dim, src.m_is_rat,
src.m_order[0], src.m_order[1], src.m_order[2],
src.m_cv_count[0], src.m_cv_count[1], src.m_cv_count[2]
) )
{
if ( m_order[0] >= 2 && m_cv_count[0] >= m_order[0] && m_knot[0] && src.m_knot[0] )
memcpy( m_knot[0], src.m_knot[0], KnotCount(0)*sizeof(m_knot[0][0]));
if ( m_order[1] >= 2 && m_cv_count[1] >= m_order[1] && m_knot[1] && src.m_knot[1] )
memcpy( m_knot[1], src.m_knot[1], KnotCount(1)*sizeof(m_knot[1][0]));
if ( m_order[2] >= 2 && m_cv_count[2] >= m_order[2] && m_knot[2] && src.m_knot[2] )
memcpy( m_knot[2], src.m_knot[2], KnotCount(2)*sizeof(m_knot[2][0]));
if ( m_cv && src.m_cv && m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0 )
{
const int cv_dim = CVSize();
const int sizeofcv = cv_dim*sizeof(m_cv[0]);
if ( m_cv_stride[0] == src.m_cv_stride[0]
&& m_cv_stride[1] == src.m_cv_stride[1]
&& m_cv_stride[2] == src.m_cv_stride[2] )
{
memcpy(m_cv,src.m_cv,m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*sizeofcv);
}
else
{
int i, j, k;
double* cv = m_cv;
for ( i = 0; i < m_cv_count[0]; i++ )
for ( j = 0; j < m_cv_count[1]; j++ )
for ( k = 0; k < m_cv_count[2]; k++ )
{
memcpy( cv, src.CV(i,j,k), sizeofcv );
cv += cv_dim;
}
}
}
}
else
{
Destroy();
}
}
return *this;
}
bool ON_NurbsCage::IsValid(
ON_TextLog* //text_log
) const
{
if ( 0 == m_cv )
return false;
if ( 0 == m_knot[0] )
return false;
if ( 0 == m_knot[1] )
return false;
if ( 0 == m_knot[2] )
return false;
if ( m_order[0] < 2 )
return false;
if ( m_order[1] < 2 )
return false;
if ( m_order[2] < 2 )
return false;
if ( m_cv_count[0] < m_order[0] )
return false;
if ( m_cv_count[1] < m_order[1] )
return false;
if ( m_cv_count[2] < m_order[2] )
return false;
if ( m_dim <= 0 )
return false;
if ( m_is_rat != 0 && m_is_rat != 1 )
return false;
const int cvdim = m_is_rat ? (m_dim+1) : m_dim;
if ( m_cv_capacity > 0 && m_cv_capacity < cvdim*m_cv_count[0]*m_cv_count[1]*m_cv_count[2] )
return false;
int i[3];
i[0] = (m_cv_stride[0] <= m_cv_stride[1]) ? 0 : 1;
i[1] = 1-i[0];
if ( m_cv_stride[2] < m_cv_stride[i[0]] )
{
i[2] = i[1];
i[1] = i[0];
i[0] = 2;
}
else if ( m_cv_stride[2] < m_cv_stride[i[1]] )
{
i[2] = i[1];
i[1] = 2;
}
else
{
i[2] = 2;
}
if ( m_cv_stride[i[0]] < cvdim )
return false;
if ( m_cv_stride[i[1]] < m_cv_stride[i[0]]*m_cv_count[i[0]] )
return false;
if ( m_cv_stride[i[2]] < m_cv_stride[i[1]]*m_cv_count[i[1]] )
return false;
return true;
}
void ON_NurbsCage::Dump( ON_TextLog& dump ) const
{
dump.Print( "ON_NurbsCage dim = %d is_rat = %d\n"
" order = (%d, %d, %d) \n",
" cv_count = (%d, %d, %d) \n",
m_dim, m_is_rat,
m_order[0], m_order[1], m_order[2],
m_cv_count[0], m_cv_count[1], m_cv_count[2] );
int dir;
for ( dir = 0; dir < 3; dir++ )
{
dump.Print( "Knot Vector %d ( %d knots )\n", dir, KnotCount(dir) );
dump.PrintKnotVector( m_order[dir], m_cv_count[dir], m_knot[dir] );
}
dump.Print( "Control Points %d %s points\n"
" index value\n",
m_cv_count[0]*m_cv_count[1]*m_cv_count[2],
(m_is_rat) ? "rational" : "non-rational" );
if ( !m_cv )
{
dump.Print(" nullptr cv array\n");
}
else
{
int i,j;
char sPreamble[128] = { 0 };
const size_t sPremable_capacity = sizeof(sPreamble) / sizeof(sPreamble[0]);
for ( i = 0; i < m_order[0]; i++ )
{
for ( j = 0; j < m_order[1]; j++ )
{
if ( i > 0 || j > 0)
dump.Print("\n");
sPreamble[0] = 0;
ON_String::FormatIntoBuffer(sPreamble, sPremable_capacity," CV[%2d][%2d]", i, j);
dump.PrintPointList( m_dim, m_is_rat,
m_cv_count[2], m_cv_stride[2],
CV(i,j,0),
sPreamble );
}
if ( i < m_order[0]-1)
dump.Print("\n");
}
}
}
int ON_NurbsCage::Dimension() const
{
return m_dim;
}
bool ON_NurbsCage::Create( const ON_BoundingBox& bbox,
int order0, int order1, int order2,
int cv_count0, int cv_count1, int cv_count2
)
{
/*
7______________6
|\ |\
| \ | \
| \ _____________\
| 4 | 5
| | | |
| | | |
3---|----------2 |
\ | \ |
\ |z \ |
y \ | \ |
\0_____________\1
x
*/
ON_3dPoint box_corners[8];
box_corners[0] = bbox.Corner(0,0,0);
box_corners[1] = bbox.Corner(1,0,0);
box_corners[2] = bbox.Corner(1,1,0);
box_corners[3] = bbox.Corner(0,1,0);
box_corners[4] = bbox.Corner(0,0,1);
box_corners[5] = bbox.Corner(1,0,1);
box_corners[6] = bbox.Corner(1,1,1);
box_corners[7] = bbox.Corner(0,1,1);
return Create(box_corners,order0,order1,order2,cv_count0,cv_count1,cv_count2);
}
bool ON_NurbsCage::Create( int dim, bool is_rat,
int order0, int order1, int order2,
int cv_count0, int cv_count1, int cv_count2
)
{
Destroy();
if ( order0 < 2 || order1 < 2 || order2 < 2 )
{
if ( 0 == dim && 0 == is_rat
&& 0 == order0 && 0 == order1 && 0 == order2
&& 0 == cv_count0 && 0 == cv_count1 && 0 == cv_count2 )
{
return true;
}
ON_ERROR("ON_NurbsCage::Create - invalid orders");
return false;
}
if ( cv_count0 < order0 || cv_count1 < order1 || cv_count2 < order2 )
{
ON_ERROR("ON_NurbsCage::Create - invalid cv counts");
return false;
}
if ( dim < 1 )
{
ON_ERROR("ON_NurbsCage::Create - invalid dim");
return false;
}
if ( is_rat != true && is_rat != false )
{
ON_ERROR("ON_NurbsCage::Create - invalid is_rat");
return false;
}
m_dim = dim;
m_is_rat = is_rat ? 1 : 0;
m_order[0] = order0;
m_order[1] = order1;
m_order[2] = order2;
m_cv_count[0] = cv_count0;
m_cv_count[1] = cv_count1;
m_cv_count[2] = cv_count2;
// Other ON_NurbsCage member functions, like operator=,
// depend on the strides being set this way. If you anything
// in the next three lines, then you need to read all the
// code in the ON_NurbsCage member functions and adjust
// it accordingly.
m_cv_stride[2] = m_dim+m_is_rat;
m_cv_stride[1] = m_cv_stride[2]*m_cv_count[2];
m_cv_stride[0] = m_cv_stride[1]*m_cv_count[1];
ReserveCVCapacity(m_cv_stride[0]*m_cv_count[0]);
ReserveKnotCapacity(0,ON_KnotCount(m_order[0],m_cv_count[0]));
ReserveKnotCapacity(1,ON_KnotCount(m_order[1],m_cv_count[1]));
ReserveKnotCapacity(2,ON_KnotCount(m_order[2],m_cv_count[2]));
ON_MakeClampedUniformKnotVector(m_order[0],m_cv_count[0],m_knot[0],1.0);
ON_MakeClampedUniformKnotVector(m_order[1],m_cv_count[1],m_knot[1],1.0);
ON_MakeClampedUniformKnotVector(m_order[2],m_cv_count[2],m_knot[2],1.0);
ON_SetKnotVectorDomain( m_order[0], m_cv_count[0], m_knot[0], 0.0, 1.0);
ON_SetKnotVectorDomain( m_order[1], m_cv_count[1], m_knot[1], 0.0, 1.0);
ON_SetKnotVectorDomain( m_order[2], m_cv_count[2], m_knot[2], 0.0, 1.0);
return IsValid() ? true : false;
}
bool ON_NurbsCage::Create(
const ON_3dPoint* box_corners,
int order0, int order1, int order2,
int cv_count0, int cv_count1, int cv_count2
)
{
int i, j, k;
double r,s,t;
//bool rc = false;
if ( 0 == box_corners )
return false;
for( i = 0; i < 8; i++ )
{
if ( !box_corners[i].IsValid() )
return false;
}
// create trilinear "cube" to make it easy
// to calculate CV locations.
ON_BezierCage cube(3,0,2,2,2);
cube.SetCV(0,0,0,box_corners[0]);
cube.SetCV(1,0,0,box_corners[1]);
cube.SetCV(1,1,0,box_corners[2]);
cube.SetCV(0,1,0,box_corners[3]);
cube.SetCV(0,0,1,box_corners[4]);
cube.SetCV(1,0,1,box_corners[5]);
cube.SetCV(1,1,1,box_corners[6]);
cube.SetCV(0,1,1,box_corners[7]);
if ( 2 == cv_count0 && 2 == cv_count1 && 2 == cv_count2 )
{
operator=(cube);
}
else
{
if (!Create(3,0,order0,order1,order2,cv_count0,cv_count1,cv_count2))
return false;
double* g0 = (double*)onmalloc(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*sizeof(*g0));
double* g1 = g0 + m_cv_count[0];
double* g2 = g1 + m_cv_count[1];
ON_GetGrevilleAbcissae(m_order[0],m_cv_count[0],m_knot[0],false,g0);
ON_GetGrevilleAbcissae(m_order[1],m_cv_count[1],m_knot[1],false,g1);
ON_GetGrevilleAbcissae(m_order[2],m_cv_count[2],m_knot[2],false,g2);
for (i = 0; i < m_cv_count[0]; i++)
{
r = g0[i];
for (j = 0; j < m_cv_count[1]; j++)
{
s = g1[j];
for (k = 0; k < m_cv_count[2]; k++)
{
t = g2[k];
SetCV(i,j,k,cube.PointAt(r,s,t));
}
}
}
onfree(g0);
}
return IsValid()?true:false;
}
void ON_NurbsCage::Destroy()
{
DestroyRuntimeCache();
if ( m_cv && m_cv_capacity > 0 )
{
onfree(m_cv);
m_cv = 0;
}
if ( m_knot[0] && m_knot_capacity[0] > 0 )
{
onfree(m_knot[0]);
m_knot[0] = 0;
}
if ( m_knot[1] && m_knot_capacity[1] > 0 )
{
onfree(m_knot[1]);
m_knot[1] = 0;
}
if ( m_knot[2] && m_knot_capacity[2] > 0 )
{
onfree(m_knot[2]);
m_knot[2] = 0;
}
m_cv_capacity = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
m_dim = 0;
m_is_rat = 0;
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
}
void ON_NurbsCage::EmergencyDestroy()
{
DestroyRuntimeCache(false);
m_cv = 0;
m_knot[0] = 0;
m_knot[1] = 0;
m_knot[2] = 0;
m_cv_capacity = 0;
m_knot_capacity[0] = 0;
m_knot_capacity[1] = 0;
m_knot_capacity[2] = 0;
m_cv_stride[0] = 0;
m_cv_stride[1] = 0;
m_cv_stride[2] = 0;
m_dim = 0;
m_is_rat = 0;
m_order[0] = 0;
m_order[1] = 0;
m_order[2] = 0;
}
bool ON_NurbsCage::GetBBox( // returns true if successful
double* boxmin, // minimum
double* boxmax, // maximum
bool bGrowBox // true means grow box
) const
{
int i, j;
bool rc = ( 0 != m_cv
&& m_cv_count[0] >= 2 && m_cv_count[1] >= 2 && m_cv_count[2] >= 2
&& m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0 ) ? true : false;
if ( !rc )
{
ON_ERROR("ON_NurbsCage::GetBBox - invalid input");
}
else
{
for ( i = 0; rc && i < m_cv_count[0]; i++ )
for ( j = 0; rc && j < m_cv_count[1]; j++ )
{
rc = ON_GetPointListBoundingBox( m_dim, m_is_rat, m_cv_count[2], m_cv_stride[2],
CV(i,j,0),
boxmin, boxmax, bGrowBox?true:false );
bGrowBox = true;
}
}
return rc;
}
bool ON_NurbsCage::Transform( const ON_Xform& xform )
{
// Call the base class so any user data is transformed.
if (!this->ON_Geometry::Transform(xform))
return false;
int i,j;
bool rc = (m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2]) ? true : false;
if ( rc || !xform.IsIdentity() )
{
if ( 0 == m_is_rat )
{
if ( xform.m_xform[3][0] != 0.0 || xform.m_xform[3][1] != 0.0 || xform.m_xform[3][2] != 0.0 )
{
MakeRational();
}
}
for ( i = 0; rc && i < m_cv_count[0]; i++ )
{
for ( j = 0; rc && j < m_cv_count[1]; j++ )
{
rc = ON_TransformPointList( m_dim, m_is_rat,
m_cv_count[2], m_cv_stride[2],
CV(i,j,0), xform );
}
}
}
return rc;
}
ON_Interval ON_NurbsCage::Domain(
int dir
) const
{
ON_Interval d;
if ( dir < 0 || dir > 2 || !ON_GetKnotVectorDomain( m_order[dir], m_cv_count[dir], m_knot[dir], &d.m_t[0], &d.m_t[1] ) || !d.IsIncreasing() )
d = ON_Interval::EmptyInterval;
return d;
}
bool ON_EvaluateNurbsCageSpan(
int dim,
bool is_rat,
int order0, int order1, int order2,
const double* knot0,
const double* knot1,
const double* knot2,
int cv_stride0, int cv_stride1, int cv_stride2,
const double* cv0,
int der_count,
double t0, double t1, double t2,
int v_stride,
double* v
)
{
double c;
double* N_0, *N_1, *N_2, *P, *P0, *P00;
const double *cv;
int j0, j1, j2, d0, d1, d2, d;
const int cvdim = is_rat ? (dim+1) : dim;
const int dcv2 = cv_stride2 - cvdim;
const int der_count0 = (der_count >= order0) ? order0-1 : der_count;
const int der_count1 = (der_count >= order1) ? order1-1 : der_count;
const int der_count2 = (der_count >= order1) ? order2-2 : der_count;
int Pcount = der_count*(der_count*(der_count*2 + 9)+13)/6 + 1;
int Psize = cvdim<<3;
int i = order0*order0;
int j = order1*order1;
int k = order2*order2;
// don't declare any variable below here to avoid problems caused
// by compiler/optimizer/alloca() bugs that can't keep the SP
// properly set.
N_0 = (double*)alloca( ((i+j+k)*sizeof(*N_0)) + Pcount*Psize);
N_1 = N_0 + i;
N_2 = N_1 + j;
P0 = N_2 + k;
memset( P0, 0, Pcount*Psize );
ON_EvaluateNurbsBasis( order0, knot0, t0, N_0 );
ON_EvaluateNurbsBasis( order1, knot1, t1, N_1 );
ON_EvaluateNurbsBasis( order2, knot2, t2, N_2 );
if ( der_count0 > 0 )
{
ON_EvaluateNurbsBasisDerivatives( order0, knot0, der_count0, N_0 );
ON_EvaluateNurbsBasisDerivatives( order1, knot1, der_count1, N_1 );
ON_EvaluateNurbsBasisDerivatives( order2, knot2, der_count2, N_2 );
}
// compute point
P = P0;
for ( j0 = 0; j0 < order0; j0++)
{
for ( j1 = 0; j1 < order1; j1++ )
{
cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
for ( j2 = 0; j2 < order2; j2++ )
{
c = N_0[j0]*N_1[j1]*N_2[j2];
j = cvdim;
while (j--)
{
*P++ += c* *cv++;
}
P -= cvdim;
cv += dcv2;
}
}
}
if ( der_count > 0 )
{
// quickly compute first derivatives
P += cvdim; // step over point
for ( j0 = 0; j0 < order0; j0++)
{
for ( j1 = 0; j1 < order1; j1++ )
{
cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
for ( j2 = 0; j2 < order2; j2++ )
{
// "Dr"
c = N_0[j0+order0]*N_1[j1]*N_2[j2];
j = cvdim;
while (j--)
*P++ += c* *cv++;
cv -= cvdim;
// "Ds"
c = N_0[j0]*N_1[j1+order1]*N_2[j2];
j = cvdim;
while (j--)
*P++ += c* *cv++;
cv -= cvdim;
// "Dt"
c = N_0[j0]*N_1[j1]*N_2[j2+order2];
j = cvdim;
while (j--)
*P++ += c* *cv++;
P -= 3*cvdim;
cv += dcv2;
}
}
}
// compute higher order derivatives in generic loop
for ( d = 2; d <= der_count; d++ )
{
// compute second derivatives
P += (cvdim*d*(d+1))>>1; // step over (d-1) derivatives
// P points to first coordinate of Dr^d
if ( der_count0+der_count1+der_count2 > 1 )
{
for ( j0 = 0; j0 < order0; j0++)
{
for ( j1 = 0; j1 < order1; j1++)
{
cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
for ( j2 = 0; j2 < order2; j2++ )
{
P00 = P;
for ( d0 = d; d0 >= 0; d0-- )
{
for ( d1 = d-d0; d1 >= 0; d1-- )
{
d2 = d-d0-d1;
if ( d0 > der_count0 || d1 > der_count1 || d2 > der_count2 )
{
// this partial is zero
P += cvdim;
}
else
{
c = N_0[j0 + d0*order0]*N_1[j1 + d1*order1]*N_2[j2 + d2*order2];
j = cvdim;
while(j--)
*P++ += c* *cv++;
cv -= cvdim;
}
}
}
P = P00;
cv += cv_stride2;
}
}
}
}
}
}
if ( is_rat )
{
ON_EvaluateQuotientRule3( dim, der_count, cvdim, P0 );
Psize -= 8;
}
Pcount = (der_count+1)*(der_count+2)*(der_count+3)/6;
for ( i = 0; i < Pcount; i++)
{
memcpy( v, P0, Psize );
v += v_stride;
P0 += cvdim;
}
return true;
}
bool ON_NurbsCage::Evaluate( // returns false if unable to evaluate
double r, double s, double t, // evaluation parameter
int der_count, // number of derivatives (>=0)
int v_stride, // array stride (>=Dimension())
double* v, // array of length stride*(ndir+1)*(ndir+2)/2
int side, // optional - determines which side to evaluate from
// 0 = default
// 1 = from upper NE quadrant
// 2 = from upper NW quadrant
// 3 = from upper SW quadrant
// 4 = from upper SE quadrant
// 5 = from lower NE quadrant
// 6 = from lower NW quadrant
// 7 = from lower SW quadrant
// 8 = from lower SE quadrant
int* hint
) const
{
int side0 = (side&&(side==2||side==3||side==6||side==7))?-1:1;
int side1 = (side&&(side==3||side==4||side==7||side==8))?-1:1;
int side2 = (side>=5&&side<=8)?-1:1;
int hint0 = (hint) ? hint[0] : 0;
int hint1 = (hint) ? hint[1] : 0;
int hint2 = (hint) ? hint[2] : 0;
const int span_index0 = ON_NurbsSpanIndex(m_order[0],m_cv_count[0],m_knot[0],r,side0,hint0);
const int span_index1 = ON_NurbsSpanIndex(m_order[1],m_cv_count[1],m_knot[1],s,side1,hint1);
const int span_index2 = ON_NurbsSpanIndex(m_order[2],m_cv_count[2],m_knot[2],t,side2,hint2);
bool rc = ON_EvaluateNurbsCageSpan(m_dim,m_is_rat,
m_order[0],m_order[1],m_order[2],
m_knot[0]+span_index0,
m_knot[1]+span_index1,
m_knot[2]+span_index2,
m_cv_stride[0],m_cv_stride[1],m_cv_stride[2],
m_cv + (m_cv_stride[0]*span_index0+m_cv_stride[1]*span_index1+m_cv_stride[2]*span_index2),
der_count,
r,s,t,
v_stride,v);
if( hint )
{
hint[0] = span_index0;
hint[1] = span_index1;
hint[2] = span_index2;
}
return rc;
}
ON_3dPoint ON_NurbsCage::PointAt(
double r,
double s,
double t
) const
{
ON_3dPoint pt;
if ( m_dim <= 3 )
{
pt.x = 0.0;
pt.y = 0.0;
pt.z = 0.0;
Evaluate(r,s,t,0,3,&pt.x);
}
else
{
double* v = (double*)alloca(m_dim*sizeof(*v));
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
Evaluate(r,s,t,0,m_dim,v);
pt.x = v[0];
pt.y = v[1];
pt.z = v[2];
}
return pt;
}
ON_3dPoint ON_NurbsCage::PointAt( ON_3dPoint rst ) const
{
ON_3dPoint pt;
if ( m_dim <= 3 )
{
pt.x = 0.0;
pt.y = 0.0;
pt.z = 0.0;
Evaluate(rst.x,rst.y,rst.z,0,3,&pt.x);
}
else
{
double* v = (double*)alloca(m_dim*sizeof(*v));
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
Evaluate(rst.x,rst.y,rst.z,0,m_dim,v);
pt.x = v[0];
pt.y = v[1];
pt.z = v[2];
}
return pt;
}
ON_NurbsSurface* ON_NurbsCage::IsoSurface(
int dir,
double c,
ON_NurbsSurface* srf
) const
{
// c = 0; cage(c,s,t) = srf(s,t)
// c = 1; cage(r,c,t) = srf(r,t)
// c = 2; cage(r,s,c) = srf(r,s)
if ( dir < 0 || dir > 2 )
{
ON_ERROR("ON_NurbsCage::IsoSurface - invalid dir parameter");
return 0;
}
if ( m_order[dir] < 2 || m_cv_count[dir] < m_order[dir] || 0 == m_knot[dir] )
{
ON_ERROR("ON_NurbsCage::IsoSurface - invalid NURBS cage");
return 0;
}
const int cage_cvdim = CVSize();
int span_index = ON_NurbsSpanIndex(m_order[dir],m_cv_count[dir],m_knot[dir],c,0,0);
ON_NurbsCurve nurbs_curve;
nurbs_curve.m_dim = cage_cvdim*m_cv_count[0]*m_cv_count[1]*m_cv_count[2]/m_cv_count[dir];
nurbs_curve.m_is_rat = 0;
nurbs_curve.m_order = m_order[dir];
nurbs_curve.m_cv_count = nurbs_curve.m_order;
nurbs_curve.ReserveCVCapacity(nurbs_curve.m_dim*nurbs_curve.m_cv_count);
nurbs_curve.m_cv_stride = nurbs_curve.m_dim;
// nurbs_curve.m_knot[] shares memory with m_knot[dir] + span_index. nurbs_curve destructor does not free nurbs_curve.m_knot[]
nurbs_curve.ManageKnotForExperts(0, m_knot[dir] + span_index);
int ii,jj,kk;
/*
int i0 = 0;
int i1 = m_cv_count[0];
int j0 = 0;
int j1 = m_cv_count[1];
int k0 = 0;
int k1 = m_cv_count[2];
*/
//int i0 = span_index;
//int i1 = span_index+m_order[dir];
ii = dir;
switch(dir)
{
case 0:
jj = 1;
kk = 2;
break;
case 1:
jj = 0;
kk = 2;
break;
case 2:
jj = 0;
kk = 1;
break;
default: // to keep lint happy
ii = 0;
jj = 1;
kk = 2;
break;
};
double* cv;
const int cage_sizeofcv = cage_cvdim*sizeof(*cv);
//int i0 = span_index;
int i1 = span_index+m_order[ii];
int j1 = m_cv_count[jj];
int k1 = m_cv_count[kk];
int i,j,k;
int cage_ijk[3];
for ( i = span_index; i < i1; i++)
{
cv = nurbs_curve.CV(i-span_index);
cage_ijk[ii] = i;
for ( j = 0; j < j1; j++ )
{
cage_ijk[jj] = j;
for ( k = 0; k < k1; k++ )
{
cage_ijk[kk] = k;
memcpy(cv,CV(cage_ijk[0],cage_ijk[1],cage_ijk[2]),cage_sizeofcv);
cv += cage_cvdim;
}
}
}
ON_NurbsSurface* iso_srf = srf ? srf : ON_NurbsSurface::New();
iso_srf->Create(m_dim,m_is_rat,m_order[jj],m_order[kk],m_cv_count[jj],m_cv_count[kk]);
nurbs_curve.Evaluate(c,0,nurbs_curve.m_dim,iso_srf->m_cv,0,0);
nurbs_curve.m_knot = 0;
memcpy(iso_srf->m_knot[0],m_knot[jj],iso_srf->KnotCount(0)*sizeof(*iso_srf->m_knot[0]));
memcpy(iso_srf->m_knot[1],m_knot[kk],iso_srf->KnotCount(1)*sizeof(*iso_srf->m_knot[1]));
return iso_srf;
}
bool ON_NurbsCage::IsRational() const
{
return m_is_rat ? true : false;
}
int ON_NurbsCage::CVSize() const
{
return ( m_is_rat && m_dim>0 ) ? m_dim+1 : m_dim;
}
int ON_NurbsCage::Order( int dir ) const
{
return (dir>=0&&dir<=2) ? m_order[dir] : 0;
}
int ON_NurbsCage::Degree(int dir) const
{
int order = Order(dir);
return (order>=2) ? order-1 : 0;
}
bool ON_NurbsCage::IsClosed(int dir) const
{
bool bIsClosed = false;
if ( dir >= 0 && dir <= 2 && m_dim > 0)
{
if ( ON_IsKnotVectorClamped( m_order[dir], m_cv_count[dir], m_knot[dir] ) )
{
const double *cv0, *cv1;
int i,j,k,d[3] = {0,0,0};
d[dir] = m_cv_count[dir] - 1;
for ( i = 0; i+d[0] < m_cv_count[0]; i++ )
{
for ( j = 0; j+d[1] < m_cv_count[1]; j++ )
{
for ( k = 0; k+d[2] < m_cv_count[2]; k++ )
{
cv0 = CV(i,j,k);
cv1 = CV(i+d[0],j+d[1],k+d[2]);
if ( false == ON_PointsAreCoincident( m_dim, m_is_rat, cv0, cv1 ) )
return false;
}
}
}
bIsClosed = true;
}
else
{
bIsClosed = IsPeriodic(dir);
}
}
return bIsClosed;
}
bool ON_NurbsCage::IsPeriodic(int dir) const
{
bool bIsPeriodic = false;
if ( dir >= 0 && dir <= 2 && m_dim > 0 )
{
bIsPeriodic = ON_IsKnotVectorPeriodic( m_order[dir], m_cv_count[dir], m_knot[dir] );
if ( bIsPeriodic )
{
const double *cv0, *cv1;
int i,j,k,d[3] = {0,0,0};
d[dir] = m_cv_count[dir] - (m_order[dir]-1);
for ( i = 0; i+d[0] < m_cv_count[0]; i++ )
{
for ( j = 0; j+d[1] < m_cv_count[1]; j++ )
{
for ( k = 0; k+d[2] < m_cv_count[2]; k++ )
{
cv0 = CV(i,j,k);
cv1 = CV(i+d[0],j+d[1],k+d[2]);
if ( false == ON_PointsAreCoincident(m_dim, m_is_rat, cv0, cv1 ) )
return false;
}
}
}
}
}
return bIsPeriodic;
}
double* ON_NurbsCage::CV( int i, int j, int k ) const
{
#if defined(ON_DEBUG)
if ( 0 == m_cv )
{
ON_ERROR("ON_NurbsCage::CV - nullptr m_cv");
return 0;
}
if ( i < 0 || i >= m_cv_count[0] || j< 0 || j >= m_cv_count[1] || k < 0 || k >= m_cv_count[2])
{
ON_ERROR("ON_NurbsCage::CV - (i,j,k) out of range");
return 0;
}
#endif
return (m_cv) ? (m_cv + i*m_cv_stride[0] + j*m_cv_stride[1] + k*m_cv_stride[2]) : 0;
}
ON::point_style ON_NurbsCage::CVStyle() const
{
return m_is_rat ? ON::homogeneous_rational : ON::not_rational;
}
double ON_NurbsCage::Weight( int i, int j, int k ) const
{
return (m_cv && m_is_rat) ? m_cv[i*m_cv_stride[0] + j*m_cv_stride[1] + k*m_cv_stride[2] + + m_dim] : 1.0;
}
bool ON_NurbsCage::SetWeight( int i, int j, int k, double w )
{
bool rc = false;
if ( m_is_rat )
{
double* cv = CV(i,j,k);
if (cv)
{
cv[m_dim] = w;
rc = true;
}
}
else if ( w == 1.0 )
{
rc = true;
}
return rc;
}
bool ON_NurbsCage::SetCV( int i, int j, int k, ON::point_style style, const double* Point )
{
bool rc = true;
int n;
double w;
double* cv = CV(i,j,k);
if ( !cv )
return false;
switch ( style ) {
case ON::not_rational: // input Point is not rational
memcpy( cv, Point, m_dim*sizeof(*cv) );
if ( IsRational() ) {
// NURBS surface is rational - set weight to one
cv[m_dim] = 1.0;
}
break;
case ON::homogeneous_rational: // input Point is homogeneous rational
if ( IsRational() ) {
// NURBS surface is rational
memcpy( cv, Point, (m_dim+1)*sizeof(*cv) );
}
else {
// NURBS surface is not rational
w = (Point[m_dim] != 0.0) ? 1.0/Point[m_dim] : 1.0;
for ( n = 0; n < m_dim; n++ ) {
cv[n] = w*Point[n];
}
}
break;
case ON::euclidean_rational: // input Point is euclidean rational
if ( IsRational() ) {
// NURBS surface is rational - convert euclean point to homogeneous form
w = Point[m_dim];
for ( n = 0; n < m_dim; n++ )
cv[i] = w*Point[i];
cv[m_dim] = w;
}
else {
// NURBS surface is not rational
memcpy( cv, Point, m_dim*sizeof(*cv) );
}
break;
case ON::intrinsic_point_style:
n = m_is_rat?m_dim+1:m_dim;
memcpy(cv,Point,n*sizeof(*cv));
break;
default:
rc = false;
break;
}
return rc;
}
bool ON_NurbsCage::SetCV( int i, int j, int k, const ON_3dPoint& point )
{
bool rc = false;
double* cv = CV(i,j,k);
if ( cv ) {
cv[0] = point.x;
if ( m_dim > 1 ) {
cv[1] = point.y;
if ( m_dim > 2 )
cv[2] = point.z;
}
if ( m_is_rat ) {
cv[m_dim] = 1.0;
}
rc = true;
}
return rc;
}
bool ON_NurbsCage::SetCV( int i, int j, int k, const ON_4dPoint& point )
{
bool rc = false;
double* cv = CV(i,j,k);
if ( cv ) {
if ( m_is_rat ) {
cv[0] = point.x;
if ( m_dim > 1 ) {
cv[1] = point.y;
if ( m_dim > 2 )
cv[2] = point.z;
}
cv[m_dim] = point.w;
rc = true;
}
else {
double w;
if ( point.w != 0.0 ) {
w = 1.0/point.w;
rc = true;
}
else {
w = 1.0;
}
cv[0] = w*point.x;
if ( m_dim > 1 ) {
cv[1] = w*point.y;
if ( m_dim > 2 ) {
cv[2] = w*point.z;
}
}
}
}
return rc;
}
bool ON_NurbsCage::GetCV( int i, int j, int k, ON::point_style style, double* Point ) const
{
const double* cv = CV(i,j,k);
if ( !cv )
return false;
int dim = Dimension();
double w = ( IsRational() ) ? cv[dim] : 1.0;
switch(style) {
case ON::euclidean_rational:
Point[dim] = w;
// no break here
case ON::not_rational:
if ( w == 0.0 )
return false;
w = 1.0/w;
while(dim--) *Point++ = *cv++ * w;
break;
case ON::homogeneous_rational:
Point[dim] = w;
memcpy( Point, cv, dim*sizeof(*Point) );
break;
default:
return false;
}
return true;
}
bool ON_NurbsCage::GetCV( int i, int j, int k, ON_3dPoint& point ) const
{
bool rc = false;
const double* cv = CV(i,j,k);
if ( cv ) {
if ( m_is_rat ) {
if (cv[m_dim] != 0.0) {
const double w = 1.0/cv[m_dim];
point.x = cv[0]*w;
point.y = (m_dim>1)? cv[1]*w : 0.0;
point.z = (m_dim>2)? cv[2]*w : 0.0;
rc = true;
}
}
else {
point.x = cv[0];
point.y = (m_dim>1)? cv[1] : 0.0;
point.z = (m_dim>2)? cv[2] : 0.0;
rc = true;
}
}
return rc;
}
bool ON_NurbsCage::GetCV( int i, int j, int k, ON_4dPoint& point ) const
{
bool rc = false;
const double* cv = CV(i,j,k);
if ( cv ) {
point.x = cv[0];
point.y = (m_dim>1)? cv[1] : 0.0;
point.z = (m_dim>2)? cv[2] : 0.0;
point.w = (m_is_rat) ? cv[m_dim] : 1.0;
rc = true;
}
return rc;
}
bool ON_NurbsCage::SetKnot(
int dir,
int knot_index,
double knot_value
)
{
bool rc;
// Validate input so invalid input does not crash Rhino.
// Expert programmers who want to write fast code can directly
// access the m_knot[] arrays.
if ( dir >= 0 && dir < 3
&& 0 != m_knot[dir]
&& knot_index >= 0
&& knot_index < m_order[dir]+m_cv_count[dir]-2
)
{
m_knot[dir][knot_index] = knot_value;
rc = true;
}
else
{
ON_ERROR("ON_NurbsCage::SetKnot - invalid input parameters");
rc = false;
}
return rc;
}
double ON_NurbsCage::Knot(
int dir,
int knot_index
) const
{
double knot_value;
// Validate input so invalid input does not crash Rhino.
// Expert programmers who want to write fast code can directly
// access the m_knot[] arrays.
if ( dir >= 0 && dir < 3
&& 0 != m_knot[dir]
&& knot_index >= 0
&& knot_index < m_order[dir]+m_cv_count[dir]-2
)
{
knot_value = m_knot[dir][knot_index];
}
else
{
ON_ERROR("ON_NurbsCage::Knot - invalid input parameters");
knot_value = ON_UNSET_VALUE;
}
return knot_value;
}
bool ON_NurbsCage::ZeroCVs()
{
// zeros control vertices and, if rational, sets weights to 1
bool rc = false;
int i,j,k;
if ( m_cv ) {
if ( m_cv_capacity > 0 ) {
memset( m_cv, 0, m_cv_capacity*sizeof(*m_cv) );
if ( m_is_rat ) {
for ( i = 0; i < m_order[0]; i++ ) {
for ( j = 0; j < m_order[1]; j++ ) {
for ( k = 0; k < m_order[2]; k++ ) {
SetWeight( i,j,k, 1.0 );
}
}
}
}
rc = true;
}
else {
double* cv;
int s = CVSize()*sizeof(*cv);
for ( i = 0; i < m_order[0]; i++ ) {
for ( j = 0; j < m_order[1]; j++ ) {
for ( k = 0; k < m_order[2]; k++ ) {
cv = CV(i,j,k);
memset(cv,0,s);
if ( m_is_rat )
cv[m_dim] = 1.0;
}
}
}
rc = (i>0) ? true : false;
}
}
return rc;
}
bool ON_NurbsCage::MakeRational()
{
if ( !IsRational() )
{
const int dim = Dimension();
if ( m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2] > 0 && dim > 0 )
{
int i,j,k;
if ( m_cv_stride[0] <= dim || m_cv_stride[1] <= dim || m_cv_stride[2] <= dim )
{
// there's not room for the weight in the existing m_cv array - adjust the strides
double* new_cv = (double*)onmalloc(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1)*sizeof(*new_cv));
double* cv1 = new_cv;
const int sizeofoldcv = dim*sizeof(*cv1);
for (i = 0; i < m_cv_count[0]; i++)
{
for(j = 0; j < m_cv_count[1]; j++)
{
for(k = 0; k < m_cv_count[2]; k++)
{
memcpy(cv1,CV(i,j,k),sizeofoldcv);
cv1 += dim;
*cv1++ = 1.0;
}
}
}
m_is_rat = 1;
ReserveCVCapacity(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1));
memcpy(m_cv,new_cv,m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1)*sizeof(*m_cv));
onfree(new_cv);
m_cv_stride[2] = dim+1;
m_cv_stride[1] = m_cv_stride[2]*m_cv_count[2];
m_cv_stride[0] = m_cv_stride[1]*m_cv_count[1];
}
else
{
// there's room for the weight in the existing m_cv array
for (i = 0; i < m_cv_count[0]; i++)
{
for(j = 0; j < m_cv_count[1]; j++)
{
for(k = 0; k < m_cv_count[2]; k++)
{
CV(i,j,k)[dim] = 1.0;
}
}
}
m_is_rat = 1;
}
}
}
return IsRational();
}
bool ON_NurbsCage::MakeNonRational()
{
if ( IsRational() && m_dim > 0 )
{
int i,j,k,n;
double* cv;
double w;
for (i = 0; i < m_cv_count[0]; i++)
for (j = 0; j < m_cv_count[1]; j++)
for (k = 0; k < m_cv_count[2]; k++)
{
cv = CV(i,j,k);
w = cv[m_dim];
if ( w != 1.0 && w != 0.0 )
{
w = 1.0/w;
n = m_dim;
while(n--)
{
*cv++ *= w;
}
*cv = 1.0;
}
}
m_is_rat = 0;
}
return ( IsRational() ) ? false : true;
}
/////////////////////////////////////////////////////////////////
// Tools for managing CV and knot memory
bool ON_NurbsCage::ReserveCVCapacity(
int capacity// number of doubles to reserve
)
{
if ( capacity > 0 && m_cv_capacity < capacity )
{
if ( m_cv )
{
if ( m_cv_capacity )
{
m_cv = (double*)onrealloc( m_cv, capacity*sizeof(*m_cv) );
m_cv_capacity = (m_cv) ? capacity : 0;
}
// else user supplied m_cv[] array
}
else
{
m_cv = (double*)onmalloc( capacity*sizeof(*m_cv) );
m_cv_capacity = (m_cv) ? capacity : 0;
}
}
return ( m_cv ) ? true : false;
}
bool ON_NurbsCage::ReserveKnotCapacity(
int dir,
int knot_capacity
)
{
bool rc = false;
if ( dir >= 0 && dir <= 2 && knot_capacity > 0 )
{
if ( m_knot_capacity[dir] < knot_capacity )
{
if ( m_knot[dir] )
{
if( m_knot_capacity[dir] )
{
m_knot[dir] = (double*)onrealloc(m_knot[dir],knot_capacity*sizeof(m_knot[dir][0]));
m_knot_capacity[dir] = m_knot[dir] ? knot_capacity : 0;
}
// else user supplied m_knot[dir] array.
}
else
{
m_knot[dir] = (double*)onmalloc(knot_capacity*sizeof(m_knot[dir][0]));
m_knot_capacity[dir] = m_knot[dir] ? knot_capacity : 0;
}
}
rc = m_knot[dir] != 0;
}
return rc;
}
bool ON_NurbsCage::IsSingular( // true if surface side is collapsed to a point
int //side // side of parameter space to test
// 0 = south, 1 = east, 2 = north, 3 = west, 4 = bottom, 5 =top
) const
{
ON_ERROR("TODO: fill in ON_NurbsCage::IsSingular\n");
return false;
}
bool ON_GetCageXform( const ON_NurbsCage& cage, ON_Xform& cage_xform )
{
bool rc = false;
cage_xform = ON_Xform::IdentityTransformation;
if ( cage.IsValid() )
{
ON_3dPoint P000, P100, P010, P001;
if ( !cage.GetCV(0,0,0,P000) )
return false;
if ( !cage.GetCV(cage.CVCount(0)-1,0,0,P100))
return false;
if (!cage.GetCV(0,cage.CVCount(1)-1,0,P010))
return false;
if (!cage.GetCV(0,0,cage.CVCount(2)-1,P001))
return false;
ON_3dVector X0 = P100 - P000;
ON_3dVector Y0 = P010 - P000;
ON_3dVector Z0 = P001 - P000;
double dx0 = X0.Length();
double dy0 = Y0.Length();
double dz0 = Z0.Length();
ON_Interval d0 = cage.Domain(0);
ON_Interval d1 = cage.Domain(1);
ON_Interval d2 = cage.Domain(2);
X0.Unitize();
Y0.Unitize();
Z0.Unitize();
ON_Xform x1;
x1.Rotation(
P000, X0, Y0, Z0,
ON_3dPoint::Origin, ON_3dVector::XAxis, ON_3dVector::YAxis, ON_3dVector::ZAxis
);
const ON_Xform x2(ON_Xform::DiagonalTransformation( d0.Length()/dx0, d1.Length()/dy0, d2.Length()/dz0 ));
const ON_Xform x3(ON_Xform::TranslationTransformation( d0[0],d1[0],d2[0]));
cage_xform = x3*(x2*x1);
rc = true;
}
return rc;
}
ON_CageMorph::ON_CageMorph()
{
m_control = 0;
}
ON_CageMorph::~ON_CageMorph()
{
m_control = 0;
}
bool ON_MorphControl::IsIdentity( const ON_BoundingBox& bbox ) const
{
int i, count = m_localizers.Count();
bool rc = (count > 0);
for (i = 0; i < count && rc; i++ )
{
rc = m_localizers[i].IsZero(bbox);
}
return rc;
}
bool ON_CageMorph::IsIdentity( const ON_BoundingBox& bbox ) const
{
return m_control ? m_control->IsIdentity(bbox) : true;
}
ON_MorphControl::ON_MorphControl()
: m_varient(0)
{
m_sporh_tolerance = 0.0;
m_sporh_bQuickPreview = false;
m_sporh_bPreserveStructure = false;
}
ON_MorphControl::~ON_MorphControl()
{
}
void ON_MorphControl::Destroy()
{
m_varient = 0;
m_nurbs_cage0 = ON_Xform::IdentityTransformation;
m_nurbs_curve0.Destroy();
m_nurbs_curve.Destroy();
m_nurbs_curve_domain = ON_Interval::EmptyInterval;
m_nurbs_surface0.Destroy();
m_nurbs_surface.Destroy();
m_nurbs_surface_domain[0] = ON_Interval::EmptyInterval;
m_nurbs_surface_domain[1] = ON_Interval::EmptyInterval;
m_nurbs_cage.Destroy();
m_captive_id.Empty();
m_localizers.Destroy();
m_sporh_tolerance = 0.0;
m_sporh_bQuickPreview = false;
m_sporh_bPreserveStructure = false;
}
void ON_MorphControl::MemoryRelocate()
{
m_nurbs_curve0.MemoryRelocate();
m_nurbs_curve.MemoryRelocate();
m_nurbs_surface0.MemoryRelocate();
m_nurbs_surface.MemoryRelocate();
m_nurbs_cage.MemoryRelocate();
ON_Geometry::MemoryRelocate();
}
bool ON_MorphControl::IsValid( ON_TextLog* text_log ) const
{
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve0.IsValid(text_log);
if (rc)
rc = m_nurbs_curve.IsValid(text_log);
break;
case 2:
rc = m_nurbs_surface0.IsValid(text_log);
if (rc)
rc = m_nurbs_surface.IsValid(text_log);
break;
case 3:
rc = m_nurbs_cage.IsValid(text_log);
break;
default:
rc = false;
if ( text_log )
{
text_log->Print("m_varient = %d - should be 1, 2, or 3\n",m_varient);
}
break;
}
return rc;
}
void ON_MorphControl::Dump( ON_TextLog& text_log ) const
{
text_log.Print("Varient: %d\n",m_varient);
text_log.Print("Control object:\n");
text_log.PushIndent();
switch(m_varient)
{
case 1:
m_nurbs_curve0.Dump(text_log);
m_nurbs_curve.Dump(text_log);
break;
case 2:
m_nurbs_surface0.Dump(text_log);
m_nurbs_surface.Dump(text_log);
break;
case 3:
text_log.Print(m_nurbs_cage0);
m_nurbs_cage.Dump(text_log);
break;
}
text_log.PopIndent();
}
unsigned int ON_MorphControl::SizeOf() const
{
unsigned int sz = sizeof(*this)
- 2*sizeof(ON_NurbsCurve)
- 2*sizeof(ON_NurbsSurface)
- sizeof(m_nurbs_cage);
sz += m_nurbs_curve0.SizeOf();
sz += m_nurbs_curve.SizeOf();
sz += m_nurbs_surface0.SizeOf();
sz += m_nurbs_surface.SizeOf();
sz += m_nurbs_cage.SizeOf();
sz += m_localizers.SizeOfArray();
return sz;
}
ON::object_type ON_MorphControl::ObjectType() const
{
return ON::morph_control_object;
}
void ON_MorphControl::DestroyRuntimeCache( bool bDelete )
{
m_nurbs_curve.DestroyRuntimeCache(bDelete);
m_nurbs_surface.DestroyRuntimeCache(bDelete);
m_nurbs_cage.DestroyRuntimeCache(bDelete);
}
int ON_MorphControl::Dimension() const
{
int dim = 0;
switch(m_varient)
{
case 1:
dim = m_nurbs_curve.Dimension();
break;
case 2:
dim = m_nurbs_surface.Dimension();
break;
case 3:
dim = m_nurbs_cage.Dimension();
break;
}
return dim;
}
bool ON_MorphControl::GetBBox(
double* boxmin,
double* boxmax,
bool bGrowBox
) const
{
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.GetBBox(boxmin,boxmax,bGrowBox);
break;
case 2:
rc = m_nurbs_surface.GetBBox(boxmin,boxmax,bGrowBox);
break;
case 3:
rc = m_nurbs_cage.GetBBox(boxmin,boxmax,bGrowBox);
break;
}
return rc;
}
bool ON_MorphControl::GetTightBoundingBox(
ON_BoundingBox& tight_bbox,
bool bGrowBox,
const ON_Xform* xform
) const
{
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.GetTightBoundingBox(tight_bbox,bGrowBox);
break;
case 2:
rc = m_nurbs_surface.GetTightBoundingBox(tight_bbox,bGrowBox);
break;
case 3:
rc = m_nurbs_cage.GetTightBoundingBox(tight_bbox,bGrowBox);
break;
}
return rc;
}
void ON_MorphControl::ClearBoundingBox()
{
}
bool ON_MorphControl::Transform(
const ON_Xform& xform
)
{
// Call the base class so any user data is transformed.
if (!this->ON_Geometry::Transform(xform))
return false;
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.Transform(xform);
break;
case 2:
rc = m_nurbs_surface.Transform(xform);
break;
case 3:
rc = m_nurbs_cage.Transform(xform);
break;
}
return rc;
}
bool ON_MorphControl::HasBrepForm() const
{
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.HasBrepForm();
break;
case 2:
rc = m_nurbs_surface.HasBrepForm();
break;
case 3:
rc = m_nurbs_cage.HasBrepForm();
break;
}
return rc;
}
ON_Brep* ON_MorphControl::BrepForm( ON_Brep* brep ) const
{
switch(m_varient)
{
case 1:
brep = m_nurbs_curve.BrepForm(brep);
break;
case 2:
brep = m_nurbs_surface.BrepForm(brep);
break;
case 3:
brep = m_nurbs_cage.BrepForm(brep);
break;
default:
brep = 0;
break;
}
return brep;
}
bool ON_MorphControl::IsRational() const
{
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.IsRational();
break;
case 2:
rc = m_nurbs_surface.IsRational();
break;
case 3:
rc = m_nurbs_cage.IsRational();
break;
}
return rc;
}
bool ON_MorphControl::MakeRational()
{
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.MakeRational();
break;
case 2:
rc = m_nurbs_surface.MakeRational();
break;
case 3:
rc = m_nurbs_cage.MakeRational();
break;
}
return rc;
}
bool ON_MorphControl::MakeNonRational()
{
bool rc = false;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.MakeNonRational();
break;
case 2:
rc = m_nurbs_surface.MakeNonRational();
break;
case 3:
rc = m_nurbs_cage.MakeNonRational();
break;
}
return rc;
}
int ON_MorphControl::CVCount() const
{
int rc = 0;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.CVCount();
break;
case 2:
rc = m_nurbs_surface.CVCount();
break;
case 3:
rc = m_nurbs_cage.CVCount();
break;
}
return rc;
}
int ON_MorphControl::CVCount(int dir) const
{
int rc = 0;
switch(m_varient)
{
case 1:
rc = (0==dir) ? m_nurbs_curve.CVCount() : 0;
break;
case 2:
rc = m_nurbs_surface.CVCount(dir);
break;
case 3:
rc = m_nurbs_cage.CVCount(dir);
break;
}
return rc;
}
int ON_MorphControl::Order(int dir) const
{
int rc = 0;
switch(m_varient)
{
case 1:
rc = (0==dir) ? m_nurbs_curve.Order() : 0;
break;
case 2:
rc = m_nurbs_surface.Order(dir);
break;
case 3:
rc = m_nurbs_cage.Order(dir);
break;
}
return rc;
}
ON_3dex ON_MorphControl::MaxCVIndex() const
{
ON_3dex maxdex;
maxdex.i = maxdex.j = maxdex.k = 0;
switch(m_varient)
{
case 1:
maxdex.i = m_nurbs_curve.CVCount();
maxdex.j = maxdex.k = 1;
break;
case 2:
maxdex.i = m_nurbs_surface.CVCount(0);
maxdex.j = m_nurbs_surface.CVCount(1);
maxdex.k = 1;
break;
case 3:
maxdex.i = m_nurbs_cage.CVCount(0);
maxdex.j = m_nurbs_cage.CVCount(1);
maxdex.k = m_nurbs_cage.CVCount(2);
break;
}
return maxdex;
}
const double* ON_MorphControl::Knot(int dir) const
{
const double* knot = 0;
switch(m_varient)
{
case 1:
knot = (0 == dir) ? m_nurbs_curve.m_knot : 0;
break;
case 2:
knot = (0 == dir || 1 == dir) ? m_nurbs_surface.m_knot[dir] : 0;
break;
case 3:
knot = (0 <= dir && dir <= 2) ? m_nurbs_cage.m_knot[dir] : 0;
break;
}
return knot;
}
const double* ON_MorphControl::CV(ON_3dex ijk) const
{
const double* cv = 0;
switch(m_varient)
{
case 1:
cv = (0 == ijk.j && 0 == ijk.k) ? m_nurbs_curve.CV(ijk.i) : 0;
break;
case 2:
cv = (0 == ijk.k) ? m_nurbs_surface.CV(ijk.i,ijk.j) : 0;
break;
case 3:
cv = m_nurbs_cage.CV(ijk.i,ijk.j,ijk.k);
break;
}
return cv;
}
double ON_MorphControl::Weight(ON_3dex ijk) const
{
double w = 1.0;
switch(m_varient)
{
case 1:
w = (0 == ijk.j && 0 == ijk.k) ? m_nurbs_curve.Weight(ijk.i) : 1.0;
break;
case 2:
w = (0 == ijk.k) ? m_nurbs_surface.Weight(ijk.i,ijk.j) : 1.0;
break;
case 3:
w = m_nurbs_cage.Weight(ijk.i,ijk.j,ijk.k);
break;
}
return w;
}
bool ON_MorphControl::GetCageMorph(ON_CageMorph& cage_morph) const
{
cage_morph.m_control = this;
cage_morph.SetPreserveStructure(m_sporh_bPreserveStructure);
cage_morph.SetQuickPreview(m_sporh_bQuickPreview);
cage_morph.SetTolerance(m_sporh_tolerance);
return true;
}
bool ON_MorphControl::Read( ON_BinaryArchive& archive )
{
Destroy();
int major_version = 0;
int minor_version = 0;
bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,
&major_version,
&minor_version);
while(rc)
{
if ( 1 == major_version )
{
m_varient = 3;
if (rc)
rc = m_nurbs_cage.Read(archive)?true:false;
if (rc)
rc = m_captive_id.Read(archive);
if (rc)
rc = archive.ReadXform(m_nurbs_cage0);
}
else if ( 2 == major_version )
{
rc = archive.ReadInt(&m_varient);
if (!rc) break;
int mjv = 0;
int mnv = 0;
rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
if (!rc) break;
rc = (1 == mjv);
if (rc)
{
switch(m_varient)
{
case 1:
rc = m_nurbs_curve0.Read(archive)?true:false;
if (rc)
m_nurbs_curve_domain = m_nurbs_curve0.Domain();
break;
case 2:
rc = m_nurbs_surface0.Read(archive)?true:false;
if (rc)
{
m_nurbs_surface_domain[0] = m_nurbs_surface0.Domain(0);
m_nurbs_surface_domain[1] = m_nurbs_surface0.Domain(1);
}
break;
case 3:
rc = archive.ReadXform(m_nurbs_cage0);
break;
}
}
if ( !archive.EndRead3dmChunk() )
rc = false;
if(!rc)
break;
mjv = 0;
mnv = 0;
rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
if (!rc) break;
rc = (1 == mjv);
if (rc)
{
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.Read(archive)?true:false;
break;
case 2:
rc = m_nurbs_surface.Read(archive)?true:false;
break;
case 3:
rc = m_nurbs_cage.Read(archive)?true:false;
break;
}
}
if ( !archive.EndRead3dmChunk() )
rc = false;
// captive ids
rc = m_captive_id.Read(archive);
if (!rc)
break;
// localizers
mjv = 0;
mnv = 0;
rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
if (!rc)
break;
int i, count = 0;
rc = (1 == mjv);
if (rc)
rc = archive.ReadInt(&count);
if (rc)
m_localizers.Reserve(count);
for ( i = 0; i < count && rc; i++ )
{
m_localizers.AppendNew();
rc = m_localizers[i].Read(archive);
}
if ( !archive.EndRead3dmChunk() )
rc = false;
if ( !rc)
break;
if ( minor_version >= 1 )
{
rc = archive.ReadDouble(&m_sporh_tolerance);
if (!rc)
break;
rc = archive.ReadBool(&m_sporh_bQuickPreview);
if (!rc)
break;
rc = archive.ReadBool(&m_sporh_bPreserveStructure);
if (!rc)
break;
}
}
else
{
rc = false;
}
if ( !archive.EndRead3dmChunk() )
rc = false;
break;
}
return rc;
}
bool ON_MorphControl::Write( ON_BinaryArchive& archive ) const
{
bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,2,1);
if (!rc)
return false;
while(rc)
{
rc = archive.WriteInt(m_varient);
if (!rc) break;
// control start location
rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
if (!rc) break;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve0.Write(archive)?true:false;
break;
case 2:
rc = m_nurbs_surface0.Write(archive)?true:false;
break;
case 3:
rc = archive.WriteXform(m_nurbs_cage0);
break;
}
if ( !archive.EndWrite3dmChunk() )
rc = false;
if(!rc)
break;
// control end location
rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
if (!rc) break;
switch(m_varient)
{
case 1:
rc = m_nurbs_curve.Write(archive)?true:false;
break;
case 2:
rc = m_nurbs_surface.Write(archive)?true:false;
break;
case 3:
rc = m_nurbs_cage.Write(archive)?true:false;
break;
}
if ( !archive.EndWrite3dmChunk() )
rc = false;
if ( !rc)
break;
// captive ids
rc = m_captive_id.Write(archive);
if (!rc)
break;
// localizers
rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
if (!rc)
break;
int i, count = m_localizers.Count();
rc = archive.WriteInt(count);
for ( i = 0; i < count && rc; i++ )
{
rc = m_localizers[i].Write(archive);
}
if ( !archive.EndWrite3dmChunk() )
rc = false;
if ( !rc)
break;
// 2.1 fields
rc = archive.WriteDouble(m_sporh_tolerance);
if (!rc)
break;
rc = archive.WriteBool(m_sporh_bQuickPreview);
if (!rc)
break;
rc = archive.WriteBool(m_sporh_bPreserveStructure);
if (!rc)
break;
break;
}
if ( !archive.EndWrite3dmChunk() )
rc = false;
return rc;
}
bool ON_MorphControl::AddControlLocalizer(
double support_distance,
double falloff_distance
)
{
bool rc = (support_distance >= 0.0 && falloff_distance > 0.0 );
if (rc)
{
switch(m_varient)
{
case 1:
case 2:
{
ON_Localizer& localizer = m_localizers.AppendNew();
localizer.m_type = ON_Localizer::distance_type;
localizer.m_d.Set(support_distance+falloff_distance,support_distance);
rc = true;
}
break;
case 3:
{
ON_Xform xform = m_nurbs_cage0;
xform.Invert();
ON_Interval d[3];
d[0] = m_nurbs_cage.Domain(0);
d[1] = m_nurbs_cage.Domain(1);
d[2] = m_nurbs_cage.Domain(2);
ON_SimpleArray<ON_Plane> planes(6);
ON_3dPoint C(d[0].ParameterAt(0.5),d[1].ParameterAt(0.5),d[2].ParameterAt(0.5));
ON_3dPoint P;
ON_3dVector N;
int i;
double det = (xform.Determinant() < 0.0) ? -1.0 : 1.0;
for ( i = 0; i < 3; i++ )
{
P = C;
N = ON_3dVector::ZeroVector;
N[i] = -det;
P[i] = d[i][0];
ON_Plane& plane0 = planes.AppendNew();
plane0.CreateFromNormal(P,N);
plane0.Transform(xform);
P[i] = d[i][1];
N[i] = det;
ON_Plane& plane1 = planes.AppendNew();
plane1.CreateFromNormal(P,N);
plane1.Transform(xform);
}
rc = AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
}
break;
default:
rc = false;
break;
}
}
return rc;
}
bool ON_MorphControl::AddSphereLocalizer(
ON_3dPoint center,
double support_distance,
double falloff_distance
)
{
bool rc = (center.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
if (rc)
{
ON_Localizer& localizer = m_localizers.AppendNew();
rc = localizer.CreateSphereLocalizer(
center,
support_distance+falloff_distance,
support_distance);
}
return rc;
}
bool ON_MorphControl::AddCylinderLocalizer(
ON_Line axis,
double support_distance,
double falloff_distance
)
{
bool rc = (axis.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
if (rc)
{
ON_Localizer& localizer = m_localizers.AppendNew();
rc = localizer.CreateCylinderLocalizer(
axis.from,axis.Tangent(),
support_distance+falloff_distance,
support_distance);
}
return rc;
}
bool ON_MorphControl::AddBoxLocalizer(
ON_BoundingBox bbox,
double support_distance,
double falloff_distance
)
{
ON_SimpleArray<ON_Plane> planes(6);
bool rc = (bbox.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
if (rc)
{
ON_3dPoint C = bbox.Center();
ON_3dVector N;
ON_3dPoint P;
int i;
for ( i = 0; i < 3; i++ )
{
P = C;
N = ON_3dVector::ZeroVector;
ON_Plane& plane0 = planes.AppendNew();
P[i] = bbox.m_min[i];
N[i] = -1.0;
plane0.CreateFromNormal(P,N);
ON_Plane& plane1 = planes.AppendNew();
P[i] = bbox.m_max[i];
N[i] = 1.0;
plane1.CreateFromNormal(P,N);
}
rc = AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
}
return rc;
}
bool ON_MorphControl::AddPlaneLocalizer(
const ON_Plane& plane,
double support_distance,
double falloff_distance
)
{
ON_SimpleArray<ON_Plane> planes(1);
planes.Append(plane);
return AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
}
bool ON_MorphControl::AddConvexPolygonLocalizer(
const ON_SimpleArray<ON_Plane>& planes,
double support_distance,
double falloff_distance
)
{
int i, count = planes.Count();
bool rc = (support_distance >= 0.0 && falloff_distance > 0.0 );
if (rc)
{
m_localizers.Reserve(m_localizers.Count() + count);
for( i = 0; i < count && rc; i++)
{
const ON_Plane& plane = planes[i];
ON_Localizer& localizer = m_localizers.AppendNew();
rc = localizer.CreatePlaneLocalizer(
plane.origin,plane.zaxis,
support_distance+falloff_distance,
support_distance);
}
}
return rc;
}