我正在为绘图应用程序生成bezier曲线,使用这里描述的解决方案初始曲线算法。为了便于参考,我将描述这里使用的一些代码。我用这个初始算法遇到的问题是,曲线不能保证穿过实际需要的y值,这是我正在做的图表必须的。我最终发现两个bezier控制点实际上位于生成的曲线的顶点,所以我实现了一个解决方案,将曲线向上移动,直到它最终到达所需的点。下面是绘制贝塞尔曲线的代码,也包含了我刚才描述的移位解决方案:
public float findControlPointYValue(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)
{
float maxYValue = Float.MIN_VALUE;
for(float t = 0; t < 1; t = t + 0.01f)
{
float xValue = (1 - t) * ((1 - t) * ((1 - t) * x0 + t * x1) + t * ((1 - t) * x1 + t * x2)) + t * ((1 - t) * ((1 - t) * x1 + t * x2) + t * ((1 - t) * x2 + t * x3));
float yValue = (1 - t) * ((1 - t) * ((1 - t) * y0 + t * y1) + t * ((1 - t) * y1 + t * y2)) + t * ((1 - t) * ((1 - t) * y1 + t * y2) + t * ((1 - t) * y2 + t * y3));
// the maximum/minimum of the curve occurs right after the xValue crosses the
// Bezier control point, at about t = 0.4999998.
if(xValue >= x2 && maxYValue == Float.MIN_VALUE)
return yValue;
}
return maxYValue;
}
public void drawBezierConnectedLines(PDPageContentStream cs, PDFPoint[] points, float smoothFactor) throws IOException
{
cs.moveTo(points[0].getXValue(), points[0].getYValue());
PDFPoint previousLastPoint = points[0];
if(points.length == 2)
{
cs.lineTo(points[1].getXValue(), points[1].getYValue());
cs.stroke();
return;
}
int previousShiftAmount = 0;
for (int i = 0; i < points.length - 9; i++)
{
int shiftAmount = 0;
PDFPoint[] pts = this.computeBeizerConnectedLines(points[i], points[i + 1], points[i + 2], smoothFactor, i == 0, i == points.length - 3);
// determine whether to adjust the points acquired in pts based on whether the
// curve actually crosses the desired point in the line chart
float maxYValue = Float.MIN_VALUE;
Float x0 = null, y0 = null, x1 = null, y1 = null, x2 = null, y2 = null, x3 = null, y3 = null;
if(pts.length == 5)
{
x0 = pts[1].getXValue();
y0 = pts[1].getYValue();
x1 = pts[2].getXValue();
x2 = pts[2].getXValue();
y1 = pts[2].getYValue();
y2 = pts[2].getYValue();
x3 = pts[3].getXValue();
y3 = pts[3].getYValue();
}
else if(pts.length == 4)
{
x0 = pts[0].getXValue();
y0 = pts[0].getYValue();
x1 = pts[1].getXValue();
x2 = pts[1].getXValue();
y1 = pts[1].getYValue();
y2 = pts[1].getYValue();
x3 = pts[2].getXValue();
y3 = pts[2].getYValue();
}
// only apply this algorithm if at least 4 points are available
if(pts.length == 5 || pts.length == 4)
{
maxYValue = findControlPointYValue(x0, y0, x1, y1, x2, y2, x3, y3);
if(maxYValue == Float.MIN_VALUE)
{
System.out.println("ERROR: Y value at control point is invalid! Exiting.");
System.exit(0);
}
// determine the direction of the required shift
boolean shiftUp = false;
boolean shiftDown = false;
float desiredYValue = points[i + 1].getYValue();
if(desiredYValue > maxYValue)
shiftUp = true;
else if(desiredYValue < maxYValue)
shiftDown = true;
float currentControlYValue = Float.MIN_VALUE;
int maxIterationAmount = 1000000;
if(shiftUp)
{
while(currentControlYValue < desiredYValue)
{
shiftAmount++;
// prevent infinite looping
if(shiftAmount >= maxIterationAmount)
{
System.out.println("ERROR: Max iteration exceeded while recomputing points. Exiting.");
System.exit(0);
}
PDFPoint pointTwo = new PDFPoint(points[i + 1].getXValue(), points[i + 1].getYValue() + shiftAmount);
pts = this.computeBeizerConnectedLines(points[i], pointTwo, points[i + 2], smoothFactor, i == 0, i == points.length - 3);
// TO-DO: Modularize this algorithm later
if(pts.length == 5)
{
x0 = pts[1].getXValue();
y0 = pts[1].getYValue();
x1 = pts[2].getXValue();
x2 = pts[2].getXValue();
y1 = pts[2].getYValue();
y2 = pts[2].getYValue();
x3 = pts[3].getXValue();
y3 = pts[3].getYValue();
}
else if(pts.length == 4)
{
x0 = pts[0].getXValue();
y0 = pts[0].getYValue();
x1 = pts[1].getXValue();
x2 = pts[1].getXValue();
y1 = pts[1].getYValue();
y2 = pts[1].getYValue();
x3 = pts[2].getXValue();
y3 = pts[2].getYValue();
}
currentControlYValue = findControlPointYValue(x0, y0, x1, y1, x2, y2, x3, y3);
}
}
else if(shiftDown)
{
while(currentControlYValue > desiredYValue)
{
shiftAmount--;
// prevent infinite looping
if(shiftAmount <= -maxIterationAmount)
{
System.out.println("ERROR: Max iteration exceeded while recomputing points. Exiting.");
System.exit(0);
}
PDFPoint pointTwo = new PDFPoint(points[i + 1].getXValue(), points[i + 1].getYValue() + shiftAmount);
pts = this.computeBeizerConnectedLines(points[i], pointTwo, points[i + 2], smoothFactor, i == 0, i == points.length - 3);
// TO-DO: Modularize this algorithm later
if(pts.length == 5)
{
x0 = pts[1].getXValue();
y0 = pts[1].getYValue();
x1 = pts[2].getXValue();
x2 = pts[2].getXValue();
y1 = pts[2].getYValue();
y2 = pts[2].getYValue();
x3 = pts[3].getXValue();
y3 = pts[3].getYValue();
}
else if(pts.length == 4)
{
x0 = pts[0].getXValue();
y0 = pts[0].getYValue();
x1 = pts[1].getXValue();
x2 = pts[1].getXValue();
y1 = pts[1].getYValue();
y2 = pts[1].getYValue();
x3 = pts[2].getXValue();
y3 = pts[2].getYValue();
}
currentControlYValue = findControlPointYValue(x0, y0, x1, y1, x2, y2, x3, y3);
}
}
}
switch (pts.length)
{
case 2: // Intermediate/last section - straight lines
System.out.println("Case 2\n" );
System.out.println("Drawing line - x: " + previousLastPoint.getXValue() + " y:" + previousLastPoint.getYValue() );
System.out.println("Drawing line - x: " + pts[1].getXValue() + " y:" + pts[1].getYValue() );
cs.lineTo(previousLastPoint.getXValue(), previousLastPoint.getYValue());
cs.lineTo(pts[1].getXValue(), pts[1].getYValue());
previousLastPoint = pts[1];
break;
case 3: // First section - straight lines
System.out.println("Case 3\n" );
System.out.println("Drawing line - x: " + previousLastPoint.getXValue() + " y:" + previousLastPoint.getYValue() );
System.out.println("Drawing line - x: " + pts[1].getXValue() + " y:" + pts[1].getYValue() );
System.out.println("Drawing line - x: " + pts[2].getXValue() + " y:" + pts[2].getYValue() );
cs.lineTo(previousLastPoint.getXValue(), previousLastPoint.getYValue());
cs.lineTo(pts[1].getXValue(), pts[1].getYValue());
cs.lineTo(pts[2].getXValue(), pts[2].getYValue());
previousLastPoint = pts[2];
break;
case 4: // Intermediate/last section
pts[3] = new PDFPoint(pts[3].getXValue(), pts[3].getYValue());
System.out.println("Case 4\n" );
System.out.println("Drawing line - x: " + previousLastPoint.getXValue() + " y:" + previousLastPoint.getYValue() );
System.out.println("Drawing curve - x1, x2: " + pts[1].getXValue() + " y1, y2:" + pts[1].getYValue() + " x3: " + pts[2].getXValue() + "y3 " + pts[2].getYValue());
System.out.println("Drawing line - x: " + pts[3].getXValue() + " y:" + pts[3].getYValue() );
cs.lineTo(previousLastPoint.getXValue(), previousLastPoint.getYValue());
cs.curveTo(pts[1].getXValue(), pts[1].getYValue(), pts[1].getXValue(), pts[1].getYValue(), pts[2].getXValue(), pts[2].getYValue());
cs.lineTo(pts[3].getXValue(), pts[3].getYValue());
previousLastPoint = pts[3];
break;
case 5: // First section
System.out.println("Case 5\n" );
System.out.println("Drawing line - x: " + previousLastPoint.getXValue() + " y:" + previousLastPoint.getYValue() );
System.out.println("Drawing line - x: " + pts[1].getXValue() + " y:" + pts[1].getYValue() );
System.out.println("Drawing curve - x1, x2: " + pts[2].getXValue() + " y1, y2:" + pts[2].getYValue() + " x3: " + pts[3].getXValue() + "y3 " + pts[3].getYValue());
System.out.println("Drawing line - x: " + pts[4].getXValue() + " y:" + pts[4].getYValue() );
cs.lineTo(previousLastPoint.getXValue(), previousLastPoint.getYValue());
cs.lineTo(pts[1].getXValue(), pts[1].getYValue());
cs.curveTo(pts[2].getXValue(), pts[2].getYValue(), pts[2].getXValue(), pts[2].getYValue(), pts[3].getXValue(), pts[3].getYValue());
cs.lineTo(pts[4].getXValue(), pts[4].getYValue());
previousLastPoint = pts[4];
break;
}
previousShiftAmount = shiftAmount;
}
cs.stroke();
}
如果有帮助的话,需要绘制的y值是{1106f、1373f、2052f、2151f、1161f},它们通过内部转换算法转换成不同的y值(x轴值彼此之间总是一个常量值)。这条线之所以不平滑,是因为当当前曲线向上移动时,来自上一条曲线的这条线并不能解释这一移动。在附图中,#1显示了我在绘制平滑线方面的最佳尝试。我注意到我的移位算法导致端点的y值上移了3个单位,所以我把上一条曲线上移了3个单位,还有从它出来的那条线。这条线看起来不错,但仍然不是100%平滑#2显示了尽管我的移位算法使曲线在所需的y轴值上对齐,但它会导致曲线不均匀#3显示原始算法,显示曲线与所需y轴值不对齐的核心问题。以下是#2和#3的输出:
2
Case 5
Drawing line - x: 103.0 y:471.39502
Drawing line - x: 133.54544 y:492.92197
Drawing curve - x1, x2: 143.72726 y1, y2:500.0975 x3: 153.90909 y3: 518.3456
Drawing line - x: 174.2727 y:554.8418
Shift Amount: 0
Case 4
Drawing line - x: 174.2727 y:554.8418
Drawing curve - x1, x2: 184.45453; y1, y2:575.08997; x3: 194.63635 y3: 577.25055
Drawing line - x: 214.99997 y:581.5718
Shift Amount: 2
Case 4
Drawing line - x: 214.99997 y:581.5718
Drawing curve - x1, x2: 225.1818; y1, y2:587.7325; x3: 235.36362 y3: 560.1261
Drawing line - x: 255.72723 y:504.9137
Shift Amount: 4
3
Case 5
Drawing line - x: 103.0 y:471.39502
Drawing line - x: 133.54544 y:492.92197
Drawing curve - x1, x2: 143.72726; y1, y2:500.0975; x3: 153.90909 y3: 518.3456
Drawing line - x: 174.2727 y:554.8418
Shift Amount: 0
Case 4
Drawing line - x: 174.2727 y:554.8418
Drawing curve - x1, x2: 184.45453; y1, y2:573.08997; x3: 194.63635 y3: 575.7506
Drawing line - x: 214.99997 y:581.0719
Case 4
Drawing line - x: 214.99997 y:581.0719
Drawing curve - x1, x2: 225.1818; y1, y2:583.7325; x3: 235.36362 y3: 557.12604
Drawing line - x: 255.72723 y:503.91357
老实说,我似乎不知道该怎么做。解决方案可能很简单,只需调整一点代码,但我似乎无法找到匹配的方法。您可以根据需要随意使用和测试代码。非常感谢您的帮助,如果您有任何问题,请告诉我。
暂无答案!
目前还没有任何答案,快来回答吧!