2016-11-24 107 views
2

我必须使用pdfbox绘制饼图。如何使用pdfbox绘制饼图?

让数据是:

对象标记在百分比马克以度累积度
分1 80 80 80
子2 70 70 150
子3 65 65 215
撒哈拉4 90 90 305
分5 55 55 360

让半径和中心是100个像素和(250,400)。

让我们把初始线平行于x轴。
绘图初始行语句将为:
contentStream.drawLine(250,400,350,400);

我卡住了:
一个)找到X,Y点的上即从初始行一定程度远画出半径使用贝塞尔曲线的两个点之间
b)中绘制圆弧的圆坐标。

任何有关解决问题的帮助将不胜感激!

回答

2

根据角度找到圆上的x,y坐标是学校数学,即sin()和cos(),棘手的部分是绘制具有贝塞尔曲线的圆弧。

下面是一些代码,绘制了您要求的饼图。请注意,createSmallArc()只能在角度高达90°的情况下工作。如果你想要更多,你需要通过绘制几个弧来修改代码,直到你回到(0,0),或者只画几个切片。

createSmallArc()Hans Muller,许可证:Creative Commons Attribution 3.0所做的更改:实现原AS代码转换成Java算法是Aleksas Riškus

public class PieChart 
{ 
    public static void main(String[] args) throws IOException 
    { 
     PDDocument doc = new PDDocument(); 
     PDPage page = new PDPage(); 
     doc.addPage(page); 
     PDPageContentStream cs = new PDPageContentStream(doc, page); 

     cs.transform(Matrix.getTranslateInstance(250, 400)); 

     cs.setNonStrokingColor(Color.yellow); 
     drawSlice(cs, 100, 0, 80); 
     cs.fill(); 
     cs.setNonStrokingColor(Color.red); 
     drawSlice(cs, 100, 80, 150); 
     cs.fill(); 
     cs.setNonStrokingColor(Color.green); 
     drawSlice(cs, 100, 150, 215); 
     cs.fill(); 
     cs.setNonStrokingColor(Color.blue); 
     drawSlice(cs, 100, 215, 305); 
     cs.fill(); 
     cs.setNonStrokingColor(Color.ORANGE); 
     drawSlice(cs, 100, 305, 360); 
     cs.fill(); 

     cs.close(); 
     doc.save("piechart.pdf"); 
     doc.close(); 
    } 

    private static void drawSlice(PDPageContentStream cs, float rad, float startDeg, float endDeg) throws IOException 
    { 
     cs.moveTo(0, 0); 
     List<Float> smallArc = createSmallArc(rad, Math.toRadians(startDeg), Math.toRadians(endDeg)); 
     cs.lineTo(smallArc.get(0), smallArc.get(1)); 
     cs.curveTo(smallArc.get(2), smallArc.get(3), smallArc.get(4), smallArc.get(5), smallArc.get(6), smallArc.get(7)); 
     cs.closePath(); 
    } 

    /** 
    * From https://hansmuller-flex.blogspot.com/2011/10/more-about-approximating-circular-arcs.html 
    * 
    * Cubic bezier approximation of a circular arc centered at the origin, 
    * from (radians) a1 to a2, where a2-a1 &lt; pi/2. The arc's radius is r. 
    * 
    * Returns a list with 4 points, where x1,y1 and x4,y4 are the arc's end points 
    * and x2,y2 and x3,y3 are the cubic bezier's control points. 
    * 
    * This algorithm is based on the approach described in: 
    * Aleksas Riškus, "Approximation of a Cubic Bezier Curve by Circular Arcs and Vice Versa," 
    * Information Technology and Control, 35(4), 2006 pp. 371-378. 
    */ 
    private static List<Float> createSmallArc(double r, double a1, double a2) 
    { 
     // Compute all four points for an arc that subtends the same total angle 
     // but is centered on the X-axis 
     double a = (a2 - a1)/2; 
     double x4 = r * Math.cos(a); 
     double y4 = r * Math.sin(a); 
     double x1 = x4; 
     double y1 = -y4; 
     double q1 = x1*x1 + y1*y1; 

     double q2 = q1 + x1*x4 + y1*y4; 
     double k2 = 4/3d * (Math.sqrt(2 * q1 * q2) - q2)/(x1 * y4 - y1 * x4); 
     double x2 = x1 - k2 * y1; 
     double y2 = y1 + k2 * x1; 
     double x3 = x2; 
     double y3 = -y2; 

     // Find the arc points' actual locations by computing x1,y1 and x4,y4 
     // and rotating the control points by a + a1 

     double ar = a + a1; 
     double cos_ar = Math.cos(ar); 
     double sin_ar = Math.sin(ar); 

     List<Float> list = new ArrayList<Float>(); 
     list.add((float) (r * Math.cos(a1))); 
     list.add((float) (r * Math.sin(a1))); 
     list.add((float) (x2 * cos_ar - y2 * sin_ar)); 
     list.add((float) (x2 * sin_ar + y2 * cos_ar)); 
     list.add((float) (x3 * cos_ar - y3 * sin_ar)); 
     list.add((float) (x3 * sin_ar + y3 * cos_ar)); 
     list.add((float) (r * Math.cos(a2))); 
     list.add((float) (r * Math.sin(a2))); 
     return list; 
    } 
} 
+0

我能够得出使用code.But我不半圆不想让线段与弧线一起绘制。我该如何去除线条。我尝试了对lineTo命令的评论,但它不起作用。 –

+0

@VK删除第一个moveto;用moveto替换lineto(但只是第一次,删除其余部分);删除closepath()。 –

+0

它的工作。但我不明白该行“但只有第一次,删除其余”。 –