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: 2026-03-26 23:25:44 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, std::vector<double> &x)
      76             : 
      77             : {
      78             :     int nplusc, /* nplus2, */ i;
      79             : 
      80           0 :     nplusc = n + c;
      81             :     /* nplus2 = n + 2; */
      82             : 
      83             : #if defined(__GNUC__)
      84             : #pragma GCC diagnostic push
      85             : #pragma GCC diagnostic ignored "-Wnull-dereference"
      86             : #endif
      87             : 
      88           0 :     x[1] = 0;
      89           0 :     for (i = 2; i <= nplusc; i++)
      90             :     {
      91           0 :         x[i] = i - 1;
      92             :     }
      93             : 
      94             : #if defined(__GNUC__)
      95             : #pragma GCC diagnostic pop
      96             : #endif
      97           0 : }
      98             : 
      99             : /************************************************************************/
     100             : /*                                knot()                                */
     101             : /************************************************************************/
     102             : 
     103             : /*
     104             :     Subroutine to generate a B-spline open knot vector with multiplicity
     105             :     equal to the order at the ends.
     106             : 
     107             :     c            = order of the basis function
     108             :     n            = the number of defining polygon vertices
     109             :     nplus2       = index of x() for the first occurrence of the maximum knot
     110             :    vector value nplusc       = maximum value of the knot vector -- $n + c$ x()
     111             :    = array containing the knot vector
     112             : */
     113             : 
     114           1 : static void knot(int n, int c, double x[])
     115             : 
     116             : {
     117           1 :     const int nplusc = n + c;
     118           1 :     const int nplus2 = n + 2;
     119             : 
     120           1 :     x[1] = 0.0;
     121          11 :     for (int i = 2; i <= nplusc; i++)
     122             :     {
     123          10 :         if ((i > c) && (i < nplus2))
     124           4 :             x[i] = x[i - 1] + 1.0;
     125             :         else
     126           6 :             x[i] = x[i - 1];
     127             :     }
     128           1 : }
     129             : 
     130             : /************************************************************************/
     131             : /*                               basis()                                */
     132             : /************************************************************************/
     133             : 
     134             : /*  Subroutine to generate B-spline basis functions--open knot vector
     135             : 
     136             :         C code for An Introduction to NURBS
     137             :         by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     138             :         All rights reserved.
     139             : 
     140             :         Name: rbasis (split into rbasis and basis by AT)
     141             :         Language: C
     142             :         Subroutines called: none
     143             :         Book reference: Chapter 4, Sec. 4. , p 296
     144             : 
     145             :     c        = order of the B-spline basis function
     146             :     d        = first term of the basis function recursion relation
     147             :     e        = second term of the basis function recursion relation
     148             :     h[]      = array containing the homogeneous weights
     149             :     npts     = number of defining polygon vertices
     150             :     nplusc   = constant -- npts + c -- maximum number of knot values
     151             :     r[]      = array containing the rationalbasis functions
     152             :                r[1] contains the basis function associated with B1 etc.
     153             :     t        = parameter value
     154             :     N[]      = array output from bbasis containing the values of the
     155             :                basis functions; should have capacity npts + c + 1
     156             :     x[]      = knot vector
     157             : */
     158             : 
     159        1322 : void basis(int c, double t, int npts, double x[], double N[])
     160             : 
     161             : {
     162        1322 :     const int nplusc = npts + c;
     163             : 
     164             :     /* calculate the first order nonrational basis functions n[i] */
     165             : 
     166       13082 :     for (int i = 1; i <= nplusc - 1; i++)
     167             :     {
     168       11760 :         if ((t >= x[i]) && (t < x[i + 1]))
     169        1292 :             N[i] = 1.0;
     170             :         else
     171       10468 :             N[i] = 0.0;
     172             :     }
     173             : 
     174             :     /* calculate the higher order nonrational basis functions */
     175             : 
     176        5288 :     for (int k = 2; k <= c; k++)
     177             :     {
     178       31314 :         for (int i = 1; i <= nplusc - k; i++)
     179             :         {
     180       27348 :             double d = 0.0;
     181       27348 :             double e = 0.0;
     182       27348 :             if (N[i] != 0) /* if the lower order basis function is zero skip the
     183             :                               calculation */
     184             :             {
     185        7656 :                 double denom = x[i + k - 1] - x[i];
     186        7656 :                 if (denom != 0)
     187        7656 :                     d = ((t - x[i]) * N[i]) / denom;
     188             :             }
     189             :             // else
     190             :             //    d = 0.0 ;
     191             : 
     192       27348 :             if (N[i + 1] != 0) /* if the lower order basis function is zero skip
     193             :                                   the calculation */
     194             :             {
     195        7656 :                 double denom = x[i + k] - x[i + 1];
     196        7656 :                 if (denom != 0)
     197        7656 :                     e = ((x[i + k] - t) * N[i + 1]) / denom;
     198             :             }
     199             :             // else
     200             :             //     e = 0.0;
     201             : 
     202       27348 :             N[i] = d + e;
     203             :         }
     204             :     }
     205             : 
     206        1322 :     if (t == (double)x[nplusc])
     207             :     { /* pick up last point */
     208          30 :         N[npts] = 1;
     209             :     }
     210        1322 : }
     211             : 
     212             : /************************************************************************/
     213             : /*                               rbasis()                               */
     214             : /*                                                                      */
     215             : /*      Subroutine to generate rational B-spline basis functions.       */
     216             : /*      See the comment for basis() above.                              */
     217             : /************************************************************************/
     218             : 
     219        1320 : static void rbasis(int c, double t, int npts, double x[], double h[],
     220             :                    double r[])
     221             : 
     222             : {
     223        1320 :     const int nplusc = npts + c;
     224             : 
     225        2640 :     std::vector<double> temp;
     226        1320 :     temp.resize(nplusc + 1);
     227             : 
     228        1320 :     basis(c, t, npts, x, &temp[0]);
     229             : 
     230             :     /* calculate sum for denominator of rational basis functions */
     231             : 
     232        1320 :     double sum = 0.0;
     233        9104 :     for (int i = 1; i <= npts; i++)
     234             :     {
     235        7784 :         sum = sum + temp[i] * h[i];
     236             :     }
     237             : 
     238             :     /* form rational basis functions and put in r vector */
     239             : 
     240        9104 :     for (int i = 1; i <= npts; i++)
     241             :     {
     242        7784 :         if (sum != 0)
     243             :         {
     244        7784 :             r[i] = (temp[i] * h[i]) / (sum);
     245             :         }
     246             :         else
     247             :         {
     248           0 :             r[i] = 0;
     249             :         }
     250             :     }
     251        1320 : }
     252             : 
     253             : /************************************************************************/
     254             : /*                             rbspline2()                              */
     255             : /************************************************************************/
     256             : 
     257             : /*  Subroutine to generate a rational B-spline curve.
     258             : 
     259             :     C code for An Introduction to NURBS
     260             :     by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     261             :     All rights reserved.
     262             : 
     263             :     Name: rbspline.c
     264             :     Language: C
     265             :     Subroutines called: knot.c, rbasis.c, fmtmul.c
     266             :     Book reference: Chapter 4, Alg. p. 297
     267             : 
     268             :     b[]         = array containing the defining polygon vertices
     269             :                   b[1] contains the x-component of the vertex
     270             :                   b[2] contains the y-component of the vertex
     271             :                   b[3] contains the z-component of the vertex
     272             :     h[]         = array containing the homogeneous weighting factors
     273             :     k           = order of the B-spline basis function
     274             :     nbasis      = array containing the basis functions for a single value of t
     275             :     nplusc      = number of knot values
     276             :     npts        = number of defining polygon vertices
     277             :     p[,]        = array containing the curve points
     278             :                   p[1] contains the x-component of the point
     279             :                   p[2] contains the y-component of the point
     280             :                   p[3] contains the z-component of the point
     281             :     p1          = number of points to be calculated on the curve
     282             :     t           = parameter value 0 <= t <= npts - k + 1
     283             :     bCalculateKnots  = when set to true, x will be filled with the knot()
     284             :    routine, otherwise its content will be used. knots[]     = array containing
     285             :    the knot vector (must be npts + k + 1 large)
     286             : */
     287             : 
     288          30 : void rbspline2(int npts, int k, int p1, double b[], double h[],
     289             :                bool bCalculateKnots, double knots[], double p[])
     290             : 
     291             : {
     292          30 :     const int nplusc = npts + k;
     293             : 
     294          60 :     std::vector<double> nbasis;
     295          30 :     nbasis.resize(npts + 1);
     296             : 
     297             :     /* generate the uniform open knot vector */
     298             : 
     299          30 :     if (bCalculateKnots == true)
     300           1 :         knot(npts, k, knots);
     301             : 
     302          30 :     int icount = 0;
     303             : 
     304             :     /*    calculate the points on the rational B-spline curve */
     305             : 
     306          30 :     double t = knots[1];
     307          30 :     const double step = (knots[nplusc] - knots[1]) / ((double)(p1 - 1));
     308             : 
     309          30 :     const double eps = 5e-6 * (knots[nplusc] - knots[1]);
     310             : 
     311        1350 :     for (int i1 = 1; i1 <= p1; i1++)
     312             :     {
     313             :         /* avoid undershooting the final knot */
     314        1320 :         if ((double)knots[nplusc] - t < eps)
     315             :         {
     316          30 :             t = (double)knots[nplusc];
     317             :         }
     318             : 
     319             :         /* generate the basis function for this value of t */
     320        1320 :         rbasis(k, t, npts, knots, h, &(nbasis[0]));
     321        5280 :         for (int j = 1; j <= 3; j++)
     322             :         { /* generate a point on the curve */
     323        3960 :             int jcount = j;
     324        3960 :             p[icount + j] = 0.;
     325             : 
     326       27312 :             for (int i = 1; i <= npts; i++)
     327             :             { /* Do local matrix multiplication */
     328       23352 :                 const double temp = nbasis[i] * b[jcount];
     329       23352 :                 p[icount + j] = p[icount + j] + temp;
     330       23352 :                 jcount = jcount + 3;
     331             :             }
     332             :         }
     333        1320 :         icount = icount + 3;
     334        1320 :         t = t + step;
     335             :     }
     336          30 : }
     337             : 
     338             : /************************************************************************/
     339             : /*                              rbspline()                              */
     340             : /************************************************************************/
     341             : 
     342             : /*  Subroutine to generate a rational B-spline curve using an uniform open knot
     343             :    vector
     344             : 
     345             :     C code for An Introduction to NURBS
     346             :     by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     347             :     All rights reserved.
     348             : 
     349             :     Name: rbspline.c
     350             :     Language: C
     351             :     Subroutines called: knot.c, rbasis.c, fmtmul.c
     352             :     Book reference: Chapter 4, Alg. p. 297
     353             : 
     354             :     b[]         = array containing the defining polygon vertices
     355             :                   b[1] contains the x-component of the vertex
     356             :                   b[2] contains the y-component of the vertex
     357             :                   b[3] contains the z-component of the vertex
     358             :     h[]         = array containing the homogeneous weighting factors
     359             :     k           = order of the B-spline basis function
     360             :     nbasis      = array containing the basis functions for a single value of t
     361             :     nplusc      = number of knot values
     362             :     npts        = number of defining polygon vertices
     363             :     p[,]        = array containing the curve points
     364             :                   p[1] contains the x-component of the point
     365             :                   p[2] contains the y-component of the point
     366             :                   p[3] contains the z-component of the point
     367             :     p1          = number of points to be calculated on the curve
     368             :     t           = parameter value 0 <= t <= npts - k + 1
     369             :     x[]         = array containing the knot vector
     370             : */
     371             : 
     372           0 : void rbspline(int npts, int k, int p1, double b[], double h[], double p[])
     373             : 
     374             : {
     375           0 :     std::vector<double> x(npts + k + 1, 0.0);
     376           0 :     rbspline2(npts, k, p1, b, h, true, &x[0], p);
     377           0 : }
     378             : 
     379             : /************************************************************************/
     380             : /*                              rbsplinu()                              */
     381             : /************************************************************************/
     382             : 
     383             : /*  Subroutine to generate a rational B-spline curve using an uniform periodic
     384             :    knot vector
     385             : 
     386             :     C code for An Introduction to NURBS
     387             :     by David F. Rogers. Copyright (C) 2000 David F. Rogers,
     388             :     All rights reserved.
     389             : 
     390             :     Name: rbsplinu.c
     391             :     Language: C
     392             :     Subroutines called: knotu.c, rbasis.c, fmtmul.c
     393             :     Book reference: Chapter 4, Alg. p. 298
     394             : 
     395             :     b[]         = array containing the defining polygon vertices
     396             :                   b[1] contains the x-component of the vertex
     397             :                   b[2] contains the y-component of the vertex
     398             :                   b[3] contains the z-component of the vertex
     399             :     h[]         = array containing the homogeneous weighting factors
     400             :     k           = order of the B-spline basis function
     401             :     nbasis      = array containing the basis functions for a single value of t
     402             :     nplusc      = number of knot values
     403             :     npts        = number of defining polygon vertices
     404             :     p[,]        = array containing the curve points
     405             :                   p[1] contains the x-component of the point
     406             :                   p[2] contains the y-component of the point
     407             :                   p[3] contains the z-component of the point
     408             :     p1          = number of points to be calculated on the curve
     409             :     t           = parameter value 0 <= t <= npts - k + 1
     410             :     x[]         = array containing the knot vector
     411             : */
     412             : 
     413           0 : void rbsplinu(int npts, int k, int p1, double b[], double h[], double p[])
     414             : 
     415             : {
     416             :     int i, j, icount, jcount;
     417             :     int i1;
     418             :     int nplusc;
     419             : 
     420             :     double step;
     421             :     double t;
     422             :     double temp;
     423           0 :     std::vector<double> nbasis;
     424           0 :     std::vector<double> x;
     425             : 
     426           0 :     nplusc = npts + k;
     427             : 
     428           0 :     x.resize(nplusc + 1);
     429           0 :     nbasis.resize(npts + 1);
     430             : 
     431             :     /*  zero and redimension the knot vector and the basis array */
     432             : 
     433           0 :     for (i = 0; i <= npts; i++)
     434             :     {
     435           0 :         nbasis[i] = 0.;
     436             :     }
     437             : 
     438           0 :     for (i = 0; i <= nplusc; i++)
     439             :     {
     440           0 :         x[i] = 0;
     441             :     }
     442             : 
     443             :     /* generate the uniform periodic knot vector */
     444             : 
     445           0 :     knotu(npts, k, x);
     446             : 
     447           0 :     icount = 0;
     448             : 
     449             :     /*    calculate the points on the rational B-spline curve */
     450             : 
     451           0 :     t = k - 1;
     452           0 :     step = ((double)((npts) - (k - 1))) / ((double)(p1 - 1));
     453             : 
     454           0 :     for (i1 = 1; i1 <= p1; i1++)
     455             :     {
     456             : 
     457           0 :         if (x[nplusc] - t < 5e-6)
     458             :         {
     459           0 :             t = x[nplusc];
     460             :         }
     461             : 
     462           0 :         rbasis(
     463           0 :             k, t, npts, &(x[0]), h,
     464           0 :             &(nbasis[0])); /* generate the basis function for this value of t */
     465             : 
     466           0 :         for (j = 1; j <= 3; j++)
     467             :         { /* generate a point on the curve */
     468           0 :             jcount = j;
     469           0 :             p[icount + j] = 0.;
     470             : 
     471           0 :             for (i = 1; i <= npts; i++)
     472             :             { /* Do local matrix multiplication */
     473           0 :                 temp = nbasis[i] * b[jcount];
     474           0 :                 p[icount + j] = p[icount + j] + temp;
     475           0 :                 jcount = jcount + 3;
     476             :             }
     477             :         }
     478           0 :         icount = icount + 3;
     479           0 :         t = t + step;
     480             :     }
     481           0 : }

Generated by: LCOV version 1.14