LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - intronurbs.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 67 108 62.0 %
Date: 2024-05-03 15:49:35 Functions: 4 7 57.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DXF Translator
       4             :  * Purpose:  Low level spline interpolation.
       5             :  * Author:   David F. Rogers
       6             :  *
       7             :  ******************************************************************************
       8             : 
       9             : This code is derived from the code associated with the book "An Introduction
      10             : to NURBS" by David F. Rogers.  More information on the book and the code is
      11             : available at:
      12             : 
      13             :   http://www.nar-associates.com/nurbs/
      14             : 
      15             : David F. Rogers agreed explicitly that the subset of his code in this file to
      16             : be used under the following license (cf
      17             : https://github.com/OSGeo/gdal/issues/6524)
      18             : 
      19             : Copyright (c) 2009, David F. Rogers
      20             : All rights reserved.
      21             : 
      22             : Redistribution and use in source and binary forms, with or without
      23             : modification, are permitted provided that the following conditions are met:
      24             : 
      25             :     * Redistributions of source code must retain the above copyright notice,
      26             :       this list of conditions and the following disclaimer.
      27             :     * Redistributions in binary form must reproduce the above copyright notice,
      28             :       this list of conditions and the following disclaimer in the documentation
      29             :       and/or other materials provided with the distribution.
      30             :     * Neither the name of David F. Rogers nor the names of its contributors
      31             :       may be used to endorse or promote products derived from this software
      32             :       without specific prior written permission.
      33             : 
      34             : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      35             : AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      36             : IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      37             : ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
      38             : LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      39             : CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      40             : SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      41             : INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      42             : CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      43             : ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      44             : POSSIBILITY OF SUCH DAMAGE.
      45             : */
      46             : 
      47             : #include <stdio.h>
      48             : #include <vector>
      49             : #include "cpl_port.h"
      50             : 
      51             : /* used by ogrdxflayer.cpp */
      52             : void rbspline2(int npts, int k, int p1, double b[], double h[],
      53             :                bool bCalculateKnots, double x[], double p[]);
      54             : 
      55             : /* used by ogrdxf_leader.cpp */
      56             : void basis(int c, double t, int npts, double x[], double N[]);
      57             : 
      58             : /* used by DWG driver */
      59             : void rbspline(int npts, int k, int p1, double b[], double h[], double p[]);
      60             : void rbsplinu(int npts, int k, int p1, double b[], double h[], double p[]);
      61             : 
      62             : /************************************************************************/
      63             : /*                               knotu()                                */
      64             : /************************************************************************/
      65             : 
      66             : /*  Subroutine to generate a B-spline uniform (periodic) knot vector.
      67             : 
      68             :     c            = order of the basis function
      69             :     n            = the number of defining polygon vertices
      70             :     nplus2       = index of x() for the first occurrence of the maximum knot
      71             :    vector value nplusc       = maximum value of the knot vector -- $n + c$ x[]
      72             :    = array containing the knot vector
      73             : */
      74             : 
      75           0 : static void knotu(int n, int c, double x[])
      76             : 
      77             : {
      78             :     int nplusc, /* nplus2, */ i;
      79             : 
      80           0 :     nplusc = n + c;
      81             :     /* nplus2 = n + 2; */
      82             : 
      83           0 :     x[1] = 0;
      84           0 :     for (i = 2; i <= nplusc; i++)
      85             :     {
      86           0 :         x[i] = i - 1;
      87             :     }
      88           0 : }
      89             : 
      90             : /************************************************************************/
      91             : /*                                knot()                                */
      92             : /************************************************************************/
      93             : 
      94             : /*
      95             :     Subroutine to generate a B-spline open knot vector with multiplicity
      96             :     equal to the order at the ends.
      97             : 
      98             :     c            = order of the basis function
      99             :     n            = the number of defining polygon vertices
     100             :     nplus2       = index of x() for the first occurrence of the maximum knot
     101             :    vector value nplusc       = maximum value of the knot vector -- $n + c$ x()
     102             :    = array containing the knot vector
     103             : */
     104             : 
     105           1 : static void knot(int n, int c, double x[])
     106             : 
     107             : {
     108           1 :     const int nplusc = n + c;
     109           1 :     const int nplus2 = n + 2;
     110             : 
     111           1 :     x[1] = 0.0;
     112          11 :     for (int i = 2; i <= nplusc; i++)
     113             :     {
     114          10 :         if ((i > c) && (i < nplus2))
     115           4 :             x[i] = x[i - 1] + 1.0;
     116             :         else
     117           6 :             x[i] = x[i - 1];
     118             :     }
     119           1 : }
     120             : 
     121             : /************************************************************************/
     122             : /*                                basis()                               */
     123             : /************************************************************************/
     124             : 
     125             : /*  Subroutine to generate B-spline basis functions--open knot vector
     126             : 
     127             :         C code for An Introduction to NURBS
     128             :         by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     129             :         All rights reserved.
     130             : 
     131             :         Name: rbasis (split into rbasis and basis by AT)
     132             :         Language: C
     133             :         Subroutines called: none
     134             :         Book reference: Chapter 4, Sec. 4. , p 296
     135             : 
     136             :     c        = order of the B-spline basis function
     137             :     d        = first term of the basis function recursion relation
     138             :     e        = second term of the basis function recursion relation
     139             :     h[]      = array containing the homogeneous weights
     140             :     npts     = number of defining polygon vertices
     141             :     nplusc   = constant -- npts + c -- maximum number of knot values
     142             :     r[]      = array containing the rationalbasis functions
     143             :                r[1] contains the basis function associated with B1 etc.
     144             :     t        = parameter value
     145             :     N[]      = array output from bbasis containing the values of the
     146             :                basis functions; should have capacity npts + c + 1
     147             :     x[]      = knot vector
     148             : */
     149             : 
     150        1322 : void basis(int c, double t, int npts, double x[], double N[])
     151             : 
     152             : {
     153        1322 :     const int nplusc = npts + c;
     154             : 
     155             :     /* calculate the first order nonrational basis functions n[i] */
     156             : 
     157       13082 :     for (int i = 1; i <= nplusc - 1; i++)
     158             :     {
     159       11760 :         if ((t >= x[i]) && (t < x[i + 1]))
     160        1292 :             N[i] = 1.0;
     161             :         else
     162       10468 :             N[i] = 0.0;
     163             :     }
     164             : 
     165             :     /* calculate the higher order nonrational basis functions */
     166             : 
     167        5288 :     for (int k = 2; k <= c; k++)
     168             :     {
     169       31314 :         for (int i = 1; i <= nplusc - k; i++)
     170             :         {
     171       27348 :             double d = 0.0;
     172       27348 :             double e = 0.0;
     173       27348 :             if (N[i] != 0) /* if the lower order basis function is zero skip the
     174             :                               calculation */
     175             :             {
     176        7656 :                 double denom = x[i + k - 1] - x[i];
     177        7656 :                 if (denom != 0)
     178        7656 :                     d = ((t - x[i]) * N[i]) / denom;
     179             :             }
     180             :             // else
     181             :             //    d = 0.0 ;
     182             : 
     183       27348 :             if (N[i + 1] != 0) /* if the lower order basis function is zero skip
     184             :                                   the calculation */
     185             :             {
     186        7656 :                 double denom = x[i + k] - x[i + 1];
     187        7656 :                 if (denom != 0)
     188        7656 :                     e = ((x[i + k] - t) * N[i + 1]) / denom;
     189             :             }
     190             :             // else
     191             :             //     e = 0.0;
     192             : 
     193       27348 :             N[i] = d + e;
     194             :         }
     195             :     }
     196             : 
     197        1322 :     if (t == (double)x[nplusc])
     198             :     { /* pick up last point */
     199          30 :         N[npts] = 1;
     200             :     }
     201        1322 : }
     202             : 
     203             : /************************************************************************/
     204             : /*                               rbasis()                               */
     205             : /*                                                                      */
     206             : /*      Subroutine to generate rational B-spline basis functions.       */
     207             : /*      See the comment for basis() above.                              */
     208             : /************************************************************************/
     209             : 
     210        1320 : static void rbasis(int c, double t, int npts, double x[], double h[],
     211             :                    double r[])
     212             : 
     213             : {
     214        1320 :     const int nplusc = npts + c;
     215             : 
     216        2640 :     std::vector<double> temp;
     217        1320 :     temp.resize(nplusc + 1);
     218             : 
     219        1320 :     basis(c, t, npts, x, &temp[0]);
     220             : 
     221             :     /* calculate sum for denominator of rational basis functions */
     222             : 
     223        1320 :     double sum = 0.0;
     224        9104 :     for (int i = 1; i <= npts; i++)
     225             :     {
     226        7784 :         sum = sum + temp[i] * h[i];
     227             :     }
     228             : 
     229             :     /* form rational basis functions and put in r vector */
     230             : 
     231        9104 :     for (int i = 1; i <= npts; i++)
     232             :     {
     233        7784 :         if (sum != 0)
     234             :         {
     235        7784 :             r[i] = (temp[i] * h[i]) / (sum);
     236             :         }
     237             :         else
     238             :         {
     239           0 :             r[i] = 0;
     240             :         }
     241             :     }
     242        1320 : }
     243             : 
     244             : /************************************************************************/
     245             : /*                             rbspline2()                              */
     246             : /************************************************************************/
     247             : 
     248             : /*  Subroutine to generate a rational B-spline curve.
     249             : 
     250             :     C code for An Introduction to NURBS
     251             :     by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     252             :     All rights reserved.
     253             : 
     254             :     Name: rbspline.c
     255             :     Language: C
     256             :     Subroutines called: knot.c, rbasis.c, fmtmul.c
     257             :     Book reference: Chapter 4, Alg. p. 297
     258             : 
     259             :     b[]         = array containing the defining polygon vertices
     260             :                   b[1] contains the x-component of the vertex
     261             :                   b[2] contains the y-component of the vertex
     262             :                   b[3] contains the z-component of the vertex
     263             :     h[]         = array containing the homogeneous weighting factors
     264             :     k           = order of the B-spline basis function
     265             :     nbasis      = array containing the basis functions for a single value of t
     266             :     nplusc      = number of knot values
     267             :     npts        = number of defining polygon vertices
     268             :     p[,]        = array containing the curve points
     269             :                   p[1] contains the x-component of the point
     270             :                   p[2] contains the y-component of the point
     271             :                   p[3] contains the z-component of the point
     272             :     p1          = number of points to be calculated on the curve
     273             :     t           = parameter value 0 <= t <= npts - k + 1
     274             :     bCalculateKnots  = when set to true, x will be filled with the knot()
     275             :    routine, otherwise its content will be used. knots[]     = array containing
     276             :    the knot vector (must be npts + k + 1 large)
     277             : */
     278             : 
     279          30 : void rbspline2(int npts, int k, int p1, double b[], double h[],
     280             :                bool bCalculateKnots, double knots[], double p[])
     281             : 
     282             : {
     283          30 :     const int nplusc = npts + k;
     284             : 
     285          60 :     std::vector<double> nbasis;
     286          30 :     nbasis.resize(npts + 1);
     287             : 
     288             :     /* generate the uniform open knot vector */
     289             : 
     290          30 :     if (bCalculateKnots == true)
     291           1 :         knot(npts, k, knots);
     292             : 
     293          30 :     int icount = 0;
     294             : 
     295             :     /*    calculate the points on the rational B-spline curve */
     296             : 
     297          30 :     double t = knots[1];
     298          30 :     const double step = (knots[nplusc] - knots[1]) / ((double)(p1 - 1));
     299             : 
     300          30 :     const double eps = 5e-6 * (knots[nplusc] - knots[1]);
     301             : 
     302        1350 :     for (int i1 = 1; i1 <= p1; i1++)
     303             :     {
     304             :         /* avoid undershooting the final knot */
     305        1320 :         if ((double)knots[nplusc] - t < eps)
     306             :         {
     307          30 :             t = (double)knots[nplusc];
     308             :         }
     309             : 
     310             :         /* generate the basis function for this value of t */
     311        1320 :         rbasis(k, t, npts, knots, h, &(nbasis[0]));
     312        5280 :         for (int j = 1; j <= 3; j++)
     313             :         { /* generate a point on the curve */
     314        3960 :             int jcount = j;
     315        3960 :             p[icount + j] = 0.;
     316             : 
     317       27312 :             for (int i = 1; i <= npts; i++)
     318             :             { /* Do local matrix multiplication */
     319       23352 :                 const double temp = nbasis[i] * b[jcount];
     320       23352 :                 p[icount + j] = p[icount + j] + temp;
     321       23352 :                 jcount = jcount + 3;
     322             :             }
     323             :         }
     324        1320 :         icount = icount + 3;
     325        1320 :         t = t + step;
     326             :     }
     327          30 : }
     328             : 
     329             : /************************************************************************/
     330             : /*                              rbspline()                              */
     331             : /************************************************************************/
     332             : 
     333             : /*  Subroutine to generate a rational B-spline curve using an uniform open knot
     334             :    vector
     335             : 
     336             :     C code for An Introduction to NURBS
     337             :     by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     338             :     All rights reserved.
     339             : 
     340             :     Name: rbspline.c
     341             :     Language: C
     342             :     Subroutines called: knot.c, rbasis.c, fmtmul.c
     343             :     Book reference: Chapter 4, Alg. p. 297
     344             : 
     345             :     b[]         = array containing the defining polygon vertices
     346             :                   b[1] contains the x-component of the vertex
     347             :                   b[2] contains the y-component of the vertex
     348             :                   b[3] contains the z-component of the vertex
     349             :     h[]         = array containing the homogeneous weighting factors
     350             :     k           = order of the B-spline basis function
     351             :     nbasis      = array containing the basis functions for a single value of t
     352             :     nplusc      = number of knot values
     353             :     npts        = number of defining polygon vertices
     354             :     p[,]        = array containing the curve points
     355             :                   p[1] contains the x-component of the point
     356             :                   p[2] contains the y-component of the point
     357             :                   p[3] contains the z-component of the point
     358             :     p1          = number of points to be calculated on the curve
     359             :     t           = parameter value 0 <= t <= npts - k + 1
     360             :     x[]         = array containing the knot vector
     361             : */
     362             : 
     363           0 : void rbspline(int npts, int k, int p1, double b[], double h[], double p[])
     364             : 
     365             : {
     366           0 :     std::vector<double> x(npts + k + 1, 0.0);
     367           0 :     rbspline2(npts, k, p1, b, h, true, &x[0], p);
     368           0 : }
     369             : 
     370             : /************************************************************************/
     371             : /*                              rbsplinu()                              */
     372             : /************************************************************************/
     373             : 
     374             : /*  Subroutine to generate a rational B-spline curve using an uniform periodic
     375             :    knot vector
     376             : 
     377             :     C code for An Introduction to NURBS
     378             :     by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     379             :     All rights reserved.
     380             : 
     381             :     Name: rbsplinu.c
     382             :     Language: C
     383             :     Subroutines called: knotu.c, rbasis.c, fmtmul.c
     384             :     Book reference: Chapter 4, Alg. p. 298
     385             : 
     386             :     b[]         = array containing the defining polygon vertices
     387             :                   b[1] contains the x-component of the vertex
     388             :                   b[2] contains the y-component of the vertex
     389             :                   b[3] contains the z-component of the vertex
     390             :     h[]         = array containing the homogeneous weighting factors
     391             :     k           = order of the B-spline basis function
     392             :     nbasis      = array containing the basis functions for a single value of t
     393             :     nplusc      = number of knot values
     394             :     npts        = number of defining polygon vertices
     395             :     p[,]        = array containing the curve points
     396             :                   p[1] contains the x-component of the point
     397             :                   p[2] contains the y-component of the point
     398             :                   p[3] contains the z-component of the point
     399             :     p1          = number of points to be calculated on the curve
     400             :     t           = parameter value 0 <= t <= npts - k + 1
     401             :     x[]         = array containing the knot vector
     402             : */
     403             : 
     404           0 : void rbsplinu(int npts, int k, int p1, double b[], double h[], double p[])
     405             : 
     406             : {
     407             :     int i, j, icount, jcount;
     408             :     int i1;
     409             :     int nplusc;
     410             : 
     411             :     double step;
     412             :     double t;
     413             :     double temp;
     414           0 :     std::vector<double> nbasis;
     415           0 :     std::vector<double> x;
     416             : 
     417           0 :     nplusc = npts + k;
     418             : 
     419           0 :     x.resize(nplusc + 1);
     420           0 :     nbasis.resize(npts + 1);
     421             : 
     422             :     /*  zero and redimension the knot vector and the basis array */
     423             : 
     424           0 :     for (i = 0; i <= npts; i++)
     425             :     {
     426           0 :         nbasis[i] = 0.;
     427             :     }
     428             : 
     429           0 :     for (i = 0; i <= nplusc; i++)
     430             :     {
     431           0 :         x[i] = 0;
     432             :     }
     433             : 
     434             :     /* generate the uniform periodic knot vector */
     435             : 
     436           0 :     knotu(npts, k, &(x[0]));
     437             : 
     438           0 :     icount = 0;
     439             : 
     440             :     /*    calculate the points on the rational B-spline curve */
     441             : 
     442           0 :     t = k - 1;
     443           0 :     step = ((double)((npts) - (k - 1))) / ((double)(p1 - 1));
     444             : 
     445           0 :     for (i1 = 1; i1 <= p1; i1++)
     446             :     {
     447             : 
     448           0 :         if (x[nplusc] - t < 5e-6)
     449             :         {
     450           0 :             t = x[nplusc];
     451             :         }
     452             : 
     453           0 :         rbasis(
     454           0 :             k, t, npts, &(x[0]), h,
     455           0 :             &(nbasis[0])); /* generate the basis function for this value of t */
     456             : 
     457           0 :         for (j = 1; j <= 3; j++)
     458             :         { /* generate a point on the curve */
     459           0 :             jcount = j;
     460           0 :             p[icount + j] = 0.;
     461             : 
     462           0 :             for (i = 1; i <= npts; i++)
     463             :             { /* Do local matrix multiplication */
     464           0 :                 temp = nbasis[i] * b[jcount];
     465           0 :                 p[icount + j] = p[icount + j] + temp;
     466           0 :                 jcount = jcount + 3;
     467             :             }
     468             :         }
     469           0 :         icount = icount + 3;
     470           0 :         t = t + step;
     471             :     }
     472           0 : }

Generated by: LCOV version 1.14