当前位置: 首页 > news >正文

计算机图形学中的曲线问题

文章目录

    • 免责
    • 前言
    • 拉格朗日插值多项式
      • 第一步:得到一个基函数
      • 第二步:得到所有基函数
      • 第三步:对所有基函数进行线性组合
      • 举例验证
    • 三次埃尔米特插值多项式
      • 第一步:得到第一维基函数
      • 第二步:得到第二维基函数
      • 第三步:对基函数进行线性组合
      • 一些后话
    • 规范化的三次埃尔米特多项式
      • 第一步:得到第一维基函数
      • 第二步:得到第二维基函数
      • 第三步:对基函数进行线性组合
      • 一些后话
    • 讲点儿时的回忆
    • 三次贝塞尔曲线
      • 三次贝塞尔曲线的光滑拼接
      • 三次伯恩斯坦基函数
      • 贝塞尔曲线的几何作图法
    • 三次均匀 B 样条曲线
      • 局部基函数及其混淆
      • 四阶三次均匀 B 样条曲线
      • B 样条绘制范例
    • 未完待续 ...
    • 一个理念

免责

又来快乐地误人子弟了。 最近学习了一些计算机图形学中的曲线与曲面,感觉很多东西还是蛮有趣的,就打算写篇文章总结总结。
文章中如有疏漏,请联系 premierbob2015@gmail.com 进行更正,笔者感激不尽。

前言

在工业设计中,我们经常会遇到各种各样的绘图问题。随着计算机技术的发展,现代的工业设计正在逐步脱离纸质的工图,转而使用由计算机辅助绘图并设计的电子工图。这种电子版的设计图不仅便于存储与传输,还能更直接地转化为控制数控机床 / 3D打印机 的控制信号,实现工业生产的全自动化。

经过先前的学习,我们了解到在计算机中存储的图像大致可分为点阵图矢量图两类。作为存储图像的不同格式,点阵图和矢量图各有千秋。而上文中所说的电子工图往往使用矢量图的格式进行存储。

优点缺点
点阵图易于从相机等设备直接获得,适合近似描述真实世界中的事物使用像素矩阵存储,不能无限放大,放大会使得图像变得不清晰
矢量图使用函数或参数方程存储图像,可以无限放大难以从相机等设备直接获得

本文并不介绍这些图纸在计算机中具体以何种矢量图格式存储,只在数学层面介绍一些非常简单的曲线,而这些曲线在工业设计中有着广泛的应用。(当然,我对工业设计没啥兴趣,我只希望自己将来有一天,能够开发一款用于动漫的绘制辅助工具——属于是老二刺螈了。)

拉格朗日插值多项式

两点确定一条直线,三点确定一条二次函数,不难让我们联想到 nnn 个定点能唯一确定一条的 n−1n-1n1 次多项式曲线。形式化的来说给定函数上的 nnn 个横坐标互不相同的点:
P1=(x1,y1),P2=(x2,y2),⋯,Pn=(xn,yn)P_1=(x_1, y_1), P_2=(x_2, y_2), \cdots, P_n=(x_n, y_n) P1=(x1,y1),P2=(x2,y2),,Pn=(xn,yn)
我们能够唯一地确定一个多项式函数:
y=an−1xn−1+an−2xn−2+⋯+a1x+a0y=a_{n-1}x^{n-1}+a_{n-2}x^{n-2}+\cdots+a_1x+a_0 y=an1xn1+an2xn2++a1x+a0
其中 a0,a1,⋯,an−1a_{0}, a_1, \cdots, a_{n-1}a0,a1,,an1 是函数中的参数,xxx 是自变量,yyy 是因变量。唯一地确定就是指,将这 nnn 个点坐标带入函数中后,我们恰好能够得到系数向量 a0,a1,⋯,an−1a_0, a_1, \cdots, a_{n-1}a0,a1,,an1 的一个唯一解。严谨的证明可以参考范德蒙德行列式,在此不再赘述。

对于拉格朗日插值而言,即使我们没有从数学上证明这种唯一确定性,按照下面给出的方法,我们也可以使用一种构造性的方式构造出一个恰好通过 P1,P2,⋯,PnP_1, P_2, \cdots, P_nP1,P2,,Pnnnn 个点的一个 n−1n-1n1 次函数。

第一步:得到一个基函数

既然我们不能很轻松地让我们的曲线经过所有点,那我们就先试着让我们的曲线经过其中的一个点而在其他点横坐标对应位置的值为零。令 x1,x2,⋯,xnx_1, x_2, \cdots, x_nx1,x2,,xn 为互不相同的常数,我们能否构造一个 n−1n-1n1 次多项式函数 f1(x)f_1(x)f1(x) 使得 :

  1. f1(x1)=1f_1(x_1)=1f1(x1)=1
  2. f1(x2)=f1(x3)=⋯=f1(xn)=0f_1(x_2)=f_1(x_3)=\cdots=f_1(x_n)=0f1(x2)=f1(x3)==f1(xn)=0

很显然是可以的。首先看到这个函数 f1(x)f_1(x)f1(x)n−1n-1n1 个零点,分别是 x2,x3,⋯,xnx_2, x_3, \cdots, x_nx2,x3,,xn,我们很自然地想到设 g1(x)=(x−x2)(x−x3)⋯(x−xn)g_1(x) = (x-x_2)(x-x_3)\cdots(x-x_n)g1(x)=(xx2)(xx3)(xxn)。虽然这个函数已经满足了 g1(x2)=g1(x3)=⋯=g1(xn)=0g_1(x_2)=g_1(x_3)=\cdots=g_1(x_n)=0g1(x2)=g1(x3)==g1(xn)=0 这一条件,但是我们并不能保证 g1(x1)=1g_1(x_1)=1g1(x1)=1。由于 x1,x2,⋯,xnx_1, x_2, \cdots, x_nx1,x2,,xn 互不相同,所以 g(x1)=(x1−x2)(x1−x3)⋯(x1−xn)g(x_1)=(x_1-x_2)(x_1-x_3)\cdots(x_1-x_n)g(x1)=(x1x2)(x1x3)(x1xn) 一定不等于零。不妨令:
f1(x)=g1(x)g1(x1)f_1(x)=\frac{g_1(x)}{g_1(x_1)} f1(x)=g1(x1)g1(x)

因为 x1x_1x1 是常数,所以 g1(x1)g_1(x_1)g1(x1) 就是常数,而这样得到的 f1(x)f_1(x)f1(x) 是在 g1(x)g_1(x)g1(x) 基础之上进行了一次常数倍的缩放。此时我们所要求的两个条件就都被满足了。

第二步:得到所有基函数

在第一步中,我们定义了一个名为 fif_ifi 的函数。仿照第一步的思路,对于 i=1,2,⋯,ni=1, 2, \cdots, ni=1,2,,n,我们定义:
fi(x)=gi(x)gi(xi)f_i(x)=\frac{g_i(x)}{g_i(x_i)} fi(x)=gi(xi)gi(x)

其中:
gi(x)=∏j=1,2,⋯n且j≠i(x−xj)g_i(x)=\prod_{ j=1,2,\cdots n 且 j\neq i }(x-x_j) gi(x)=j=1,2,nj=i(xxj)

我们就得到了 nnn 个函数 f1(x),f2(x),⋯,fn(x)f_1(x), f_2(x), \cdots, f_n(x)f1(x),f2(x),,fn(x),根据第一步中的描述,fi(x)f_i(x)fi(x) 一定满足:

  1. fi(xi)=1f_i(x_i)=1fi(xi)=1
  2. fi(xj)=0,f_i(x_j)=0,fi(xj)=0,j=1,2,⋯,nj=1, 2, \cdots, nj=1,2,,nj≠ij\neq ij=i

这些函数如此的重要以至于我们要给这些函数起一个好听的名字——拉格朗日基函数。

第三步:对所有基函数进行线性组合

有了拉格朗日基函数后,我们令:

f(x)=y1⋅f1(x)+y2⋅f2(x)⋯+yn⋅fn(x)f(x)=y_1\cdot f_1(x)+y_2\cdot f_2(x)\cdots +y_n\cdot f_n(x) f(x)=y1f1(x)+y2f2(x)+ynfn(x)

我们可以断言,函数 f(x)f(x)f(x) 一定经过点 P1(x1,y1),P2(x2,y2),⋯Pn(xn,yn)P_1(x_1, y_1), P_2(x_2, y_2), \cdots P_n(x_n, y_n)P1(x1,y1),P2(x2,y2),Pn(xn,yn)。例如,当 x=x1x=x_1x=x1 时,f1(x)=f1(x1)=1f_1(x)=f_1(x_1)=1f1(x)=f1(x1)=1f2(x)=f3(x)=⋯=fn(x)=0f_2(x)=f_3(x)=\cdots=f_n(x)=0f2(x)=f3(x)==fn(x)=0。因此:
f(x1)=y1⋅1+y2⋅0+y3⋅0+⋯+yn⋅0=y1f(x_1)=y_1\cdot1+y_2\cdot0+y_3\cdot0+\cdots+y_n\cdot 0=y_1 f(x1)=y11+y20+y30++yn0=y1

对于 f(x2)=y2,f(x3)=y3,⋯,f(xn)=ynf(x_2)=y_2, f(x_3)=y_3, \cdots, f(x_ n)=y_nf(x2)=y2,f(x3)=y3,,f(xn)=yn 我们也可以使用同样的方法进行验证。

举例验证

假设一条曲线经过点 (−1,−14),(0,−4),(1,−4),(2,10)(-1, -14), (0, -4), (1, -4), (2, 10)(1,14),(0,4),(1,4),(2,10)。则可以计算出:

y1f1y_1f_1y1f1y2f2y_2f_2y2f2y3f3y_3f_3y3f3y4f4y_4f_4y4f4
yifi(x)y_if_i(x)yifi(x)73(x−0)(x−1)(x−2)\frac 7 3(x-0)(x-1)(x-2)37(x0)(x1)(x2)−2(x+1)(x−1)(x−2)-2(x+1)(x-1)(x-2)2(x+1)(x1)(x2)2(x+1)(x−0)(x−2)2(x+1)(x-0)(x-2)2(x+1)(x0)(x2)53(x+1)(x−0)(x−1)\frac 5 3 (x+1)(x-0)(x-1)35(x+1)(x0)(x1)
yifi(−1)y_if_i(-1)yifi(1)−14-1414000000000
yifi(0)y_if_i(0)yifi(0)000−4-44000000
yifi(1)y_if_i(1)yifi(1)000000−4-44000
yifi(2)y_if_i(2)yifi(2)000000000101010

三次埃尔米特插值多项式

在工业设计中,有时我们不仅需要指定一条曲线经过哪些点,我们还需要指定这条曲线在某些位置的导数。

考虑一个最简单的情况:设 f(x)=a3⋅x3+a2⋅x2+a1⋅x+a0f(x)=a_3\cdot x^3+a_2\cdot x^2 + a_1 \cdot x + a_0f(x)=a3x3+a2x2+a1x+a0 是一个三次多项式。我们要找到一个 f(x)f(x)f(x) 使得它经过点 P0(x0,y0)P_0(x_0, y_0)P0(x0,y0)P1(x1,y1)P_1(x_1, y_1)P1(x1,y1) 且在点 P0P_0P0 处的导数为 y0′y_0'y0,在点 P1P_1P1 处的导数为 y1′y_1'y1,其中 x0,x1,y0,y1,y0′,y1′x_0, x_1, y_0, y_1, y_0', y_1'x0,x1,y0,y1,y0,y1 均为常数。

使用类似拉格朗日插值法中的构造方法,我们也能够得到这个 f(x)f(x)f(x)

第一步:得到第一维基函数

x0≠x1x_0\neq x_1x0=x1 且二者均为常数,令 p0(x)p_0(x)p0(x) 是一个三次多项式,它满足如下两个性质:

  1. p0(x0)=1p_0(x_0)=1p0(x0)=1
  2. p0(x1)=0,p0′(x1)=0p_0(x_1)=0, p_0'(x_1)=0p0(x1)=0,p0(x1)=0

由于 p0(x1)=p0′(x1)=0p_0(x_1)=p_0'(x_1)=0p0(x1)=p0(x1)=0,我们很直观地感受到,x1x_1x1 应该是函数 p0(x)p_0(x)p0(x) 的重根。不妨令 g0(x)=(x−x1)2g_0(x)=(x-x_1)^2g0(x)=(xx1)2,那么我们有 g0′(x)=2(x−x1)g_0'(x)=2(x-x_1)g0(x)=2(xx1),因此 g0(x1)=g0′(x1)=0g_0(x_1)=g_0'(x_1)=0g0(x1)=g0(x1)=0

按照拉格朗日插值的思路,我们构造了一个函数:
p0(x)=g0(x)g0(x0)p_0(x)=\frac{g_0(x)}{g_0(x_0)} p0(x)=g0(x0)g0(x)

因为 x0x_0x0 是常数,所以 g0(x0)g_0(x_0)g0(x0) 也是常数,我们可以看到:

p0(x0)=1(因为我们构造的系数恰好是g0(x0)的倒数)p0′(x0)=g0′(x0)g0(x0)=2(x0−x1)(x0−x1)2=2x0−x1≠0p0(x1)=p0′(x1)=0\begin{aligned} p_0(x_0) &=1\;(因为我们构造的系数恰好是g_0(x_0)的倒数)\\ p_0'(x_0) &=\frac{g_0'(x_0)}{g_0(x_0)}=\frac{2(x_0-x_1)}{(x_0-x_1)^2}=\frac{2}{x_0-x_1}\neq 0\\ p_0(x_1) &=p_0'(x_1)=0 \end{aligned} p0(x0)p0(x0)p0(x1)=1(g0(x0))=g0(x0)g0(x0)=(x0x1)22(x0x1)=x0x12=0=p0(x1)=0

有了函数 p0p_0p0,我们就可以在不改变 p0(x1)p_0(x_1)p0(x1)p0′(x1)p_0'(x_1)p0(x1) 的值的前提下随意控制 p0(x0)p_0(x_0)p0(x0) 的值了。但是现在我们还无法控制 p0′(x0)p_0'(x_0)p0(x0) 的值。因此我们要在第二步构造一个函数,使得我们能够分离 p0′(x0)p_0'(x_0)p0(x0)p0(x0)p_0(x_0)p0(x0) 之间的倍数关系。

第二步:得到第二维基函数

类似第一步,我们还需要构造三次函数 q0(x)q_0(x)q0(x) 满足这样两条性质:

  1. q0(x0)=0,q0′(x0)=1q_0(x_0)=0, q_0'(x_0)=1q0(x0)=0,q0(x0)=1
  2. q0(x1)=0,q0′(x1)=0q_0(x_1)=0, q_0'(x_1)=0q0(x1)=0,q0(x1)=0

