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

481 lines
12 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_CurveOnSurface,ON_Curve,"4ED7D4D8-E947-11d3-BFE5-0010830122F0");
ON_CurveOnSurface::ON_CurveOnSurface() ON_NOEXCEPT
: m_c2(0)
, m_c3(0)
, m_s(0)
{}
ON_CurveOnSurface::~ON_CurveOnSurface()
{
if ( m_c2 )
{
delete m_c2;
m_c2 = 0;
}
if ( m_c3 )
{
delete m_c3;
m_c3 = 0;
}
if ( m_s )
{
delete m_s;
m_s = 0;
}
}
#if defined(ON_HAS_RVALUEREF)
ON_CurveOnSurface::ON_CurveOnSurface( ON_CurveOnSurface&& src) ON_NOEXCEPT
: ON_Curve(std::move(src))
, m_c2(src.m_c2)
, m_c3(src.m_c3)
, m_s(src.m_s)
{
src.m_c2 = 0;
src.m_c3 = 0;
src.m_s = 0;
}
ON_CurveOnSurface& ON_CurveOnSurface::operator=( ON_CurveOnSurface&& src)
{
if ( this != &src )
{
this->ON_CurveOnSurface::~ON_CurveOnSurface();
ON_Curve::operator=(std::move(src));
m_c2 = src.m_c2;
m_c3 = src.m_c3;
m_s = src.m_s;
src.m_c2 = 0;
src.m_c3 = 0;
src.m_s = 0;
}
return *this;
}
#endif
ON_CurveOnSurface::ON_CurveOnSurface( ON_Curve* c2, ON_Curve* c3, ON_Surface* s )
: m_c2(c2), m_c3(c3), m_s(s)
{}
ON_CurveOnSurface::ON_CurveOnSurface( const ON_CurveOnSurface& src ) : m_c2(0), m_c3(0), m_s(0)
{
*this = src;
}
unsigned int ON_CurveOnSurface::SizeOf() const
{
unsigned int sz = ON_Curve::SizeOf();
sz += sizeof(*this) - sizeof(ON_Curve);
if ( m_c2 )
sz += m_c2->SizeOf();
if ( m_c3 )
sz += m_c3->SizeOf();
if ( m_s )
sz += m_s->SizeOf();
return sz;
}
ON_CurveOnSurface& ON_CurveOnSurface::operator=( const ON_CurveOnSurface& src )
{
if ( this != &src ) {
ON_Curve::operator=(src);
if ( m_c2 ) {
delete m_c2;
m_c2 = 0;
}
if ( m_c3 ) {
delete m_c3;
m_c3 = 0;
}
if ( m_s ) {
delete m_s;
m_s = 0;
}
if ( ON_Curve::Cast(src.m_c2) ) {
m_c2 = ON_Curve::Cast(src.m_c2->Duplicate());
}
if ( ON_Curve::Cast(src.m_c3) ) {
m_c3 = ON_Curve::Cast(src.m_c3->Duplicate());
}
if ( ON_Surface::Cast(src.m_s) ) {
m_s = ON_Surface::Cast(src.m_s->Duplicate());
}
}
return *this;
}
bool ON_CurveOnSurface::IsValid( ON_TextLog* text_log ) const
{
if ( !m_c2 )
return false;
if ( !m_s )
return false;
if ( !m_c2->IsValid() )
return false;
if ( m_c2->Dimension() != 2 ) {
ON_ERROR("ON_CurveOnSurface::IsValid() m_c2 is not 2d.");
return false;
}
if ( !m_s->IsValid() )
return false;
if ( m_c3 ) {
if ( !m_c3->IsValid() )
return false;
if ( m_c3->Dimension() != m_s->Dimension() ) {
ON_ERROR("ON_CurveOnSurface::IsValid() m_c3 and m_s have different dimensions.");
return false;
}
}
return true;
}
void
ON_CurveOnSurface::Dump( ON_TextLog& dump ) const
{
dump.Print("ON_CurveOnSurface \n");
}
bool
ON_CurveOnSurface::Write(
ON_BinaryArchive& file // open binary file
) const
{
bool rc = IsValid();
if (rc)
rc = file.WriteObject(*m_c2);
if (rc)
rc = file.WriteInt( m_c3?1:0 );
if ( rc && m_c3 )
rc = file.WriteObject(*m_c3);
if (rc)
rc = file.WriteObject(*m_s);
return rc;
}
bool
ON_CurveOnSurface::Read(
ON_BinaryArchive& file // open binary file
)
{
delete m_c2;
delete m_c3;
m_c2 = 0;
m_c3 = 0;
delete m_s;
m_s = 0;
ON_Object *o=0;
bool rc = file.ReadObject(&o);
if (rc && o) {
m_c2 = ON_Curve::Cast(o);
if ( !m_c2 ) {
delete o;
} rc = false;
}
o = 0;
int bHasC3 = 0;
rc = file.ReadInt( &bHasC3 );
if ( rc && bHasC3 ) {
if (rc)
rc = file.ReadObject(&o);
if ( rc && o ) {
m_c2 = ON_Curve::Cast(o);
if ( !m_c2 ) {
delete o;
} rc = false;
}
}
o = 0;
if (rc)
rc = file.ReadObject(&o);
if (rc&&o) {
m_s = ON_Surface::Cast(o);
if ( !m_s ) {
delete o;
rc = false;
}
}
return rc;
}
int
ON_CurveOnSurface::Dimension() const
{
return ( m_s ) ? m_s->Dimension() : false;
}
bool ON_CurveOnSurface::GetBBox( // returns true if successful
double* boxmin, // minimum
double* boxmax, // maximum
bool bGrowBox
) const
{
return ( m_s ) ? m_s->GetBBox(boxmin,boxmax,bGrowBox) : false;
}
bool
ON_CurveOnSurface::Transform( const ON_Xform& xform )
{
TransformUserData(xform);
DestroyCurveTree();
return ( m_s ) ? m_s->Transform(xform) : false;
}
bool
ON_CurveOnSurface::SwapCoordinates( int i, int j )
{
return ( m_s ) ? m_s->SwapCoordinates(i,j) : false;
}
ON_Interval ON_CurveOnSurface::Domain() const
{
ON_Interval d;
if ( m_c2 )
d = m_c2->Domain();
return d;
}
int ON_CurveOnSurface::SpanCount() const
{
return m_c2 ? m_c2->SpanCount() : 0;
}
bool ON_CurveOnSurface::GetSpanVector( // span "knots"
double* s // array of length SpanCount() + 1
) const
{
return m_c2 ? m_c2->GetSpanVector(s) : false;
}
int ON_CurveOnSurface::Degree() const
{
return m_c2 ? m_c2->Degree() : 0;
}
bool
ON_CurveOnSurface::GetParameterTolerance(
double t, // t = parameter in domain
double* tminus, // tminus
double* tplus // tplus
) const
{
return (m_c2) ? m_c2->GetParameterTolerance(t,tminus,tplus) : false;
}
bool
ON_CurveOnSurface::IsLinear( // true if curve locus is a line segment
double tolerance // tolerance to use when checking linearity
) const
{
bool rc = (m_c2&&ON_PlaneSurface::Cast(m_s)) ? (ON_PlaneSurface::Cast(m_s) && m_c2->IsLinear(tolerance)) : false;
if ( rc ) {
// TODO: rc = m_s->IsPlanar(tolerance)
}
return rc;
}
bool
ON_CurveOnSurface::IsArc( // true if curve locus in an arc or circle
const ON_Plane* plane, // if not nullptr, test is performed in this plane
ON_Arc* arc, // if not nullptr and true is returned, then arc
// arc parameters are filled in
double tolerance // tolerance to use when checking linearity
) const
{
return (m_c2&&ON_PlaneSurface::Cast(m_s)) ? m_c2->IsArc(plane,arc,tolerance) : false;
}
bool
ON_CurveOnSurface::IsPlanar(
ON_Plane* plane, // if not nullptr and true is returned, then plane parameters
// are filled in
double tolerance // tolerance to use when checking linearity
) const
{
// todo 9-June-23 GBA This just seams wrong?!
return ( ON_PlaneSurface::Cast(m_s) ) ? true : false;
}
bool
ON_CurveOnSurface::IsInPlane(
const ON_Plane& plane, // plane to test
double tolerance // tolerance to use when checking linearity
) const
{
return false;
}
bool
ON_CurveOnSurface::IsClosed() const
{
bool rc = ( m_c2 && m_s ) ? m_c2->IsClosed() : false;
if ( !rc )
rc = ON_Curve::IsClosed();
return rc;
}
bool
ON_CurveOnSurface::IsPeriodic() const
{
return ( m_c2 && m_s ) ? m_c2->IsPeriodic() : false;
}
bool
ON_CurveOnSurface::Reverse()
{
bool rc = ( m_c2 ) ? m_c2->Reverse() : false;
if ( rc && m_c3 ) rc = m_c3->Reverse();
DestroyCurveTree();
return rc;
}
bool
ON_CurveOnSurface::Evaluate( // returns false if unable to evaluate
double t, // evaluation parameter
int der_count, // number of derivatives (>=0)
int v_stride, // v[] array stride (>=Dimension())
double* v, // v[] array of length stride*(ndir+1)
int side, // optional - determines which side to evaluate from
// 0 = default
// < 0 to evaluate from below,
// > 0 to evaluate from above
int* hint // optional - evaluation hint (int) used to speed
// repeated evaluations
) const
{
ON_3dVector c[5];
ON_3dVector s[15], d;
const int dim = Dimension();
bool rc = (dim > 0 && dim <= 3 ) ? true : false;
if ( rc ) {
int chint=0, shint[2]={0,0};
if(hint) {
chint = (*hint)&0xFFF;
shint[0] = (*hint)>>16;
shint[1] = shint[0]>>8;
shint[0] &= 0xFF;
}
rc = ( m_c2&&m_s ) ? m_c2->Evaluate(t,der_count,3,c[0],side,&chint) : false;
if (rc) {
side = 0;
if ( der_count>0 ) {
if ( c[1].x >= 0.0 ) {
side = ( c[1].y >= 0.0 ) ? 1 : 4;
}
else {
side = ( c[1].y >= 0.0 ) ? 2 : 3;
}
}
rc = m_s->Evaluate( c[0].x, c[0].y, der_count, 3, s[0], side, shint );
if ( rc ) {
if ( hint ) {
*hint = (chint&0xFFFF) | ((shint[0]&0xFF)<<16) | ((shint[1]&0xFF)<<24);
}
v[0] = s[0].x;
if ( dim > 1 ) v[1] = s[0].y;
if ( dim > 2 ) v[2] = s[0].z;
v += v_stride;
if (der_count >= 1 ) {
const double du = c[1].x;
const double dv = c[1].y;
d = du*s[1] + dv*s[2];
v[0] = d.x;
if ( dim > 1 ) v[1] = d.y;
if ( dim > 2 ) v[2] = d.z;
v += v_stride;
if ( der_count >= 2 ) {
const double ddu = c[2].x;
const double ddv = c[2].y;
d = ddu*s[1] + ddv*s[2] + du*du*s[3] + 2.0*du*dv*s[4] + dv*dv*s[5];
v[0] = d.x;
if ( dim > 1 ) v[1] = d.y;
if ( dim > 2 ) v[2] = d.z;
v += v_stride;
if ( der_count >= 3 ) {
const double dddu = c[3].x;
const double dddv = c[3].y;
d = dddu*s[1] + dddv*s[2]
+ 3.0*du*ddu*s[3] + 3.0*(ddu*dv + du*ddv)*s[4] + 3.0*dv*ddv*s[5]
+ du*du*du*s[6] + 3.0*du*du*dv*s[7] + 3.0*du*dv*dv*s[8] + dv*dv*dv*s[9];
v[0] = d.x;
if ( dim > 1 ) v[1] = d.y;
if ( dim > 2 ) v[2] = d.z;
v += v_stride;
if ( der_count >= 4 ) {
int n;
for ( n = 4; n <= der_count; n++ ) {
v[0] = 0.0;
if ( dim > 1 ) v[1] = 0.0;
if ( dim > 2 ) v[2] = 0.0;
v += v_stride;
rc = false; // TODO - generic chain rule
}
}
}
}
}
}
}
}
return rc;
}
int ON_CurveOnSurface::GetNurbForm( // returns 0: unable to create NURBS representation
// with desired accuracy.
// 1: success - returned NURBS parameterization
// matches the curve's to wthe desired accuracy
// 2: success - returned NURBS point locus matches
// the curve's to the desired accuracy but, on
// the interior of the curve's domain, the
// curve's parameterization and the NURBS
// parameterization may not match to the
// desired accuracy.
ON_NurbsCurve& nurbs,
double tolerance, // (>=0)
const ON_Interval* subdomain // OPTIONAL subdomain of 2d curve
) const
{
ON_ERROR("TODO - finish ON_CurveOnSurface::GetNurbForm().");
return 0;
}