圆角矩形的绘制和曲线均匀化
摘要: 圆角矩形是软件 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…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...
简单介绍C++中 string与wstring
在C中,string和wstring是两种用于处理不同字符编码的字符串类型,分别基于char和wchar_t字符类型。以下是它们的详细说明和对比: 1. 基础定义 string 类型:std::string 字符类型:char(通常为8位)…...
Selenium 查找页面元素的方式
Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素,以下是主要的定位方式: 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...







