mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-02 12:37:02 +08:00
481 lines
12 KiB
C++
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;
|
|
}
|
|
|