View Javadoc
1   package org.djutils.draw.curve;
2   
3   /**
4    * Common code used to generated Bézier curves.
5    * <p>
6    * Copyright (c) 2013-2025 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
7    * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
8    * </p>
9    * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
10   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
11   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
12   */
13  public final class Bezier
14  {
15      /** T values of numerical approach of Legendre-Gauss to determine B&eacute;zier length. */
16      static final double[] T =
17              new double[] {-0.0640568928626056260850430826247450385909, 0.0640568928626056260850430826247450385909,
18                      -0.1911188674736163091586398207570696318404, 0.1911188674736163091586398207570696318404,
19                      -0.3150426796961633743867932913198102407864, 0.3150426796961633743867932913198102407864,
20                      -0.4337935076260451384870842319133497124524, 0.4337935076260451384870842319133497124524,
21                      -0.5454214713888395356583756172183723700107, 0.5454214713888395356583756172183723700107,
22                      -0.6480936519369755692524957869107476266696, 0.6480936519369755692524957869107476266696,
23                      -0.7401241915785543642438281030999784255232, 0.7401241915785543642438281030999784255232,
24                      -0.8200019859739029219539498726697452080761, 0.8200019859739029219539498726697452080761,
25                      -0.8864155270044010342131543419821967550873, 0.8864155270044010342131543419821967550873,
26                      -0.9382745520027327585236490017087214496548, 0.9382745520027327585236490017087214496548,
27                      -0.9747285559713094981983919930081690617411, 0.9747285559713094981983919930081690617411,
28                      -0.9951872199970213601799974097007368118745, 0.9951872199970213601799974097007368118745};
29  
30      /** C values of numerical approach of Legendre-Gauss to determine B&eacute;zier length. */
31      static final double[] C =
32              new double[] {0.1279381953467521569740561652246953718517, 0.1279381953467521569740561652246953718517,
33                      0.1258374563468282961213753825111836887264, 0.1258374563468282961213753825111836887264,
34                      0.121670472927803391204463153476262425607, 0.121670472927803391204463153476262425607,
35                      0.1155056680537256013533444839067835598622, 0.1155056680537256013533444839067835598622,
36                      0.1074442701159656347825773424466062227946, 0.1074442701159656347825773424466062227946,
37                      0.0976186521041138882698806644642471544279, 0.0976186521041138882698806644642471544279,
38                      0.086190161531953275917185202983742667185, 0.086190161531953275917185202983742667185,
39                      0.0733464814110803057340336152531165181193, 0.0733464814110803057340336152531165181193,
40                      0.0592985849154367807463677585001085845412, 0.0592985849154367807463677585001085845412,
41                      0.0442774388174198061686027482113382288593, 0.0442774388174198061686027482113382288593,
42                      0.0285313886289336631813078159518782864491, 0.0285313886289336631813078159518782864491,
43                      0.0123412297999871995468056670700372915759, 0.0123412297999871995468056670700372915759};
44  
45      /** The default number of points to use to construct a B&eacute;zier curve. */
46      public static final int DEFAULT_BEZIER_SIZE = 64;
47  
48      /** Cached factorial values. */
49      private static long[] fact = new long[] {1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L,
50              479001600L, 6227020800L, 87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L,
51              121645100408832000L, 2432902008176640000L};
52  
53      /** Utility class. */
54      private Bezier()
55      {
56          // do not instantiate
57      }
58  
59      /**
60       * Calculate the B&eacute;zier point of degree n, with B(t) = &Sigma;(i = 0..n) [C(n, i) * (1 - t)<sup>n-i</sup>
61       * t<sup>i</sup> P<sub>i</sub>], where C(n, k) is the binomial coefficient defined by n! / ( k! (n-k)! ), ! being the
62       * factorial operator.
63       * @param t the fraction
64       * @param p the points of the curve, where the first and last are begin and end point, and all intermediate ones
65       *            are control points
66       * @return the B&eacute;zier value B(t) of degree n, where n is the number of points in the <code>p</code> array
67       */
68      @SuppressWarnings("checkstyle:methodname")
69      static double Bn(final double t, final double... p)
70      {
71          if (p.length == 0)
72          {
73              return 0.0;
74          }
75          double b = 0.0;
76          double m = (1.0 - t);
77          int n = p.length - 1;
78          double fn = factorial(n);
79          for (int i = 0; i <= n; i++)
80          {
81              double c = fn / (factorial(i) * (factorial(n - i)));
82              b += c * Math.pow(m, n - i) * Math.pow(t, i) * p[i];
83          }
84          return b;
85      }
86  
87      /**
88       * Calculate factorial(k), which is k * (k-1) * (k-2) * ... * 1. For factorials up to 20, a lookup table is used.
89       * @param k the parameter
90       * @return k!
91       */
92      private static double factorial(final int k)
93      {
94          if (k < fact.length)
95          {
96              return fact[k];
97          }
98          double f = 1;
99          for (int i = 2; i <= k; i++)
100         {
101             f = f * i;
102         }
103         return f;
104     }
105 
106     /**
107      * Returns the derivative for one dimension of a B&eacute;zier, which is a B&eacute;zier of 1 order lower.
108      * @param in coefficients of one dimension of a B&eacute;zier
109      * @return coefficients of one dimension of the derivative B&eacute;zier
110      */
111     public static double[] derivative(final double[] in)
112     {
113         if (in.length == 0) // Derivative of a zero order B&eacute;zier is a zero order B&eacute;zier
114         {
115             return in; //  No need to create a new one
116         }
117         int n = in.length - 1;
118         double[] result = new double[n];
119         for (int i = 0; i < n; i++)
120         {
121             result[i] = n * (in[i + 1] - in[i]);
122         }
123         return result;
124     }
125 
126 }