Java B样条基函数似乎产生了不正确的值
我想在JavaSwing应用程序中实现B样条曲线。从4号开始。我几乎什么都试过了,把空闲时间的每一分钟都花在了身上,但我做得不对——从昨天起我就头痛了:/ 为了实现B样条曲线,我使用了 我制作了一个演示版(与之相关),可以在这里找到: 代码显示了这个问题,它被设置为在swing JPanel drawcomponent方法中调用。但您可以注释这一行并取消注释71 其他一些信息:Java B样条基函数似乎产生了不正确的值,java,swing,curves,splines,Java,Swing,Curves,Splines,我想在JavaSwing应用程序中实现B样条曲线。从4号开始。我几乎什么都试过了,把空闲时间的每一分钟都花在了身上,但我做得不对——从昨天起我就头痛了:/ 为了实现B样条曲线,我使用了 我制作了一个演示版(与之相关),可以在这里找到: 代码显示了这个问题,它被设置为在swing JPanel drawcomponent方法中调用。但您可以注释这一行并取消注释71 其他一些信息: my basis函数中的a和b返回值1,但不应返回值(参见wikipedia) 我想自己实现b样条曲线-我不想使用库
- my basis函数中的a和b返回值<0或>1,但不应返回值(参见wikipedia)
- 我想自己实现b样条曲线-我不想使用库
- 参考维基百科artikel:
- 基本函数是B(x)
- 德布尔是S(x)
对于阅读此的thx,我无法想象一个合适的答案不包含一段代码,您可以编译和运行(无需插入主方法和周围的GUI…*wink*),无论它与您的代码有多不同 然而,您分配给T数组的权重似乎很奇怪,基函数的指数似乎偏离+/-1。我试图解决这个问题,但它仍然不完全正确,也许你或其他人喜欢继续调试它
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.util.Arrays;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class BSplineTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1, 1));
BSplineTestPanel bSplineTestPanel = new BSplineTestPanel();
frame.getContentPane().add(bSplineTestPanel);
frame.setSize(500,500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class BSplineTestPanel extends JPanel
{
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Bspline bspline = new Bspline();
bspline.calculatePath(g);
}
}
class Bspline
{
double[][] P;
double[] T;
int _k = 3;
public Bspline()
{
P = new double[4][2];
P[0][0] = 100;
P[0][1] = 100;
P[1][0] = 50;
P[1][1] = 50;
P[2][0] = 100;
P[2][1] = 200;
P[3][0] = 50;
P[3][1] = 200;
update();
}
private void update()
{
if (P.length < 2)
return;
T = new double[_k + P.length + 1];
double d = 1.0 / (T.length-1);
for (int i = 0; i<T.length; i++)
{
T[i] = i * d;
}
System.out.println(Arrays.toString(T));
}
private double basisFunc(int i, int k, double t)
{
if (k == 0)
{
if (T[i] <= t && t < T[i + 1])
return 1;
return 0;
}
double a = (t - T[i]) / (T[i + k] - T[i]);
double b = (T[i + k + 1] - t) / (T[i + k + 1] - T[i + 1]);
return a * basisFunc(i, k - 1, t) + b * basisFunc(i + 1, k - 1, t);
}
private double[] DeBoor(double t)
{
double[] V = new double[2];
for (int i = 0; i < P.length; i++)
{
double scale = basisFunc(i, _k, t);
V[0] += P[i][0] * scale;
V[1] += P[i][1] * scale;
}
return V;
}
public void calculatePath(Graphics g)
{
if (P.length < 2)
{
return; // zu wenige punkte um ein pfad zu zeichnen
}
double[] v = null;
double delta = 1 / 32.0;
for (double t = T[2]; t < T[5]; t += delta)
{
double[] p = DeBoor(t);
if (v != null)
{
g.setColor(new Color((int)(t*255), 0, 0));
g.drawLine((int) v[0], (int) v[1], (int) p[0], (int) p[1]);
}
v = p;
}
for (int i = 0; i < P.length; i++)
{
int x = (int)P[i][0];
int y = (int)P[i][1];
g.setColor(Color.RED);
g.fillOval(x-2, y-2, 4, 4);
g.drawString(String.valueOf(i), x, y+15);
}
}
}
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.GridLayout;
导入java.util.array;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
公共类BSplineTest
{
公共静态void main(字符串[]args)
{
SwingUtilities.invokeLater(新的Runnable()
{
@凌驾
公开募捐
{
createAndShowGUI();
}
});
}
私有静态void createAndShowGUI()
{
JFrame=新JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(新的GridLayout(1,1));
BSplineTestPanel BSplineTestPanel=新的BSplineTestPanel();
frame.getContentPane().add(bSplineTestPanel);
框架。设置尺寸(500500);
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
}
类BSplineTestPanel扩展了JPanel
{
@凌驾
受保护组件(图形g)
{
超级组件(g);
Bspline Bspline=新的Bspline();
b.计算路径(g);
}
}
类Bspline
{
双[]P;
双[]T;
int_k=3;
公共Bspline()
{
P=新双[4][2];
P[0][0]=100;
P[0][1]=100;
P[1][0]=50;
P[1][1]=50;
P[2][0]=100;
P[2][1]=200;
P[3][0]=50;
P[3][1]=200;
更新();
}
私有void更新()
{
如果(P.长度<2)
返回;
T=新双精度[_k+P.长度+1];
双d=1.0/(T.length-1);
对于(int i=0;通常情况下,a值1000多个链接公式png。只是出于好奇:目的是实现这一点,对吗?如果你想创建样条曲线,你可以使用Path2D
。不确定是否有人会帮你调试,不过…请回答thx。是的,我想实现样条曲线myself,我的要点是独立的,我提到了我有问题的部分。与MCVE相关,它是最小的、完整的,并且非常可行。png公式只是参考…哇,thx,看起来不错。我的结值是这样的,因为我想多次计算第一个和最后一个结。我没有时间检查更多,但很晚了r那天。谢谢你!好的,测试了它,它看起来很好,只有一个例外:我想要一个开放的统一结向量,如[0,0,0.33,0.66,1,1]
,但是我得到了一条从(0,0)开始的线(由于0个分段)这是我的问题earlier@Soraphis是的,我提到它仍然不完全正确。但是我很难想象有人愿意检查你的代码并检查你在哪里犯了一些索引错误。我从另一个网站插入了一个工作版本。当然,这并不令人满意(不要犹豫,取消投票——我真的没有在你的问题上帮你这么多),但对我来说(个人)一方面,调试他人的代码是不令人满意的,另一方面,创建像自己的deBoor实现那样无用的东西是不值得的……然而,最初的问题可能与您没有插入新的控制点有关,正如这一著名的“金字塔计划”所示你可以在所有假装解释deBoor算法的网站上找到它。我很确定它在索引方面没有问题,因为它认为问题是0除法,这是……想要的。在德国维基百科中,它说“有可能,递归公式中的分母可能是0,但函数是空函数”但是…我不知道如何实现它…我尝试的每件事看起来都不对)我之前尝试过C算法,但是没有“WichInterval”对我有效,再次:我不知道结向量是如何建立的-这是我的问题。向上投票:你的Answare是一个有效的算法,所以没有理由删除向上投票:D
// From http://chi3x10.wordpress.com/2009/10/18/de-boor-algorithm-in-c/
double[] deBoor(int k,int degree, int i, double x, double knots[], double ctrlPoints[][])
{
if( k == 0)
{
i = Math.max(0, Math.min(ctrlPoints.length-1, i));
return ctrlPoints[i];
}
else
{
double alpha = (x-knots[i])/(knots[i+degree+1-k]-knots[i]);
double p0[] = deBoor(k-1,degree, i-1, x, knots, ctrlPoints);
double p1[] = deBoor(k-1,degree, i, x, knots, ctrlPoints);
double p[] = new double[2];
p[0] = p0[0] *(1-alpha ) + p1[0]*alpha;
p[1] = p0[1] *(1-alpha ) + p1[1]*alpha;
return p;
}
}
int WhichInterval(double x, double knot[], int ti)
{
int index = -1;
for(int i = 1; i <= ti - 1; i++)
{
if(x < knot[i]) {
index = i - 1;
break;
}
}
if(x == knot[ti - 1]) {
index = ti - 1;
}
return index;
}
private double[] DeBoor(double t)
{
int i = WhichInterval(t, T, T.length);
return deBoor(_k, 3, i, t, T, P);
}