看起来也不难构造,零点又多了一个 x0x_0x0。令 k0(x)=(x−x0)(x−x1)2k_0(x)=(x-x_0)(x-x_1)^2k0(x)=(xx0)(xx1)2,则:
k0′(x)=(x−x1)2+2(x−x0)(x−x1)=(x−x1)(3x−2x0−x1)k_0'(x)=(x-x_1)^2+2(x-x_0)(x-x_1)=(x-x_1)(3x-2x_0-x_1) k0(x)=(xx1)2+2(xx0)(xx1)=(xx1)(3x2x0x1)

令:
q0(x)=k0(x)k0′(x0)q_0(x)=\frac{k_0(x)}{k_0'(x_0)}q0(x)=k0(x0)k0(x)

由于 x0x_0x0 是常数因此 k0′(x0)=(x0−x1)2k_0'(x_0)=(x_0-x_1)^2k0(x0)=(x0x1)2 也是常数,我们可以看到:
q0(x0)=0(因为k0(x0)=0)q0′(x0)=1(因为我们构造的系数恰好是k0′(x0)的倒数)q0(x1)=q0′(x1)=0\begin{aligned} q_0(x_0)&=0\;(因为k_0(x_0)=0)\\ q_0'(x_0)&=1\;(因为我们构造的系数恰好是k_0'(x_0)的倒数)\\ q_0(x_1)&=q_0'(x_1)=0 \end{aligned} q0(x0)q0(x0)q0(x1)=0(k0(x0)=0)=1(k0(x0))=q0(x1)=0

第三步:对基函数进行线性组合

开门见山,令:
f0(x)=y0⋅(p0(x)−2x0−x1⋅q0(x))+y0′⋅q0(x)f_0(x)=y_0\cdot (p_0(x)-\frac{2}{x_0-x_1}\cdot q_0(x))+y_0'\cdot q_0(x) f0(x)=y0(p0(x)x0x12q0(x))+y0q0(x)

为什么要这么构造呢?p0(x)p_0(x)p0(x)x0x_0x0 处的导数值为 2x0−x1≠0\frac{2}{x_0-x_1}\neq 0x0x12=0,因此在它身上减去一个 2x0−x1⋅q0(x)\frac{2}{x_0-x_1}\cdot q_0(x)x0x12q0(x) 就能使得它在 x0x_0x0 处的导数为零,而由于 q0(x)q_0(x)q0(x)x1x_1x1 点的函数值和导数值都为零,因此无论我们如何将 p0(x)p_0(x)p0(x)q0(x)q_0(x)q0(x) 进行线性组合,都不会影响函数在 x1x_1x1 点处的函数值和导数值。

此时函数 f0(x)f_0(x)f0(x) 满足:

  1. f0(x0)=y0,f0′(x0)=y0′f_0(x_0)=y_0,f_0'(x_0)=y_0'f0(x0)=y0,f0(x0)=y0
  2. f0(x1)=0,f0′(x1)=0f_0(x_1)=0, f_0'(x_1)=0f0(x1)=0,f0(x1)=0

类似地,我们可以使用同样的方法得到一个函数 f1(x)f_1(x)f1(x),满足:

  1. f1(x0)=0,f1′(x0)=0f_1(x_0)=0,f_1'(x_0)=0f1(x0)=0,f1(x0)=0
  2. f1(x1)=y1,f1′(x1)=y1′f_1(x_1)=y_1, f_1'(x_1)=y_1'f1(x1)=y1,f1(x1)=y1

具体怎么做不再赘述,整理后得到的表达式我也不是很关心。我所关心的只有一件事那就是,当我们令 f(x)=f0(x)+f1(x)f(x)=f_0(x)+f_1(x)f(x)=f0(x)+f1(x),这样得到的 f(x)f(x)f(x) 一定经过 P0(x0,y0)P_0(x_0, y_0)P0(x0,y0)P1(x1,y1)P_1(x_1, y_1)P1(x1,y1) 且在点 P0P_0P0 处的导数为 y0′y_0'y0,在点 P1P_1P1 处的导数为 y1′y_1'y1

一些后话

如果我们想要找到一个函数使得他定义在 [x1,xn][x_1, x_n][x1,xn] 上且函数光滑(可导),且经过点 P1(x1,y1),P2(x2,y2),⋯,Pn(xn,yn)P_1(x_1, y_1), P_2(x_2, y_2), \cdots, P_n(x_n, y_n)P1(x1,y1),P2(x2,y2),,Pn(xn,yn),且在 PiP_iPi 处导数值为 yi′y_i'yii=1,2⋯,ni=1, 2\cdots, ni=1,2,n),其中 xi,yi,yi′x_i, y_i, y_i'xi,yi,yi 均为常数(i=1,2,⋯,ni=1, 2, \cdots, ni=1,2,,n),且满足 x1<x2<⋯<xnx_1<x_2<\cdots<x_nx1<x2<<xn

我们可以在区间 [x1,x2][x_1, x_2][x1,x2] 上依据 y1,y2,y1′,y2′y_1, y_2, y_1', y_2'y1,y2,y1,y2 构造一个三次埃尔米特插值函数,在 [x2,x3][x_2, x_3][x2,x3] 上依据 y2,y3,y2′,y3y_2, y_3, y_2', y_3y2,y3,y2,y3 构造插值函数,⋯\cdots,在 [xn−1,xn][x_{n-1}, x_{n}][xn1,xn] 上根据 yn−1,yn,yn−1′,yn′y_{n-1}, y_{n}, y_{n-1}', y_n'yn1,yn,yn1,yn 构造插值函数。最后再将每一段上的函数以分段函数的形式连接起来,由于连接点处的左右函数值、左右导数值均相等,因此函数在区间 (x1,xn)(x_1, x_n)(x1,xn) 上光滑。

规范化的三次埃尔米特多项式

如果我们的目的只是绘制一个函数,使用普通的埃尔米特多项式似乎已经实现了我们想要的。但是函数这东西,自变量 xxx 的每一个取值至多只有一个 yyy 值与之对应,如果我想绘制任意平面曲线甚至空间曲线,那上文给出的方法就不那么好用了。想到可以用参数方程的方法来实现。

  • 下文中我们令P0,P1,D0,D1P_0, P_1, D_0, D_1P0,P1,D0,D1 是二维常向量,我们要构造参数方程 f⃗(t)\vec{f}(t)f(t) 使得 f⃗(0)=P0,f⃗(1)=P1,∇f⃗(0)=D0,∇f⃗(1)=D1\vec f (0)=P_0, \vec f(1) = P_1, \nabla \vec f(0) = D_0, \nabla \vec f(1)=D_1f(0)=P0,f(1)=P1,f(0)=D0,f(1)=D1

注:梯度算子 ∇\nabla,其实就是对函数值的 xxxyyy 分量函数分别求导,例如当 f⃗(t)=[fx(t),fy(t)]\vec f(t) = [f_x(t), f_y(t)]f(t)=[fx(t),fy(t)]∇f⃗(t)=[fx′(t),fy′(t)]\nabla \vec f(t)=[f_x'(t), f_y'(t)]f(t)=[fx(t),fy(t)]

对于一个标量函数 f(t)f(t)f(t) 而言,假如 P∈R2P\in \R^2PR2 是一个二维常向量(即 Px,Py∈RP_x, P_y\in \RPx,PyR 是两个常数),那么 Pf(t)=[Pxf(t),Pyf(t)]Pf(t)=[P_xf(t), P_yf(t)]Pf(t)=[Pxf(t),Pyf(t)] 就是一个平面上的参数方程。对这个函数计算梯度,得到 ∇(Pf(t))=[Pxf′(t),Pyf′(t)]=P⋅f′(t)\nabla(Pf(t))=[P_xf'(t), P_yf'(t)]=P\cdot f'(t)(Pf(t))=[Pxf(t),Pyf(t)]=Pf(t)。此处的点运算 ‘⋅\cdot’ 不表示向量的内积,而表示“数乘”,其中 P∈R2P\in \R^2PR2 是 “向量”,f(t)∈Rf(t)\in \Rf(t)R 是定义在实数上的标量函数。

类似上文的方法,我们仍然可以构造出符合条件的向量函数 f⃗(t)\vec f(t)f(t)

第一步:得到第一维基函数

在这一步中我们要构造标量函数 p0(t)p_0(t)p0(t)p1(t)p_1(t)p1(t),其中 p0(t)p_0(t)p0(t) 满足:

  1. p0(0)=1p_0(0)=1p0(0)=1;
  2. p0(1)=0,p0′(1)=0p_0(1)=0, p_0'(1)=0p0(1)=0,p0(1)=0;

同理,p1(t)p_1(t)p1(t) 满足:

  1. p1(1)=1p_1(1)=1p1(1)=1
  2. p1(0)=0,p1′(0)=0p_1(0)=0, p_1'(0)=0p1(0)=0,p1(0)=0

为了方便表述,我们把 p0(t)p_0(t)p0(t) 称为 t=0t=0t=0 处的常数控制基函数p1(t)p_1(t)p1(t) 称为 t=1t=1t=1 处的常数控制基函数,它们的存在就是为了用于将它们线性组合以调整函数在 t=0t=0t=0 处以及 t=1t=1t=1 处的函数值。

由于这两个函数都比较简单,稍微构造构造就能构造出来(拿眼睛看就能看出来,不信你试试):
p0(t)=(t−1)2p1(t)=t2\begin{aligned} p_0(t)&=(t-1)^2\\ p_1(t)&=t^2 \end{aligned} p0(t)p1(t)=(t1)2=t2

为了方便下一步中消去 p0(t)p_0(t)p0(t)p1(t)p_1(t)p1(t) 对导数的影响,我们可以提前计算出 p0′(0)p_0'(0)p0(0)p1′(1)p_1'(1)p1(1)

p0′(t)=2(t−1)∴p0′(0)=−2p1′(t)=2t∴p1′(1)=2\begin{aligned} p_0'(t)&=2(t-1)& \therefore p_0'(0)&=-2\\ p_1'(t)&=2t& \therefore p_1'(1)&=2 \end{aligned} p0(t)p1(t)=2(t1)=2tp0(0)p1(1)=2=2

第二步:得到第二维基函数

类似上文中对三次埃尔米特插值多项式的构造,我们要构造 q0(t)q_0(t)q0(t)q1(t)q_1(t)q1(t),其中 q0(t)q_0(t)q0(t) 满足:

  1. q0(0)=0,q0′(0)=1q_0(0)=0, q_0'(0)=1q0(0)=0,q0(0)=1
  2. q0(1)=0,q0′(1)=0q_0(1)=0, q_0'(1)=0q0(1)=0,q0(1)=0

类似地,q1(t)q_1(t)q1(t) 满足:

  1. q1(0)=0,q1′(0)=0q_1(0) = 0, q_1'(0) = 0q1(0)=0,q1(0)=0
  2. q1(1)=0,q1′(1)=1q_1(1) = 0, q_1'(1)=1q1(1)=0,q1(1)=1

想解方程也不是不行,只不过确实可以直接看出结果:
q0(t)=t(t−1)2q1(t)=t2(t−1)\begin{aligned} q_0(t)&=t(t-1)^2\\ q_1(t)&=t^2(t-1)\\ \end{aligned} q0(t)q1(t)=t(t1)2=t2(t1)

同样为了方便表述,我们把 q0(t)q_0(t)q0(t) 称为 t=0t=0t=0 处的导数控制基函数q1(t)q_1(t)q1(t) 称为 t=1t=1t=1 处的导数控制基函数,它们有两重作用:一重是和 p0p_0p0p1p_1p1 线性组合,从而消去常数控制基函数对导函数的影响,另外一重作用是设置导函数的值。接下来我们分别从这两个角度来阐述导数控制基函数的作用。

考虑,第一方面的作用,记:
g0(t)=p0(t)−p0′(0)⋅q0(t)=(t−1)2+2t(t−1)2=(t−1)2(2t+1)g1(t)=p1(t)−p1′(1)⋅q1(t)=t2−2t2(t−1)=t2(3−2t)\begin{aligned} g_0(t)&=p_0(t)-p_0'(0)\cdot q_0(t)=&(t-1)^2+2t(t-1)^2&=(t-1)^2(2t+1)\\ g_1(t)&=p_1(t)-p_1'(1)\cdot q_1(t)=&t^2-2t^2(t-1)&=t^2(3-2t) \end{aligned} g0(t)g1(t)=p0(t)p0(0)q0(t)==p1(t)p1(1)q1(t)=(t1)2+2t(t1)2t22t2(t1)=(t1)2(2t+1)=t2(32t)

这样我们得到的 g0(t)g_0(t)g0(t)g1(t)g_1(t)g1(t) 就能够实现导数无关的常数控制,因为我们用 q0q_0q0 抵消了 p0p_0p0x=0x=0x=0 处对导数的影响,用 q1q_1q1 抵消了 p1p_1p1x=1x=1x=1 处的导数影响。为了和 p0p_0p0p1p_1p1 加以区分,我们称 g0g_0g0g1g_1g1导数无关的控制基函数

顺便说一嘴,g0,g1,q0,q1g_0, g_1, q_0, q_1g0,g1,q0,q1 这四个函数可以用待定系数法列方程求解,但是列方程多无聊啊,构造出来多有趣。

第三步:对基函数进行线性组合

f⃗(t)=P0⋅g0(t)+P1⋅g1(t)+D0⋅q0(t)+D1⋅q1(t),t∈[0,1]\vec f(t)=P_0 \cdot g_0(t) +P_1 \cdot g_1(t)+D_0\cdot q_0(t)+D_1\cdot q_1(t), t\in[0, 1] f(t)=P0g0(t)+P1g1(t)+D0q0(t)+D1q1(t),t[0,1]

不难证明这个东西就是我们想要的,把含 ttt 的解析式带入得到:
f⃗(t)=P0(2t3−3t2+1)+P1(−2t3+3t2)+D0(t3−2t2+t)+D1(t3−t2),t∈[0,1]\vec f(t)=P_0(2t^3-3t^2+1)+P_1(-2t^3+3t^2)+D_0(t^3-2t^2+t)+D_1(t^3-t^2), t\in[0, 1] f(t)=P0(2t33t2+1)+P1(2t3+3t2)+D0(t32t2+t)+D1(t3t2),t[0,1]

一些后话

上文中讨论的规范化三次埃尔米特插值曲线可以用类似一般的三次埃尔米特插值曲线一样逐段连接起来,形成一条经过多个控制点的光滑曲线段。例如,我们可能找到这样的一个 f⃗(t),t∈[t1,tn]\vec f(t),t\in[t_1, t_n]f(t),t[t1,tn] 使得 t=t1t=t_1t=t1f⃗(t)=P1\vec f(t) = P_1f(t)=P1∇f⃗(t)=D1\nabla \vec f(t) = D_1f(t)=D1t=t2t=t_2t=t2f⃗(t)=P2\vec f(t) = P_2f(t)=P2∇f⃗(t)=D2\nabla \vec f(t) = D_2f(t)=D2⋯\cdotst=tnt=t_nt=tnf⃗(t)=Pn\vec f(t) = P_nf(t)=Pn∇f⃗(t)=Dn\nabla \vec f(t) = D_nf(t)=Dn。分别对 [t1,t2][t_1, t_2][t1,t2][t2,t3][t_2, t_3][t2,t3]⋯\cdots[tn−1,tn][t_{n-1}, t_n][tn1,tn] 建立一个规范化三次埃尔米特插值曲线后再用分段函数连接起来即可。

