2016-11-24 117 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

它的工作。但我不明白該行「但只有第一次,刪除其餘」。 –