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

1187 lines
27 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_SumSurface, ON_Surface, "C4CD5359-446D-4690-9FF5-29059732472B" );
void ON_SumSurface::DestroyRuntimeCache( bool bDelete )
{
ON_Surface::DestroyRuntimeCache(bDelete);
if ( 0 != m_curve[0] )
m_curve[0]->DestroyRuntimeCache(bDelete);
if ( 0 != m_curve[1] )
m_curve[1]->DestroyRuntimeCache(bDelete);
// 15 August 2003 Dale Lear:
// Added the call to destroy the cached bounding box
m_bbox.Destroy();
}
ON_SumSurface* ON_SumSurface::New()
{
return new ON_SumSurface();
}
ON_SumSurface* ON_SumSurface::New( const ON_SumSurface& rev_surface )
{
return new ON_SumSurface(rev_surface);
}
ON_SumSurface::ON_SumSurface()
{
ON__SET__THIS__PTR(m_s_ON_SumSurface_ptr);
m_curve[0] = nullptr;
m_curve[1] = nullptr;
}
ON_SumSurface::~ON_SumSurface()
{
Destroy();
}
void ON_SumSurface::Destroy()
{
// GBA 24-Sept-2004. Since there now could be a surface tree it need to be cleared out.
DestroyRuntimeCache();
for ( int i = 0; i < 2; i++ )
{
if ( m_curve[i] ) {
delete m_curve[i];
m_curve[i] = nullptr;
}
}
m_bbox = ON_BoundingBox::EmptyBoundingBox;
m_basepoint = ON_3dPoint::Origin;
}
void ON_SumSurface::EmergencyDestroy()
{
m_curve[0] = nullptr;
m_curve[1] = nullptr;
m_bbox = ON_BoundingBox::EmptyBoundingBox;
m_basepoint = ON_3dPoint::Origin;
}
void ON_SumSurface::Internal_CopyFrom(const ON_SumSurface& src)
{
m_curve[0] = nullptr;
m_curve[1] = nullptr;
for ( int i = 0; i < 2; i++ )
{
if ( nullptr != src.m_curve[i] )
m_curve[i] = src.m_curve[i]->DuplicateCurve();
}
m_basepoint = src.m_basepoint;
m_bbox = src.m_bbox;
}
ON_SumSurface::ON_SumSurface( const ON_SumSurface& src )
: ON_Surface(src)
{
ON__SET__THIS__PTR(m_s_ON_SumSurface_ptr);
m_curve[0] = nullptr;
m_curve[1] = nullptr;
Internal_CopyFrom(src);
}
unsigned int ON_SumSurface::SizeOf() const
{
unsigned int sz = ON_Surface::SizeOf();
if ( m_curve[0] )
sz += m_curve[0]->SizeOf();
if ( m_curve[1] )
sz += m_curve[1]->SizeOf();
return sz;
}
ON__UINT32 ON_SumSurface::DataCRC(ON__UINT32 current_remainder) const
{
if ( m_curve[0] )
current_remainder = m_curve[0]->DataCRC(current_remainder);
if ( m_curve[1] )
current_remainder = m_curve[1]->DataCRC(current_remainder);
return current_remainder;
}
ON_SumSurface& ON_SumSurface::operator=(const ON_SumSurface& src )
{
if ( this != &src )
{
Destroy();
ON_Surface::operator=(src);
Internal_CopyFrom(src);
}
return *this;
}
bool ON_SumSurface::Create( const ON_Curve& curve, ON_3dVector vector )
{
Destroy();
bool rc = false;
if ( !vector.IsZero() )
{
ON_Curve* pCurve = curve.DuplicateCurve();
rc = Create( pCurve, vector );
}
return rc;
}
bool ON_SumSurface::Create( ON_Curve* pCurve, ON_3dVector vector )
{
Destroy();
bool rc = false;
if ( !vector.IsZero() )
{
ON_LineCurve* pLineCurve = new ON_LineCurve( ON_Line( ON_3dPoint::Origin, vector ) );
pLineCurve->SetDomain( 0.0, vector.Length() );
m_curve[0] = pCurve;
m_curve[1] = pLineCurve;
m_basepoint.Set(0.0,0.0,0.0);
ON_BoundingBox bbox0 = pCurve->BoundingBox();
ON_BoundingBox bbox1 = bbox0;
bbox1.m_min += vector;
bbox1.m_max += vector;
m_bbox.Union( bbox0, bbox1 );
rc = true;
}
return rc;
}
bool ON_SumSurface::Create( const ON_Curve& curve, const ON_Curve& path_curve )
{
Destroy();
ON_Curve* pCurve = curve.DuplicateCurve();
ON_Curve* pPathCurve = path_curve.DuplicateCurve();
bool rc = Create( pCurve, pPathCurve );
return rc;
}
bool ON_SumSurface::Create( ON_Curve* pCurve, ON_Curve* pPathCurve )
{
Destroy();
bool rc = false;
if ( pCurve && pPathCurve )
{
m_curve[0] = pCurve;
m_curve[1] = pPathCurve;
m_basepoint = ON_3dPoint::Origin - pPathCurve->PointAtStart();
m_bbox.Destroy();
BoundingBox();
rc = true;
}
return rc;
}
////////////////////////////////////////////////////////////
//
// overrides of virtual ON_Object functions
//
bool ON_SumSurface::IsValid( ON_TextLog* text_log ) const
{
for ( int i = 0; i < 2; i++ )
{
if ( !m_curve[i] )
{
if ( text_log )
text_log->Print("ON_SumSurface.m_curve[%d] is nullptr.\n",i);
return false;
}
if ( m_curve[i]->Dimension() != 3 )
{
if ( text_log )
text_log->Print("ON_SumSurface.m_curve[%d]->m_dim = %d (should be 3).\n",i,m_curve[i]->Dimension());
return false;
}
if ( !m_curve[i]->IsValid(text_log) )
{
if ( text_log )
text_log->Print("ON_SumSurface.m_curve[%d] is not valid.\n",i);
return false;
}
}
if ( !m_basepoint.IsValid() )
{
if ( text_log )
text_log->Print("ON_SumSurface.m_basepoint is not valid.\n");
return false;
}
return true;
}
void ON_SumSurface::Dump( ON_TextLog& dump ) const
{
ON_Object::Dump(dump);
dump.PushIndent();
dump.Print("basepoint = ");
dump.Print(m_basepoint);
dump.Print("\n");
for ( int i = 0; i < 2; i++ )
{
if ( m_curve[i] )
{
dump.Print("m_curve[%d]:\n",i);
dump.PushIndent();
m_curve[i]->Dump(dump);
dump.PopIndent();
}
else
dump.Print("m_curve[%d] = nullptr\n",i);
}
}
bool ON_SumSurface::Write( ON_BinaryArchive& file ) const
{
bool rc = file.Write3dmChunkVersion(1,0);
if ( rc ) {
rc = file.WriteVector( m_basepoint );
rc = file.WriteBoundingBox( m_bbox );
if ( rc ) rc = file.WriteObject( m_curve[0] );
if ( rc ) rc = file.WriteObject( m_curve[1] );
}
return rc;
}
bool ON_SumSurface::Read( ON_BinaryArchive& file )
{
Destroy();
int major_version = 0;
int minor_version = 0;
bool rc = file.Read3dmChunkVersion( &major_version, &minor_version );
if (rc && major_version == 1 ) {
ON_Object* obj;
rc = file.ReadVector( m_basepoint );
if (rc) rc = file.ReadBoundingBox( m_bbox );
obj = 0;
if (rc) rc = file.ReadObject(&obj);
if (rc) {
m_curve[0] = ON_Curve::Cast(obj);
if ( !m_curve[0] )
delete obj;
}
obj = 0;
if (rc) rc = file.ReadObject(&obj);
if (rc) {
m_curve[1] = ON_Curve::Cast(obj);
if ( !m_curve[1] )
delete obj;
}
}
return rc;
}
////////////////////////////////////////////////////////////
//
// overrides of virtual ON_Geometry functions
//
int ON_SumSurface::Dimension() const
{
int dim = 0;
if ( m_curve[0] && m_curve[1] ) {
dim = m_curve[0]->Dimension();
if ( dim > 0 ) {
if ( dim != m_curve[1]->Dimension() )
dim = 0;
}
}
return dim;
}
void ON_SumSurface::ClearBoundingBox()
{
m_bbox.Destroy();
}
bool ON_SumSurface::GetBBox( // returns true if successful
double* boxmin, // boxmin[dim]
double* boxmax, // boxmax[dim]
bool bGrowBox
) const
{
bool rc = m_bbox.IsValid();
if (!rc )
{
// lazy bounding box evaluation
ON_BoundingBox bboxA, bboxB;
if ( m_curve[0] )
bboxA = m_curve[0]->BoundingBox();
if ( m_curve[1] )
bboxB = m_curve[1]->BoundingBox();
if ( bboxA.IsValid() && bboxB.IsValid() )
{
ON_SumSurface* pS = const_cast<ON_SumSurface*>(this);
pS->m_bbox.m_min = bboxA.m_min + bboxB.m_min + m_basepoint;
pS->m_bbox.m_max = bboxA.m_max + bboxB.m_max + m_basepoint;
}
rc = m_bbox.IsValid();
}
if ( rc )
{
int dim = Dimension();
int j;
ON_BoundingBox bbox;
if ( bGrowBox && boxmin && boxmax )
{
for ( j = 0; j < 3 && j < dim; j++ )
{
bbox.m_min[j] = boxmin[j];
bbox.m_max[j] = boxmax[j];
}
if ( !bbox.IsValid() )
bbox = m_bbox;
else
bbox.Union(m_bbox);
}
else
bbox = m_bbox;
dim = Dimension();
for ( j = 0; j < 3 && j < dim; j++ )
{
if(boxmin)
boxmin[j] = bbox.m_min[j];
if(boxmax)
boxmax[j] = bbox.m_max[j];
}
for ( j = 3; j < dim; j++ )
{
if (boxmin)
boxmin[j] = 0.0;
if (boxmax)
boxmax[j] = 0.0;
}
}
return rc;
}
bool ON_SumSurface::IsDeformable() const
{
bool rc = true;
if ( m_curve[0] )
rc = m_curve[0]->IsDeformable();
if (rc && m_curve[1] )
rc = m_curve[1]->IsDeformable();
return rc;
}
bool ON_SumSurface::MakeDeformable()
{
bool rc = true;
if ( m_curve[0] && !m_curve[0]->IsDeformable() )
{
DestroyRuntimeCache();
rc = rc && m_curve[0]->MakeDeformable();
}
if (m_curve[1] && !m_curve[1]->IsDeformable() )
{
DestroyRuntimeCache();
rc = rc && m_curve[1]->MakeDeformable();
}
return rc;
}
bool ON_SumSurface::Transform( const ON_Xform& xform )
{
DestroyRuntimeCache();
TransformUserData(xform);
bool rc = false;
ON_3dPoint A0, A1, A2;
if ( m_curve[0] )
{
A0 = m_curve[0]->PointAtStart();
rc = m_curve[0]->Transform(xform);
}
if ( m_curve[1] )
{
A1 = m_curve[1]->PointAtStart();
if ( !m_curve[1]->Transform(xform) )
rc = false;
}
else
rc = false;
if ( rc )
{
// because xform may be affine
A2 = m_basepoint;
m_basepoint = xform*(A0+A1+A2) - xform*A0 - xform*A1;
}
m_bbox.Destroy();
m_bbox = BoundingBox();
return rc;
}
////////////////////////////////////////////////////////////
//
// overrides of virtual ON_Surface functions
//
bool ON_SumSurface::SetDomain(
int dir, // 0 sets first parameter's domain, 1 gets second parameter's domain
double t0,
double t1
)
{
bool rc = false;
if ( t0 < t1 && dir >= 0 && dir <= 1 )
{
if ( 0 != m_curve[dir] )
{
rc = m_curve[dir]->SetDomain(t0,t1) ? true : false;
DestroyRuntimeCache();
}
}
return rc;
}
ON_Interval ON_SumSurface::Domain( int dir ) const
{
ON_Interval domain;
if ( dir == 0 && m_curve[0] )
domain = m_curve[0]->Domain();
else if ( dir == 1 && m_curve[1] )
domain = m_curve[1]->Domain();
return domain;
}
bool ON_SumSurface::GetSurfaceSize(
double* width,
double* height
) const
{
bool rc = true;
double* ptr[2];
ptr[0] = width;
ptr[1] = height;
int j;
for ( j = 0; j < 2; j++ )
{
if ( ptr[j] == nullptr )
continue;
*ptr[j] = 0.0;
if (m_curve[j] == nullptr)
{
rc = false;
continue;
}
int i, imax = 64, hint = 0;
double length_estimate = 0.0;
const double d = 1.0 / ((double)imax);
ON_Interval cdom = m_curve[j]->Domain();
ON_3dPoint pt0 = ON_3dPoint::UnsetPoint;
ON_3dPoint pt;
for ( i = 0; i <= imax; i++ )
{
if (m_curve[j]->EvPoint(cdom.ParameterAt(i * d), pt, 0, &hint) && pt.IsValid())
{
if (pt0 != ON_3dPoint::UnsetPoint)
length_estimate += pt0.DistanceTo(pt);
pt0 = pt;
}
else
rc = false;
}
if (length_estimate > 0.0)
*ptr[j] = length_estimate;
else
rc = false;
}
return rc;
}
int ON_SumSurface::SpanCount( int dir ) const
{
int span_count = 0;
if ( dir == 0 && m_curve[0] )
span_count = m_curve[0]->SpanCount();
else if ( dir == 1 && m_curve[1] )
span_count = m_curve[1]->SpanCount();
return span_count;
}
bool ON_SumSurface::GetSpanVector( int dir, double* s ) const
{
bool rc = false;
if ( dir == 0 && m_curve[0] )
rc = m_curve[0]->GetSpanVector(s);
else if ( dir == 1 && m_curve[1] )
rc = m_curve[1]->GetSpanVector(s);
return rc;
}
int ON_SumSurface::Degree( int dir ) const
{
int degree = 0;
if ( dir == 0 && m_curve[0] )
degree = m_curve[0]->Degree();
else if ( dir == 1 && m_curve[1] )
degree = m_curve[1]->Degree();
return degree;
}
bool ON_SumSurface::GetParameterTolerance( // returns tminus < tplus: parameters tminus <= s <= tplus
int dir, // 0 gets first parameter, 1 gets second parameter
double t, // t = parameter in domain
double* tminus, // tminus
double* tplus // tplus
) const
{
bool rc = false;
if ( dir == 0 && m_curve[0] )
rc = m_curve[0]->GetParameterTolerance(t,tminus,tplus);
else if ( dir == 1 && m_curve[1] )
rc = m_curve[1]->GetParameterTolerance(t,tminus,tplus);
return rc;
}
bool ON_SumSurface::IsPlanar(
ON_Plane* plane,
double tolerance
) const
{
ON_Plane pln;
ON_3dPoint center;
ON_3dVector normal, du, dv;
ON_Interval udom = Domain(0);
ON_Interval vdom = Domain(1);
bool rc = EvNormal( udom.ParameterAt(0.5), vdom.ParameterAt(0.5), center, du, dv, normal );
if (rc)
{
if ( fabs( normal.Length() - 1.0 ) > 0.01 )
rc = false;
else
{
pln.origin = center;
pln.zaxis = normal;
if ( du.Unitize() )
{
pln.xaxis = du;
pln.yaxis = ON_CrossProduct( pln.zaxis, pln.xaxis );
pln.yaxis.Unitize();
pln.UpdateEquation();
}
else if ( dv.Unitize() )
{
pln.yaxis = dv;
pln.xaxis = ON_CrossProduct( pln.yaxis, pln.zaxis );
pln.xaxis.Unitize();
pln.UpdateEquation();
}
else
{
pln.CreateFromNormal( center, normal );
}
if ( plane )
*plane = pln;
int j;
for ( j = 0; j < 2 && rc ; j++ )
{
pln.origin = m_curve[j]->PointAtStart();
pln.UpdateEquation();
rc = m_curve[j]->IsInPlane( pln, tolerance );
}
if (rc && plane )
{
pln.origin = center;
pln.UpdateEquation();
*plane = pln;
}
}
}
return rc;
}
bool ON_SumSurface::IsClosed( int dir ) const
{
bool rc = false;
if ( dir == 0 && m_curve[0] )
rc = m_curve[0]->IsClosed();
else if ( dir == 1 && m_curve[1] )
rc = m_curve[1]->IsClosed();
return rc;
}
bool ON_SumSurface::IsPeriodic( int dir ) const
{
bool rc = false;
if ( dir == 0 && m_curve[0] )
rc = m_curve[0]->IsPeriodic();
else if ( dir == 1 && m_curve[1] )
rc = m_curve[1]->IsPeriodic();
return rc;
}
bool ON_SumSurface::IsSingular( int side ) const
{
return false;
}
bool ON_SumSurface::GetNextDiscontinuity(
int dir,
ON::continuity c,
double t0,
double t1,
double* t,
int* hint,
int* dtype,
double cos_angle_tolerance,
double curvature_tolerance
) const
{
// 28 Jan 2005 - untested code
bool rc = false;
if ( 0 == dir || 1 == dir )
{
if (0 != m_curve[dir] )
{
rc = m_curve[dir]->GetNextDiscontinuity(
c,
t0,t1,t,
(hint?&hint[dir]:0),
dtype,
cos_angle_tolerance,
curvature_tolerance);
}
}
return rc;
}
bool ON_SumSurface::IsContinuous(
ON::continuity desired_continuity,
double s,
double t,
int* hint, // default = nullptr,
double point_tolerance, // default=ON_ZERO_TOLERANCE
double d1_tolerance, // default==ON_ZERO_TOLERANCE
double d2_tolerance, // default==ON_ZERO_TOLERANCE
double cos_angle_tolerance, // default==ON_DEFAULT_ANGLE_TOLERANCE_COSINE
double curvature_tolerance // default==ON_SQRT_EPSILON
) const
{
bool rc = true;
if ( m_curve[0] && m_curve[1] )
{
int crv_hint[2] = {0,0};
if ( hint )
{
crv_hint[0] = (*hint) & 0xFFFF;
crv_hint[1] = ((*hint) & 0xFFFF0000) >> 16;
}
rc = m_curve[0]->IsContinuous( desired_continuity, s, &crv_hint[0],
point_tolerance, d1_tolerance, d2_tolerance,
cos_angle_tolerance, curvature_tolerance );
if (rc )
rc = m_curve[1]->IsContinuous( desired_continuity, t, &crv_hint[1],
point_tolerance, d1_tolerance, d2_tolerance,
cos_angle_tolerance, curvature_tolerance );
if ( hint )
{
*hint = ( (crv_hint[0]&0xFFFF) | (crv_hint[1]<<16) );
}
}
return rc;
}
bool ON_SumSurface::Reverse( int dir )
{
bool rc = false;
if ( dir == 0 && m_curve[0] )
rc = m_curve[0]->Reverse();
else if ( dir == 1 && m_curve[1] )
rc = m_curve[1]->Reverse();
DestroySurfaceTree();
return rc;
}
bool ON_SumSurface::Transpose()
{
ON_Curve* c = m_curve[0];
m_curve[0] = m_curve[1];
m_curve[1] = c;
DestroySurfaceTree();
return true;
}
bool ON_SumSurface::Evaluate( // returns false if unable to evaluate
double s, double t, // evaluation parameters
int nder, // 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 quadrant to evaluate from
// 0 = default
// 1 from NE quadrant
// 2 from NW quadrant
// 3 from SW quadrant
// 4 from SE quadrant
int* hint // optional - evaluation hint (int[2]) used to speed
// repeated evaluations
) const
{
bool rc = false;
const int dim = Dimension();
if ( dim > 0 )
{
int crv_hint[2] = {0,0};
if ( hint )
{
crv_hint[0] = (*hint) & 0xFFFF;
crv_hint[1] = ((*hint) & 0xFFFF0000) >> 16;
}
double* v0 = (double*)onmalloc( 2*(nder+1)*dim*sizeof(*v0) );
double* v1 = v0 + (nder+1)*dim;
int side0, side1;
switch(side)
{
case 1:
side0 = 1;
side1 = 1;
break;
case 2:
side0 = -1;
side1 = 1;
break;
case 3:
side0 = -1;
side1 = -1;
break;
case 4:
side0 = 1;
side1 = -1;
break;
default:
side0 = 1;
side1 = 1;
break;
}
rc = m_curve[0]->Evaluate(s,nder,dim,v0,side0,hint ? &crv_hint[0] : 0);
if ( rc )
rc = m_curve[1]->Evaluate(t,nder,dim,v1,side1,hint ? &crv_hint[1] : 0);
if (rc)
{
int j,ds,dt,der;
for ( j = 0; j < dim; j++ )
{
v[j] = m_basepoint[j] + v0[j] + v1[j];
}
for ( der = 1; der <= nder; der++ )
{
for ( ds = der, dt = 0; ds >= 0; ds--, dt++ )
{
v += v_stride;
for ( j = 0; j < dim; j++ )
v[j] = 0.0;
// Mar 18 CCW - Fixed bug in evaluator that
// returned non-zero values for mixed partials.
if (ds && dt)
continue;
if ( ds )
{
for ( j = 0; j < dim; j++ )
v[j] += v0[j+dim*ds];
}
if ( dt )
{
for ( j = 0; j < dim; j++ )
v[j] += v1[j+dim*dt];
}
}
}
}
if ( hint )
{
*hint = crv_hint[0] | (crv_hint[1] << 16);
}
onfree(v0);
}
return rc;
}
ON_Curve* ON_SumSurface::IsoCurve(int dir, double c ) const
{
ON_Curve* iso_curve = 0;
if ( dir >= 0 && dir <= 1 && m_curve[0] && m_curve[1] )
{
iso_curve = m_curve[dir]->Duplicate();
ON_3dPoint p = m_curve[1-dir]->PointAt(c);
ON_3dVector v = p + m_basepoint;
if ( !v.IsZero() )
{
if ( !iso_curve->Translate(v) )
{
delete iso_curve;
iso_curve = 0;
}
}
}
return iso_curve;
}
class ON_SumTensor : public ON_TensorProduct
{
public:
int dim;
ON_3dPoint basepoint;
int DimensionA() const;
int DimensionB() const;
int DimensionC() const;
bool Evaluate( double, // a
const double*, // A
double, // b
const double*, // B
double* // C
);
};
int ON_SumTensor::DimensionA() const
{
return dim;
}
int ON_SumTensor::DimensionB() const
{
return dim;
}
int ON_SumTensor::DimensionC() const
{
return dim;
}
bool ON_SumTensor::Evaluate( double a, const double* CurveA, double b, const double* CurveB, double* SrfPoint )
{
SrfPoint[0] = a*CurveA[0] + b*CurveB[0] + basepoint.x;
SrfPoint[1] = a*CurveA[1] + b*CurveB[1] + basepoint.y;
SrfPoint[2] = a*CurveA[2] + b*CurveB[2] + basepoint.z;
return true;
}
int ON_SumSurface::GetNurbForm(
ON_NurbsSurface& nurbs_surface,
double tolerance
) const
{
nurbs_surface.Destroy();
int rc = 0;
int dim = Dimension();
if ( dim > 0 )
{
ON_NurbsCurve tmpA, tmpB;
int rcA = 0;
int rcB = 0;
const ON_NurbsCurve* nurbs_curveA=0;
const ON_NurbsCurve* nurbs_curveB=0;
nurbs_curveA = ON_NurbsCurve::Cast(m_curve[0]);
if ( !nurbs_curveA )
{
rcA = 1;
rcA = m_curve[0]->GetNurbForm( tmpA, tolerance );
if ( rcA > 0 )
nurbs_curveA = &tmpA;
}
if ( nurbs_curveA )
{
rcB = 1;
nurbs_curveB = ON_NurbsCurve::Cast(m_curve[1]);
if ( !nurbs_curveB )
{
rcB = m_curve[1]->GetNurbForm( tmpB, tolerance );
if ( rcB > 0 )
nurbs_curveB = &tmpB;
}
}
if ( nurbs_curveA && nurbs_curveB )
{
ON_SumTensor sum_tensor;
sum_tensor.dim = dim;
sum_tensor.basepoint = m_basepoint;
if ( !nurbs_surface.TensorProduct( *nurbs_curveA, *nurbs_curveB, sum_tensor ) )
nurbs_surface.Destroy();
else
rc = (rcA >= rcB) ? rcA : rcB;
}
}
return rc;
}
int ON_SumSurface::HasNurbForm() const
{
if (Dimension() <= 0)
return 0;
int rc = 1;
int i;
for (i=0; i<2; i++){
int nf = m_curve[i]->HasNurbForm();
if (nf == 0)
return 0;
if (nf == 2)
rc = 2;
}
return rc;
}
bool ON_SumSurface::GetSurfaceParameterFromNurbFormParameter(
double nurbs_s, double nurbs_t,
double* surface_s, double* surface_t
) const
{
// NOTE: overrides ON_Surface virtual function
bool rc = (m_curve[0] && m_curve[1]) ? true : false;
*surface_s = nurbs_s;
*surface_t = nurbs_t;
if ( m_curve[0] )
{
if ( !m_curve[0]->GetCurveParameterFromNurbFormParameter( nurbs_s, surface_s ) )
rc = false;
}
if ( m_curve[1] )
{
if (!m_curve[1]->GetCurveParameterFromNurbFormParameter( nurbs_t, surface_t ))
rc = false;
}
return rc;
}
bool ON_SumSurface::GetNurbFormParameterFromSurfaceParameter(
double surface_s, double surface_t,
double* nurbs_s, double* nurbs_t
) const
{
// NOTE: overrides ON_Surface virtual function
bool rc = (m_curve[0] && m_curve[1]) ? true : false;
*nurbs_s = surface_s;
*nurbs_t = surface_t;
if ( m_curve[0] )
{
if ( !m_curve[0]->GetNurbFormParameterFromCurveParameter( surface_s, nurbs_s ) )
rc = false;
}
if ( m_curve[1] )
{
if (!m_curve[1]->GetNurbFormParameterFromCurveParameter( surface_t, nurbs_t ))
rc = false;
}
return rc;
}
bool ON_SumSurface::Trim(int dir,
const ON_Interval& domain
)
{
if ( dir < 0 || dir > 1 )
return false;
ON_Interval current_domain = Domain(dir);
if ( current_domain[0] == ON_UNSET_VALUE && current_domain[1] == ON_UNSET_VALUE )
current_domain = domain;
ON_Interval trim_domain;
trim_domain.Intersection(domain, Domain(dir) );
if ( !trim_domain.IsIncreasing() )
return false;
if (trim_domain[0] == current_domain[0]
&& trim_domain[1] == current_domain[1] )
return true;
m_bbox.Destroy();
DestroySurfaceTree();
return m_curve[dir]->Trim(trim_domain);
}
bool ON_SumSurface::Extend(
int dir,
const ON_Interval& domain
)
{
if ( dir < 0 || dir > 1 )
return false;
if (IsClosed(dir))
return false;
//ON_Interval current_domain = Domain(dir);
if (nullptr == m_curve[dir])
return false;
bool rc = m_curve[dir]->Extend(domain);
if (rc)
{
DestroySurfaceTree();
m_bbox.Destroy();
}
return rc;
}
bool ON_SumSurface::Split(int dir,
double c,
ON_Surface*& west_or_south_side,
ON_Surface*& east_or_north_side
) const
{
if ( dir < 0 || dir > 1 )
return false;
if ( !Domain(dir).Includes( c, true ) )
return false;
ON_SumSurface* left_srf = 0;
ON_SumSurface* right_srf = 0;
if ( west_or_south_side )
{
left_srf = ON_SumSurface::Cast( west_or_south_side );
if ( !left_srf )
return false;
left_srf->DestroySurfaceTree();
left_srf->m_bbox.Destroy();
}
if ( east_or_north_side )
{
right_srf = ON_SumSurface::Cast( east_or_north_side );
if ( !right_srf )
return false;
right_srf->DestroySurfaceTree();
right_srf->m_bbox.Destroy();
}
if (!left_srf) left_srf = ON_SumSurface::New(*this);
else if (left_srf != this) *left_srf = *this;
if (!right_srf) right_srf = ON_SumSurface::New(*this);
else if (right_srf != this) *right_srf = *this;
if (left_srf == this && right_srf == this)
return false;
if (left_srf != this) {
delete left_srf->m_curve[dir];
left_srf->m_curve[dir] = 0;
}
if (right_srf != this) {
delete right_srf->m_curve[dir];
right_srf->m_curve[dir] = 0;
}
if (!m_curve[dir]->Split(c, left_srf->m_curve[dir],
right_srf->m_curve[dir])){
if (!west_or_south_side) delete left_srf;
if (!east_or_north_side) delete right_srf;
return false;
}
if (!west_or_south_side) west_or_south_side = left_srf;
if (!east_or_north_side) east_or_north_side = right_srf;
return true;
}
/*
bool ON_SumSurface::GetSurfaceParameterFromNurbFormParameter(
double nurbs_s, double nurbs_t,
double* surface_s, double* surface_t
) const
{
// NOTE: overrides ON_Surface virtual function
bool rc;
if ( m_curve[0] )
{
rc = m_curve[0]->GetCurveParameterFromNurbFormParameter( nurbs_s, surface_s );
}
else
{
rc = false;
*surface_s = nurbs_s;
}
if ( m_curve[1] )
{
if ( m_curve[1]->GetCurveParameterFromNurbFormParameter( nurbs_t, surface_t ) )
rc = false;
}
else
{
rc = false;
*surface_t = nurbs_t;
}
return rc;
}
bool ON_SumSurface::GetNurbFormParameterFromSurfaceParameter(
double surface_s, double surface_t,
double* nurbs_s, double* nurbs_t
) const
{
// NOTE: overrides ON_Surface virtual function
bool rc;
if ( m_curve[0] )
{
rc = m_curve[0]->GetNurbFormParameterFromCurveParameter( surface_s, nurbs_s );
}
else
{
rc = false;
*surface_s = nurbs_s;
}
if ( m_curve[1] )
{
if ( m_curve[1]->GetNurbFormParameterFromCurveParameter( surface_t, nurbs_t ) )
rc = false;
}
else
{
rc = false;
*surface_t = nurbs_t;
}
return rc;
}
*/