我正在寻找一种通过多个点制作直线曲线的方法.最好使用3个点,尽管我认为为了给出进入点的线的角度的上下文,可能需要更多来给出曲线的上下文.
通常,起点P1,控制点P2和终点P3,该线应从P1弯曲到P2,然后从P2到P3弯曲.
事实上,这是我希望实现的效果的完美示例:
如果我能做到这一点,我真的会永远感激!
到目前为止,在Java中,我尝试过玩QuadCurve2D.Double,Cub icCurve2D.Double和Path2D.Double(使用带有Path2D.Double的curveTo),但无济于事 – 绘制的曲线甚至不接近通过指定的控制点.
这是我到目前为止尝试过的方法的图像:
这是我用来生成图像中的点和曲线的代码:
Graphics2D g = (Graphics2D) window.getGraphics();
g.setColor(Color.blue);
int d = 4;
// P0
int x0 = window.getWidth()/8;
int y0 = 250;
g.drawString("P0", x0, y0 + 4*d);
g.fillRect(x0, y0, d, d);
// P1
int x1 = (window.getWidth()/7)*2;
int y1 = 235;
g.drawString("P1", x1, y1 + 4*d);
g.fillRect(x1, y1, d, d);
// P2
int x2 = (window.getWidth()/2);
int y2 = 200;
g.drawString("P2", x2, y2 - 2*d);
g.fillRect(x2, y2, d, d);
// P3
int x3 = (window.getWidth()/7)*5;
int y3 = 235;
g.drawString("P3", x3, y3 + 4*d);
g.fillRect(x3, y3, d, d);
// P4
int x4 = (window.getWidth()/8)*7;
int y4 = 250;
g.drawString("P4", x4, y4 + 4*d);
g.fillRect(x4, y4, d, d);
g.setColor(Color.cyan);
QuadCurve2D quadCurve = new QuadCurve2D.Double(x0, y0, x2, y2, x4, y4);
g.draw(quadCurve);
g.setColor(Color.YELLOW);
CubicCurve2D.Double cubicCurve = new CubicCurve2D.Double((double)x0, (double)y0,
(double)x1, (double)y1,
(double)x2, (double)y2,
(double)x4, (double)y4);
g.draw(cubicCurve);
g.setColor(Color.red);
Path2D.Double path1 = new Path2D.Double();
path1.moveTo(x1, y1);
path1.curveTo(x0, y0, x2, y2, x4, y4);
g.draw(path1);
我希望曲线穿过点的原因是我想要“平滑”我写的线图上顶点之间的过渡.在任何人提到它之前,JFree Chart不是一个选项.我知道使用了不同类型的曲线和样条曲线但是我没有太多运气来理解它们的确切工作方式或如何实现适合我需要的东西.
如果有任何帮助,我将非常感激 – 提前致谢.
解决方法:
我认为你错过了控制点的概念.控制点通常不在路径本身上.相反,它们控制路径曲线在点之间的形状.有关详细信息,请参阅spline tutorial.
现在针对手头的问题,曲线上有点,但没有实际的控制点.有一些技术,如Cardinal Spline,用于导出控制点,然后传递给您提到的曲线绘制API之一.您可能需要Path2D.Double选项,以便可以将各个曲线平滑地串在一起.
因此,从P1到P2到P3,而不是
Path2D.Double path1 = new Path2D.Double();
path1.moveTo(x1, y1);
path1.curveTo(x0, y0, x2, y2, x4, y4);
g.draw(path1);
你要
Path2D.Double path1 = new Path2D.Double();
path1.moveTo(x1, y1);
path1.curveTo(cx1a, cy1a, cx1b, cy1b, x2, y2);
path1.curveTo(cx2a, cy2a, cx2b, cy2b, x3, y3);
g.draw(path1);
其中cx和cy坐标是您的派生控制点,每个三次样条线段有两个控制点.可能的话,
cx1a = x1 + (x2 - x1) / 3;
cy1a = y1 + (y2 - y1) / 3;
cx1b = x2 - (x3 - x1) / 3;
cy1b = y2 - (y3 - y1) / 3;
cx2a = x2 + (x3 - x1) / 3;
cy2a = y2 + (y3 - y1) / 3;
cx2b = x3 - (x3 - x2) / 3;
cy2b = y3 - (y3 - y2) / 3;
这里的模式是对于内部点(在这种情况下仅为P2),它之前和之后的控制点(c1b和c2a)被它之前和之后的点之间的线的斜率(P1和P3)偏移.对于边缘点,控制点基于该点与下一个最近点之间的斜率.
如果您有特定于域的信息,则可以选择不同的控制点.例如,您可能希望强制终点处的斜率为0.