我想创建一个命令在 Asymptote 中绘制 B-Spline,我看了一下 pst-bspline。
这是我的 Asymptote 代码。
import graph;
import math;
size(5cm);
pair Bezier(pair P[], real t)
{
pair Bezi;
// real choose(int n, int k); // Mathematical functions (page 69)
for (int k=0; k <= P.length-1; ++k)
{
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve
Bezi=Bezi+choose(P.length-1,k)*(1-t)^(P.length-1-k)*t^k*P[k];
}
return Bezi;
}
//-------------------
path[] Bspline(pair BS[], bool BsplineE = false)
{
/* Bspline BSpline; */
pair[] TwoPointsonSegment(pair A, pair B)
{
pair z[]=new pair[2];
z[0]=A+1/3*(B-A);
z[1]=A+2/3*(B-A);
return z;
}
pair[] R,L,S;
path[] BSpline;
// Divide each line segment B_{k−1}B_{k} into equal thirds.
L.push((0,0)); // For any L[0]. "(0,0) can replaced optionally"
for (int k=0; k < BS.length - 1; ++k)
{
R.push(TwoPointsonSegment(BS[k],BS[k+1])[0]); // R[0],R[1],...
L.push(TwoPointsonSegment(BS[k],BS[k+1])[1]); // L[1],L[2],...
}
//--------------
// letting S_{k} denote the midpoint
S.push(BS[0]); // inserts BS[0] into the array at index 0.
for (int k=1; k < BS.length - 1; ++k) // k=1
{
S.push((L[k]+R[k])/2);
}
S.push(BS[BS.length -1]); // inserts BS[BS.length -1] into the array at last index.
//------------------
// construct the cubic Bézier curve with control points ...
for (int i = (BsplineE==false) ? 1 : 2; i <= ((BsplineE==false) ? BS.length -1 : BS.length -2 ); ++i)
{
BSpline.push(graph(new pair(real t){return Bezier(new pair[]{ S[i-1], R[i-1], L[i], S[i] },t); }, 0, 1));
/* 0,1 is equal to "parametrized by k − 1 <= t <= k." */
}
return operator ..(... BSpline);
}
path[] BsplineE(pair BS[]){return Bspline(BS,true);}
pair[] Bs={(-1.3,13.6),(0,4),(8.5,5.5),(10,0),(15,13),(8.6,10.5)};
draw(Bspline(Bs),blue+0.8bp);
draw(BsplineE(Bs),blue);
dot(Bs);
draw(operator --(... Bs),dashed);
add(grid(15,15,dotted));
for (real i: sequence(16)){ label("$"+(string) i+"$",(i,0),dir(-90)); }
for (real i: sequence(16)){ label("$"+(string) i+"$",(0,i),dir(180)); }
我(-1.3,13.6),(0,4),(8.5,5.5),(10,0),(15,13),(8.6,10.5)
从它和我已经检查过坐标很多次了但我无法获得相同的链接图像。
这是输出。
这是 PSTricks 代码!
\documentclass{article}
\usepackage{pstricks}
\usepackage{multido,pst-node,pst-bspline}
\begin{document}
\SpecialCoor % essential for pst-bspline package
\begin{pspicture}[showgrid=true](15,15)
\psBspline[showframe=true]{B}(-1.3,13.6)(0,4)(8.5,5.5)(10,0)(15,13)(8.6,10.5)
\end{pspicture}
\end{document}
输出
PSTricks 的输出与 Asymptote 的输出相同。然而,两者都不同于
问题:
我哪里失败了?
import graph;
import math;
unitsize(1cm);
pair Bezier(pair P[], real t)
{
pair Bezi;
// real choose(int n, int k); // Mathematical functions (page 69)
for (int k=0; k <= P.length-1; ++k)
{
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve
Bezi=Bezi+choose(P.length-1,k)*(1-t)^(P.length-1-k)*t^k*P[k];
}
return Bezi;
}
//-------------------
/*
struct Bspline
{
pair[] TwoPointsonSegment;
pair[] R,L,S;
path[] BSpline;
}
*/
path[] Bspline(pair BS[], bool BsplineE = false)
{
/* Bspline BSpline; */
pair[] TwoPointsonSegment(pair A, pair B)
{
pair z[]=new pair[2];
z[0]=A+1/3*(B-A);
z[1]=A+2/3*(B-A);
return z;
}
pair[] R,L,S;
path[] BSpline;
// Divide each line segment B_{k−1}B_{k} into equal thirds.
L.push((0,0)); // For any L[0]. "(0,0) can replaced optionally"
for (int k=0; k < BS.length - 1; ++k)
{
R.push(TwoPointsonSegment(BS[k],BS[k+1])[0]); // R[0],R[1],...
L.push(TwoPointsonSegment(BS[k],BS[k+1])[1]); // L[1],L[2],...
}
//--------------
// letting S_{k} denote the midpoint
S.push(BS[0]); // inserts BS[0] into the array at index 0.
for (int k=1; k < BS.length - 1; ++k) // k=1
{
S.push((L[k]+R[k])/2);
}
S.push(BS[BS.length -1]); // inserts BS[BS.length -1] into the array at last index.
//------------------
// construct the cubic Bézier curve with control points ...
for (int i = (BsplineE==false) ? 1 : 2; i <= ((BsplineE==false) ? BS.length -1 : BS.length -2 ); ++i)
{
BSpline.push(graph(new pair(real t){return Bezier(new pair[]{ S[i-1], R[i-1], L[i], S[i] },t); }, 0, 1));
/* 0,1 is equal to "parametrized by k − 1 <= t <= k." */
}
return operator ..(... BSpline);
}
path[] BsplineE(pair BS[]){return Bspline(BS,true);}
pair[] Bs={(.5,.5),(2,0),(5,2),(6,4),(4,5),(2,4)};
draw(Bspline(Bs),red+2bp);
draw(BsplineE(Bs),blue+0.8bp);
dot(Bs);
draw(operator --(... Bs),dashed);
label("$B_0$",Bs[0],dir(90));
label("$B_1$",Bs[1],dir(0));
label("$B_2$",Bs[2],dir(-40));
label("$B_3$",Bs[3],dir(45));
label("$B_4$",Bs[4],dir(90));
label("$B_5$",Bs[5],dir(90));
add(grid(6,5,dotted));
for (int i: sequence(7)){ label("$"+(string) i+"$",(i,0),dir(-90)); }
for (int i: sequence(6)){ label("$"+(string) i+"$",(0,i),dir(180)); }
import graph;
import math;
size(5cm);
pair Bezier(pair P[], real t)
{
pair Bezi;
// real choose(int n, int k); // Mathematical functions (page 69)
for (int k=0; k <= P.length-1; ++k)
{
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve
Bezi=Bezi+choose(P.length-1,k)*(1-t)^(P.length-1-k)*t^k*P[k];
}
return Bezi;
}
//-------------------
path BsplineC(pair BS[])
{
pair[] TwoPointsonSegment(pair A, pair B)
{
pair z[]=new pair[2];
z[0]=A+1/3*(B-A);
z[1]=A+2/3*(B-A);
return z;
}
// BS.length = 6
pair[] R,L,S;
path[] BSpline;
BS.push(BS[0]); // BS.length = 7
BS.push(BS[1]); // BS.length = 8
L.push((0,0)); // For any L[0]. "(0,0) can replaced optionally"
for (int k=0; k < BS.length - 1; ++k) // k < 7
{
R.push(TwoPointsonSegment(BS[k],BS[k+1])[0]); // R[0],R[1],...
L.push(TwoPointsonSegment(BS[k],BS[k+1])[1]); // L[1],L[2],...
}
//--------------
// letting S_{k} denote the midpoint
S.push(BS[0]); // inserts BS[0] into the array at index 0.
for (int k=1; k < BS.length - 1; ++k) // k < 7
{
S.push((L[k]+R[k])/2);
}
//S.push(BS[BS.length -1]); // inserts BS[BS.length -1] into the array at last index.
S[0]=S[S.length-1];
//------------------
// construct the cubic Bézier curve with control points ...
for (int i = 1; i < BS.length - 1 ; ++i) // i<7
{
BSpline.push(graph(new pair(real t){return Bezier(new pair[]{ S[i-1], R[i-1], L[i], S[i] },t); }, 0, 1));
/* 0,1 is equal to "parametrized by k − 1 <= t <= k." */
}
BS.delete(BS.length-2,BS.length-1);
return operator .. (... BSpline) ..cycle;
}
//-------------------------
pair[] Bs={(.5,.5),(2,0),(5,2),(6,4),(4,5),(2,4)};
//draw(operator -- (... Bs) --cycle,dashed);
draw(BsplineC(Bs),blue+dashed);
draw(operator -- (... Bs) --cycle,dashed);
dot(Bs);
label("$B_0$",Bs[0],dir(90));
label("$B_1$",Bs[1],dir(0));
label("$B_2$",Bs[2],dir(-40));
label("$B_3$",Bs[3],dir(45));
label("$B_4$",Bs[4],dir(90));
label("$B_5$",Bs[5],dir(90));
add(grid(6,5,dotted));
for (int i: sequence(7)){ label("$"+(string) i+"$",(i,0),dir(-90)); }
for (int i: sequence(6)){ label("$"+(string) i+"$",(0,i),dir(180)); }
答案1
每个间隔(两点之间)有 25 个节点:
\documentclass[pstricks,border=20pt]{standalone}
\usepackage{multido,pst-plot,pst-bspline}
\begin{document}
\begin{pspicture}[showgrid=true](-1,-1)(15,14)
\psBspline[showframe=true]{B}(-1.3,13.6)(0,4)(8.5,5.5)(10,0)(15,13)(8.6,10.5)
\psBspline[linewidth=2pt,linecolor=red]{B}(-1.3,13.6)(0,4)(8.5,5.5)(10,0)(15,13)(8.6,10.5)
\bspcurvepoints[plotpoints=25]{B}{5}{P}
%\multido{\iA=0+1}{100}{(!P.X \iA\space get P.Y \iA\space get)}
\multido{\iA=37+1,\iB=38+1}{45}{%
\psline[linecolor=blue,linewidth=2pt]%
(!P.X \iA\space get P.Y \iA\space get)(!P.X \iB\space get P.Y \iB\space get)}
\end{pspicture}
\end{document}