由于规范化三次埃尔米特插值曲线的自变量 ttt 的取值范围总是在 [0,1][0,1][0,1] 中,因此需要为每一段的参数进行换元。令 ui(t)=t−titi+1−tiu_i(t)=\frac{t-t_{i}}{t_{i+1}-t_i}ui(t)=ti+1titti 其中 i=1,2,⋯n−1i=1, 2, \cdots n-1i=1,2,n1,则有当 t∈[ti,ti+1]t\in[t_i, t_{i+1}]t[ti,ti+1] 时,ui(t)u_i(t)ui(t)000 线性地变化为 111,因此我们想要的分段函数即为:

f⃗(t)={P1g0(u1(t))+P2g1(u1(t))+D1q0(u1(t))+D2q1(u1(t)),t∈[t1,t2)P2g0(u2(t))+P3g1(u2(t))+D2q0(u2(t))+D3q1(u2(t)),t∈[t2,t3)⋯Pn−1g0(un−1(t))+Png1(un−1(t))+Dn−1q0(un−1(t))+Dnq1(un−1(t)),t∈[tn−1,tn)\vec f(t) = \left\{\begin{aligned} P_1g_0(u_1(t))+P_2g_1(u_1(t))+D_1q_0(u_1(t))+D_2q_1(u_1(t)),&t\in[t_1, t_2)\\ P_2g_0(u_2(t))+P_3g_1(u_2(t))+D_2q_0(u_2(t))+D_3q_1(u_2(t)),&t\in[t_2, t_3)\\ \cdots\\ P_{n-1}g_0(u_{n-1}(t))+P_ng_1(u_{n-1}(t))+D_{n-1}q_0(u_{n-1}(t))+D_nq_1(u_{n-1}(t)),&t\in[t_{n-1}, t_n)\\ \end{aligned}\right. f(t)=P1g0(u1(t))+P2g1(u1(t))+D1q0(u1(t))+D2q1(u1(t)),P2g0(u2(t))+P3g1(u2(t))+D2q0(u2(t))+D3q1(u2(t)),Pn1g0(un1(t))+Png1(un1(t))+Dn1q0(un1(t))+Dnq1(un1(t)),t[t1,t2)t[t2,t3)t[tn1,tn)

在自变量 ttt 的变化过程中,这个分段函数每一段中的 uiu_iui 都能从 000 开始到 111 结束——“规范化”想要表达的就是这重含义。表达式中的 g0,g1g_0, g_1g0,g1导数无关的常数控制基函数q0,q1q_0, q_1q0,q1导数控制基函数

具体而言,无论是描述空间中的曲线还是平面中的曲线,我们都可以使用这样的一种方式:先确定一系列的控制点(例如上文中的 P0,P1P_0, P_1P0,P1),之后再将这些控制点与一组标量函数对应相乘,这组标量函数一般被称为基函数

讲点儿时的回忆

贝塞尔曲线让我回忆起了我小时候经常玩的一个画图游戏:

  1. 在纸上画出两条登场的线段首位顺次相接,如下图中的 AB=BCAB=BCAB=BC 且使 ABABAB 垂直于 BCBCBC
  2. ABABAB 边上取一点 DDD,在 BCBCBC 边上取一点 EEE,使得 AD=BEAD=BEAD=BE
  3. 在纸上借助直尺连接 DEDEDE
  4. 随机更换 DDD 点的选取和 EEE 点的选取,但始终保持 AD=BEAD=BEAD=BE 不变,转步骤 3;

随着连接得到的线段越来越多,这些线段下方空白部分逐渐形成了一个曲线弧的形状(我上小学的时候画过不少这种东西,尽管那时的我不知道这个曲线是一条抛物线的一部分,一直以为它是一个圆弧)。
绘制
如何简单地说明这个曲线是一条抛物线呢,比较直观的方法就是先把焦点和准线找出来。对于这种绘制方式而言,想要证明绘制出的曲线是抛物线并不容易,但是我们可以反过来,去证明一个抛物线可以用这种方法进行绘制(虽然数学上这种证法并不严谨,但是我们做这个证明还有其他的用处)。

抛物线
上图中红色的抛物线为 y=14x2y=\frac 1 4 x^2y=41x2MMM 是抛物线ACACAC 段上的任意一点,过 MMM 做抛物线的切线 DEDEDE,交 ABABABBCBCBCD,ED,ED,E 两点,此时我们只需要证明 AD=BEAD=BEAD=BE 即可说明上文中的绘制方式能够绘制一条抛物线。

由于 y′=12xy'=\frac 1 2 xy=21x,设 MMM 点横坐标为 x0x_0x0,得到 MMM 点出的切线方程为 y=12x0(x−x0)+14x02y=\frac 1 2 x_0(x-x_0)+\frac 1 4 x_0^2y=21x0(xx0)+41x02,将切线方程分别与 ABABAB 方程、BCBCBC 方程联立可以解得 D,ED, ED,E 两点的坐标。最后我们可以验证 xD−xA=xE−xBx_D-x_A=x_E-x_BxDxA=xExB。其中 xD=12x0−1,xE=1+12x0x_D=\frac 1 2 x_0-1, x_E=1+\frac 1 2 x_0xD=21x01,xE=1+21x0 带入成立。

对此我们还可以验证得到 AD:DB=DM:MEAD:DB=DM:MEAD:DB=DM:ME,这也恰好为我们提供了一种二次贝塞尔曲线的绘制方式(几何作图法)。假设 A,B,CA, B, CA,B,C 是我们在平面上选取的三个点,我们根据这种比例绘制的方式可以得到 MMM 移动得到的的参数方程曲线。 设 t∈[0,1]t\in[0, 1]t[0,1],当 t=0t=0t=0MMMAAA 点重合,当 t=1t=1t=1MMMCCC 点重合。

首先我们能很容易的得到 D=(1−t)A+tBD=(1-t)A+tBD=(1t)A+tB,换言之,t=0t=0t=0DDDAAA 重合,t=1t=1t=1DDDBBB 重合,t∈(0,1)t\in(0, 1)t(0,1)DDDA→BA\to BAB 上做匀速运动。同理 E=(1−t)B+tCE=(1-t)B+tCE=(1t)B+tC,而根据我们上文指出的比例关系,我们知道 DM:ME=AD:DB=t:(1−t)DM:ME=AD:DB=t:(1-t)DM:ME=AD:DB=t:(1t),因此得到 M(t)=(1−t)D+tE=(1−t)2A+2t(1−t)B+t2CM(t)=(1-t)D+tE=(1-t)^2A+2t(1-t)B+t^2CM(t)=(1t)D+tE=(1t)2A+2t(1t)B+t2C。当 ttt 取遍 [0,1][0, 1][0,1] 中的所有值时,M(t)M(t)M(t) 取遍抛物线在 AAACCC 之间的所有点。其中,我们称 (1−t)2(1-t)^2(1t)22t(1−t)2t(1-t)2t(1t)t2t^2t2 这三个函数为“二次伯恩斯坦基函数”。

三次贝塞尔曲线

不难发现其实“二次伯恩斯坦基函数”就是对 ((1−t)+t)2((1-t)+t)^2((1t)+t)2 进行牛顿二项式展开之后的每一项。类比地,我们可以得到四个三次伯恩斯坦基函数
(1−t)3,3(1−t)2t,3(1−t)t2,t3(1-t)^3,3(1-t)^2t,3(1-t)t^2,t^3 (1t)3,3(1t)2t,3(1t)t2,t3

当我们有四个平面上的常数点 A,B,C,DA, B, C, DA,B,C,D 时,我们可以确定一条三次贝塞尔函数:
M(t)=(1−t)3A+3(1−t)2tB+3(1−t)t2C+t3D,t∈[0,1]M(t)=(1-t)^3A+3(1-t)^2tB+3(1-t)t^2C+t^3D,t\in[0, 1] M(t)=(1t)3A+3(1t)2tB+3(1t)t2C+t3D,t[0,1]

虽然有高次的贝塞尔函数,但是三次的贝塞尔曲线已经可以实现光滑光顺的拼接,所以我觉得不介绍高次贝塞尔曲线也罢。总而言之“nnn 次的伯恩斯坦基函数”就是对 ((1−t)+t)n((1-t)+t)^n((1t)+t)n 进行牛顿二项式展开之后的每一项,其中的第 iii 项为 (i=0,1,⋯,ni=0, 1, \cdots, ni=0,1,,n):
Bi(t)=Cni⋅ti(1−t)n−iB_i(t)=C_n^i\cdot t^i(1-t)^{n-i} Bi(t)=Cniti(1t)ni

我们将 n+1n+1n+1nnn 次伯恩斯坦基函数与 nnn 个控制点坐标对应相乘就得到了一条 nnn 次的贝塞尔曲线。美中不足的一点是,由于这 n+1n+1n+1nnn 次伯恩斯坦基函数的定义域都是全体实数,因此每当我们改变一个控制点的位置,整条曲线上的每一个点位置都会发生一定的改变,这不利于工业设计上的局部微调。

想象我们正在使用贝塞尔曲线绘制一位二次元少女的右脸,当我们觉得不满意时打算对这一段曲线进行微调,于是调整了右脸处的某个控制点,而这导致原本已经绘制得很不错的左脸发生了变形,这是一件多么悲伤的事。

艾拉

三次贝塞尔曲线的光滑拼接

假设我们现在有两条贝塞尔曲线:
P(t)=(1−t)3P0+3(1−t)2tP1+3(1−t)t2P2+t3P3,t∈[0,1]Q(t)=(1−t)3Q0+3(1−t)2tQ1+3(1−t)t2Q2+t3Q3,t∈[0,1]\begin{aligned} P(t)&=(1-t)^3P_0+3(1-t)^2tP_1+3(1-t)t^2P_2+t^3P_3&,t\in[0, 1]\\ Q(t)&=(1-t)^3Q_0+3(1-t)^2tQ_1+3(1-t)t^2Q_2+t^3Q_3&,t\in[0, 1] \end{aligned} P(t)Q(t)=(1t)3P0+3(1t)2tP1+3(1t)t2P2+t3P3=(1t)3Q0+3(1t)2tQ1+3(1t)t2Q2+t3Q3,t[0,1],t[0,1]

其中 P0,P1,P2,P3,Q0,Q1,Q2,Q3P_0, P_1, P_2, P_3, Q_0, Q_1, Q_2, Q_3P0,P1,P2,P3,Q0,Q1,Q2,Q3 是平面上的常数点。我们希望把曲线 QQQ 光滑地接在曲线 PPP 地后面,只需要保证:

  1. 连续: P(1)=Q(0)P(1)=Q(0)P(1)=Q(0)
  2. 梯度同向平行:∇P(1)⋅∇Q(0)=∣∇P(1)∣⋅∣∇Q(0)∣\nabla P(1) \cdot \nabla Q(0)= |\nabla P(1)|\cdot|\nabla Q(0)|P(1)Q(0)=P(1)Q(0) (其中第一个点运算是向量内积,第二个是标量乘法);

由于 P(1)=P3P(1)=P_3P(1)=P3Q(0)=Q0Q(0)=Q_0Q(0)=Q0,所以想要保证连续只需要保证 P3=Q0P_3=Q_0P3=Q0
∇P(t)=∇((1−t)((1−t)2P0+3(1−t)tP1+3t2P2)+t3P3)=−((1−t)2P0+3(1−t)tP1+3t2P2)+(1−t)(⋯)+3t2P3\begin{aligned} \nabla P(t)&=\nabla ((1-t)((1-t)^2P_0+3(1-t)tP_1+3t^2P_2)+t^3P_3)\\ &=-((1-t)^2P_0+3(1-t)tP_1+3t^2P_2)+(1-t)(\cdots)+3t^2P_3 \end{aligned} P(t)=((1t)((1t)2P0+3(1t)tP1+3t2P2)+t3P3)=((1t)2P0+3(1t)tP1+3t2P2)+(1t)()+3t2P3

由于我们想计算的是 ∇P(1)\nabla P(1)P(1) 所以 ⋯\cdots 的部分我不想算了(反正乘上一个 1−t=01-t=01t=0 后也一定等于零),得到 ∇P(1)=3(P3−P2)\nabla P(1)=3(P_3-P_2)P(1)=3(P3P2)。同理可以计算得到:
∇Q(t)=∇((1−t)3Q0+t(3(1−t)2Q1+3(1−t)tQ2+t2Q3))=−3(1−t)2Q0+(3(1−t)2Q1+3(1−t)tQ2+t2Q3)+t(⋯)\begin{aligned} \nabla Q(t)&=\nabla ((1-t)^3Q_0 + t(3(1-t)^2Q_1+3(1-t)tQ_2+t^2Q_3))\\ &=-3(1-t)^2Q_0+(3(1-t)^2Q_1+3(1-t)tQ_2+t^2Q_3)+t(\cdots) \end{aligned} Q(t)=((1t)3Q0+t(3(1t)2Q1+3(1t)tQ2+t2Q3))=3(1t)2Q0+(3(1t)2Q1+3(1t)tQ2+t2Q3)+t()

得到:∇Q(0)=3(Q1−Q0)\nabla Q(0)=3(Q_1-Q_0)Q(0)=3(Q1Q0)。因此只要在 P3=Q0P_3=Q_0P3=Q0 的基础上保证 P2P3⟶//Q0Q1⟶\stackrel \longrightarrow {P_2P_3}//\stackrel \longrightarrow{Q_0Q_1}P2P3//Q0Q1 即可保证(还要注意同向哦)。

三次伯恩斯坦基函数

我们看到三次的贝塞尔曲线有四个控制点:
M(t)=(1−t)3A+3(1−t)2tB+3(1−t)t2C+t3D,t∈[0,1]M(t)=(1-t)^3A+3(1-t)^2tB+3(1-t)t^2C+t^3D,t\in[0, 1] M(t)=(1t)3A+3(1t)2tB+3(1t)t2C+t3D,t[0,1]

每当给定一个 ttt 时,曲线上的点 M(t)M(t)M(t) 实际上就是对 A,B,C,DA, B, C, DA,B,C,D 四个控制点的坐标进行了一个加权求平均数的过程。当 t→0t\to 0t0 时,M(t)→AM(t)\to AM(t)A,当 t→1t\to 1t1M(t)→DM(t)\to DM(t)D。具体而言我们可以将 A,B,C,DA, B, C, DA,B,C,D 四个点分别对应的基函数绘制到一个坐标系中,让我们观察这四个点对整条曲线究竟起到了多大的作用。
基函数
可以看到,当 t=13t=\frac 1 3t=31 时,BBB 前的系数变得最大,此时曲线最靠近 BBB 点;当 t=23t=\frac 2 3t=32 时,CCC 前的系数变得最大,此时曲线最靠近 CCC 点。

换言之,这也为我们进一步研究曲线的表示提供了一个思路:给定 nnn 个控制点,我们只需要给出 nnn 个标量函数作为基函数和这 nnn 个点的坐标对应相乘,就能得到一条大趋势与这 nnn 个点的走势基本接近的曲线。这 nnn 个标量函数都是上凸单峰的,使得曲线在当前标量函数的极值点处最接近该控制点,从而使得曲线近似拟合了这 nnn 个控制点构成的折线。

贝塞尔曲线的几何作图法

在上面介绍儿时的回忆中,我们介绍了对于抛物线绘制的一种方法。先确定三个控制点 A,B,CA, B, CA,B,C,连接 ABABABBCBCBC。我们在 ABABAB 上取一点 DDD,在 BCBCBC 上取一点 EEE 使得:
ADAB=BEBC=t\frac {AD}{AB}=\frac{BE}{BC}=t ABAD=BCBE=t

其中 ttt 是一个定义在 [0,1][0, 1][0,1] 区间上的数。之后我们再连接 DEDEDE 并在 DEDEDE 上取一点 FFF 使得:
DFDE=t\frac{DF}{DE}=t DEDF=t

ttt[0,1][0, 1][0,1] 之间变化时,FFF 点的轨迹就是一条抛物线(换言之,二次贝塞尔曲线)。

曲线绘制

三次均匀 B 样条曲线

由于三次贝塞尔曲线只能有四个控制点,贝塞尔曲线控制点越多次数越高。我们希望构造一种这样的曲线:

  1. 控制点个数可以无限增多,但函数次数保持为三次;
  2. 每个控制点只会影响自己附近的一小段曲线而对其他部分曲线没有任何影响;
  3. 曲线是光滑的。

局部基函数及其混淆

我们的目的非常明确,我们想要构造一种基函数,这种基函数只在很小的一段区间上有定义,而在此区间之外的部分均为零。例如这样的一个函数就是我们想要的一个函数:
N1(t)={1,0≤t≤10,elsewhereN_1(t)=\left\{\begin{aligned}1, &0\leq t \leq 1\\0,&\text{elsewhere} \end{aligned}\right. N1(t)={1,0,0t1elsewhere

这个函数又被称作“平台函数”,因为它在非零区间 [0,1][0, 1][0,1] 上的取值始终是一。由于这个函数的非零区间为 [0,1][0, 1][0,1],因此我们称这个局部基函数的宽度111。类似的,如果一个定义在实数上的函数只在区间 [0,L][0, L][0,L] 上有非零值,我们可以称这个函数的“宽度”为 LLL局部基函数

当我们用一组局部基函数与一组控制点对应相乘再求和从而得到目标曲线时,每一个控制点自然也只会影响曲线的一个局部(在局部基函数的宽度范围内会产生影响),而不会影响整个曲线上的绝大多数位置的取值。

假如我们已经有了一个宽度为 LLL 的局部基函数,我们可以使用一次混淆操作得到一个宽度为 L+1L+1L+1 的局部基函数,这使得我们可以控制每个控制点在目标曲线上到底能够造成多大范围的影响,宽度越大影响范围自然也越大。

对于平台函数 N1N_1N1 进行混淆,第一步我们要将 N1(t)N_1(t)N1(t) 右移一个单位长度得到 N1(t−1)N_1(t-1)N1(t1),我们希望能够将 N1(t)N_1(t)N1(t)N1(t−1)N_1(t-1)N1(t1) 加权求平均,使得我们得到的新函数在 t=0→1t=0\to1t=01 段上函数值线性增加,在 t=1→2t=1\to2t=12 段上函数值线性减少。很直观的想法就是,我们可以在 N1(t)N_1(t)N1(t) 身上乘以一个单调递增的线性函数,并在 N1(t−1)N_1(t-1)N1(t1) 身上乘以一个单调递减的线性函数:
N2(t)=t⋅N1(t)+(2−t)⋅N1(t−1)N_2(t)=t\cdot N_1(t)+(2-t)\cdot N_1(t-1)N2(t)=tN1(t)+(2t)N1(t1)

为什么我们在 N1(t−1)N_1(t-1)N1(t1) 身上乘以的是一个 2−t2-t2t 而不是 1−t1-t1t 呢,这是因为 N1(t−1)N_1(t-1)N1(t1) 的非零区间为 [1,2][1, 2][1,2],如果乘以 1−t1-t1t 会导致我们最终的结果出现负数,下图展示了 N1(t),N1(t−1)N_1(t), N_1(t-1)N1(t),N1(t1)N2(t)N_2(t)N2(t)

曲线
其中绿色的虚线表示 N1(t)N_1(t)N1(t),蓝色的虚线代表 N1(t−1)N_1(t-1)N1(t1),红色的虚线代表 N2(t)N_2(t)N2(t)。不难看出 N2(t)N_2(t)N2(t) 是一个宽度为 222 的局部基函数。这样得到的 N2(t)N_2(t)N2(t) 已经是一个最高次为 111 次的单峰函数,使用这种函数作为基函数,我们可以得到一段连续的折线。例如,我们可以令:
M2(t)=A⋅N2(t)+B⋅N2(t−1),t∈[1,2]M_2(t)=A\cdot N_2(t)+B\cdot N_2(t-1), t\in[1, 2] M2(t)=AN2(t)+BN2(t1),t[1,2]
这样得到的 M2(t)M_2(t)M2(t) 就是一个连接了 AAA 点和 BBB 点的线段。我们之所以要限制 t∈[1,2]t\in[1, 2]t[1,2] 是因为在 t∈[0,1]t\in [0, 1]t[0,1] 时只有 N1(t)N_1(t)N1(t) 非零,N1(t−1)N_1(t-1)N1(t1) 为零,我们潜在地在对 AAA 点和原点进行加权求平均,而我们显然不希望原点影响到我们的图像的形状。假如我们将定义域定义成 t∈[0,3]t\in[0, 3]t[0,3],会导致 M2(t)M_2(t)M2(t) 的图象变为了三段线段,第一段连接了原点和 AAA 点,第二段连接了 AAA 点和 BBB 点,第三段连接了 BBB 点和原点。我们还可以令:
M3(t)=A⋅N2(t)+B⋅N2(t−1)+C⋅N2(t−2),t∈[1,3]M_3(t)=A\cdot N_2(t)+B\cdot N_2(t-1)+C\cdot N_2(t-2), t\in[1, 3] M3(t)=AN2(t)+BN2(t1)+CN2(t2),t[1,3]
这样我们得到的 M3(t)M_3(t)M3(t) 就是两段线段的拼接,其中第一段连接了 AAA 点与 BBB 点,第二段连接了 BBB 点与 CCC 点。为什么能实现这个效果呢?是因为 N2(t−2)N_2(t-2)N2(t2) 只在 t∈[2,4]t\in[2, 4]t[2,4] 区间内有非零值,因此在区间 t∈[1,2]t\in[1, 2]t[1,2]M3(t)=M2(t)M_3(t)=M_2(t)M3(t)=M2(t),因此为一段连接了 AAABBB 的线段。

更普遍地,设 NLN_LNL 是一个宽度为 LLL 的局部基函数,对函数 NLN_LNL 的混淆记为 Mix[NL]Mix[N_L]Mix[NL]
NL+1(t)=Mix[NL](t)=tL⋅NL(t)+(L+1)−t(L+1)−1⋅NL(t−1)N_{L+1}(t)=Mix[N_L](t)=\frac{t}{L}\cdot N_L(t)+\frac{(L+1) - t}{(L+1) - 1} \cdot N_L(t-1) NL+1(t)=Mix[NL](t)=LtNL(t)+(L+1)1(L+1)tNL(t1)

简而言之就是在 NL(t)N_L(t)NL(t) 身上乘以了一个他的非零区间内的线性递增函数,在 NL(t−1)N_L(t-1)NL(t1) 身上乘以了一个他的非零区间内的线性递减函数。下图给出了 N2(t),N2(t−1)N_2(t), N_2(t-1)N2(t),N2(t1) 以及 N3(t)N_3(t)N3(t) 的函数图像:

对比图
其中绿色的曲线是 N2(t)N_2(t)N2(t),蓝色的曲线是 N2(t−1)N_2(t-1)N2(t1),红色的曲线是 N3(t)N_3(t)N3(t)。使用 N3(t)N_3(t)N3(t) 作为基函数已经可以较好的定义出一条连续且光滑的曲线了,例如我们令:

M3(t)=A⋅N3(t)+B⋅N3(t−1)+C⋅N3(t−2)+D⋅N3(t−3),t∈[2,4]M_3(t)=A\cdot N_3(t)+B\cdot N_3(t-1)+C\cdot N_3(t-2)+D\cdot N_3(t-3), t\in[2, 4] M3(t)=AN3(t)+BN3(t1)+CN3(t2)+DN3(t3),t[2,4]

和先前的例子类似,在这里我们需要将定义域限制到 [2,4][2, 4][2,4] 也是为了避免原点位置影响曲线的绘制。而我们这里用来做基函数的 N1(t),N2(t),⋯N_1(t), N_2(t), \cdotsN1(t),N2(t), 其实就是所谓的 B 样条基函数。具体而言,对于一个给定一个正整数 LLL,我们称 NL(t)N_L(t)NL(t)LLL 阶(L−1L-1L1 次)B 样条基函数。

四阶三次均匀 B 样条曲线

N3(t)N_3(t)N3(t) 进行混淆可以得到 N4(t)N_4(t)N4(t),其中 N4(t)N_4(t)N4(t) 是一个宽度为 444 的局部基函数,我们称它为四阶三次 B 样条基函数,下图展示了它的大致形状:
示意图
二阶 B 样条至少要有两个控制点(不然线段怎么连),三阶 B 样条至少要有三个控制点(不然二次曲线怎么画),因此四阶 B 样条至少要有四个控制点。B 样条相对于贝塞尔曲线的有点在于,即使四阶三次 B 样条有多于四个控制点,它的次数仍然是三次,而且每个控制点的变化只会影响与他接近的一段曲线,而不会影响整个目标曲线(因为 N4(t)N_4(t)N4(t) 宽度为 444,这也就意味着与 N4(t)N_4(t)N4(t) 相乘的那个控制点不会在这个宽度之外造成任何影响)。

假设我们有 nnn 个常数点 P0,P1,⋯,Pn−1P_0, P_1, \cdots, P_{n-1}P0,P1,,Pn1,其中 n≥4n\geq 4n4,我们可以定义一条四阶三次均匀 B 样条曲线:
M(t)=P0⋅N4(t−0)+P1⋅N4(t−1)+⋯+Pn−1⋅N4(t−(n−1)),t∈[3,n]M(t)=P_0\cdot N_4(t-0)+P_1\cdot N_4(t-1)+\cdots+P_{n-1}\cdot N_4(t-(n-1)),t\in[3, n] M(t)=P0N4(t0)+P1N4(t1)++Pn1N4(t(n1)),t[3,n]

和贝塞尔曲线相比,B 样条往往不会经过自己的第一个控制点 P0P_0P0Pn−1P_{n-1}Pn1,而贝塞尔曲线一定会经过这两个点。

B 样条绘制范例

随便画了一个有七个控制点的 B 样条,特别地,如果我们让 P2=P6,P1=P5,P0=P4P_2=P_6, P_1=P_5, P_0=P_4P2=P6,P1=P5,P0=P4,那么我们能够绘制一条闭合的 B 样条曲线。
七个点的等距B样条

换言之,任给一个多边形,我们都能找到这个多边形控制的一条闭合 B 样条曲线。如果这个多边形是一个凸多边形,感性理解一下不能得到这个闭合的 B 样条曲线一定完全位于整个多边形的内部。

闭合
上文中的所有图形都是使用几何画板绘制的感兴趣的同学可以联系我(邮箱见免责)获得这些几何画板文件,下图中给出了用于生成这两个 B 样条范例的配置:

配置

未完待续 …

一个理念

不得不说我们的教材内容丰富充实,兼顾了严谨性与知识性。但我对我们的图形学教材仍有一个略有不满的地方,就是教材中没有贯彻一个目的性与实践性的假设:任何工业设计理论都带有其目的。当我们提出一个概念/公式时,指导我们的所谓“灵感”不是拍脑袋想出来的,更不是从天上掉下来的,而是来自真真正正的生产实践的需要。我们的图形学教材并不是没有这种理念,但是它没有贯彻这种理念,换言之,这种理念仅仅停留在每一章的简介部分,而没有真正深入到每一章的具体内容中。不要先给出一个复杂的公式,再利用这个公式解决问题,要先从最简单、最必要、最直观的概念入手逐渐让我们知道我们为什么要这么做(目的),而不是先告诉我们怎么做(方法)。否则学生很容易不知所云。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-3833622.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

Matlab:使用乘法合并分类数组

Matlab:使用乘法合并分类数组 合并两个分类数组类别的笛卡尔积使用未定义元素的乘法有序分类数组的笛卡尔积此示例说明如何使用 times 函数来合并分类数组,包括有序分类数组和包含未定义元素的数组。当对两个分类数组调用 times 时,将会输出一个包含新类别的分类数组。新类别…...

游戏工作室换IP与挂机的基础知识

许多刚刚做手游工作室的朋友都会遇到一个难题&#xff0c;就是遇到了游戏封号&#xff0c;一分钱没赚到反而赔了不少钱&#xff0c;很苦恼却找不到解决办法&#xff0c;这里给大家普及一下手游防封最基本的事情和一些必须安装的软件(比如代理ip软件)。 如何做游戏防封? 其实…...

bios调整服务器性能模式吗,怎样更改BIOS设置提高显卡性能

使用电脑的时候,都希望自己的电脑软件运行速度快,图片清晰程度高&#xff0c;那么怎样更改BIOS设置提高显卡性能呢?接下来大家跟着学习啦小编一起来了解一下更改BIOS设置提高显卡性能的解决方法吧。更改BIOS设置提高显卡性能方法在BIOS中&#xff0c;一般如下设置&#xff1a;…...

Java高级面试题整理(附答案)

这是我收集的10道高级Java面试问题列表。这些问题主要来自 Java 核心部分 ,不涉及 Java EE 相关问题。你可能知道这些棘手的 Java 问题的答案&#xff0c;或者觉得这些不足以挑战你的 Java 知识&#xff0c;但这些问题都是容易在各种 Java 面试中被问到的&#xff0c;而且包括我…...

微信浏览器缓存怎么清理?

微信浏览器缓存怎么清理? 用微信内置浏览器打开这个网页debugx5.qq.com 或 http://debugtbs.qq.com/ 做微信公众号和调试手机页面的时候&#xff0c;避免不了页面要跳转到微信浏览器打开&#xff0c;调试阶段&#xff0c;android版微信浏览器一直都默认缓存html静态资源&…...

ros develop 相关

ROS中PCL的数据类型转换 - 楸壳 - 博客园1、ROS中的点云数据类型 sensor_msgs::PointClous // 包含 x、y 和 z 点&#xff08;所有浮点数&#xff09;以及多个通道&#xff1b; 每个通道都有一个字符串名称和一个浮点值数组 sensor_msghttps://www.cnblogs.com/zhongllmm/p/160…...

R语言核密度估计

核密度估计是在概率论中用来估计未知的密度函数&#xff0c;属于非参数检验方法之一&#xff0c;由Rosenblatt (1955)和Emanuel Parzen(1962)提出&#xff0c;又名Parzen窗&#xff08;Parzen window&#xff09;。 假设我们有n个数X1-Xn,我们要计算某一个数X的概率密度有多大。…...

一文看懂蓝牙在物联网中的应用场景

不看这几篇好文&#xff0c;就别说自己了解物联网 简介 蓝牙作为一项发明于上世纪的近距离无线通信技术&#xff0c;在手机&#xff0c;电脑领域已经有了充分地基础&#xff0c;那么这项技术在物联网领域又会有哪些应用场景呢&#xff1f; 蓝牙技术的优势 蓝牙标准是由蓝牙技…...

三种基于CUDA的归约计算

归约在并行计算中很常见&#xff0c;并且在实现上具有一定的套路。本文分别基于三种机制&#xff08;Intrinsic&#xff0c;共享内存&#xff0c;atomic&#xff09;&#xff0c;实现三个版本的归约操作&#xff0c;完成一个warp&#xff08;32&#xff09;大小的整数数组的归约…...

Android开发——实现数字时钟

前言 在最近的项目当中&#xff0c;我遇到一个在界面中实现系统数字时钟的需求。一看这个其实挺简单的&#xff0c;开个一个子线程获取当前的系统时间睡眠1分钟发送当前时间&#xff0c;然后利用Handler去修改当前显示的时间&#xff0c;直接撸代码。 第一种:HandlerThread …...

Flash视频教程一把抓,自动获取Flash教程----谭石南

——另类下载 Flash真是一个神奇的软件&#xff0c;我们不仅可以利用它制作精美的动画&#xff0c;还可以用它来做成Flash的小游戏。要想把Flash学好也不是一件容易的事&#xff0c;在课堂上老师只给我们讲了一点入门的知识&#xff0c;利用这些还不能做成完整的动画制作。但就…...

一键搭建自己的网络加速器

一键搭建自己的vpn如何安装使用如何搭建服务器如何使用客户端如何安装使用 程序链接: https://github.com/ChengZu/easyvpn 文件说明&#xff1a; build/EasyVpn.jar为服务器程序 build/app-release.apk为android客户端程序 如何搭建服务器 我这里讲在ubuntu下的搭建 安装…...

java面试之常见场景题

1.线程安全的单例模式 //饿汉式 线程安全的 class danlie1 {private danlie1(){}private static danlie1 dnew danlie1();public static danlie1 get(){return d;} } //懒汉式 线程不安全 class Single {private Single(){}private static Single dnull;public static Singl…...

8086CPU 的寻址方式(重点)

8086CPU 的寻址方式8086 CPU寻址方式(重点)一、立即寻址二、寄存器寻址三、存储器寻址1&#xff0c;直接寻址2&#xff0c;寄存器间接寻址3&#xff0c;基址寻址4&#xff0c;变址寻址5、基址变址位移寻址6&#xff0c;基址变址寻址指令就是计算机完成某种操作的命令。机器指令…...

html如何添加多个视频教程,html多格式视频教程

html多格式视频教程[2021-02-20 05:54:15] 简介:php去除nbsp的方法&#xff1a;首先创建一个PHP代码示例文件&#xff1b;然后通过“preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/", " ", strip_tags($val));”方法去除所有nbsp即可。推荐&#xff1a;《…...

核密度估计python_机器学习 – 具有固定协方差的高斯核密度估计(使用python)

我可以通过简单的运行使用scipy库执行高斯核密度估计from scipy import statskernel stats.gaussian_kde(data)但是我想将协方差修正为某个预定义值并用它来执行KDE.有没有一种简单的方法可以在没有明确编写优化过程的情况下在python的帮助下实现这一点(如果没有现有的库提供这…...

FusionCompute集群知识

文章目录一、集群策略1、主机内存复用2、负载均衡3、NUMA4、HA5、计算资源调度6、IMC一、集群策略 1、主机内存复用 内存复用使用了三种技术&#xff0c;内存共享、内存置换、内存气泡 内存共享 所有的虚拟机共享一段内存&#xff0c;共享的内存段是只读的内存置换 我们在Li…...

潭州教育学python_潭州教育-Python学习笔记6@函数基础,必备参数,位置参数,可选参数...

6.1 函数定义&#xff1a; def BiJiao(a,b): #驼峰规则(首字母大写)&#xff0c;见名知意-函数名大写 if a>b: print(a) elif ab : print(xiangdeng) else: print(b) 运行&#xff1a; BiJiao(1,3) 3 6.2函数参数-默认参数、可选参数、必备参数 6.2.1&#xff0c;无参数 def…...

LSD直线检测和霍夫线变换的学习建议

最近笔者学习霍夫线变换和LSD直线检测算法&#xff0c;有一些学习建议&#xff0c;希望可以给予大家一些帮助。 学习霍夫变换的感想 每个人理解的霍夫变换或许略有差异&#xff0c;但是最主要的是笛卡尔坐标系跟极坐标系的相互转换。 霍夫变换分为标准霍夫变换&#xff08;SHT&…...

Qt QML加载和使用字体

Qt &#xff31;&#xff2d;&#xff2c;加载和使用字体 加载函数 bool loadFonts(const QString &baseFile) {QString assetsPath qApp->applicationDirPath();QString path assetsPathQStringLiteral("/fonts/");QString fontFile pathbaseFile;const…...

python毕业设计作品基于django框架个人博客系统毕设成品(7)中期检查报告

整个项目包含了&#xff1a;开题报告 开题报告PPT 任务书 中期报告 论文模板 答辩PPT等 项目源码 主要安介绍了系统在开发过程中所应用到的一些关键的技术 主要python技术介绍&#xff1b;框架Django概要&#xff1b;MySQL数据库知识&#xff1b; 以及常规的网页技术HTM…...

百度首页HTML(简单代码)

百度首页HTML(简单代码) 新手小白在练习阶段&#xff0c;如果有什么好的建议可以给我留言哦 html代码 <body><div class"nav"><div class"navleft"><a href"#">新闻</a><a href"#">hao123</…...

Android测试工具-Monkey详解

Monkey详解Monkey详解一 Monkey简介二 Monkey测试环境配置三 执行Monkey四 常用monkey命令五 Monkey测试问题分析Monkey详解 一 Monkey简介 Monkey是Android SDK自带的工具&#xff0c;其原理是利用socket通讯&#xff08;Android客户端与服务器以TCP/UDP方式&#xff09;&am…...

Java坦克大战

目录 项目git地址&#xff1a;https://gitee.com/java-course-design_1/java-programming-tank-game 项目简介&#xff1a; 项目技术&#xff1a; 功能需求分析 功能架构图&#xff1a; 编写思路及部分代码 游戏窗口初始化 坦克类的定义 地图类 游戏常量类 优化 &…...

Android TV开机优化

Android开机优化相关点 1 关键路径 bootloader > kernel > init > zygote > system server > launcher 2 打印优化 2.1 关闭bootloader打印 2.2 关闭 kernel打印 2.3 提高Android log打印等级 system/core/logd/LogBuffer.cpp int get_log_level() {char …...

Mybatis(3)

朋友们大家好&#xff0c;我们又见面了&#xff0c;回顾上一章我们简单了解了Mybatis优化等,下面让我们先来简单的回顾一下&#xff1a; 回顾&#xff1a; 1. mybatis的优化 ① 引入数据库属性文件 ② 引入日志文件 ③ 解决列名和属性名不一致。【1】起别名--与属性名一致…...

国际海运、陆运、空运有什么优点和缺点?

陆运多是是指汽车运输的,距离短,快,可以实现门到门的运输,费用成本较高的,适合内陆的运输,距离不要太长的城市间 海运多数就是出口了,当然中国也有南北航线,走沿海的,也不错.适合距离远的,货物多时间要求没有那么严格的,像是家具啊,板材啊,工具啊什么的,现在也有海运的冷藏箱的…...

oracle时间比较

今天在学习公司的项目中&#xff0c;发现了些问题&#xff0c;在这里记录下。 因为以前培训的时候&#xff0c;培训老师觉得oracle安装卸载麻烦就没教。所以oracle只是略懂而已&#xff0c;很多东西还不清楚&#xff0c;就比如今天遇到的问题&#xff0c;oracle的时间比较。 …...

辗转相除法的原理

...

加密狗的选择

李国帅 2011.10.12 在2011年使用过加密狗&#xff0c;一些使用经过记录下来。聊胜于无&#xff0c;也许可以给人帮助。说明&#xff1a; 前期筛选了4家&#xff0c;仔细了看了其网站和介绍。其中广州亚斯技术力量太差&#xff0c;不再考虑&#xff1b;对于以下三家产品做了一些…...

移动端手机横屏事件

移动端中添加了 orientationchange 事件&#xff0c;以便开发人员能够确定用户何时将设备由横向查看模式切换为纵向查看模式。移动端的 window.orientation 属性中可能包含3个值&#xff1a;0 表示肖像模式&#xff0c; 90 表示向左旋转的横向模式&#xff08;“主屏幕”按钮在…...

《白话大数据与机器学习》

白话大数据与机器学习第四章高斯距离 曼哈顿距离同比和环比高斯分布&#xff08;正态分布&#xff09;泊松分布伯努利分布第六章 信息论信息量香农公式信息熵多维空间第八章 回归&#xff08;分类算法&#xff09;线性回归过拟合欠拟合第九章 聚类9.1 K-means 算法9.3 孤立点9.…...

海康Ehome协议服务端搭建

概述一.海康EHome协议预览流程1.0 简介1.1.流程图1.2.ehome协议接入步骤二.设备注册报文2.2.Device to Platform 海康设备注册后会主动连接配置的ehome平台2.3. ehome平台在收到设备注册指令后三.预览请求报文3.1. Platfrom>>Device&#xff0c; ehome平台发起预览3.2. D…...

无内鬼来点干货,银行java开发面试题(含答案)

目录前言1、在多线程环境中使用HashMap会有什么问题&#xff1f;在什么情况下使用get()方法会产生无限循环&#xff1f;2、不重写Bean的hashCode()方法是否会对性能带来影响&#xff1f;3、对于一个不可修改的类&#xff0c;它的每个对象是不是都必须声明成final的&#xff1f;…...

腾讯T1~T9工程师技术剖析以及评定标准、能力要求

今天给大家分享的是由腾讯内部制定出来的岗位T1—T9级别&#xff0c;具备的专业知识能力技术点&#xff0c;至于知识点掌握的深度就看大家对技术点知识点理解的程度&#xff0c;个人而言知识点理解的程度跟你定位的级别是有很大的关系。 很多朋友跟我说在学习编程的过程中不知…...

《MLB棒球创造营》:走近棒球运动·多伦多蓝鸟队

多伦多蓝鸟队&#xff08;英语&#xff1a;Toronto Blue Jays&#xff09;&#xff0c;是位于加拿大多伦多的美国职棒大联盟队伍。他们隶属于美国联盟&#xff08;以下简称美联&#xff09;的东区&#xff0c;并是唯一曾经赢得世界大赛冠军的加拿大球队。由于蒙特利尔博览队在2…...

如何实现产品外观智能质检?百度产品外观瑕疵质检来帮忙

一些比较精密的产品&#xff0c;外观上的瑕疵靠人工是难以发现的&#xff0c;那该怎么办呢&#xff1f;如何实现产品外观智能质检&#xff1f;莫慌莫慌&#xff0c;百度产品外观瑕疵质检来帮忙&#xff0c;下面小编给大家做详细介绍&#xff1a;   产品外观瑕疵质检   智能…...

微信浏览器缓存问题

移动端缓存问题 1.html5 解决方案如下&#xff1a; 在每个页面头部添加禁止缓存代码 <meta http-equiv"pragma" content"no-cache"/> <meta http-equiv"expires" content"0"> 禁止缓存效果不明显 2.通过修改文件名称&…...

qt输出自定义的pdf文件源码详解

qt中有两种方式可以输出pdf&#xff1a; 方式1&#xff1a;使用QPrinter即打印机的方式打印pdf 这种方式&#xff0c;在qt4成为唯一的方式。 QPrinter printer(QPrinter::HighResolution); //高清晰度 printer.setPageSize(QPrinter::A4); //设置纸张大小 pri…...

(原文)基于甘特图的深度强化学习方法求解端到端在线重调度

获取更多资讯&#xff0c;赶快关注上面的公众号吧&#xff01; 文章目录介绍关注公众号&#xff0c;后台回复"甘特图"获取原文新方法重调度环境优化目标重调度策略重调度方法调度状态表达调度动作奖励函数训练算法马尔可夫决策过程实验结果实验1&#xff1a;紧急插单…...

implementation file-视频系统

// SetPwd.cpp : implementation file // #include "stdafx.h" #include "play.h" #include "SetPwd.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] __FILE__; #endif / // CSetPwd dialog CSetPwd::C...

ioca0中断 pic单片机_关于PIC单片机的一些经验总结

为了给前一段时间学习PIC16F616型单片机的一个总结和方便大家的交流,我写了这篇关于PIC单片机的学习心得,都是在看了手册和编程调试后用自己的语言组织的,其中有不足或者有疑问的地方希望大家能及时的给予纠正和批评,提出宝贵的意见.2.PIC单片机的概述PIC16F616是一款14引脚、8…...

Linux开发工具的使用

&#x1f339;人生最大的遗憾&#xff0c;就是在遗憾过去的遗憾。 目录 &#x1f3c6;一、Linux软件包管理器-yum &#x1f453;1.1 什么是软件包-yum的滥觞 &#x1f339;①什么是软件包 1.2 yum使用的常见指令 &#x1f339;①yum install &#x1f339;②yum list &…...

MATLAB核密度函数如何用,MATLAB中自带的核密度估计函数

我们在统计数据处理时&#xff0c;经常计算一个样本的概率密度估计&#xff0c;也就是说给出一组统计数据&#xff0c;要求你绘制出它的概率分布曲线&#xff0c;matlab的统计工具箱中有直接的函数 就是&#xff1a;Ksdensity 核心平滑密度估计[f,xi] ksdensity(x)计算样本向…...

中山积分制入户,有哪些职业资格或专业技术职称能加分

《中山市流动人员积分制管理实施细则》公布&#xff0c;职业资格或专业技术职称最高可加60分&#xff0c;规定职业资格证书应属于42个工种范畴。业内人士预计&#xff0c;随着积分制的实施&#xff0c;各种职业资格或专业技术职称认证的培训将出现火爆。    职业认证只限于42…...

Java求100000以内素数_100000以内的质数表

最近在PKU上面做题&#xff0c;发现好多题目都用到了质数表&#xff0c;于是干脆把100000以内的质数表和生成质数的程序贴上来好了&#xff0c;大家也好抄&#xff0c;直接用~~~ 嘿嘿……Program:#include #define N 100000int sieve[N 1];void main(){for(int i 2; i <…...

基于MES系统的追溯管理功能,没你想的那么复杂

如今&#xff0c;众多企业在生产过程普遍存在品种多、批次多的情况&#xff0c;一个批次的零部件或者半成品往往用在多个产品型号、不同批次订单生产中。当制造过程或产品质量有异常时&#xff0c;要调查出问题零部件或者半成品具体用在哪个订单&#xff1f;哪几个批次&#xf…...

利用edge对自定义内容进行大声朗读

因为前些天需要练习对一段文字的英文朗读&#xff0c;当时自然而然想到了edge的大声朗读功能&#xff0c;但是网上搜了一下发现并没有什么好用的方法可以实现自定义内容朗读&#xff0c;看样子官方自己并没有做这个东西&#xff0c;最终在github上找到一个项目&#xff0c;项目…...

touchgfx视频教程

正点原子平台的手把手教你学touchgfx视频教程,讲解的非常到位,干货很多,给大家分享一下视频地址: https://www.yuanzige.com/course/detail/80229 论坛地址: http://www.openedv.com/forum.php?modviewthread&tid328102&extrapage%3D1 为了避免周期拉的太长,本视频教…...

LQ0109 正则问题【DFS】

题目来源&#xff1a;蓝桥杯2017初赛 C A组E题 题目描述 考虑一种简单的正则表达式&#xff1a;只由 x ( ) | 组成的正则表达式。 小明想求出这个正则表达式能接受的最长字符串的长度。 例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是&#xff1a; xxxxxx&#xff0c;长度是…...

计算机内图片怎么自定义排序,win7电脑中如何设置图片排序方式?

不管你是否喜欢照片&#xff0c;想必大家的电脑中都少不了照片的位置吧?或者说&#xff0c;咱们的工作中也需要涉及到照片的处理&#xff0c;咱们先撇开自己命名的照片不说&#xff0c;如果不是自己刻意去命名的&#xff0c;大家是否可以找到文件夹中图片文件的排序规律呢?有…...

高德地图哪个语音包最好_用高德地图录制语音包,听自己的声音导航更有个性...

“出发喽,回家路上要慢点,别让宝贝担心你”,打开高德地图导航,传来的不是志玲姐姐“嗲嗲”的导航语音播报,而是你的挚爱女友充满爱意的嘱咐。亲密而熟悉的声音相伴,会不会让你在出行旅途中感受到多一份温暖? 小编惊喜地发现,在原有林志玲、TFBOYS、郭德纲、罗永浩等语音…...

你学习的目的到底是什么?

上学时我们学习的目的基本上就是为了考试&#xff0c;大考、小考、模拟考&#xff0c;最后一考终极考—高考。 大学毕业以后很多人停止了学习&#xff0c;也忘记了学习这件事情&#xff0c;绝大多数人其实并没有学习的习惯&#xff0c;上学时只是应付而已&#xff0c;一旦脱离…...

Python数据分析-绘图-1-Matplotlib绘图基础

注&#xff1a;编码中用到的国民生产总值的数据可以在国家数据网站获得。 matplotlib图像可以分为如下四层结构&#xff1a; 1.canvas&#xff08;画板&#xff09;&#xff1a;位于最底层&#xff0c;导入库时就存在。 2.figure&#xff08;画布&#xff09;&#xff1a;在…...

moto+早期android手机,七款摩托罗拉早期经典机型回顾

谷歌于昨日宣布已与摩托罗拉移动签署最终协议&#xff0c; 将以每股40美元的现金收购后者&#xff0c;总价约125亿美元。毫无疑问被收购之后的摩托罗拉移动将专注于Android智能手机的开发。2009年&#xff0c;摩托罗拉以一款带侧滑全键盘的Android机型milestone里程碑打了一场漂…...

20221026,开启DevOps之路。冲击最大的是项目上或者功能的英文名词。现在记录如下

职务 PMO PME HRBP 职位&#xff1a; PM ( Product Manager ) 产品经理&#xff1a; 产品的构想、框架的设计、用户的调研等。 RD&#xff08;Research and Development&#xff09;研发&#xff1a; 如&#xff1a;软件RD工程师就是软件研发工程师&#xff0c;诸如PHP程…...

C语言 - 自定义类型

结构体 struct 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 结构的声明 struct tag { 成员变量&#xff1b; }变量列表 //全局变量 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h>struct School {char…...

【零散知识】核密度估计(Kernel Density Estimation)

前言&#xff1a; { 由于有代码需要调试&#xff0c;这一次也是选择了一部分小内容来更新。 这次更新的内容是我之前见到到但没仔细了解的核密度估计&#xff08;Kernel Density Estimation&#xff09; } 正文&#xff1a; { 按照维基百科对核密度估计的介绍[1]&#xff0c…...

ansible配置文件介绍

文章目录ansible主目录结构ansible配置文件优先级主配置文件/etc/ansible/ansible.cfg解析[defaults] 默认配置常用参数主机清单拓展ansible主目录结构 /etc/ansible有以下三个文件或者目录生成 1、Hosts 主机清单配置文件 2、ansible.cfg Ansible配置文件 3、Roles 角色定义目…...

Reac.js入门Redux05

知识点 1、Redux概念简述 2、Redux的工作流程 3、使用Antd实现TodoList页面布局 4、创建Redux中的store 5、Action和Reducer的编写 6、使用Redux完成TodoList删除功能 7、ActionTypes的拆分 8、使用actionCreator统一创建action 9、Redux知识点复习补充 1、Redux概念简述 由于…...

【Altium designer】Ctrl+M测量的尺寸数据无法清除

目录 问题分析 解决方案 问题分析 AD18跟以前的版本有很大不同,绘制PCB封装库时,在使用 Ctrl + M 测量距离后,尺寸字符信息无法选中当然也无法剪切、backspace、delete,如图1所示,反正你拿它没办法,无法清除。 图1 Ctrl+M测量距离后尺寸信息无法消除 解决方案...

神经网络尺寸和参数量计算

前言 这里写个参数计算&#xff0c;会借鉴各路大神的杰作&#xff0c;主要是整理一下怕自己以后忘了找起来麻烦 大部分引自https://blog.csdn.net/qian99/article/details/79008053 参数计算方法 首先是卷积层的计算 下面是一个32x32x3的输入&#xff0c;我们用5x5x3的滤波…...

通俗易懂理解几何光学(四)光学系统中的光阑与光束限制

目录前言光阑光阑概述孔径光阑入射光瞳与出射光瞳入射光瞳&#xff08;入瞳&#xff0c;Entrance Pupils&#xff09;出射光瞳&#xff08;出瞳&#xff0c;Exit Pupils&#xff09;入射光瞳与出射光瞳主光线与边缘光线系统孔径光阑的确定相对孔径视场视场光阑&#xff08;Fiel…...

X509V3数字证书介绍

文章目录参考目的约定文章思路脑图数字证书基础定义用途工作原理数字签名摘要算法基础非对称密钥基础组成数字签名示例数字签名部分数字证书部分文件编码格式DER&#xff08;Distinguished Encoding Rules&#xff09;Identifier octets typeLength octetsContents octetsPEM&a…...

极致案例|打造城商行数字运维成功实践样本

为了充分展示不同企业在数字化转型过程中&#xff0c;对IT运维的实践经验和理念洞察。广通优云特推出【极致案例】系列文章。 本栏目将从业务实践和行业场景出发&#xff0c;解析如何借助前沿技术推动业务创新和行业转型&#xff0c;与读者分享涵盖金融、海关、税务、平安城市等…...

一文看懂对称加密、非对称加密、摘要、数字签名、数字证书

文章目录前言从一个故事说起1. 对称加密2. 非对称加密3. 摘要4. 数字签名5. 中间人攻击6. 数字证书参考资料前言 最近需要实现一个艺术品买卖交易平台。由于安全性的需求&#xff0c;学习了各种加密方法。这里总结一下。 从一个故事说起 Alice要和Bob互传消息&#xff0c;消…...

数字化转型的定义

来啦&#xff0c;坐。 我是冠军&#xff0c;《数据赋能&#xff1a;IT团队技术管理实战》作者&#xff0c;“四季逗”文风创始人。 这是《数字化转型》系列的第一篇&#xff0c;定义。 【一句话解释下&#xff1a;企业数字化转型是一个庞大的系统工程来的&#xff0c;数字化✕…...

java 数字金字塔,含详细解说

/*需求&#xff1a;数字金字塔 第i行 空格数量 左边的数字 右边的数字| 1 | i1 3个 1到1 0(没有数字)| 121 | i2 2个 1到2 1到1| 12321 | i3 1个 1到3 2到1| 123…...

生活数字化 小故事告诉你什么是大数据

生活数字化 小故事告诉你什么是大数据 很多人对大数据这一概念云里雾里&#xff0c;实际上&#xff0c;大数据就发生在你我身边&#xff0c;虽然你看不到它&#xff0c;但它却时时影响着我们的生活。 现阶段&#xff0c;和大数据相关的企业有三种。一种是工具类公司&#xff0c…...

Win11的两个实用技巧系列之如何关闭文字热门搜索、任务栏上的应用

目录 in10和Win11 22H2如何关闭文字热门搜索? Win11 22H2关闭文字热门搜索 Win10 22H2关闭文字热门搜索 Win11中如何不用鼠标打开已固定在任务栏上的应用 鼠标的操作方式如下&#xff1a; 点击拿去 in10和Win11 22H2如何关闭文字热门搜索? 不管是Win10还是Win11&#…...

奇妙生活-神奇数字-9的故事

987654321 * 9 08888888889 987654321 * 18 17777777778 987654321 * 27 26666666667 987654321 * 36 35555555556 987654321 * 45 44444444445 987654321 * 54 53333333334 987654321 * 63 62222222223 987654321 * 72 71111111112 987654321 * 81 80000000001 9876...

python简单小游戏代码教程,Python简单小游戏代码

球球各位大神怎么用python写一个猜词小游戏的代码&#xff1f; key input(请输入一个单词&#xff1a;)description input(输入单词描述&#xff1a;)chance 5mark 5print(现在开始游戏)print(description \t 这是单词的描述,请你输入这个单词&#xff1a; )for i in ra…...

Mac下如何把iphone资料备份到移动硬盘

一般的备份方法 首先新系统的iphone备份已经转到了访达 连接iphone后在访达左边栏会看到你的手机 在终端输入下面这段命令行 ln -s /Volumes/Data/ios_backup &#xff5e;/Library/Application\ Support/MobileSync/Backup /Volumes/Data/ios_backup 这行是你想要指定的目…...

Mac电脑如何使用时间机器进行备份?

如何轻松对你的mac进行备份呢&#xff1f;Mac电脑的时间机器Time Machine可以轻松对您的所有文件进行自动备份&#xff0c;包括应用、音乐、照片、电子邮件、文稿和系统文件。不管是当机还是死机、换机都可以通过备份恢复。 备份数据前准备工作 ▪Mac电脑(所需备份的电脑) ▪外…...

并发编程知识总结

并发编程知识总结 最近学习了&#xff1a;冰河《深入理解高并发编程》&#xff1b;《并发编程的艺术》&#xff1b; 特此简要对学习做了部分总结&#xff0c;方便后续对并发编程知识的完善和巩固&#xff1b; 若想深入了解学习&#xff0c;可阅读上述参考原著&#xff1b; 线…...

视频压缩 ffmpeg

用到的开源库&#xff1a;https://github.com/WritingMinds/ffmpeg-android-java...

未压缩视频数据计算方式

未压缩视频数据计算方式1280 x 720的视频码率为604Mbps。我有一个6秒钟的不压缩视频大小为491MB。视频格式显示为RGB。码率的算法也很简单128072024(颜色位数)*30&#xff08;帧率&#xff09;663552000bps632Mbps。文件大小632&#xff08;码率&#xff09;*6&#xff08;秒&a…...

视频太大怎么在线压缩变小

一些比较大的视频放在手机中很容易占内存&#xff0c;那么我们是怎么进行视频压缩的呢&#xff1f;下面就简单给大家介绍一下。 步骤一&#xff1a;点击在线视频压缩&#xff0c;我们可以看到在线视频压缩的立即使用&#xff1b; 步骤二&#xff1a;我们可以进行文件的压缩设置…...

IB究竟在考什么?IB真的有传闻中的那么难吗?

提起学习“国际课程之王”IB的感受&#xff0c;学生们估计都能开一个“吐槽大会”了&#xff0c;IB很难&#xff0c;不少人学IB&#xff0c;GET到的第一个技能&#xff0c;就是“熬夜”。▲IB学生做的搞笑图&#xff1a;凌晨三点&#xff0c;唯一一扇亮着灯的窗户一定是属于IB学…...

写一个类似大众点评的城市选择控件

来自Leo的原创博客&#xff0c;转载请著名出处 我的stackoverflow 最终效果 当然&#xff0c;这个项目也支持push 和 present方式选择 源代码 LHCityPickerController 支持 搜索所有县级市快速索引自定义热门城市自动保存访问历史&#xff08;最多6个&#xff09;提供接口…...

Python案例:查询城市天气并绘制最高气温与最低气温折线图

Python案例:查询城市天气并绘制最高气温与最低气温折线图 一、解决思路 比如要查询“泸州”的天气。 1、首先获取泸州的城市代码 http://toy1.weather.com.cn/search?cityname=泸州 其中“?cityname=泸州 ”是查询字符串。 在返回的数据里,看第一项数据的ref值,其开头…...

基于STM32单片机的智能家居测量系统设计

当今的家庭生活面临着各种环境和健康问题&#xff0c;周围的生活参数存在潜在的隐患&#xff0c;包括室温、气体中有害物质的浓度等。在新时代&#xff0c;人们越来越关注健康及其相关因素。随着微电子技术的应用&#xff0c;电器的普及&#xff0c;以及单片机和传感器性能的快…...

ACS基于Tr069协议的通信终端测试和管理平台

编写目的用户使用本系统对Cpe进行操作。本系统适用于电信、移动、联通&#xff08;EPON、GPON、ETH上行接口&#xff09;各种型号的Cpe。为整新、检测Cpe的用户提供方便、快捷、高效的生产工具。 项目背景组网后终端PC可以通过&#xff08;ONU-分光器-Olt或ETH上行&#xff09…...

移动终端基础数据管理系统

一、背景 随着移动设备硬件和移动互联技术的发展&#xff0c;移动设备在城市管理工作中广泛应用&#xff0c;通过移动GIS技术将规划数据与空间信息在移动端展现&#xff0c;便于领导和设计人员在移动终端上查阅。移动系统在给我们带来便利的同时&#xff0c;也面临着数据和设备…...

一、微信支付介绍和接入指引

目录一、微信支付介绍和接入指引1、微信支付产品介绍1.1、付款码支付1.2、JSAPI支付1.3、小程序支付1.4、Native支付1.5、APP支付1.6、刷脸支付1.7、申请费用2、接入指引申请流程简述接入微信支付&#xff08;以小程序为例&#xff09;2.1、获取登录账户2.2、获取AppID2.3、绑定…...

微信小程序 - 核心

1、Web页面 2、项目结构 Ps1&#xff1a;应用程序的三个文件app.js、app.json、app.wxss在整个小程序中是唯一的&#xff0c;是全局的&#xff1b;页面级别的会覆盖全局的样式和json&#xff08;配置&#xff09;,就近原则。 Ps2&#xff1a;project.config.json是自动生成的,…...

android微信下拉出现小程序,Android仿微信首页下拉显示小程序列表

花点时间重新熟悉一下AndroidUI方面的东西&#xff0c;把古董PullToRefreshView又撸了一遍&#xff0c;技术这种东西真是忘得快啊...在基础上新增一点东西&#xff0c;粗糙地实现了仿微信首页下拉显示小程序列表的样式&#xff0c;是的&#xff0c;粗糙粗糙...PullToRefreshVie…...

HTML5和JAVA在微信,html5 调起微信支付

本文主要是梳理在微信浏览器中调起微信支付的整个过程&#xff0c;以及主要过程当中界面的展现效果。虽然整个交易过程看起来很简单&#xff0c;就是输入金额&#xff0c;而后调起微信支付&#xff0c;输入密码完成交易&#xff0c;可是在实现过程当中&#xff0c;是须要对接微…...

容器编译apache,部署web

部署httpd [rootlocalhost ~]# mkdir /data [rootlocalhost ~]# cd /data/ [rootlocalhost data]# wget https://mirrors.aliyun.com/apache/apr/apr-1.6.5.tar.gz --2022-08-11 09:12:01-- https://mirrors.aliyun.com/apache/apr/apr-1.6.5.tar.gz Resolving mirrors.aliyu…...

ngrok内网穿透教程 -- 将本地IP映射成对外可访问的域名

下载安装 打开官网 https://ngrok.com/ 首先注册账号&#xff0c;之后下载安装&#xff0c;windows版本直接解压.zip文件 配置 双击安装的 ngrok.exe 文件&#xff0c;进入如下命令窗口&#xff0c;根据官网给出的命令&#xff0c;运行连接自己的帐号&#xff0c;保存 authto…...

Docker源码部署Web服务自启动

Docker源码部署Web服务自启动 文章目录基于容器源码部署httpd基于容器制作镜像测试镜像&#xff0c;部署家具商城网站基于容器源码部署httpd //下载编译安装httpd所需的源码包 [rootlocalhost ~]# mkdir /data [rootlocalhost ~]# cd /data/ [rootlocalhost data]# wget https…...

容器内源码部署httpd

docker源码部署httpd 文章目录容器内源码部署httpd制作镜像测试镜像容器内源码部署httpd //拉取centos的镜像到本地仓库 [rootlocalhost ~]# docker pull centos Using default tag: latest latest: Pulling from library/centos a1d0c7532777: Pull complete Digest: sha256…...

在容器中部署一个web站点

在容器中部署一个web站点 文章目录在容器中部署一个web站点编译安装apache制作镜像测试镜像&#xff0c;并部署网页编译安装apache 拉取centos镜像 [rootlocalhost ~]# docker pull centos:8 8: Pulling from library/centos a1d0c7532777: Pull complete Digest: sha256:a2…...

【超详细】Docker从入门到干活,就看这一篇文章

容器简介 什么是 Linux 容器 Linux容器是与系统其他部分隔离开的一系列进程&#xff0c;从另一个镜像运行&#xff0c;并由该镜像提供支持进程所需的全部文件。 容器提供的镜像包含了应用的所有依赖项&#xff0c;因而在从开发到测试再到生产的整个过程中&#xff0c;它都具…...

Devops常用工具软件之ansible部署使用

一、背景 因某业务环境部署agent采集&#xff0c;且OS多为Linux&#xff0c;部分windows&#xff1b;考虑采用ansible进行批量部署&#xff1b; 二、概要 ansible作为一款自动化运维工具&#xff0c;它是基于Python开发&#xff0c;集合了众多运维工具&#xff08;puppet、c…...

docker镜像管理与镜像制作

docker镜像管理与镜像制作 文章目录docker镜像管理与镜像制作1:镜像制作2&#xff1a;commit制作镜像3&#xff1a; 镜像上传dockerhub4:dockerfile制作镜像1:镜像制作 制作属于自己的Docker镜像&#xff0c;一般有两种方式&#xff1a; 第一种为commit方式&#xff0c;利用已…...

2021 HECTF 部分WP

MISC 快来公众号ya 关注公众号回复签到 SangFor{AaKjtQr_OjJpdA3QwBV_ndsKdn3vPgc_}JamesHarden 一个未知文件&#xff0c;拖入010 发现是zip的前缀&#xff0c;改个文件后缀压缩 是一个.class文件&#xff0c;没见过&#xff0c;用记事本打开 发现疑是凯撒密码的字符串…...

让Windows加倍好看

前言 之前也给大家分享过好多期美化桌面的小工具 包括改图标、任务栏、壁纸、桌面整理等等但这些对桌面外观的改变都很小&#xff0c;要想进行Windows整体风格的美化&#xff0c;修改主题是最方便的 主题美化之前没发过&#xff0c;今天给大家带来大量Windows主题 Win7-Win…...

【2022最全最细】Docker 从入门到精通(建议收藏的教程)

docker不是一个值得投入的领域&#xff0c;它解决的问题是Unix系统最初设计的一个疏忽。从一个不会用docker的小白&#xff0c;自己一步一步的摸索&#xff0c;中间也踩过许多坑。但任然&#xff0c;坚持从哪里跌倒就从哪里爬起来。不求感动自己&#xff0c;但求人生无悔。 1 容…...

Docker基于apache镜像 使用存储挂载 制作web站点

在容器中部署安装HTTP服务 把官方源换成阿里云源 [rootbfc8e35857cb /]# cd /etc/yum.repos.d/ [rootbfc8e35857cb yum.repos.d]# rm -rf * [rootbfc8e35857cb yum.repos.d]# ls -l total 0 [rootbfc8e35857cb yum.repos.d]# curl -o /etc/yum.repos.d/CentOS-Base.repo http…...

最新天龙八部环境-GS环境教程-【长期稳定版本】

前言&#xff1a;本环境开源免费&#xff0c;无毒无后门。有疑问或者BUG&#xff0c;请提交到is https://gitee.com/yulinzhihou/gstlenv/issues 不要再猜测安装了环境被远控&#xff0c;被注入偷取服务端&#xff0c;偷取数据库&#xff0c;远程注入木马及其他程序的可能 开…...

dockers部署web站点

dockers部署web站点 文章目录dockers部署web站点环境需求拉取centos镜像基于centos镜像启动一个容器并进入在容器中部署Apache服务下载并解压APR源码包&#xff0c;编译安装APR下载并解压httpd源码包&#xff0c;编译安装httpd配置Apache服务&#xff0c;验证服务基于容器制作镜…...

[青少年CTF]Crypto—Easy by 周末

闲的没事写份wp(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e; 个人博客&#xff1a;https://www.st1ck4r.top 0x01 一起下棋 考点&#xff1a;棋盘密码 在线解密&#xff1a;https://www.qqxiuzi.cn/bianma/qipanmima.php 0x02 emoji 考点&#xff1a;Emoji表情符…...

Debezium同步之oracle rac数据到oracle单机的安装步骤

1、创建目录 [rootdbz ~]# mkdir /dbz 2、上传执行文件&#xff0c;文件内容如下&#xff1a; [rootdbz ~]# cd /dbz [rootdbz dbz]# ll total 4 -rwxr-xr-x 1 root root 1827 Apr 28 11:14 startdbz1.8.sh 编辑startdbz1.8.sh执行文件 [rootdbz dbz]# vi startdbz1.8.sh #…...

Ubuntu安装Oracle时解压报错,Ubuntu 14.04搭建PHP5+Apache2+Oracle及Oracle管理软件SQL Developer...

Ubuntu 14.04搭建PHP5Apache2Oracle环境最近开发的一个项目&#xff0c;数据库使用Oracle。Oracle本身支持Red Hat&#xff0c;对Ubuntu的支持并不好&#xff0c;如果Ubuntu需要安装Oracle&#xff0c;系统本身需要做伪装等很多工作&#xff0c;所以我只打算使用远程服务器上的…...

wamp扩展php zip.dll,WAMP环境中扩展oracle函数库(oci)

同事昨天接到一个任务,要用php处理oracle数据库的内容,但是php打开oracle扩展不是像mysql那样直接用就行,需要下一点东西才能打开第一步 需要到oracle官方下载一个install client 包,在win下找到你对应系统版本的zip(注意这里是系统版本)例如选择 Instant Client for Microsoft…...

Java算法——判断一个数是否是回文数

原文:https://blog.csdn.net/beyond1123/article/details/52176240?utm_mediumdistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control&dist_request_id&depth_1-utm_sourcedistribute.pc_relevant.none-task-blog-BlogCommendFromMachine…...

回文数算法分析

判断一个整数是否是回文数。回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 示例 1: 输入: 121 输出: true示例 2: 输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个…...

java判断一个数是否是回文数_java编写判断是否是回文数

一个五位数&#xff0c;要你用java编写程序判断它是不是回文数你知道代码是怎样的吗?下面给大家分享的就是这方面的一道java编程题目&#xff0c;一起来看看题目以及解题方法吧。一、题目下面是具体的题目&#xff0c;大家要详细看看哦。一个5位数&#xff0c;判断它是不是回文…...

【Mybatis 使用】mybatis-config.xml 配置(properties 和 settings)

【Mybatis 使用】mybatis-config.xml 配置&#xff08;properties 和 settings&#xff09; 文章目录【Mybatis 使用】mybatis-config.xml 配置&#xff08;properties 和 settings&#xff09;一、可配置的属性二、properties&#xff08;属性&#xff09;1. 基础配置2. 外部配…...

python求100到200的回文数_Python计算回文数的方法

本文实例讲述了Python计算回文数的方法。分享给大家供大家参考。具体如下&#xff1a;这里检查数字是不是回文数&#xff0c;用196算法生成一个数字的回文数num 905;def is_Palindrome(num):"""判断一个数字是不是回文数&#xff0c;这里有些取巧了:param num:…...

python找出回文数_使用python实现回文数的四种方法小结

回文数就是指整数倒过来和原整数相等。 Example 1:Input: 121Output: true Example 2:Input: -121Output: falseExplanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. Example 3:Input: 10Output: falseE…...

五位数回文数c语言程序,五位数的回文数有多少个

2018-12-16数学中有哪些回文数&#xff1f;简介折叠编辑本段回文数是指一个像16461这样“对称”的数&#xff0c;即&#xff1a;将这个数的数字按相反的顺序重新排列后&#xff0c;所得到的数和原来的数一样。这里&#xff0c;“回文”是指像“妈妈爱我&#xff0c;我爱妈妈”这…...

Java算法:回文数

一个正整数&#xff0c;如果交换高低位以后和原数相等&#xff0c;那么称这个数为回文数。比如 121121&#xff0c;23322332都是回文数&#xff0c;13,456713,4567 不是回文数。 任意一个正整数&#xff0c;如果其不是回文数&#xff0c;将该数交换高低位以后和原数相加得到一…...

c语言里判断回文数的函数,(C语言)回文数的判断

问题描述&#xff1a;判断一个数是否为回文数&#xff1b;121&#xff1b;12321&#xff1b;1234321&#xff1b;程序分析&#xff1a;1.回文数(palindromic number)&#xff1a;是指一个数的最高位和最低位上的数相等&#xff0c;第二高位与次低位上的数相等&#xff0c;也就是…...

C语言中判断回文数用数组的方法,【C语言】回文数和回文字符串的判断

一、名词解释&#xff1a;如果一个数正着反着都是一样,就称为这个数是回文数。例如:6, 66, 606, 6666同理如果一个字符串正着反着都是一样就称为这个字符串是回文字符串&#xff0c;例如“aba”&#xff0c;"aabb"二、解题思路回文数解题思路一&#xff1a;可以将整数…...

C语言求三位数的回文数,回文数 C语言求解

#9unsigned long getRevNum(unsigned long x, int n){unsigned long y0;for(i0;i{ y*10;yx%10;}return y;}unsigned long sumrev(unsigned long x, int n)return x getRevNum(x,n);)int isplalindrome(unsigned long x,int n){ int i,j1;int res1;for(i1;iif(xfor(i10;i<...

10000内的回文数c语言,回文数

“回文”是指正读反读都能读通的句子&#xff0c;它是古今中外都有的一种修辞方式和文字游戏&#xff0c;如“我为人人&#xff0c;人人为我”等。在数学中也有这样一类数字有这样的特征&#xff0c;成为回文数(palindrome number)。[1]设n是一任意自然数。若将n的各位数字反向…...

Rust中的所有权是什么

文章目录所有权规则变量作用域内存与分配变量与数据交互的方式移动克隆所有权&#xff08;系统&#xff09;是 Rust 最为与众不同的特性&#xff0c;对语言的其他部分有着深刻含义。它让 Rust 无需垃圾回收&#xff08;garbage collector&#xff09;即可保障内存安全&#xff…...

java学习计划

java学习计划 虚拟机软件vmware 后端全部&#xff0c;从架构开始&#xff0c;开发&#xff0c;部署&#xff0c;调优 https://baijiahao.baidu.com/s?id1711770044606618180&wfrspider&forpc 知乎&#xff0c;腾讯技术总监推荐&#xff1a;https://www.zhihu.com/que…...

Google《Android性能优化》学习笔记一

Google近期在Udacity上发布了Android性能优化的在线课程&#xff0c;分别从渲染&#xff0c;运算与内存&#xff0c;电量几个方面介绍了如何去优化性能&#xff0c;这些课程是Google之前在Youtube上发布的Android性能优化典范专题课程的细化与补充。下面是本文作者胡凯me对渲染…...

Linux网络技术管理及进程管理

OSI七层模型和TCP/IP四层模型 OSI七层模型&#xff1a;OSI&#xff08;Open System Interconnection&#xff09;开放系统互连参考模型是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间互联的标准体系。 TCP/IP四层模型&#xff1a;TCP/IP参考模…...

计算机知识大讲堂,计算机知识大讲堂,电脑系统革新构成

新一代电脑不仅从工作原理上已经悄然改变很多&#xff0c;电脑系统的构成也随之改变。为方便说明这里将电脑的系统构成分为逻辑构成和物理构成&#xff0c;具体更新分别说明如下根据传统的冯诺依曼体系思想&#xff0c;电脑系统可分成五大逻辑部件&#xff0c;但其内涵已经悄然…...

电脑蓝屏死机

电脑蓝屏死机 2010年11月16日死机的问题&#xff0c;或许从大家使用电脑开始起的那一天就时刻伴随着你&#xff0c;这也许是我们在日常使用电脑过程中最常遇到的问题之一了。造成死机的原因多种多样&#xff0c;让人很难捉摸。这种问题在DOS系统时代&#xff0c;或许还比较好解…...

onebot 开发板_onebot一体机,这是一款简单方便的电脑

一体机&#xff0c;就是PC发展史上“创新”的代名词。在台式机炙手可热的时候&#xff0c;苹果率先开拓了一体机市场&#xff0c;由于技术与成本的限制&#xff0c;虽然未能真正颠覆传统台式机的统治地位&#xff0c;但是一体机抢占了不少台式机的份额&#xff0c;而且动摇了笔…...

菜鸟面京东

我背着包在成都被污染的空气中踽踽独行&#xff0c;沿着二环&#xff0c;神情有些萧索&#xff0c;不时发出几声咳嗽&#xff0c;却沉静于自己的思绪。 刚刚从华为那边的中兴赶过来&#xff0c;已经五点过了&#xff0c;海滨酒店的走廊里或坐或站着十数人&#xff0c;我忍受着疲…...

京东时尚“质感”升级,成为时尚产业新T台

3月1日&#xff0c;京东蝴蝶节“化蝶盛典”在北京隆重举行。发布会上&#xff0c;京东集团副总裁、京东商城时尚生活事业群时尚事业部总裁丁霞表示&#xff0c;2018年&#xff0c;京东要做有质感的时尚电商&#xff0c;在品牌品类、个性化产品、服务体验等多方面&#xff0c;为…...

直新笔试题

两小时内完成京东时尚大牌页面&#xff0c;使用JS加分 完成效果 可以使用JS,或者JQuery生成数据&#xff0c;加分项 <!DOCTYPE html> <html lang"en"> <head><!-- 必须的 meta 标签 --><meta charset"utf-8"><meta nam…...

Linux网络技术管理及进程管理(week2_day4)--技术流ken

OSI七层模型和TCP/IP四层模型 OSI七层模型&#xff1a;OSI&#xff08;Open System Interconnection&#xff09;开放系统互连参考模型是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间互联的标准体系。 TCP/IP四层模型&#xff1a;TCP/IP参考模型…...

Dubbo----------------------------配置信息整合SpringBoot的三种方式

1.启动时检查 在启动时检查依赖的服务是否可用 Dubbo 缺省会在启动时检查依赖的服务是否可用&#xff0c;不可用时会抛出异常&#xff0c;阻止 Spring 初始化完成&#xff0c;以便上线时&#xff0c;能及早发现问题&#xff0c;默认 check“true”。 可以通过 check“false”…...

网络与进程管理

OSI七层模型和TCP/IP四层模型 OSI七层模型&#xff1a;OSI&#xff08;Open System Interconnection&#xff09;开放系统互连参考模型是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间互联的标准体系。TCP/IP四层模型&#xff1a;TCP/IP参考模型…...

接口自动化测试-python-笔记

概念接口测试&#xff1a;是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换、传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。自动化测试&#xff1a;是把以人为驱动的测试行为转化为机器执行的一种过程。实现方式使用接口测试工具来实现&#xff0c;…...

动画目标匹配

1、动画目标匹配动画目标匹配主要指的是&#xff1a;当游戏中角色要以某种动作移动&#xff0c;该动作播放完毕后&#xff0c;人物的手或者脚必须落在某一个地方比如&#xff1a;角色需要跳过踏脚石或者跳跃并抓住房梁那么这时我们就需要动作目标匹配来达到想要的效果2、如何实…...

iserver配置https加密通信

1.升级iserver为https访问&#xff1a;iserver是部署在tomcat中&#xff0c;所以只要配置tomcat的相关配置就可以&#xff1a; &#xff08;1&#xff09;https访问需要用到证书&#xff0c;因此需要准备相关证书&#xff0c;证书的格式有多种&#xff0c;比如后缀为.crt格式的…...

SpringBoot可用的无数据库后台授权解决方案

1、概述此方案适用于无数据库环境的后台管理程序配置访问授权规则。通过纯文件的配置方式&#xff0c;可以对请求的url以及页面中的元素配置独立授权。2、配置方式配置方案基于ini文件格式&#xff0c;除了url、元素授权部分是动态增加&#xff0c;其他配置项是固定结构的&…...

application.yml配置文件大全汇总

application.yml文件的配置文件&#xff1a; spring:datasource:username: rootpassword: 990526url: jdbc:mysql://localhost:3306/springboot?serverTimezoneUTC&useUnicodetrue&characterEncodingUTF-8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alib…...

application.properties常用配置

application.properties #默认的四要素 key固定 spring.datasource.urljdbc:oracle:thin:localhost:1521:orcl spring.datasource.driver-class-nameoracle.jdbc.OracleDriver spring.datasource.usernamescott spring.datasource.passwordtiger#设置日志级别 #lv: TRACE, DEB…...

轻装上阵Html5游戏开发,JEESJS(四)

下面我将通过完善Demo的形式&#xff0c;来演示下用法。首先在html中导入需要的库&#xff0c;我定义了一个index.html用来作为演示的入口&#xff1a; index.html: <!DOCTYPE html> <html> <head> <title></title> <meta charset"utf-…...

java配置ssl证书实现https请求,一级域名和二级域名配置https,小程序https后台的配置

上一节给大家讲了服务器的部署&#xff0c;正常的http请求都可以实现了&#xff0c;但是我们做小程序开发时需要用到https&#xff0c;所以这一节要教大家如何让自己的后台服务器实现https请求。这节是以java部署服务器并配置https为例&#xff0c;别的语言可以把这篇文章作为参…...

大数字的单位转换方法

大数字的单位转换方法数据准备大数字转字符串字符串转大数字说明近期做了个游戏&#xff0c;用到了大数字的单位计算和转换&#xff0c;这里作为参考纪录一下。js写的&#xff0c;其他的语言应该也差不了太多。数据准备 显示的通用格式为&#xff1a; 999.999aa&#xff0c;小…...

linux 查看硬盘还是固态

lsblk -d -o name,rota 返回 0 为ssd 返回1 为硬盘...

固态硬盘linux提升,分析如何提升Linux的固态硬盘使用率?

分析如何提升Linux的固态硬盘使用率?固态硬盘(SSD)不是普通的硬盘。文件在固态硬盘中的处理方式与地普通硬盘中的方式完全不同&#xff0c;如果安装Linux不同版本时没有把这些差异考虑进去&#xff0c;就很难充分发挥固态硬盘的优势&#xff0c;而且很可能在使用一段时间后造成…...

linux固态硬盘交换分区大小,分析如何提升Linux的固态硬盘使用率?

固态硬盘(SSD)不是普通的硬盘。文件在固态硬盘中的处理方式与地普通硬盘中的方式完全不同&#xff0c;如果安装Linux不同版本时没有把这些差异考虑进去&#xff0c;就很难充分发挥固态硬盘的优势&#xff0c;而且很可能在使用一段时间后造成严重的性能下降。修改默认的固态硬盘…...

linux固态硬盘和机械盘,判断linux磁盘是固态硬盘还是机械硬盘的方法

判断linux磁盘是固态硬盘还是机械硬盘的三种方法&#xff1a; 方法一 判断cat /sys/block//queue/rotational的返回值(其中为你的硬盘设备名称&#xff0c;例如sda等等)&#xff0c;如果返回1 则表示磁盘可旋转&#xff0c;那么就是HDD了&#xff1b; 如果返回0&#xff0c;…...

收益率的分解 无风险利率

近似形式&#xff1a; 名义无风险利率 实际无风险利率 预期的通货膨胀 nominal risk-free rate real risk-free rate expected inflation rate 精确形式&#xff1a; (1 nominal risk-free rate) (1 real risk-free rate) x (1 expected inflation rate)...

使用Tushare任取场内或者场外基金历史超过2年的200个公募基金,取得过去两年的基金净值序列,通过计算夏普比率(可任意设定无风险利率),来找到19年表现最好的50个基金。

付费专栏:需要查看的请订购 使用Tushare任取场内或者场外基金历史超过2年的200个公募基金,取得过去两年的基金净值序列,通过计算夏普比率(可任意设定无风险利率),来找到19年表现最好的50个基金。通过计算平均收益率,找到2020年表现最好的50个基金。看看有多少基金在其夏…...

SAS在金融中的应用三

第一题&#xff1a; 导入数据上证综指&#xff0c;试计算2020期间各月上证综指的单期百分比收益率&#xff0c;算术平均收益率 和几何平均收益率&#xff0c;以及财富指数。&#xff08;要求&#xff1a;采用retain语句和transpose语句两种形式&#xff09; /*导入数据上证综…...

金融工程学(九):期权回报与价格分析

文章目录期权回报与价格分析期权的回报与盈亏分布期权价格的特性内在价值与时间价值内在价值实值期权、平价期权与虚值期权期权的时间价值期权价格的影响因素假设期权价格的上下限期权价格的上限期权价格的下限提前执行美式期权的合理性提前执行无收益资产美式看涨期权提前执行…...

【从零开始玩量化12】无风险利率

上文中&#xff0c;我们详细的介绍了夏普比率&#xff0c;其公式中的一个重要变量&#xff0c;就是无风险利率&#xff0c;这个概念好理解&#xff0c;但是实操过程中如何取值&#xff0c;很多平台说是4%&#xff0c;真的对吗&#xff0c;本文阐述一下。 无风险利率 就是字面…...

Huggett (1993):非完全保险经济中异质性行为者的无风险利率,及其Matlab代码

本文将详细解释1993年Huggett的经典论文&#xff1a;不完全保险经济中异质性行为者的无风险利率&#xff0c;并提供Matlab代码 Mark Huggett(1993). “The Risk-Free Rate in Heterogeneous-Agent Incomplete-Insurance Economies.” Journal of Economic Dynamics and Contro…...

浅谈Android中的Fragment

什么是Fragment? Fragment是一种可以嵌入在activity当中的一个模块化和可重复利用的组件&#xff0c;它可以定义自己的布局和监听事件&#xff0c;以及通过使用它自己的生命周期回调方法来定义的它自己的行为。Fragment的设计理念:允许你把Activity中的布局文件分散到几个不同…...

ES6入门-----解构赋值

ES6入门-----解构赋值 解构赋值是对赋值运算符的扩展。 他是一种针对数组或者对象进行模式匹配&#xff0c;然后对其中的变量进行赋值。 一&#xff1a;数组的解构赋值 基本 const arr [1, 2, 3, 4]; let [a, b, c, d] arr;默认赋值&#xff1a;当解构模式有匹配结果&…...

2021.5.19笔记 Collection集合

概述 数组中存储的是同一类型的元素&#xff0c;可以存储基本数据类型值和对象&#xff1b;集合存储的都是对象&#xff0c;而且对象的类型可以不一致。 集合的框架: Collection的一些方法 public class CollectionClass {public static void main(String[] args) {Collectio…...

ES6入门之------let 和 const

ES6入门之------let 和 const 一. let 1. let只作用在当前块级作用域内 我们首先来看一下什么是块级作用域&#xff1a; 1.通俗来说就是一对花括号中的区域{…} 2.块级作用域可以嵌套 { .... }if(){ .... }for(){ ..... } ...还有很多这里不就不举例了&#xff0c;我们特别来…...

WebServer Project-02-XML解析

XML&#xff1a;Extensible Markup Language&#xff0c;可扩展标记语言&#xff0c;左卫门数据的一种存储格式或用于存储软件的参数&#xff0c;程序解析此配置文件&#xff0c;就可以达到不修改代码就能更改程序的目的。 <?xml version"1.0" encoding"UTF…...

Android持久化存储——(包含操作SQLite数据库)

《第一行代码》读书手札 你可能会遇到的问题&#xff1a;解决File Explorer 中无显示问题 Android中&#xff0c;持久化存储&#xff0c;常见的一共有三种方法实现 &#xff08;一.&#xff09;利用文件存储 文件存储是Android存储中&#xff0c;最基本的一种存储方式。就是利…...

Android中使用LitePal操控SQLite数据库

《第一行代码》读书手札 &#xff08;一&#xff09;什么是LitePal数据库 LitePal数据库是安卓的一个开源库&#xff0c;我们在以后的开发中&#xff0c;将会遇到许许多多的开源库&#xff0c;感谢开源社 区&#xff1b;因为开源社区的存在&#xff0c;一些我们需要的功能&am…...

(二)Spring中的ioc

目录 Spring的ioc操作ioc底层使用的技术ioc底层原理ioc入门案例bean管理&#xff08;xml方式&#xff09;IOC和DI的区别Spring整合WEB的原理Spring 整合的具体操作 Spring的ioc操作 把对象的创建交给Spring管理ioc操作分为两种 配置文件方式注解方式 ioc底层使用的技术 xml配…...

吉软-人文精英班-第6次作业

<!DOCTYPE html> <html lang"en"> <head> <meta charset"utf-8"> <style type"text/css"> /* 先定义无边框编剧 */ *{ margin:0; padding:0; …...

自动驾驶、无人驾驶、车联网笔记分享

持续更新整理一些自动驾驶领域、无人驾驶领域、车联网领域的优秀资源笔记&#xff0c;分享给有需要的人。 车路协同、车联网、智慧交通、智能网联车、自动驾驶、无人驾驶、高精度地图资料汇总与整理 车路协同优质资料整理地址&#xff1a; 语雀&#xff1a;车路协同、自动驾驶…...

Python学习笔记之【函数式编程】

函数式编程的一个特点就是&#xff0c;允许把函数本身作为参数传入另一个函数&#xff0c;还允许返回一个函数。 高阶函数 变量可以指向函数 >>> f abs >>> f(-10) 10 函数名也是变量 >>> abs 10 >>> abs(-10) Traceback (most rec…...

Android Glide4缓存动态url图片

Glide是目前最流行开源图片处理框架之一&#xff0c;拥有强大的图片加载&#xff0c;缓存功能。在开发中&#xff0c;使用起来真是爽歪歪。 Glide GitHub地址&#xff1a;https://github.com/bumptech/glide Glide和Picasso的缓存策略都十分出色&#xff0c;他们都是基于图片的…...

嵌入式C语言中Volatile的陷阱

uchar * volatile reg;这行代码里volatile修饰的是reg这个变量。所以这里实际上是定义了一个uchar类型的指针&#xff0c;并且这个指针变量本身是volatile 的。但是指针所指的内容并不是volatile的&#xff01;在实际使用的时候&#xff0c;编译器对代码中指针变量reg本身的操作…...

(十五)使用任务通知实现命令行解释器

虽然这是介绍FreeRTOS系列的文章&#xff0c;但这篇文章偏重于命令行解释器的实现。这一方面是因为任务通知使用起来非常简单&#xff0c;另一方面也因为对于嵌入式程序来说&#xff0c;