/* $NoKeywords: $ */ /* // // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// */ #include "opennurbs.h" #if !defined(ON_COMPILING_OPENNURBS) // This check is included in all opennurbs source .c and .cpp files to insure // ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled. // When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined // and the opennurbs .h files alter what is declared and how it is declared. #error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs #endif bool ON_BezierCage::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_BezierCage::Read - old code unable to read new version of chunk"); rc = false; break; } int dim=0,order0=0,order1=0,order2=0; bool is_rat=false; rc = archive.ReadInt(&dim); if (!rc) break; if (dim < 1 || dim > 10000) { ON_ERROR("ON_BezierCage::Read - invalid dim"); rc=false; break; } rc = archive.ReadBool(&is_rat); if (!rc) break; rc = archive.ReadInt(&order0); if (!rc) break; if ( order0 < 2 || order0 > 10000 ) { ON_ERROR("ON_BezierCage::Read - invalid order0"); rc=false; break; } rc = archive.ReadInt(&order1); if (!rc) break; if ( order1 < 2 || order1 > 10000 ) { ON_ERROR("ON_BezierCage::Read - invalid order1"); rc=false; break; } rc = archive.ReadInt(&order2); if (!rc) break; if ( order2 < 2 || order2 > 10000 ) { ON_ERROR("ON_BezierCage::Read - invalid order2"); rc=false; break; } rc = Create(dim,is_rat,order0,order1,order2); if (!rc) break; int i,j,k; const int cv_dim = m_is_rat?(m_dim+1):m_dim; for(i = 0; i < order0 && rc; i++) { for(j = 0; j < order1 && rc; j++) { for ( k = 0; k < order2 && rc; k++) { rc = archive.ReadDouble(cv_dim,CV(i,j,k)); } } } break; } if ( !archive.EndRead3dmChunk() ) { rc = false; } } return rc; } bool ON_BezierCage::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]); int i,j,k; const int cv_dim = m_is_rat?(m_dim+1):m_dim; double* bogus_cv = 0; for(i = 0; i < m_order[0] && rc; i++) { for(j = 0; j < m_order[1] && rc; j++) { for ( k = 0; k < m_order[2] && rc; k++) { const double* cv = CV(i,j,k); if ( !cv ) { if ( 0 == bogus_cv ) { bogus_cv = (double*)onmalloc(cv_dim*sizeof(*bogus_cv)); for ( int n = 0; n < cv_dim; n++ ) bogus_cv[n] = ON_UNSET_VALUE; } cv = bogus_cv; } rc = archive.WriteDouble(cv_dim,cv); } } } if ( 0 != bogus_cv ) onfree(bogus_cv); if ( !archive.EndWrite3dmChunk() ) { rc = false; } } return rc; } ON_BezierCage::ON_BezierCage() : 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_stride[0] = 0; m_cv_stride[1] = 0; m_cv_stride[2] = 0; } ON_BezierCage::ON_BezierCage( int dim, bool is_rat, int order0, int order1, int order2 ) : 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_stride[0] = 0; m_cv_stride[1] = 0; m_cv_stride[2] = 0; Create( dim, is_rat, order0, order1, order2 ); } ON_BezierCage::ON_BezierCage( const ON_BoundingBox& bbox, int order0, int order1, int order2 ) : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0) { Create(bbox,order0,order1,order2); } ON_BezierCage::ON_BezierCage( const ON_3dPoint* box_corners, int order0, int order1, int order2 ) : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0) { Create(box_corners,order0,order1,order2); } ON_BezierCage::~ON_BezierCage() { Destroy(); } ON_BezierCage::ON_BezierCage(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_stride[0] = 0; m_cv_stride[1] = 0; m_cv_stride[2] = 0; *this = src; } ON_BezierCage& ON_BezierCage::operator=(const ON_BezierCage& src) { if ( this != &src ) { if ( Create( src.m_dim, src.m_is_rat, src.m_order[0], src.m_order[1], src.m_order[2] ) ) { const int sizeof_cv = src.CVSize()*sizeof(m_cv[0]); int i, j, k; for ( i = 0; i < m_order[0]; i++ ) for ( j = 0; j < m_order[1]; j++ ) for ( k = 0; k < m_order[2]; k++ ) { memcpy( CV(i,j,k), src.CV(i,j,k), sizeof_cv ); } } else { Destroy(); } } return *this; } bool ON_BezierCage::IsValid() const { if ( m_cv == nullptr ) 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_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_order[0]*m_order[1]*m_order[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_order[i[0]] ) return false; if ( m_cv_stride[i[2]] < m_cv_stride[i[1]]*m_order[i[1]] ) return false; return true; } void ON_BezierCage::Dump( ON_TextLog& dump ) const { dump.Print( "ON_BezierCage dim = %d is_rat = %d\n" " order = (%d, %d, %d) \n", m_dim, m_is_rat, m_order[0], m_order[1], m_order[2] ); dump.Print( "Control Points %d %s points\n" " index value\n", m_order[0]*m_order[1]*m_order[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"); ON_String::FormatIntoBuffer(sPreamble, sPremable_capacity," CV[%2d][%2d]", i, j); dump.PrintPointList( m_dim, m_is_rat, m_order[2], m_cv_stride[2], CV(i,j,0), sPreamble ); } if ( i < m_order[0]-1) dump.Print("\n"); } } } int ON_BezierCage::Dimension() const { return m_dim; } bool ON_BezierCage::Create( const ON_BoundingBox& bbox, int order0, int order1, int order2 ) { /* 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); } bool ON_BezierCage::Create( int dim, bool is_rat, int order0, int order1, int order2 ) { if ( m_cv_capacity < 1 ) m_cv = 0; m_dim = (dim>0) ? dim : 0; m_is_rat = is_rat ? 1 : 0; m_order[0] = (order0 >= 2) ? order0 : 0; m_order[1] = (order1 >= 2) ? order1 : 0; m_order[2] = (order2 >= 2) ? order2 : 0; m_cv_stride[2] = (m_dim > 0) ? m_dim+m_is_rat : 0; m_cv_stride[1] = m_cv_stride[2]*m_order[2]; m_cv_stride[0] = m_cv_stride[1]*m_order[1]; m_cv_capacity = m_cv_stride[0]*m_order[0]; m_cv = (double*)onrealloc( m_cv, m_cv_capacity*sizeof(m_cv[0]) ); return IsValid() ? true : false; } bool ON_BezierCage::Create( const ON_3dPoint* box_corners, int order0, int order1, int order2 ) { int i, j, k; double r,s,t; 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 == order0 && 2 == order1 && 2 == order2 ) { operator=(cube); } else { if (!Create(3,0,order0,order1,order2)) return false; const int d0 = Degree(0); const int d1 = Degree(1); const int d2 = Degree(2); for (i = 0; i <= d0; i++) { r = ((double)i)/((double)d0); for (j = 0; j <= d1; j++) { s = ((double)j)/((double)d1); for (k = 0; k <= d2; k++) { t = ((double)k)/((double)d2); SetCV(i,j,k,cube.PointAt(r,s,t)); } } } } return IsValid(); } void ON_BezierCage::Destroy() { if ( m_cv && m_cv_capacity > 0 ) onfree(m_cv); m_cv_capacity = 0; m_cv_stride[0] = 0; m_cv_stride[1] = 0; m_cv_stride[2] = 0; m_cv = 0; m_dim = 0; m_is_rat = 0; m_order[0] = 0; m_order[1] = 0; m_order[2] = 0; } void ON_BezierCage::EmergencyDestroy() { m_cv_capacity = 0; m_cv_stride[0] = 0; m_cv_stride[1] = 0; m_cv_stride[2] = 0; m_cv = 0; m_dim = 0; m_is_rat = 0; m_order[0] = 0; m_order[1] = 0; m_order[2] = 0; } bool ON_BezierCage::GetBBox( // returns true if successful double* boxmin, // minimum double* boxmax, // maximum bool bGrowBox // true means grow box ) const { int i, j; bool rc = (m_order[0] > 0 && m_order[1] > 0 && m_order[2] > 0) ? true : false; for ( i = 0; rc && i < m_order[0]; i++ ) for ( j = 0; rc && j < m_order[1]; j++ ) { rc = ON_GetPointListBoundingBox( m_dim, m_is_rat, m_order[2], m_cv_stride[2], CV(i,j,0), boxmin, boxmax, bGrowBox ); bGrowBox = true; } return rc; } bool ON_BezierCage::Transform( const ON_Xform& xform ) { int i,j; bool rc = (m_order[0] > 0 && m_order[1] > 0 && m_order[2]) ? true : false; if (rc) { 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_order[0]; i++ ) { for ( j = 0; rc && j < m_order[1]; j++ ) { rc = ON_TransformPointList( m_dim, m_is_rat, m_order[2], m_cv_stride[2], CV(i,j,0), xform ); } } } return rc; } bool ON_BezierCage::Rotate( double sin_angle, // sin(angle) double cos_angle, // cos(angle) const ON_3dVector& axis, // axis of rotation const ON_3dPoint& center // center of rotation ) { ON_Xform rot; rot.Rotation( sin_angle, cos_angle, axis, center ); return Transform( rot ); } bool ON_BezierCage::Rotate( double angle, // angle in radians const ON_3dVector& axis, // axis of rotation const ON_3dPoint& center // center of rotation ) { return Rotate( sin(angle), cos(angle), axis, center ); } bool ON_BezierCage::Translate( const ON_3dVector& delta ) { ON_Xform tr(ON_Xform::TranslationTransformation( delta )); return Transform( tr ); } bool ON_BezierCage::Scale( double x ) { ON_Xform s(ON_Xform::DiagonalTransformation(x)); return Transform( s ); } ON_Interval ON_BezierCage::Domain( int // dir - formal parameter intentionally ignored in this virtual function ) const { return ON_Interval(0.0,1.0); } bool ON_BezierCage::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 ) const { const int cvdim = m_is_rat?(m_dim+1):m_dim; int i,j,k,n; double Barray[64], vtmparray[10*4], Bi, Bij, Bijk, *Bj, *Bk, *vtmp; const double* CVi; const double* CVij; const double* CVijk; void* freeme1 = 0; void* freeme2 = 0; size_t sz; if ( der_count > 0 ) { // TODO - time to add support for derivative evaluation ON_ERROR("ON_BezierCage::Evaluate does not evaluate derivatives"); } sz = cvdim*sizeof(*vtmp); vtmp = m_is_rat ? (sz <= sizeof(vtmparray) ? vtmparray : (double*)(freeme1 = onmalloc(sz))) : v; memset(vtmp,0,sz); // get arrays to hold values of Bernstein basis functions sz = (m_order[1]+m_order[2])*sizeof(*Bj); Bj = (sz <= sizeof(Barray)) ? Barray : ((double*)(freeme2=onmalloc( sz ) )); Bk = Bj + m_order[1]; const int d2 = m_order[2]-1; for ( k = 0; k <= d2; k++) { Bk[k] = ON_EvaluateBernsteinBasis(d2,k,t); } const int d1 = m_order[1]-1; for ( j = 0; j <= d1; j++) { Bj[j] = ON_EvaluateBernsteinBasis(d1,j,s); } const int d0 = m_order[0]-1; for ( i = 0; i <= d0; i++ ) { CVi = m_cv + i*m_cv_stride[0]; Bi = ON_EvaluateBernsteinBasis(d0,i,r); for ( j = 0; j <= d1; j++ ) { CVij = CVi + j*m_cv_stride[1]; Bij = Bi*Bj[j]; for ( k = 0; k <= d2; k++ ) { CVijk = CVij + k*m_cv_stride[2]; Bijk = Bij*Bk[k]; n = cvdim; while(n--) { *vtmp++ += *CVijk++ * Bijk; } vtmp -= cvdim; } } } if ( m_is_rat ) { Bi = (vtmp[m_dim] != 0.0) ? (1.0/vtmp[m_dim]) : 1.0; for ( n = 0; n < m_dim; n++ ) { v[n] = vtmp[n]*Bi; } } if ( 0 != freeme1 ) onfree(freeme1); if ( 0 != freeme2 ) onfree(freeme2); return (0 == der_count); } ON_3dPoint ON_BezierCage::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 stack_buffer[16]; double* v; size_t sizeof_buffer = m_dim*sizeof(*v); v = (sizeof_buffer <= sizeof(stack_buffer)) ? stack_buffer : (double*)onmalloc(sizeof_buffer); 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]; if ( v != stack_buffer ) onfree(v); } return pt; } ON_3dPoint ON_BezierCage::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 stack_buffer[16]; double* v; size_t sizeof_buffer = m_dim*sizeof(*v); v = (sizeof_buffer <= sizeof(stack_buffer)) ? stack_buffer : (double*)onmalloc(sizeof_buffer); 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]; if ( v != stack_buffer ) onfree(v); } return pt; } bool ON_BezierCage::IsRational() const { return m_is_rat ? true : false; } int ON_BezierCage::CVSize() const { return ( m_is_rat && m_dim>0 ) ? m_dim+1 : m_dim; } int ON_BezierCage::Order( int dir ) const { return (dir>=0&&dir<=2) ? m_order[dir] : 0; } int ON_BezierCage::Degree(int dir) const { int order = Order(dir); return (order>=2) ? order-1 : 0; } double* ON_BezierCage::CV( int i, int j, int k ) const { #if defined(ON_DEBUG) if ( 0 == m_cv ) { ON_ERROR("ON_BezierCage::CV - nullptr m_cv"); return 0; } if ( i < 0 || i >= m_order[0] || j< 0 || j >= m_order[1] || k < 0 || k >= m_order[2]) { ON_ERROR("ON_BezierCage::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_BezierCage::CVStyle() const { return m_is_rat ? ON::homogeneous_rational : ON::not_rational; } double ON_BezierCage::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_BezierCage::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_BezierCage::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_BezierCage::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_BezierCage::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_BezierCage::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_BezierCage::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_BezierCage::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_BezierCage::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_BezierCage::MakeRational() { if ( !IsRational() ) { ON_ERROR("TODO: fill in ON_BezierCage::MakeRational()"); /* const int dim = Dimension(); if ( m_order[0] > 0 && m_order[1] > 0 && m_order[2] > 0 && dim > 0 ) { const double* old_cv; double* new_cv; int cvi, cvj, j, cvstride; if ( m_cv_stride[0] < m_cv_stride[1] ) { cvstride = m_cv_stride[0] > dim ? m_cv_stride[0] : dim+1; ReserveCVCapacity( cvstride*m_order[0]*m_order[1] ); new_cv = m_cv + cvstride*m_order[0]*m_order[1]-1; for ( cvj = m_order[1]-1; cvj >= 0; cvj-- ) { for ( cvi = m_order[0]-1; cvi >= 0; cvi-- ) { old_cv = CV(cvi,cvj)+dim-1; *new_cv-- = 1.0; for ( j = 0; j < dim; j++ ) { *new_cv-- = *old_cv--; } } } m_cv_stride[0] = dim+1; m_cv_stride[1] = (dim+1)*m_order[0]; } else { cvstride = m_cv_stride[1] > dim ? m_cv_stride[1] : dim+1; ReserveCVCapacity( cvstride*m_order[0]*m_order[1] ); new_cv = m_cv + cvstride*m_order[0]*m_order[1]-1; for ( cvi = m_order[0]-1; cvi >= 0; cvi-- ) { for ( cvj = m_order[1]-1; cvj >= 0; cvj-- ) { old_cv = CV(cvi,cvj)+dim-1; *new_cv-- = 1.0; for ( j = 0; j < dim; j++ ) { *new_cv-- = *old_cv--; } } } m_cv_stride[1] = dim+1; m_cv_stride[0] = (dim+1)*m_order[1]; } m_is_rat = 1; } */ } return IsRational(); } bool ON_BezierCage::MakeNonRational() { if ( IsRational() ) { ON_ERROR("TODO: fill in ON_BezierCage::MakeNonRational()"); /* const int dim = Dimension(); if ( m_order[0] > 0 && m_order[1] > 0 && dim > 0 ) { double w; const double* old_cv; double* new_cv = m_cv; int cvi, cvj, j; if ( m_cv_stride[0] < m_cv_stride[1] ) { for ( cvj = 0; cvj < m_order[1]; cvj++ ) { for ( cvi = 0; cvi < m_order[0]; cvi++ ) { old_cv = CV(cvi,cvj); w = old_cv[dim]; w = ( w != 0.0 ) ? 1.0/w : 1.0; for ( j = 0; j < dim; j++ ) { *new_cv++ = w*(*old_cv++); } } } m_cv_stride[0] = dim; m_cv_stride[1] = dim*m_order[0]; } else { for ( cvi = 0; cvi < m_order[0]; cvi++ ) { for ( cvj = 0; cvj < m_order[1]; cvj++ ) { old_cv = CV(cvi,cvj); w = old_cv[dim]; w = ( w != 0.0 ) ? 1.0/w : 1.0; for ( j = 0; j < dim; j++ ) { *new_cv++ = w*(*old_cv++); } } } m_cv_stride[1] = dim; m_cv_stride[0] = dim*m_order[1]; } m_is_rat = 0; } */ } return ( !IsRational() ) ? true : false; } ///////////////////////////////////////////////////////////////// // Tools for managing CV and knot memory bool ON_BezierCage::ReserveCVCapacity( int capacity// number of doubles to reserve ) { if ( 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_BezierCage::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_BezierCage::IsSingular\n"); return false; } const ON_Xform& ON_BezierCageMorph::WorldToUnitCube() const { // maps world point into unit cube that can be morphed by // evaluation of the BezierCage() function. return m_xyz2rst; } const ON_BezierCage& ON_BezierCageMorph::BezierCage() const { // morphs a point in the unit cube into a world point. return m_rst2xyz; } bool ON_BezierCageMorph::Transform(const ON_Xform& xform) { // transforms the VolumeMorph as a piece of geometry return m_rst2xyz.Transform(xform); } bool ON_BezierCageMorph::Read(ON_BinaryArchive& archive) { int major_version = 0; int minor_version = 0; bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( rc ) { if ( major_version != 1 ) rc = false; if (rc) rc = archive.ReadXform(m_xyz2rst); if(rc) rc = m_rst2xyz.Read(archive); if ( !archive.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_BezierCageMorph::Write(ON_BinaryArchive& archive) const { bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if (rc) { if (rc) rc = archive.WriteXform(m_xyz2rst); if(rc) rc = m_rst2xyz.Write(archive); if ( !archive.EndWrite3dmChunk() ) rc = false; } return rc; } ON_BezierCageMorph::ON_BezierCageMorph() : m_bValid(0) { } ON_BezierCageMorph::~ON_BezierCageMorph() { } bool ON_BezierCageMorph::Create( ON_3dPoint P0, ON_3dPoint P1, ON_3dPoint P2, ON_3dPoint P3, int point_countX, int point_countY, int point_countZ ) { if ( point_countX < 2 || point_countY < 2 || point_countZ < 2 || !P0.IsValid() || !P1.IsValid() || !P2.IsValid() || !P3.IsValid() ) { ON_ERROR("ON_BezierCageMorph::Create - invalid input"); } m_bValid = false; ON_3dVector X = P1-P0; ON_3dVector Y = P2-P0; ON_3dVector Z = P3-P0; ON_Xform xform(ON_Xform::IdentityTransformation); xform[0][0] = X.x; xform[1][0] = X.y; xform[2][0] = X.z; xform[0][1] = Y.x; xform[1][1] = Y.y; xform[2][1] = Y.z; xform[0][2] = Z.x; xform[1][2] = Z.y; xform[2][2] = Z.z; xform[0][3] = P0.x; xform[1][3] = P0.y; xform[2][3] = P0.z; double min_pivot = 0.0; m_bValid = xform.Invert(&min_pivot); if (m_bValid) { ON_3dPoint box_corners[8]; box_corners[0] = P0; box_corners[1] = P1; box_corners[2] = P0+X+Y; box_corners[3] = P2; box_corners[4] = P3; box_corners[5] = P3+X; box_corners[6] = P3+X+Y; box_corners[7] = P3+Y; m_bValid = m_rst2xyz.Create(box_corners,point_countX,point_countY,point_countZ); m_xyz2rst = xform; } else { ON_ERROR("ON_BezierCageMorph::Create - invalid input - P0,P1,P2,P3 are coplanar"); m_rst2xyz.Destroy(); } return m_bValid; } bool ON_BezierCageMorph::SetXform( ON_Xform world2unitcube ) { m_xyz2rst = world2unitcube; m_bValid = m_xyz2rst.IsValid() && m_rst2xyz.IsValid(); return m_bValid; } bool ON_BezierCageMorph::SetBezierCage( ON_BezierCage& unitcube2world ) { m_rst2xyz = unitcube2world; m_bValid = m_xyz2rst.IsValid() && m_rst2xyz.IsValid(); return m_bValid; }