圆角矩形的绘制和曲线均匀化
摘要: 圆角矩形是软件 UI 等视觉设计中的常见表达,一种常见的绘制方法是将矩形的四角替换为与边相切的四分之一圆弧,然而这种绘制方式会在连接处产生视觉上的切折感,这是因为圆弧和直线的连接处只满足 G1G^1G1 连续性。本文探究了如何使用高次埃米尔特插值绘制高阶连续的圆角曲线,以及如何使用常微分方程的数值解法实现曲线的均匀化。
关键词: 圆角矩形;埃米尔特插值;常微分方程数值解
引言
圆角矩形被广泛应用于产品的视觉设计中,例如智能手机的边框、移动应用的图标、家具的边角等等。人们通常将在矩形的四角改为相切的四分之一圆弧来绘制圆角矩形,如图 1a 所示,在和更高阶连续曲线的对比之下,这种方法绘制出的圆角就会在连接处产生切折感,显得不是那么顺滑,原因是这种绘制方式在圆角的连接处只能满足 G1G^1G1 连续,图 1b 直观展示了连接处的曲率突变。这种视觉效果的差别已经被 Apple 公司的视觉设计师注意到,并且成功应用于他们的产品设计中,例如 iOS 7 之后的图标边框抛弃了 圆弧和切线(图 2)。
图1(a):效果对比 | 图1(b):曲率图 |
---|---|
![]() | ![]() |
图2 |
---|
![]() |
根据数值分析的内容,通过埃米尔特插值可以构造任意高阶的多项式,从而可以满足任意高阶的连续性要求,所以我们就可以将其应用于圆角的绘制,从而得到更顺滑的圆角曲线。
问题建模
由于二维曲线上可能存在相同横坐标的点,所以一般情况下不能用形如 y=f(x)y=f(x)y=f(x) 这样的函数表达,我们可以通过引入一个隐变量 ttt 来表达任意的二维曲线:
{Px=x(t)Py=y(t)\begin{equation} \left\{\begin{array}{cc} P_x = x(t) \\ P_y = y(t) \end{array}\right. \end{equation} {Px=x(t)Py=y(t)
隐变量 ttt 可以理解为绘制过程的时间,因此公式实际上也描述了曲线的画法:对指定的时间点 ttt,可以求得要绘制的点 P=(Px,Py)=(x(t),y(t))P = (P_x, P_y) = (x(t), y(t))P=(Px,Py)=(x(t),y(t))。 例如图 1a 中的圆弧和切线组合可以表达为:
P={(0,t)t<0(1−cos(π2t),sin(π2t))0≤t<1(t,1)1≤t\begin{equation} P = \begin{cases} (0, t) & t < 0 \\ (1 - \cos(\frac{\pi}{2} t), \sin(\frac{\pi}{2} t)) & 0 \le t < 1 \\ (t, 1) & 1 \le t \end{cases} \end{equation} P=⎩⎨⎧(0,t)(1−cos(2πt),sin(2πt))(t,1)t<00≤t<11≤t
在数学上,x(t)x(t)x(t) 和 y(t)y(t)y(t) 的 kkk 阶导数连续被称为参数连续性, 使用 CkC^kCk 来表示。然而参数连续性并不能完全表达曲线的连续性,因为相同
的轨迹可能由完全不同的运动过程形成,例如下面的公式和式 2 描述了同样的轨迹,但不满足 C1C^1C1 连续性:
P={(0,t)t<0(1−cos(π2t),sin(π2t))0≤t<1(1,1)1≤t<2(t−1,1)2≤t\begin{equation} P = \begin{cases} (0, t) & t < 0 \\ (1 - \cos(\frac{\pi}{2} t), \sin(\frac{\pi}{2} t)) & 0 \le t < 1 \\ (1, 1) & 1 \le t < 2 \\ (t -1, 1) & 2 \le t \end{cases} \end{equation} P=⎩⎨⎧(0,t)(1−cos(2πt),sin(2πt))(1,1)(t−1,1)t<00≤t<11≤t<22≤t
因此,几何连续性(GkG^kGk)的概念被提出,其含义是位置 P=(x(t),y(t))P=(x(t), y(t))P=(x(t),y(t)) 关于路程 s=∫0tx′2(t)+y′2(t)dts=\int_0^t { \sqrt{x'^2(t) + y'^2(t)}\ \mathrm{d}t }s=∫0tx′2(t)+y′2(t) dt
的参数方程(称为自然参数方程)满足 kkk 阶导数 连续的要求。一般来说,如果一个曲线 P=(x(t),y(t))P=(x(t), y(t))P=(x(t),y(t)) 可以经过一个重参数化过程 P=(x(t(s)),y(t(s)))P=(x(t(s)), y(t(s)))P=(x(t(s)),y(t(s))) 变成 kkk 阶参数连续的,那么它就是 kkk 阶几何连续的。如果 x(t)x(t)x(t) 和 y(t)y(t)y(t) 都是满足 CkC^kCk 的多项式,那么根据经验易知,我们总可以经过一个非线性的时间放缩过程得到其对应的自然参数方程,因而它也是满足 GkG^kGk 的。
不失一般性,下面我们只讨论从 (0,0)(0,0)(0,0) 到 (1,1)(1,1)(1,1) 的圆角绘制问题,并且不妨限定转角的绘制时间为 [0,1][0, 1][0,1]。在这个问题中,x(t)x(t)x(t) 和 y(t)y(t)y(t) 要满足以下约束:
-
起终点位置
x(0)=0,y(0)=0,x(1)=1,y(1)=1\begin{equation} x(0) = 0,\ y(0) = 0, x(1) = 1,\ y(1) = 1 \end{equation} x(0)=0, y(0)=0,x(1)=1, y(1)=1 -
G1G^1G1 连续
圆角的起点和终点都与直线相接:
x′(0)=0,y′(0)=ky,x′(1)=kx,y′(1)=0\begin{equation} x'(0) = 0,\ y'(0) = k_y,\ x'(1) = k_x,\ y'(1) = 0 \end{equation} x′(0)=0, y′(0)=ky, x′(1)=kx, y′(1)=0
式中出现 kyk_yky 和 kxk_xkx 的原因是直线 L=(at,bt)L=(at, bt)L=(at,bt) 乘上一个系数后的结果 L′=(k⋅at,k⋅bt)L'=(k \cdot at, k \cdot bt)L′=(k⋅at,k⋅bt) 形成的图像与此前相同(即对应同样的自然参数方程)。 -
Gn(n>1)G^n\ (n>1)Gn (n>1) 连续
在曲线内部,nnn 阶多项式本身即满足 GnG^nGn 的要求。在端点处,因为直线二阶以上的导数都为 000,所以:
x(n)(0)=y(n)(0)=x(n)(1)=y(n)(1)=0\begin{equation} x^{(n)}(0) = y^{(n)}(0) = x^{(n)}(1) = y^{(n)}(1) = 0 \end{equation} x(n)(0)=y(n)(0)=x(n)(1)=y(n)(1)=0 -
关于角平分线对称
绘制的圆角应该关于角的平分线 x+y=1x+y=1x+y=1 对称:
∀t∈[0,1],∃t′∈[0,1]{x(t)+x(t′)2+y(t)+y(t′)2=1y(t′)−y(t)=x(t′)−x(t)\begin{equation} \forall t \in [0, 1], \exists t' \in [0, 1] \left\{ \begin{aligned} & \frac{x(t) + x(t')}{2} + \frac{y(t) + y(t')}{2} = 1 \\ & y(t') - y(t) = x(t') - x(t) \end{aligned} \right. \end{equation} ∀t∈[0,1],∃t′∈[0,1]⎩⎨⎧2x(t)+x(t′)+2y(t)+y(t′)=1y(t′)−y(t)=x(t′)−x(t)
圆角的绘制
我们可以通过一个更严格的充分条件保证我们设计的函数一定满足约束 4:让绘制过程也关于这条直线对称的, 即 t′=1−tt' = 1 - tt′=1−t,那么我们就可以推出:
y(t)=1−x(1−t)ky=kx\begin{equation} \begin{aligned} y(t) & = 1 - x(1 - t) \\ k_y & = k_x \end{aligned} \end{equation} y(t)ky=1−x(1−t)=kx
现在,我们只需确定 x(t)x(t)x(t) 和 kxk_xkx 即可,这极大简化了设计工作。设计满足约束 1-3 的函数 x(t)x(t)x(t) 本质上是一个插值问题,满足 GnG^nGn
的圆角曲线有 2n+22n+22n+2 个插值条件,因此可以用 2n+12n+12n+1 次埃米尔特插值构造 x(t)x(t)x(t)。
以 n=2n=2n=2 为例,构造均差表 1a,可得插值多项式:
x(t)=t3+(kx−3)t3(t−1)+(6−3kx)t3(t−1)2\begin{equation} \begin{aligned} x(t) = t^3 + (k_x - 3) t^3 (t-1) + (6 - 3k_x) t^3 (t-1)^2 \end{aligned} \end{equation} x(t)=t3+(kx−3)t3(t−1)+(6−3kx)t3(t−1)2
图 3 显示了不同 kxk_xkx 取值曲线的效果,从图上可见,kxk_xkx 值的选取对效果有非常重要的影响,而当 kx=2k_x=2kx=2 时曲线的视觉效果最顺滑。
很难去解释为什么 kx=2k_x=2kx=2 时的曲线效果最好,但观察式 9 可知 kx=2k_x=2kx=2 恰好使得中最高次项系数为 0, 此时插值多项式退化为 2n2n2n 次多项式,这不得不让人怀疑这不是一种巧合。我们有理由猜测,在求更高阶连续的曲线时,同样当 kxk_xkx 值的选取使得最高次项系数为 0 时效果最好。
图 3 |
---|
![]() |
顺着这个猜测会发现一个更有趣的事实:对于任意的高阶连续的曲线 n>1n > 1n>1,使它们最高次项系数为 0 的条件都是
kx=2k_x = 2kx=2!可以这样简单证明这个结论:把 kx=2k_x = 2kx=2 带入表 1a 得到表 1b。当 nnn 由 2 变为 3 会多出两个插值条件,反应到均差表的构造上就是会多出表 1c 中的第 4 行和第 8 行。 在表 1b 中,第 3 行的插值条件往右下和第 6 行的插值条件往右的数字刚好满足"绝对值相等、正负号交替"的性质,则根据均差表的构造规则,在表 1c 中新构造出的一层也满足这个性质,最终右下角的数字一定为两个符号和绝对值相同的数的差,因此一定为 0。
图 4 是 nnn、kxk_xkx 取不同值的效果对比,可明显看出,kx=2k_x=2kx=2 在任何阶次下的效果都是最好的。当可以绘制任意高阶连续的圆角之后,一个很自然的问题是:能否绘制无穷阶连续的圆角?答案是否定的,因为无穷阶连续会使得 x(t)x(t)x(t) 的任意阶导数都为 0,那么根据 x(0)=0x(0)=0x(0)=0,使用泰勒插值可得 x(t)≡0x(t) \equiv 0x(t)≡0,这与 x(1)=1x(1)=1x(1)=1 冲突。从图上也能直观看出,更高阶的曲线则产生更小的圆角,而当无穷阶连续时就会退化为直角。
图4 |
---|
![]() |
曲线均匀化
上一节给出的方法已经能让我们绘制出效果很好的连续圆角曲线了,但其仍有不足之处:所得插值公式在输入均匀的 ttt 时输出的点是不均匀的。这个问题在绘制虚线或者点线等不连续的线时就会显露出来,如图5,点会在拐角处更集中,因此有必要继续探索将曲线均匀化的方法。
图5 |
---|
![]() |
本质上,曲线均匀化就是从上面一节中所得的参数方程求得对应的自然参数方程的过程。自然参数方程在大多
数情况下都很难求,无法得到解析解,只能使用数值方法,在这里也不例外。我们可以通过一个非线性的重参
数化来实现均匀化,即设计一个函数 t(s)t(s)t(s),使得 P=(x(t(s)),y(t(s)))P=(x(t(s)), y(t(s)))P=(x(t(s)),y(t(s))) 满足:
(dPxds)2+(dPyds)2=1\begin{equation} \begin{aligned} \sqrt{ \left(\frac{\mathrm{d}P_x}{\mathrm{d}s}\right)^2 + \left(\frac{\mathrm{d}P_y}{\mathrm{d}s}\right)^2 } = 1 \end{aligned} \end{equation} (dsdPx)2+(dsdPy)2=1
将式 8 代入得:
dPxds2+dPyds2=(x′(t(s))⋅t′(s))2+(x′(1−t(s))⋅t′(s))2=1\begin{equation} \frac{\mathrm{d}P_x}{\mathrm{d}s}^2 + \frac{\mathrm{d}P_y}{\mathrm{d}s}^2 = \left(x'(t(s)) \cdot t'(s) \right)^2 + \left(x'(1 - t(s)) \cdot t'(s) \right)^2 = 1 \end{equation} dsdPx2+dsdPy2=(x′(t(s))⋅t′(s))2+(x′(1−t(s))⋅t′(s))2=1
整理后,可得关于 t(s)t(s)t(s) 的微分方程:
t′(s)=1x′2(t(s))+x′2(1−t(s))\begin{equation} t'(s) = \frac{1}{ \sqrt{x'^2(t(s)) + x'^2(1 - t(s))} } \end{equation} t′(s)=x′2(t(s))+x′2(1−t(s))1
其中开方后的符号对曲线的最终均匀化结果没有影响,故可以取正。
针对本圆角绘制问题,该微分方程的初值条件为 t(0)=0t(0) = 0t(0)=0。绘制均匀化圆角的完整流程如下:
- 使用上一节的方法求出多项式 x(t)x(t)x(t);
- 求出 x(t)x(t)x(t) 的导数 x′(t)x'(t)x′(t),很容易编程实现多项式的求导;
- 给定步长 sss,利用式 12 和初值条件 t(0)=0t(0)=0t(0)=0 求得均匀分布的间隔为 sss 的点对应的 ttt 值;
- 将求得的 ttt 值序列代入 x(t)x(t)x(t) 和式 8,得到最终的点坐标。
图 6b 为在 n=2n=2n=2、kx=2k_x=2kx=2 的圆角曲线上取 s=0.05s=0.05s=0.05 的绘制效果,图 6a 为对应的 ttt 值序列,从图中可以明显看出是非线性的。
图6 |
---|
![]() |
总结
由于研究时间有限,本文只讨论了最常见的 90° 直角的绘制方法,但显然可以在本文的方法上进行一些修补使之进一步推广到任意角度。总的来说,本文基于数值分析课程内容,对圆角矩形的绘制方法进行了深入研究,成功绘制出了高阶连续的均匀圆角曲线,并通过均匀化得到了虚线版本,所得曲线相比较普通的圆弧和切线组合具有更顺滑的视觉效果。附录A展示了不同阶连续的完整矩形及点线版本的效果。
附录
A 完整的圆角矩形图像
B 圆角矩形绘制代码
-
numalgo.py
"""埃米尔特插值实现 """import numpy as np from typing import Callableclass Polynomial:"""多项式函数类"""def __init__(self, a: np.ndarray) -> None:self.a = adef __call__(self, x):return self.a @ np.full_like(self.a, x) ** np.arange(0, len(self.a))def derivate(self) -> "Polynomial":"""求导一次"""return Polynomial(self.a[1:] * np.arange(1, len(self.a)))class Emmert:"""基于均差表的埃米尔特插值函数类"""def __init__(self, x: np.ndarray, y: np.ndarray) -> None:assert x.shape == y.shapeself.x = xself.y = ydef __call__(self, x):x = x - self.xfor i in range(1, len(x)):x[i] *= x[i - 1]x[1:] = x[:-1]x[0] = 1return self.y @ xdef to_polynomial(self) -> Polynomial:"""均差表转多项式"""a = np.zeros_like(self.y)b = np.zeros_like(self.y)b[0] = 1a += self.y[0] * b[0]for i in range(1, len(self.y)):b[1:] = b[:-1]b[0] = 0b[:-1] += -self.x[i - 1] * b[1:]a += self.y[i] * breturn Polynomial(a)def emmert(constraits: dict[float, list[float]]) -> Emmert:"""埃米尔特插值"""px, py = zip(*sorted(constraits.items()))indexes = [len(i) for i in py]indexes = [sum(indexes[:i]) for i in range(len(indexes) + 1)]x = np.empty(indexes[-1], dtype=np.float64)for i in range(0, len(indexes) - 1):x[indexes[i] : indexes[i + 1]] = px[i]y = np.empty_like(x)for i in range(0, len(x) - 1):for j in range(0, len(indexes) - 1):if len(py[j]) > i:y[indexes[j] + i : indexes[j + 1]] = py[j][i]# meandiffstep = i + 1y[step:] = (y[step:] - y[step - 1 : -1]) / (x[step:] - x[:-step])return Emmert(x, y)def euler(deri: Callable[[float, float], float], xs: np.ndarray, y0: float ) -> np.ndarray:"""欧拉法求微分方程数值解"""ans = np.empty_like(xs)ans[0] = y0for i in range(1, len(xs)):ans[i] = ans[i - 1] + (xs[i] - xs[i - 1]) * deri(xs[i - 1], ans[i - 1])return ansdef euler_range(deri: Callable[[float, float], float],x0: float,y0: float,stop: float,step: float, ) -> np.ndarray:"""欧拉法求微分方程数值解,均匀步长当型循环"""ans = []while y0 < stop:ans.append(y0)y0 += step * deri(x0, y0)x0 += stepreturn np.array(ans)
-
a4_roundrect.py
"""绘制完整的圆角矩形"""import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import sympy as sy from numpy import cos, pi, sinfrom numalgo import emmert, euler_rangempl.rcParams["font.family"] = "Microsoft YaHei"fig, ax = plt.subplots(1, 1, layout="constrained") fig.set_size_inches(8, 10) ax.axis("off") ax.set_xlim([-8, 8]), ax.set_ylim([-11, 11])def mirror_lefttop(arr_x, arr_y):x = np.concatenate((arr_x, -arr_x[::-1], -arr_x, arr_x[::-1]))y = np.concatenate((arr_y, arr_y[::-1], -arr_y, -arr_y[::-1]))return x, y# Gn 插值 for n in range(2, 8):pf = emmert({0: [0, 0] + [0] * (n - 1), 1: [1, 2] + [0] * (n - 1)})p0 = pf.to_polynomial()p1 = p0.derivate()tt = lambda x, y: 1 / np.sqrt(p1(y) ** 2 + p1(1 - y) ** 2)ts = np.concatenate((np.arange(-0.4, 1.3 - n * 1.5 + 0.15, -0.15)[::-1],euler_range(tt, 0, 0, 1, 0.15),np.arange(1.1, n + 0.1, 0.15),))ts0, ts1 = np.sum(ts < 0), np.sum(ts < 1)xs = ts.copy()xs[:ts0] = 0ys = ts.copy()ys[ts1:] = 1for ti in range(ts0, ts1):xs[ti] = p0(ts[ti])ys[ts0:ts1] = 1 - xs[ts1 + 1 : ts0 + 1 : -1]xs, ys = mirror_lefttop(xs - n, ys + n * 1.5 - 1.5)ax.scatter(xs, ys, 5)arr_t = np.linspace(-n * 1.5 + 0.5, n - 0.5, 1000)t0, t1 = np.sum(arr_t < 0), np.sum(arr_t < 1)arr_x, arr_y = arr_t.copy(), arr_t.copy()arr_x[:t0], arr_y[t1:] = 0, 1for ti in range(t0, t1):arr_x[ti] = p0(arr_t[ti])arr_y[t0:t1] = 1 - arr_x[t1 + 1 : t0 + 1 : -1]xs, ys = mirror_lefttop(arr_x - n - 0.5, arr_y + n * 1.5 - 1.25 + 0.5)ax.plot(xs, ys)ax.text(0,n * 1.5 + 0.1,rf"$G^{n}$",horizontalalignment="center",verticalalignment="top",fontsize=16,)# 圆形是无穷阶几何连续的 arr_t = np.arange(0, pi * 2, 0.01) xs = cos(arr_t) ys = sin(arr_t) ax.plot(xs, ys) ax.text(0,0,r"$G^\infty$",horizontalalignment="center",verticalalignment="center",fontsize=16, )# G0 画圆 + 切线 arr_t = np.linspace(-1.25, 1.5, 1000) t0, t1 = np.sum(arr_t < 0), np.sum(arr_t < 1) arr_x, arr_y = arr_t.copy(), arr_t.copy() arr_x[:t0], arr_y[t1:] = 0, 1t = arr_t[t0:t1] x = 1 - cos(t) arr_x[t0:t1] = x arr_y[t0:t1] = 1 - x[::-1]xs, ys = mirror_lefttop(arr_x - 1.5, arr_y + 1.25) ax.plot(xs, ys) ax.text(0,2.1,r"$G^1$",horizontalalignment="center",verticalalignment="top",fontsize=16, )fig.savefig("a4_roundrect.png")
相关文章:

圆角矩形的绘制和曲线均匀化
摘要: 圆角矩形是软件 UI 等视觉设计中的常见表达,一种常见的绘制方法是将矩形的四角替换为与边相切的四分之一圆弧,然而这种绘制方式会在连接处产生视觉上的切折感,这是因为圆弧和直线的连接处只满足 G1G^1G1 连续性。本文探究了…...

【Linux】环境变量,命令行参数,main函数三个参数保姆教学
目录 ☃️1.奇奇怪怪的现象和孤儿进程 ☃️2.环境变量 ☃️3.深刻理解main函数的前两个参数和命令行参数 ☃️1.奇奇怪怪的现象和孤儿进程 首先回顾一下之前我们学过的fork()创建子进程 fork(void)的返回值有两种 注意fork()头…...
美国访问学者生活中有哪些饮食文化特点?
美国的教育毋庸置疑,排在世界数一数二的位置,美食美景更是数不胜数,那么他们有哪些饮食习惯,下面51访学网小编为你们详细介绍这些内容吧。 一、美国饮食文化特点 1、美国的饮食文化体现科学、适度、快捷,以满足人体的…...
RxJava中的Subject
要使用Rxjava首先要导入两个包,其中rxandroid是rxjava在android中的扩展 implementation io.reactivex:rxandroid:1.2.1implementation io.reactivex:rxjava:1.2.0Subject Subject 既可以是一个 Observer 也可以是一个 Observerable,它是连接 Observer 和…...
vue-element-admin在git 上 clone 之后无法install
一. 无法install的原因因为vue-element-admin引入的富文本编辑插件所导致 由于tui-editor变更 名字 导致 依赖查询找不到对应的版本二. 解决的办法先删掉package.json中tui-editor:1.3.3找到 \src\components\MarkdownEditor\index.vue 把所有的import 替换成下面4个import cod…...

Linux线程调度实验
Linux线程调度实验 1.获取线程属性 #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> #include <time.h> #include <stdlib.h> #include <errno.h> #define _GNU_SOURCE#define handle_error…...

洛谷P5735 【深基7.例1】距离函数 C语言/C++
【深基7.例1】距离函数 题目描述 给出平面坐标上不在一条直线上三个点坐标 (x1,y1),(x2,y2),(x3,y3)(x_1,y_1),(x_2,y_2),(x_3,y_3)(x1,y1),(x2,y2),(x3,y3),坐标值是实数,且绝对值不超过 100.00,求围成的三角形周长。保留两位…...

企业什么要建设自有即时通讯软件系统
随着科技的不断发展,各种即时通讯软件也不断发展进步,而这也与企业的发展息息相关,因为每个人,每个企业都有属于自己的机密,属于自己的隐私。 钉钉,企业微信,等公有的即时通讯软件给企业带来便利…...

LocalDNS
目录 文章目录目录本节实战DNS优化1、dns 5s 超时问题解决办法2、NodeLocal DNSCache实验软件关于我最后本节实战 实战名称💘 实战:NodeLocal DNSCache-2022.7.30(测试成功)💘 实战:NodeLocal DNSCache-2023.2.21(测试成功) DNS优…...
线程池种类和拒绝策略
1、newCachedThreadPool():可缓存的线程池,核心线程数量为0,最大线程数量为INT_MAX。线程空闲时间超过60秒被回收。适合处理大量小任务。 2、newFixedThreadPool()。固定线程个数的线程池,线程都是核心线程,没有应急线…...

Python制作9行最简单音乐播放器?不,我不满足
嗨害大家好鸭~我是小熊猫 好久不见啦~这次就来给大家整个大福利 ~ 源码资料电子书:点击此处跳转文末名片获取 最简单的9行代码音乐播放器如下: import time import pygamefile r歌曲路径 pygame.mixer.init() print(正在播放,file) track pygame.mixer.music.lo…...

零基础小白如何学会数据分析?
随着数字经济、大数据时代的发展,数据已然成为当下时代最重要的盈利资源,让企业在做决策和计划方案时更有针对性和依据,能提前预测市场发展方向,做好布局。由此而产生的数据分析岗位也逐渐被更多企业重视,特别是中大型…...

【Linux】vim的使用及常用快捷键(不会使用vim?有这篇文章就够了)
🔥🔥 欢迎来到小林的博客!! 🛰️博客主页:✈️小林爱敲代码 🛰️欢迎关注:👍点赞🙌收藏✍️留言 目录💖vim的基本概念vi…...
刷完这19道leetcode二分查找算法,不信进不了大厂
对于二分题,其实就是设定一个中间值 mid, 然后通过这个值进行一个判断 check(mid), 通过这个函数的返回值,判断将不可能的一半剪切掉; 在刷题的时候需要注意主要是两部分,check 函数的定义以及边界的选择(…...
四、Plugin Request and Sometimes pads
Request and Sometimes pads 到目前为止,我们只处理了总是可用的pad。然而,也有一些pad仅在某些情况下创建,或者仅在应用程序请求pad时创建。第一个有时被称为a;第二个被称为请求pad。pad的可用性(always, sometimes or request)可以在pad的…...

唤醒手腕 Java 后端 Springboot 结合 Redis 数据库学习笔记(更新中)
Redis 基本介绍 Redis Introduction The open source, in-memory data store used by millions of developers as a database, cache, streaming engine, and message broker. 基本概念:redis 是一个开源的、使用 C 语言编写的、支持网络交互的、可基于内存也可持…...

robotiq 2f 140安装在UR3机械臂后面在gazebo仿真中散架、抖动
robotiq 2f 140安装在UR3机械臂后面在gazebo仿真中散架、抖动 搭建环境: ubuntu: 20.04 ros: Nonetic sensor: robotiq_ft300 gripper: robotiq_2f_140_gripper UR: UR3 通过上一篇博客配置好ur3、力传感器和robotiq夹爪的gazebo仿真环境后,夹爪看起来…...
坐标系概念 四元数 欧拉角
1、四个概念:“地理”坐标系、“机体”坐标系、他们之间换算公式、换算公式用的系数。地理坐标系:东、北、天,以下简称地理。在这个坐标系里有重力永远是(0,0,1g),地磁永远是(0,1,x)…...

从0开始写Vue项目-SpringBoot整合Mybatis-plus实现登录、注册功能
1.从0开始写Vue项目-环境和项目搭建_慕言要努力的博客-CSDN博客 2. 从0开始写Vue项目-Vue2集成Element-ui和后台主体框架搭建_慕言要努力的博客-CSDN博客 3. 从0开始写Vue项目-Vue页面主体布局和登录、注册页面_慕言要努力的博客-CSDN博客 一、前言 在之前我们以及搭建好了基…...

K8s中gRpc通信负载均衡失效
上篇文章在做 整合K8sSpringCloudK8sSpringBootgRpc 时,发现K8s中使用gRpc通信,负载均衡功能失效查了下gRpc的最佳实践,找到这里Load balancingSome load balancers dont work effectively with gRPC. L4 (transport) load balancers operate…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...

DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...