Beispiel #1
0
void ON_TextLog::PrintKnotVector( int order, int cv_count, const double* knot )
{
  int i, i0, mult, knot_count;
  if ( !knot )
    Print("NULL knot vector\n");
  if ( order < 2 )
    Print("knot vector order < 2\n");
  if ( cv_count < order )
    Print("knot vector cv_count < order\n");
  if ( order >= 2 && cv_count >= order && knot ) {
    knot_count = ON_KnotCount( order, cv_count );
    i = i0 = 0;
    Print("index                     value  mult       delta\n");
    while ( i < knot_count ) {
      mult = 1;
      while ( i+mult < knot_count && knot[i] == knot[i+mult] )
        mult++;
      if ( i == 0 ) {
        Print( "%5d  %23.20g  %4d\n", i, knot[i], mult );
      }
      else {
        Print( "%5d  %23.20g  %4d  %10.4g\n", i, knot[i], mult, knot[i]-knot[i0] );
      }
      i0 = i;
      i += mult;
    }
  }
}
Beispiel #2
0
bool ON_ClampKnotVector(
          int order,          // order (>=2)
          int cv_count,       // cv count
          double* knot,       // knot[] array
          int end             // 0 = clamp start, 1 = clamp end, 2 = clamp both ends
          )
{
  // sets initial/final order-2 knot values to match knot[order-2]/knot[cv_count-1]
  bool rc = false;
  int i, i0;
  if ( knot && order >= 2 && cv_count >= order ) {
    if ( end == 0 || end == 2 ) {
      i0 = order-2;
      for ( i = 0; i < i0; i++ ) {
        knot[i] = knot[i0];
      }
      rc = true;
    }
    if ( end == 1 || end == 2 ) {
      const int knot_count = ON_KnotCount(order,cv_count);
      i0 = cv_count-1;
      for ( i = i0+1; i < knot_count; i++ ) {
        knot[i] = knot[i0];
      }
      rc = true;
    }
  }
  return rc;
}
Beispiel #3
0
bool ON_SetKnotVectorDomain( int order, int cv_count, double* knot, double t0, double t1 )
{
  bool rc = false;
  if ( order < 2 || cv_count < order || 0 == knot || t0 >= t1 || !ON_IsValid(t0) || !ON_IsValid(t1) )
  {
    ON_ERROR("ON_SetKnotVectorDomain - invalid input");
  }
  else if (    knot[order-2] >= knot[cv_count-1] 
            || !ON_IsValid(knot[order-2]) 
            || !ON_IsValid(knot[cv_count-2]) )
  {
    ON_ERROR("ON_SetKnotVectorDomain - invalid input knot vector");
  }
  else
  {
    const ON_Interval oldd(knot[order-2],knot[cv_count-1]);
    const ON_Interval newd(t0,t1);
    if ( oldd != newd )
    {
      int i, knot_count = ON_KnotCount(order,cv_count);
      for ( i = 0; i < knot_count; i++ )
      {
        knot[i] = newd.ParameterAt(oldd.NormalizedParameterAt(knot[i]));
      }
    }
    rc = true;
  }
  return rc;
}
Beispiel #4
0
bool ON_IsKnotVectorUniform(
          int order,
          int cv_count,
          const double* knot 
          )
{
  bool rc = (order >= 2 && cv_count >= order && 0 != knot);
  if (rc)
  {
    const double delta = knot[order-1] - knot[order-2];
    const double delta_tol = ON_SQRT_EPSILON*delta;
    int i0, i1;
    double d;
    if ( ON_IsKnotVectorClamped(order,cv_count,knot) )
    {
      i0 = order;
      i1 = cv_count;
    }
    else
    {
      i0 = 1;
      i1 = ON_KnotCount(order,cv_count);
    }
    for (/*empty*/; i0 < i1 && rc; i0++ )
    {
      d = knot[i0] - knot[i0-1];
      if ( fabs(d - delta) > delta_tol )
        rc = false;
    }
  }
  return rc;
}
Beispiel #5
0
double ON_KnotTolerance( int order, int cv_count, const double* knot, 
                                    int knot_index )
{
  const int knot_count = ON_KnotCount( order, cv_count );
  int i0, i1, j;
  double a, b, tol;
  i0 = knot_index-order+1;
  if ( i0 < 0 )
    i0 = 0;
  i1 = knot_index+order-1;
  if ( i1 >= knot_count )
    i1 = knot_count-1;
  for ( j = knot_index; j > i0; j-- ) {
    if ( knot[j] != knot[knot_index] )
      break;
  }
  a = fabs(knot[knot_index] - knot[j]);
  for ( j = knot_index; j < i1; j++ ) {
    if ( knot[j] != knot[knot_index] )
      break;
  }
  b = fabs(knot[knot_index] - knot[j]);
  tol = (a==0.0 && b==0.0) ? 0.0 : (a + b + fabs(knot[knot_index]))* ON_SQRT_EPSILON;
  return tol;
}
Beispiel #6
0
int ON_CompareKnotVector( // returns 
                                      // -1: first < second
                                      //  0: first == second
                                      // +1: first > second
          int orderA,
          int cv_countA,
          const double* knotA,
          int orderB,
          int cv_countB,
          const double* knotB
          )
{
  const int knot_count = ON_KnotCount(orderA,cv_countA);
  int i;
  double a, b, atol, btol, ktol, tol;
  if ( orderA < orderB )
    return -1;
  if ( orderA > orderB )
    return 1;
  if ( cv_countA < cv_countB )
    return -1;
  if ( cv_countA > cv_countB )
    return 1;

  if ( !ON_GetKnotVectorDomain( orderA, cv_countA, knotA, &a, &b ) )
    return -1;
  atol = ON_DomainTolerance( a, b );
  if ( !ON_GetKnotVectorDomain( orderA, cv_countA, knotA, &a, &b ) )
    return 1;
  btol = ON_DomainTolerance( a, b );
  tol = (atol <= btol) ? atol : btol;

  for ( i = 0; i < knot_count; i++ ) {
    a = knotA[i];
    b = knotB[i];
    if ( a == b )
      continue;
    if ( a < b-tol )
      return -1;
    if ( b < a-tol )
      return 1;
    atol = ON_KnotTolerance( orderA, cv_countA, knotA, i );
    btol = ON_KnotTolerance( orderB, cv_countB, knotB, i );
    ktol = (atol <= btol) ? atol : btol;
    if ( a < b-ktol )
      return -1;
    if ( b < a-ktol )
      return 1;
  }
  return 0;
}
Beispiel #7
0
bool ON_KnotVectorHasBezierSpans(
          int order,          // order (>=2)
          int cv_count,       // cv count
          const double* knot  // knot[] array
          )
{
  int knot_count = ON_KnotCount( order, cv_count );
  if ( knot_count < 2 )
    return false;
  int span_count = ON_KnotVectorSpanCount( order, cv_count, knot );
  if ( span_count < 1 )
    return false;
  if ( order >= 2 && 
       cv_count >= order && 
       knot_count == (span_count+1)*(order-1) && 
       knot[0] == knot[order-2] && knot[cv_count-1] == knot[knot_count-1])
    return true;
  return false;
}
Beispiel #8
0
// Description:
//   Fill in knot values for a clamped uniform knot
//   vector.
// Parameters:
//   order - [in] (>=2) order (degree+1) of the NURBS
//   cv_count - [in] (>=order) total number of control points
//       in the NURBS.
//   knot - [in/out] Input is an array with room for 
//       ON_KnotCount(order,cv_count) doubles.  Output is
//       a periodic uniform knot vector with domain
//       (0, (1+cv_count-order)*delta).
//   delta - [in] (>0, default=1.0) spacing between knots.
// Returns:
//   true if successful
ON_DECL
bool ON_MakePeriodicUniformKnotVector(
          int order,
          int cv_count,
          double* knot,
          double delta
          )
{
  bool rc = false;
  if ( order >= 2 && cv_count >= order && knot != NULL && delta > 0.0 )
  {
    double k = 0.0;
    int i, knot_count = ON_KnotCount(order,cv_count);
    for ( i = order-2, k = 0.0; i < knot_count; i++, k += delta )
      knot[i] = k;
    for ( i = order-3, k = -delta; i >= 0; i--, k -= delta )
      knot[i] = k;
    rc = true;
  }
  return rc;
}
Beispiel #9
0
void RSpline::updateFromControlPoints() const {
#ifndef R_NO_OPENNURBS
    if (controlPoints.size()<degree+1) {
        invalidate();
        qWarning() << "RSpline::updateFromControlPoints: not enough control points: "
                   << controlPoints.size();
        return;
    }

    // periodic:
    if (periodic && !hasFitPoints()) {
        ON_3dPoint* points = new ON_3dPoint[controlPoints.size()];
        for (int i=0; i<controlPoints.size(); ++i) {
            RVector cp = controlPoints.at(i);
            points[i] = ON_3dPoint(cp.x, cp.y, cp.z);
        }
        curve.CreatePeriodicUniformNurbs(3, getOrder(), controlPoints.size(), points);
        delete[] points;
    }

    // open or from fit points:
    else {
        curve.Create(3, false, getOrder(), controlPoints.size());

        // setting control points:
        for (int i=0; i<controlPoints.size(); ++i) {
            RVector cp = controlPoints.at(i);
            ON_3dPoint onp(cp.x, cp.y, cp.z);
            curve.SetCV(i, onp);
            //qDebug() << "RSpline: controlPoints[" << i << "]: " << cp;
        }

        bool knotCondition = (knotVector.size() == getOrder() + controlPoints.size() - 2);
        //knotCondition = true;

        // genetate knot vector automatically:
        if (knotVector.isEmpty() || !knotCondition) {
//            if (!knotVector.isEmpty()) {
//                qDebug() << "RSpline: knotVector ignored";
//                qDebug() << "RSpline:   knots: " << knotVector.size();
//                qDebug() << "RSpline:   order: " << getOrder();
//                qDebug() << "RSpline:   controlPoints: " << controlPoints.size();
//            }

            int si = ON_KnotCount(getOrder(), controlPoints.size());
            double* knot = new double[si];
            //ON_MakePeriodicUniformKnotVector(getOrder(), controlPoints.size(), knot);
            ON_MakeClampedUniformKnotVector(getOrder(), controlPoints.size(), knot);
            for (int i=0; i<si; ++i) {
//                qDebug() << "RSpline: knot[" << i << "]: " << knot[i];
                curve.SetKnot(i, knot[i]);
            }
            delete[] knot;
        }
        else {
            int k=0;
            for (int i=0; i<knotVector.count(); ++i) {
                //qDebug() << "RSpline: knot[" << i << "]: " << knotVector.at(i);
                bool ok = curve.SetKnot(k++, knotVector.at(i));
                if (!ok) {
                    //qDebug() << "RSpline: knot[" << i << "]: NOT set";
                }
            }
        }
    }

    //##getExploded();
#endif
}
Beispiel #10
0
int ON_InsertKnot( 
        double knot_value, 
        int knot_multiplicity, 
        int cv_dim,   // dimension of cv's = ( = dim+1 for rational cvs )
        int order, 
        int cv_count,
        int cv_stride, 
        double* cv,   // NULL or cv array with room for at least knot_multiplicity new cvs
        double* knot, // knot array with room for at least knot_multiplicity new knots
        int* hint     // optional hint about where to search for span to add knots to
                      // pass NULL if no hint is available
        )
{
  int rc = 0; // return code = number of knots added

  if ( order < 2 || cv_count < order || !knot ) 
  {
    ON_ERROR("ON_InsertKnot(): illegal input" );
    return 0;
  }

  if ( cv ) 
  {
    if ( cv_dim < 1 || cv_stride < cv_dim ) 
    {
      ON_ERROR("ON_InsertKnot(): illegal input" );
      return 0;
    }
  }

  if ( knot_multiplicity >= order ) 
  {
    ON_ERROR("ON_InsertKnot(): requested knot_multiplicity > degree" );
    return 0;
  }

  // shift knot vector and cv array so that knot_value lies in first span
  int span_index = ON_NurbsSpanIndex( order, cv_count, knot, knot_value, 1, hint?*hint:0 );
  knot += span_index;
  if ( cv )
    cv += (span_index*cv_stride);
  cv_count -= span_index;

  const double knot_tolerance = ON_SpanTolerance( order, cv_count, knot, 0 );

  // check that knot_value is interior to NURBS domain
  if ( span_index == 0 ) 
  {
    if ( knot_value < knot[order-1] ) 
    {
      if ( knot_value <= knot[order-2] + knot_tolerance ) 
      {
        ON_ERROR("ON_InsertKnot(): requested knot_value at start of NURBS domain" );
        return 0;
      }
    }
  }
  if ( span_index == cv_count-order ) 
  {
    if ( knot_value > knot[order-2] && knot_value >= knot[order-1] - knot_tolerance ) 
    {
      ON_ERROR("ON_InsertKnot(): requested knot_value at end of NURBS domain" );
      return 0;
    }
  }

  // if knot_value is nearly equal to an existing knot, make it exactly equal
  if ( knot_value <= 0.5*(knot[order-2]+knot[order-1]) && fabs( knot_value - knot[order-2] ) <= knot_tolerance ) {
    knot_value = knot[order-2];
  }
  else if ( fabs( knot_value - knot[order-1] ) <= knot_tolerance ) {
    knot_value = knot[order-1];
  }

  const int degree = order-1;

  // set m = number of knots to add
  int m = 0; 
  int j;
  if ( knot_value == knot[order-2] ) {
    for ( j = order-2; m < knot_multiplicity && knot[j-m] == knot_value; m++ )
      ; // empty for
  }
  else if ( knot_value == knot[order-1] ) {
    for ( j = order-1; m < knot_multiplicity && knot[j+m] == knot_value; m++ )
      ; // empty for
  }
  m = knot_multiplicity - m;
  if ( hint )
    *hint = span_index+m;

  if ( m <= 0 )
    return 0; // no knots need to be added

  double* new_knot = (double*)onmalloc( ((2*degree+m) + (order+m)*cv_dim)*sizeof(*new_knot) );
  if ( !new_knot ) {
    ON_ERROR("ON_InsertKnot(): out of memory");
    return 0;
  }
  double* new_cv = 0;
  memcpy( new_knot, knot, 2*degree*sizeof(*new_knot) );
  if ( cv ) {
    new_cv = new_knot + (2*degree+m);
    for ( j = 0; j < order; j++ ) {
      memcpy( new_cv + j*cv_dim, cv + j*cv_stride, cv_dim*sizeof(*new_cv) );
    }
  }

  // add m more knots at knot_value
  rc = 0;
  while (m>0) {
    if ( !ON_InsertSingleKnot(cv_dim,order,cv_dim,new_cv,new_knot,knot_value) )
      break;
    m--;
    if ( new_cv )
      new_cv += cv_stride; 
    new_knot++; 
    rc++;
  }
  new_knot -= rc;
  new_cv -= rc*cv_stride;

  if ( rc > 0 ) {
    // make room for rc many new knots
    int i0 = ON_KnotCount( order, cv_count ) - 1; // knot[i0] = last input knot
    int i1 = i0 + rc;
    int j  = (cv_count-order);
    while (j--)
      knot[i1--] = knot[i0--];
    
    // update knot vector
    memcpy ( knot+degree, new_knot+degree, (degree+rc)*sizeof(*new_knot) );

    if ( cv ) {
      // make room for rc many new CVs
      i0 = (cv_count-1)*cv_stride;             // cv[i0] = last coord of last input cv */
      i1 = i0 + rc*cv_stride;
      j = cv_count-order;
      while (j--) {
        memcpy( cv+i1, cv+i0, cv_dim*sizeof(*cv) );
        i1 -= cv_stride;
        i0 -= cv_stride;
      }

      // update cv values
      for ( j = 0; j < order+rc; j++ ) {
        memcpy( cv, new_cv, cv_dim*sizeof(*new_cv) );
        cv += cv_stride;
        new_cv += cv_dim;
      }
    }

  }

  onfree(new_knot);

  return rc;
}
Beispiel #11
0
bool ON_GetGrevilleKnotVector( // get knots from Greville abcissa
          int g_stride,     
          const double *g,  // if not periodic, g[cv_count], 
                            // if periodic, g[cv_count-order+2]
                            // usually, g[0] = 0, g[i] = |P[i]-P[i-1]|^q
          bool bPeriodic,
          int order, 
          int cv_count, 
          double* knot
          )
{
  bool rc = false;
  double* p = NULL;
  int ki, knot_count, g_count, gi, j, degree;
  double k, dd;

  if ( g_stride < 1 || !g || !knot || order < 2 || cv_count < order )
    return false;
  if ( bPeriodic && order == 2 )
    return false;
  if ( bPeriodic && cv_count - order + 2 < 3 )
    return false;

  degree = order-1;
  if ( degree == 1 ) {
    for ( j = 0; j < cv_count; j++ ) {
      knot[j] = g[j*g_stride];
    }
    return true;
  }
  dd = 1.0/degree;
  knot_count = ON_KnotCount( order, cv_count );
  g_count = (bPeriodic) ? cv_count-order+2 : cv_count;

  if ( bPeriodic ) {
    int half_degree = (degree%2) ? degree/2 : 0;
    // step 1: set p[] = fully periodic list of abcissa
    p = (double*)onmalloc((g_count + 2*degree)*sizeof(*p));
    for ( j = 0, gi = g_count-order; j < degree; j++, gi++ ) {
      p[j] = g[0] - g[g_count-1] + g[gi];
    }
    for ( gi = 0, j = degree; gi < g_count; gi++, j++ ) {
      p[j] = g[gi];
    }
    for ( j = g_count+degree, gi = 1; j < g_count+2*degree; j++, gi++ ) {
      p[j] = g[g_count-1] - g[0] + g[gi];
    }

    // step 2: set new p[i] = old (p[i] + ... + p[i+degree-1]) / degree
    for ( j = 0; j < g_count+order; j++ ) {
      k = p[j];
      for ( ki = 1; ki < degree; ki++ ) 
        k += p[j+ki];
      k *= dd;
      if ( half_degree ) {
        // if g[]'s are uniform and degree is odd, then knots = g[]'s
        if ( fabs(k-p[j+half_degree]) <=  ON_SQRT_EPSILON*(p[j+degree-1]-p[j]) )
          k = p[j+half_degree];
      }
      p[j] = k;
    }

    // step 3: determine where g[0] maximizes NURBS basis functions
    {
      double* B = (double*)alloca(order*order*sizeof(B[0]));
      double maxB  = 0.0;
      int maxBj = 0;
      for ( j = 0; j < 2*degree; j++ ) {
        if ( g[0] > p[j+degree] )
          continue;
        if ( g[0] < p[j+degree-1] )
          break;
        ON_EvaluateNurbsBasis( order, p+j, g[0], B );
        if ( B[0] > maxB ) {
          maxB  = B[0];
          maxBj = j;
        }
      }
      memcpy( knot, &p[maxBj], knot_count*sizeof(*knot) );
    }

    rc = ON_MakeKnotVectorPeriodic( order, cv_count, knot );
  }
  else {
    // clamped knots
    rc = true;
    if ( g > knot && g < knot+knot_count ) {
      p = (double*)onmalloc(cv_count*sizeof(*p));
      for( j = 0; j < cv_count; j++ ) {
        p[j] = g[j*g_stride];
      }
      g = p;
      g_stride = 1;
    }
    for ( ki = 0; ki < degree; ki++ ) {
      knot[ki] = g[0];
    }
    for ( ki = degree, gi = 1; ki < cv_count; ki++, gi++ ) {
      k = 0.0;
      for ( j = 0; j < degree; j++ ) {
        k += g[(gi+j)*g_stride];
      }
      knot[ki] = k*dd;
      if ( knot[ki] < knot[ki-1] || knot[ki] <= knot[ki-degree] ) {
        rc = false;
      }
    }
    for ( ki = cv_count-1; ki < knot_count; ki++ ) {
      knot[ki] = g[(cv_count-1)*g_stride];
    }
  }

  if (p)
    onfree(p);
  return rc;
}