mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-02 03:57:00 +08:00
889 lines
21 KiB
C++
889 lines
21 KiB
C++
/* $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 <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_OffsetSurface,ON_SurfaceProxy,"00C61749-D430-4ecc-83A8-29130A20CF9C");
|
|
|
|
ON_OffsetSurface::ON_OffsetSurface()
|
|
: m__pSrf(0)
|
|
{
|
|
}
|
|
|
|
ON_OffsetSurface::~ON_OffsetSurface()
|
|
{
|
|
m_offset_function.SetBaseSurface( 0 );
|
|
if ( 0 != m__pSrf && this != m__pSrf )
|
|
delete m__pSrf;
|
|
m__pSrf = 0;
|
|
|
|
}
|
|
|
|
ON_OffsetSurface::ON_OffsetSurface( const ON_OffsetSurface& src)
|
|
: ON_SurfaceProxy(src),
|
|
m__pSrf(0),
|
|
m_offset_function(src.m_offset_function)
|
|
{
|
|
if ( 0 != src.m__pSrf )
|
|
{
|
|
m__pSrf = src.ON_SurfaceProxy::DuplicateSurface();
|
|
SetProxySurface(m__pSrf);
|
|
}
|
|
m_offset_function.SetBaseSurface( BaseSurface() );
|
|
}
|
|
|
|
ON_OffsetSurface& ON_OffsetSurface::operator=(const ON_OffsetSurface& src)
|
|
{
|
|
if ( this != &src )
|
|
{
|
|
if ( 0 != m__pSrf && this != m__pSrf )
|
|
delete m__pSrf;
|
|
m__pSrf = 0;
|
|
if ( 0 != src.m__pSrf )
|
|
{
|
|
m__pSrf = src.ON_SurfaceProxy::DuplicateSurface();
|
|
SetProxySurface(m__pSrf);
|
|
}
|
|
else
|
|
{
|
|
ON_SurfaceProxy::operator=(src);
|
|
}
|
|
m_offset_function = src.m_offset_function;
|
|
m_offset_function.SetBaseSurface( BaseSurface() );
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ON_OffsetSurfaceFunction& ON_OffsetSurface::OffsetFunction()
|
|
{
|
|
return m_offset_function;
|
|
}
|
|
|
|
const ON_OffsetSurfaceFunction& ON_OffsetSurface::OffsetFunction() const
|
|
{
|
|
return m_offset_function;
|
|
}
|
|
|
|
|
|
bool ON_OffsetSurface::SetBaseSurface(
|
|
const ON_Surface* base_surface
|
|
)
|
|
{
|
|
bool rc = false;
|
|
if ( this != base_surface )
|
|
{
|
|
rc = true;
|
|
if ( 0 == base_surface )
|
|
{
|
|
if ( 0 != m__pSrf && this != m__pSrf )
|
|
delete m__pSrf;
|
|
m__pSrf = 0;
|
|
ON_SurfaceProxy::SetProxySurface(0);
|
|
m_offset_function.SetBaseSurface(0);
|
|
}
|
|
else if ( BaseSurface() != base_surface )
|
|
{
|
|
if ( 0 != m__pSrf && this != m__pSrf )
|
|
delete m__pSrf;
|
|
m__pSrf = 0;
|
|
ON_SurfaceProxy::SetProxySurface(base_surface);
|
|
}
|
|
m_offset_function.SetBaseSurface( BaseSurface() );
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_OffsetSurface::SetBaseSurface(
|
|
ON_Surface* base_surface,
|
|
bool bManage
|
|
)
|
|
{
|
|
bool rc = SetBaseSurface(base_surface);
|
|
if (rc && bManage )
|
|
m__pSrf = base_surface;
|
|
return rc;
|
|
}
|
|
|
|
const ON_Surface* ON_OffsetSurface::BaseSurface() const
|
|
{
|
|
return ProxySurface();
|
|
}
|
|
|
|
bool ON_OffsetSurface::GetBBox(
|
|
double* bbox_min,
|
|
double* bbox_max,
|
|
bool bGrowBox
|
|
) const
|
|
{
|
|
bool rc = ON_SurfaceProxy::GetBBox(bbox_min,bbox_max);
|
|
if ( rc )
|
|
{
|
|
double d, distance = 0.0;
|
|
int i, count = m_offset_function.m_offset_value.Count();
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
d = fabs(m_offset_function.m_offset_value[i].m_distance);
|
|
if ( distance < d)
|
|
distance = d;
|
|
}
|
|
distance *= 2;
|
|
if ( 0 != bbox_min )
|
|
{
|
|
bbox_min[0] -= distance;
|
|
bbox_min[1] -= distance;
|
|
bbox_min[2] -= distance;
|
|
}
|
|
if ( 0 != bbox_max )
|
|
{
|
|
bbox_max[0] += distance;
|
|
bbox_max[1] += distance;
|
|
bbox_max[2] += distance;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
bool ON_OffsetSurface::Evaluate(
|
|
double s, double t,
|
|
int der_count,
|
|
int v_stride,
|
|
double* v,
|
|
int side,
|
|
int* hint
|
|
) const
|
|
{
|
|
int vv_stride = v_stride;
|
|
double* vv = v;
|
|
ON_3dVector srf_value[6];//, normal_value[3];
|
|
if ( der_count < 2 )
|
|
{
|
|
vv = &srf_value[0].x;
|
|
vv_stride = 3;
|
|
}
|
|
|
|
bool rc = ON_SurfaceProxy::Evaluate(s,t,(der_count>2?der_count:2),vv_stride,vv,side,hint);
|
|
|
|
if ( v != vv )
|
|
{
|
|
// save answer in v[] array
|
|
v[0] = srf_value[0].x;
|
|
v[1] = srf_value[0].y;
|
|
v[2] = srf_value[0].z;
|
|
if ( der_count > 0 )
|
|
{
|
|
v[v_stride] = srf_value[1].x;
|
|
v[v_stride+1] = srf_value[1].y;
|
|
v[v_stride+2] = srf_value[1].z;
|
|
v[2*v_stride] = srf_value[2].x;
|
|
v[2*v_stride+1] = srf_value[2].y;
|
|
v[2*v_stride+2] = srf_value[2].z;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
srf_value[0] = v;
|
|
srf_value[1] = v+v_stride;
|
|
srf_value[2] = v+2*v_stride;
|
|
srf_value[3] = v+3*v_stride;
|
|
srf_value[4] = v+4*v_stride;
|
|
srf_value[5] = v+5*v_stride;
|
|
}
|
|
|
|
if (rc)
|
|
{
|
|
double darray[21]; // 21 = ((5+1)*(5+2)/2) = enough room for der_count <= 5
|
|
double* d = (der_count>5)
|
|
? (double*)onmalloc(((der_count+1)*(der_count+2))/2*sizeof(d[0]))
|
|
: darray;
|
|
rc = m_offset_function.EvaluateDistance(s,t,der_count,d);
|
|
if (rc)
|
|
{
|
|
ON_3dVector N;
|
|
ON_EvNormal(side,
|
|
srf_value[1], srf_value[2],
|
|
srf_value[3], srf_value[4], srf_value[5],
|
|
N);
|
|
v[0] += d[0]*N.x;
|
|
v[1] += d[0]*N.y;
|
|
v[2] += d[0]*N.z;
|
|
|
|
if ( der_count > 0 )
|
|
{
|
|
ON_3dVector Ns, Nt;
|
|
ON_EvNormalPartials(srf_value[1], srf_value[2],
|
|
srf_value[3], srf_value[4], srf_value[5],
|
|
Ns, Nt);
|
|
v[v_stride] += d[0]*Ns.x + d[1]*N.x;
|
|
v[v_stride+1] += d[0]*Ns.y + d[1]*N.y;
|
|
v[v_stride+2] += d[0]*Ns.z + d[1]*N.z;
|
|
|
|
v[2*v_stride] += d[0]*Nt.x + d[2]*N.x;
|
|
v[2*v_stride+1] += d[0]*Nt.y + d[2]*N.y;
|
|
v[2*v_stride+2] += d[0]*Nt.z + d[2]*N.z;
|
|
}
|
|
}
|
|
if ( d != darray )
|
|
onfree(d);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
void ON_BumpFunction::Internal_EvaluateLinearBump(double t, double dt, int der_count, double* value) const
|
|
{
|
|
value[0] = t;
|
|
if (der_count>0)
|
|
{
|
|
value[1] = dt;
|
|
if ( der_count > 1 )
|
|
{
|
|
der_count--;
|
|
value += 2;
|
|
while(der_count--)
|
|
*value++ = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ON_BumpFunction::Internal_EvaluateQuinticBump(double t, double dt, int der_count, double* value) const
|
|
{
|
|
// c(t) = (1-t)^3 * (1 + 3t + 6t^2)
|
|
//bool neg = (t<0.0);
|
|
//t = fabs(t);
|
|
if ( fabs(t) < 1.0)
|
|
{
|
|
double a2 = (1-t);
|
|
double a1 = a2*a2;
|
|
double a = a1*a2;
|
|
double b = 1.0 + t*(3.0 + 6.0*t);
|
|
value[0] = a*b;
|
|
if (der_count>0)
|
|
{
|
|
a1 *= -3.0;
|
|
double b1 = 3.0 + 12.0*t;
|
|
value[1] = dt*(a1*b + b1*a);
|
|
//if ( neg )
|
|
// value[1] = - value[1];
|
|
if ( der_count > 1 )
|
|
{
|
|
value[2] = dt*dt*(6.0*a2*b + 12.0*a + 2.0*a1*b1);
|
|
if ( der_count > 2 )
|
|
{
|
|
der_count-=2;
|
|
value += 3;
|
|
while ( der_count-- )
|
|
*value++ = 0.0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ( der_count-- >= 0 )
|
|
*value++ = 0.0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
double EvaluateCubicBump(double t, double* d, double* dd) const
|
|
{
|
|
// c(t) = 1 - 3t^2 + 2t^3
|
|
// CubicBump(t) = c(t) if 0 <= t < 1
|
|
// c(-t) if -1 < t <= 0
|
|
// 0 otherwise
|
|
bool neg = (t<0.0);
|
|
t = fabs(t);
|
|
if ( t < 1.0)
|
|
{
|
|
// f(t) = 1 - 3t^2 + 2t^3
|
|
if (d)
|
|
{
|
|
// f'(t) = -6t + 6t^2
|
|
*d = (neg) ? (6.0*t*(1.0-t)) : (6.0*t*(t-1.0));
|
|
}
|
|
if (dd)
|
|
{
|
|
// f"(t) = -6 + 12t
|
|
*dd = -6.0 + 12.0*t;
|
|
}
|
|
t = 1.0+t*(t*(2.0*t-3.0));
|
|
}
|
|
else
|
|
{
|
|
t = 0.0;
|
|
if ( d )
|
|
*d = 0.0
|
|
if ( *dd )
|
|
*dd = 0.0
|
|
}
|
|
return t
|
|
}
|
|
*/
|
|
|
|
void ON_BumpFunction::Evaluate(double s, double t, int der_count, double* value) const
|
|
{
|
|
double tmp[20];
|
|
double* xvalue;
|
|
double* yvalue;
|
|
xvalue = ( der_count > 9 )
|
|
? ((double*)onmalloc((der_count+1)*2*sizeof(xvalue[0])))
|
|
: &tmp[0];
|
|
yvalue = xvalue + (der_count+1);
|
|
double x = s-m_x0;
|
|
const double dx = m_sx[x >= 0.0 ? 1 : 0];
|
|
x *= dx;
|
|
double y = t-m_y0;
|
|
const double dy = m_sy[y >= 0.0 ? 1 : 0];
|
|
y *= dy;
|
|
|
|
if ( 5 == m_type[0] )
|
|
{
|
|
Internal_EvaluateQuinticBump(x,dx,der_count,xvalue);
|
|
}
|
|
else
|
|
{
|
|
Internal_EvaluateLinearBump(x,dx,der_count,xvalue);
|
|
}
|
|
if ( 5 == m_type[1] )
|
|
{
|
|
Internal_EvaluateQuinticBump(y,dy,der_count,yvalue);
|
|
}
|
|
else
|
|
{
|
|
Internal_EvaluateLinearBump(y,dy,der_count,yvalue);
|
|
}
|
|
|
|
int n, i, j;
|
|
for ( n = 0; n <= der_count; n++ )
|
|
{
|
|
for ( i = n, j = 0; j <= n; i--, j++ )
|
|
{
|
|
*value++ = m_a*xvalue[i]*yvalue[j]; // d^nf/(ds^i dt^j)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool ON_OffsetSurfaceFunction::SetBaseSurface( const ON_Surface* srf )
|
|
{
|
|
bool rc = false;
|
|
Destroy();
|
|
m_srf = srf;
|
|
if ( 0 != m_srf )
|
|
{
|
|
m_domain[0] = m_srf->Domain(0);
|
|
m_domain[1] = m_srf->Domain(1);
|
|
rc = m_domain[0].IsIncreasing() && m_domain[1].IsIncreasing();
|
|
if ( !rc )
|
|
Destroy();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_OffsetSurfaceFunction::SetSideTangency(
|
|
int side,
|
|
bool bEnable
|
|
)
|
|
{
|
|
bool rc = false;
|
|
if ( 0 <= side && side < 4 )
|
|
{
|
|
m_bZeroSideDerivative[side] = bEnable?true:false;
|
|
m_bValid = false;
|
|
rc = true;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool ON_OffsetSurfaceFunction::SideTangency(int side) const
|
|
{
|
|
bool rc = ( 0 <= side && side < 4 )
|
|
? m_bZeroSideDerivative[side]
|
|
: false;
|
|
return rc;
|
|
}
|
|
|
|
int ON_OffsetSurfaceFunction::OffsetPointCount() const
|
|
{
|
|
return (0 != m_srf) ? m_offset_value.Count() : 0;
|
|
}
|
|
|
|
|
|
double ON_OffsetSurfaceFunction::DistanceAt(
|
|
double s,
|
|
double t
|
|
) const
|
|
{
|
|
double d = 0.0;
|
|
EvaluateDistance( s, t, 0, &d );
|
|
return d;
|
|
}
|
|
|
|
bool ON_OffsetSurfaceFunction::EvaluateDistance(
|
|
double s,
|
|
double t,
|
|
int num_der,
|
|
double* value
|
|
) const
|
|
{
|
|
const int vcnt = ((num_der+1)*(num_der+2))/2;
|
|
for ( int vi = 0; vi < vcnt; vi++ )
|
|
{
|
|
value[vi] = 0;
|
|
}
|
|
|
|
bool rc = const_cast<ON_OffsetSurfaceFunction*>(this)->Initialize();
|
|
|
|
if (rc)
|
|
{
|
|
double barray[21];
|
|
double* bump_value = (vcnt > 21)
|
|
? (double*)onmalloc(vcnt*sizeof(bump_value[0]))
|
|
: barray;
|
|
const int bump_count = m_bumps.Count();
|
|
int bump_index;
|
|
for ( bump_index = 0; bump_index < bump_count; bump_index++ )
|
|
{
|
|
m_bumps[bump_index].Evaluate( s, t, num_der, bump_value );
|
|
for ( int vi = 0; vi < vcnt; vi++ )
|
|
{
|
|
value[vi] += bump_value[vi];
|
|
}
|
|
}
|
|
if ( bump_value != barray )
|
|
onfree(bump_value);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
ON_3dPoint ON_OffsetSurfaceFunction::PointAt(
|
|
double s,
|
|
double t
|
|
) const
|
|
{
|
|
//double d = 0.0;
|
|
ON_3dPoint P(ON_3dPoint::NanPoint);
|
|
ON_3dVector N(ON_3dVector::NanVector);
|
|
if ( 0 != m_srf )
|
|
{
|
|
if ( m_srf->EvNormal(s,t,P,N) )
|
|
{
|
|
P = P + DistanceAt(s,t)*N;
|
|
}
|
|
}
|
|
return P;
|
|
}
|
|
|
|
ON_2dPoint ON_OffsetSurfaceFunction::OffsetSurfaceParameter(int i) const
|
|
{
|
|
ON_2dPoint p(ON_UNSET_VALUE,ON_UNSET_VALUE);
|
|
if ( 0 != m_srf && i >= 0 && i < m_offset_value.Count() )
|
|
{
|
|
p.x = m_offset_value[i].m_s;
|
|
p.y = m_offset_value[i].m_t;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
const ON_Surface* ON_OffsetSurfaceFunction::BaseSurface() const
|
|
{
|
|
return m_srf;
|
|
}
|
|
|
|
double ON_OffsetSurfaceFunction::OffsetDistance(int i) const
|
|
{
|
|
double d = ON_UNSET_VALUE;
|
|
if ( 0 != m_srf && i >= 0 && i < m_offset_value.Count() )
|
|
{
|
|
d = m_offset_value[i].m_distance;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
bool ON_OffsetSurfaceFunction::SetOffsetPoint(
|
|
double s,
|
|
double t,
|
|
double distance,
|
|
double radius
|
|
)
|
|
{
|
|
bool rc = false;
|
|
if ( ON_IsValid(s) && ON_IsValid(t) && ON_IsValid(distance) && ON_IsValid(radius) )
|
|
{
|
|
double u = m_domain[0].NormalizedParameterAt(s);
|
|
|
|
// 14 Jan 2008, Mikko, TRR 29861:
|
|
// Changing the clamping to happen when the
|
|
// point is outside or nearly outside the domain.
|
|
const double dTol = ON_SQRT_EPSILON; // tiny border around untrimmed edges
|
|
|
|
if ( u < dTol)
|
|
{
|
|
s = m_domain[0][0];
|
|
u = 0.0;
|
|
}
|
|
if ( u > 1.0-dTol)
|
|
{
|
|
s = m_domain[0][1];
|
|
u = 1.0;
|
|
}
|
|
|
|
double v = m_domain[1].NormalizedParameterAt(t);
|
|
if ( v < dTol)
|
|
{
|
|
t = m_domain[1][0];
|
|
v = 0.0;
|
|
}
|
|
if ( v > 1.0-dTol)
|
|
{
|
|
t = m_domain[1][1];
|
|
v = 1.0;
|
|
}
|
|
|
|
if ( u >= 0.0 && u <= 1.0 && v >= 0.0 && v <= 1.0 )
|
|
{
|
|
ON_OffsetSurfaceValue offset_value;
|
|
offset_value.m_s = s;
|
|
offset_value.m_t = t;
|
|
offset_value.m_distance = distance;
|
|
offset_value.m_radius = (radius > 0.0) ? radius : 0.0;
|
|
offset_value.m_index = (int)((u + v*4096.0)*4096.0);
|
|
int i;
|
|
for ( i = 0; i < m_offset_value.Count(); i++ )
|
|
{
|
|
if ( m_offset_value[i].m_index == offset_value.m_index )
|
|
{
|
|
m_offset_value[i] = offset_value;
|
|
break;
|
|
}
|
|
}
|
|
if (i == m_offset_value.Count())
|
|
{
|
|
m_offset_value.Append(offset_value);
|
|
m_bumps.SetCount(0);
|
|
m_bValid = false;
|
|
}
|
|
rc = true;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
bool ON_OffsetSurfaceFunction::SetDistance( int index, double distance)
|
|
{
|
|
int count = m_offset_value.Count();
|
|
if( index < 0 || index > count-1)
|
|
return false;
|
|
|
|
m_offset_value[index].m_distance = distance;
|
|
m_bValid = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ON_OffsetSurfaceFunction::SetPoint( int index, double s, double t)
|
|
{
|
|
int count = m_offset_value.Count();
|
|
if( index < 0 || index > count-1)
|
|
return false;
|
|
|
|
m_offset_value[index].m_s = s;
|
|
m_offset_value[index].m_t = t;
|
|
m_bValid = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void ON_OffsetSurfaceFunction::Destroy()
|
|
{
|
|
m_srf = 0;
|
|
m_bZeroSideDerivative[0] = false;
|
|
m_bZeroSideDerivative[1] = false;
|
|
m_bZeroSideDerivative[2] = false;
|
|
m_bZeroSideDerivative[3] = false;
|
|
|
|
m_domain[0] = ON_Interval::EmptyInterval;
|
|
m_domain[1] = ON_Interval::EmptyInterval;
|
|
m_bumps.SetCount(0);
|
|
m_bValid = false;
|
|
}
|
|
|
|
|
|
|
|
ON_OffsetSurfaceFunction::ON_OffsetSurfaceFunction()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
ON_OffsetSurfaceFunction::~ON_OffsetSurfaceFunction()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
bool ON_OffsetSurfaceFunction::Initialize()
|
|
{
|
|
const int count = m_offset_value.Count();
|
|
if ( !m_bValid && 0 != m_srf && count > 0)
|
|
{
|
|
ON_Workspace ws;
|
|
m_bumps.SetCount(0);
|
|
m_bumps.Reserve(count);
|
|
int i;
|
|
double a,b,ds,dt;
|
|
|
|
for (i = 0; i < count; i++ )
|
|
{
|
|
ON_BumpFunction& bump = m_bumps.AppendNew();
|
|
ON_OffsetSurfaceValue offset_value = m_offset_value[i];
|
|
double ds0 = offset_value.m_s - m_domain[0][0];
|
|
double ds1 = m_domain[0][1] - offset_value.m_s;
|
|
if ( 0.0 == ds0 )
|
|
ds0 = -ds1;
|
|
else if ( 0.0 == ds1 )
|
|
ds1 = -ds0;
|
|
double dt0 = offset_value.m_t - m_domain[1][0];
|
|
double dt1 = m_domain[1][1] - offset_value.m_t;
|
|
if ( 0.0 == dt0 )
|
|
dt0 = -dt1;
|
|
else if ( 0.0 == dt1 )
|
|
dt1 = -dt0;
|
|
|
|
// default is a large cubic bump
|
|
bump.m_point.x = offset_value.m_s;
|
|
bump.m_point.y = offset_value.m_t;
|
|
bump.m_x0 = bump.m_point.x;
|
|
bump.m_y0 = bump.m_point.y;
|
|
|
|
bump.m_sx[0] = -1.0/ds0;
|
|
bump.m_sx[1] = 1.0/ds1;
|
|
bump.m_sy[0] = -1.0/dt0;
|
|
bump.m_sy[1] = 1.0/dt1;
|
|
bump.m_type[0] = 5;
|
|
bump.m_type[1] = 5;
|
|
bump.m_a = 1.0;
|
|
|
|
if ( offset_value.m_radius > 0.0 )
|
|
{
|
|
// user specified cubic bump size
|
|
ON_3dPoint Pt;
|
|
ON_3dVector Ds, Dt;
|
|
if ( m_srf->Ev1Der(offset_value.m_s,offset_value.m_t,Pt,Ds,Dt) )
|
|
{
|
|
ds = (ds0>ds1) ? ds0 : ds1;
|
|
dt = (dt0>dt1) ? dt0 : dt1;
|
|
a = Ds.Length();
|
|
if ( a > ON_ZERO_TOLERANCE )
|
|
{
|
|
b = offset_value.m_radius/a;
|
|
if ( b < ds )
|
|
ds = b;
|
|
}
|
|
a = Dt.Length();
|
|
if ( a > ON_ZERO_TOLERANCE )
|
|
{
|
|
b = offset_value.m_radius/a;
|
|
if ( b < dt )
|
|
dt = b;
|
|
}
|
|
if ( !m_bZeroSideDerivative[0] || dt < dt0 )
|
|
dt0 = dt;
|
|
if ( !m_bZeroSideDerivative[1] || ds < ds1 )
|
|
ds1 = ds;
|
|
if ( !m_bZeroSideDerivative[2] || dt < dt1 )
|
|
dt1 = dt;
|
|
if ( !m_bZeroSideDerivative[3] || ds < ds0 )
|
|
ds0 = ds;
|
|
bump.m_sx[0] = -1.0/ds0;
|
|
bump.m_sx[1] = 1.0/ds1;
|
|
bump.m_sy[0] = -1.0/dt0;
|
|
bump.m_sy[1] = 1.0/dt1;
|
|
}
|
|
}
|
|
else if ( bump.m_point.x == m_domain[0][0] && bump.m_point.y == m_domain[1][0] )
|
|
{
|
|
// SW corner bilinear bump
|
|
if ( !m_bZeroSideDerivative[1] && !m_bZeroSideDerivative[3] )
|
|
{
|
|
bump.m_type[0] = 1;
|
|
bump.m_x0 = m_domain[0][1];
|
|
bump.m_sx[0] = -1.0/m_domain[0].Length();
|
|
bump.m_sx[1] = -1.0/m_domain[0].Length();
|
|
}
|
|
if ( !m_bZeroSideDerivative[0] && !m_bZeroSideDerivative[2] )
|
|
{
|
|
bump.m_type[1] = 1;
|
|
bump.m_y0 = m_domain[1][1];
|
|
bump.m_sy[0] = -1.0/m_domain[1].Length();
|
|
bump.m_sy[1] = -1.0/m_domain[1].Length();
|
|
}
|
|
}
|
|
else if ( bump.m_point.x == m_domain[0][1] && bump.m_point.y == m_domain[1][0] )
|
|
{
|
|
// SE corner bilinear bump
|
|
if ( !m_bZeroSideDerivative[1] && !m_bZeroSideDerivative[3] )
|
|
{
|
|
bump.m_type[0] = 1;
|
|
bump.m_x0 = m_domain[0][0];
|
|
bump.m_sx[0] = 1.0/m_domain[0].Length();
|
|
bump.m_sx[1] = 1.0/m_domain[0].Length();
|
|
}
|
|
if ( !m_bZeroSideDerivative[0] && !m_bZeroSideDerivative[2] )
|
|
{
|
|
bump.m_type[1] = 1;
|
|
bump.m_y0 = m_domain[1][1];
|
|
bump.m_sy[0] = -1.0/m_domain[1].Length();
|
|
bump.m_sy[1] = -1.0/m_domain[1].Length();
|
|
}
|
|
}
|
|
else if ( bump.m_point.x == m_domain[0][1] && bump.m_point.y == m_domain[1][1] )
|
|
{
|
|
// NE corner bilinear bump
|
|
if ( !m_bZeroSideDerivative[1] && !m_bZeroSideDerivative[3] )
|
|
{
|
|
bump.m_type[0] = 1;
|
|
bump.m_x0 = m_domain[0][0];
|
|
bump.m_sx[0] = 1.0/m_domain[0].Length();
|
|
bump.m_sx[1] = 1.0/m_domain[0].Length();
|
|
}
|
|
if ( !m_bZeroSideDerivative[0] && !m_bZeroSideDerivative[2] )
|
|
{
|
|
bump.m_type[1] = 1;
|
|
bump.m_y0 = m_domain[1][0];
|
|
bump.m_sy[0] = 1.0/m_domain[1].Length();
|
|
bump.m_sy[1] = 1.0/m_domain[1].Length();
|
|
}
|
|
}
|
|
else if ( bump.m_point.x == m_domain[0][0] && bump.m_point.y == m_domain[1][1] )
|
|
{
|
|
// NW corner bilinear bump
|
|
if ( !m_bZeroSideDerivative[1] && !m_bZeroSideDerivative[3] )
|
|
{
|
|
bump.m_x0 = m_domain[0][1];
|
|
bump.m_sx[0] = -1.0/m_domain[0].Length();
|
|
bump.m_sx[1] = -1.0/m_domain[0].Length();
|
|
bump.m_type[0] = 1;
|
|
}
|
|
if ( !m_bZeroSideDerivative[0] && !m_bZeroSideDerivative[2] )
|
|
{
|
|
bump.m_y0 = m_domain[1][0];
|
|
bump.m_sy[0] = 1.0/m_domain[1].Length();
|
|
bump.m_sy[1] = 1.0/m_domain[1].Length();
|
|
bump.m_type[1] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ON_Matrix M(count,count);
|
|
double* B = (double*)onmalloc(2*count*sizeof(*B));
|
|
double* X = B + count;
|
|
int j;
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
ON_2dPoint p = m_bumps[i].m_point;
|
|
B[i] = m_offset_value[i].m_distance;
|
|
for ( j = 0; j < count; j++ )
|
|
{
|
|
M[i][j] = m_bumps[j].ValueAt(p.x,p.y);
|
|
}
|
|
}
|
|
int rank = M.RowReduce(ON_ZERO_TOLERANCE,B);
|
|
if ( count == rank )
|
|
{
|
|
if ( M.BackSolve(ON_ZERO_TOLERANCE,count,B,X) )
|
|
{
|
|
m_bValid = true;
|
|
}
|
|
}
|
|
|
|
if ( !m_bValid )
|
|
{
|
|
#if 0 //defined(TL2_MATRIX_INC_)
|
|
// Have access to SVD - try it
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
ON_2dPoint p = m_bumps[i].m_point;
|
|
B[i] = m_offset_value[i].m_distance;
|
|
for ( j = 0; j < count; j++ )
|
|
{
|
|
M[i][j] = m_bumps[j].ValueAt(p.x,p.y);
|
|
}
|
|
}
|
|
ON_Matrix U, V;
|
|
double* diagonal = (double*)onmalloc(2*count*sizeof(*diagonal));
|
|
double* inverted_diagonal = diagonal + count;
|
|
if ( TL2_MatrixSVD(M,U,diagonal,V,30) )
|
|
{
|
|
rank = TL2_MatrixSVDInvertDiagonal(count,diagonal,inverted_diagonal);
|
|
if ( rank > 0 )
|
|
{
|
|
if ( TL2_MatrixSVDSolve(U,inverted_diagonal,V,1,B,1,X) )
|
|
{
|
|
m_bValid = true;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ( m_bValid )
|
|
{
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
m_bumps[i].m_a = X[i];
|
|
}
|
|
}
|
|
|
|
onfree(B);
|
|
}
|
|
return m_bValid;
|
|
}
|
|
|
|
ON_BumpFunction::ON_BumpFunction()
|
|
{
|
|
m_type[0] = 0;
|
|
m_type[1] = 0;
|
|
m_sx[0] = 0.0;
|
|
m_sx[1] = 0.0;
|
|
m_sy[0] = 0.0;
|
|
m_sy[1] = 0.0;
|
|
}
|
|
|
|
double ON_BumpFunction::ValueAt(
|
|
double s,
|
|
double t
|
|
) const
|
|
{
|
|
double v;
|
|
Evaluate(s,t,0,&v);
|
|
return v;
|
|
}
|
|
|