2009-12-25 49 views
5

Vẽ các vòng tròn trên PostScript thật dễ dàng và tôi ngạc nhiên rằng PDF dường như không mang theo cùng các nguyên thủy đó. Có rất nhiều thư viện thương mại sẽ làm điều đó, nhưng không nên đơn giản hơn thế?Làm thế nào để bạn vẽ các vòng tròn đầy và không được lấp đầy bằng PDF nguyên thủy?

Ngoài ra còn có một số thủ thuật sử dụng các đường cong Bézier, nhưng bạn không có vòng tròn hoàn hảo và bạn phải vẽ chúng trong các đoạn kết nối. Tôi không cần một vòng tròn hoàn hảo miễn là nó trông gần hoàn hảo.

Tôi đang thực hiện việc này làm bổ sung cho mô-đun Perl PDF-EasyPDF, nhưng ngôn ngữ không phải là phần tôi cần trợ giúp.

Trả lời

5

Điều đó luôn xảy ra. PDF không có vòng kết nối trong nguyên thủy, chỉ beziers. Mô hình hình ảnh PDF được xây dựng từ mô hình hình ảnh PostScript, mà chính nó chỉ cung cấp các vòng tròn bằng cách sử dụng các arc/arcto nguyên thủy, mà bản thân chúng được thực hiện trong điều khoản của beziers.

Rất kỳ quặc, tôi đã gọi để thực hiện tác vụ chính xác này trong một số mã thử nghiệm mà tôi đang thực hiện để tạo tệp PDF. Đây là cách tôi đã làm nó:

private void DrawEllipse(PdfGraphics g, double xrad, double yrad) 
    { 
     const double magic = 0.551784; 
     double xmagic = xrad * magic; 
     double ymagic = yrad * magic; 
     g.MoveTo(-xrad, 0); 
     g.CurveTo(-xrad, ymagic, -xmagic, yrad, 0, yrad); 
     g.CurveTo(xmagic, yrad, xrad, ymagic, xrad, 0); 
     g.CurveTo(xrad, -ymagic, xmagic, -yrad, 0, -yrad); 
     g.CurveTo(-xmagic, -yrad, -xrad, -ymagic, -xrad, 0); 
    } 

    private void DrawCircle(PdfGraphics g, double radius) 
    { 
     DrawEllipse(g, radius, radius); 
    } 

Giả sử rằng PdfGraphics là một lớp học mà spews ra lệnh PDF, vì vậy g.MoveTo(x, y) sẽ biến thành "x y m" trong luồng nội dung. Tôi lấy toán và số ma thuật của tôi từ Don Lancaster's fabulous explanation (PDF, tự nhiên). Điều này giả định rằng hình tròn hoặc hình elip sẽ được vẽ ở gốc. Để di chuyển nó ở một nơi khác, thực hiện chuyển đổi bản dịch trước hoặc sửa đổi mã để trừ thêm vào nguồn gốc mong muốn. Mã này cho một lỗi trường hợp xấu nhất khoảng 1/1250 (khoảng 0,08%) và trung bình 1/2500 (khoảng 0,04%).

4

plinth's answer là điều tương tự mà cuối cùng tôi đã tìm thấy. Có rất nhiều phép toán phức tạp làm giảm hằng số phép thuật và chia nhiệm vụ thành bốn đường cong Bézier riêng biệt. Tôi cần làm điều này trong các lệnh PDF thô, nhưng quá trình này giống nhau.

  • Di chuyển đến đầu đường cong đầu tiên. Đây là trung tâm của vòng tròn trừ đi bán kính theo bất kỳ hướng nào bạn thích.

  • Tìm ra phần cuối của đường cong (các giá trị $x3$y3 trong mã này). Các bảng con đến từ các nhãn điểm kiểm soát đường cong Bézier mà hầu hết mọi người sử dụng.

  • Tìm ra các điểm kiểm soát. Đó là nơi giá trị $magic hiển thị.

  • Khi bạn kết thúc với một phân khúc, hãy làm tiếp theo. Không có gì đặc biệt đặc biệt về bốn phân đoạn khác hơn là nó hoạt động độc đáo trong tọa độ Descartes với chỉ bổ sung và trừ.

  • Nếu bạn muốn điền, bạn kết thúc bằng f để vẽ bên trong đường dẫn bạn vừa tạo.

Có một số việc tái cấu trúc mà tôi có thể làm, nhưng khi tôi làm việc này thì dễ dàng hơn nhiều để thấy rằng tôi đã nhận được các dấu hiệu ngay bằng cách có các khối mã riêng biệt.Đây là chương trình con tôi đã thêm vào PDF::EasyPDF:

sub make_magic_circle 
    { 
    my($pdf, # PDF::EasyPDF object 
     $center, 
     $r # radius 
     ) = @_; 

    my($xc, $yc) = $center->xy; 

    my $magic = $r * 0.552; 
    my($x0p, $y0p) = ($xc - $r, $yc); 
    $pdf->{stream} .= "$x0p $y0p m\n"; 

    { 
    ($x0p, $y0p) = ($xc - $r, $yc); 
    my($x1, $y1) = ($x0p,    $y0p + $magic); 
    my($x2, $y2) = ($x0p + $r - $magic, $y0p + $r ); 
    my($x3, $y3) = ($x0p + $r,   $y0p + $r ); 
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n"; 
    } 

    { 
    ($x0p, $y0p) = ($xc, $yc + $r); 
    my($x1, $y1) = ($x0p + $magic, $y0p    ); 
    my($x2, $y2) = ($x0p + $r,  $y0p - $r + $magic); 
    my($x3, $y3) = ($x0p + $r,  $y0p - $r   ); 
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n"; 
    } 

    { 
    ($x0p, $y0p) = ($xc + $r, $yc); 
    my($x1, $y1) = ($x0p,    $y0p - $magic); 
    my($x2, $y2) = ($x0p - $r + $magic, $y0p - $r ); 
    my($x3, $y3) = ($x0p - $r,   $y0p - $r ); 
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n"; 
    } 

    { 
    ($x0p, $y0p) = ($xc, $yc - $r); 
    my($x1, $y1) = ($x0p - $magic,    $y0p); 
    my($x2, $y2) = ($x0p - $r, $y0p + $r - $magic ); 
    my($x3, $y3) = ($x0p - $r,   $y0p + $r ); 
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n"; 
    } 

    $pdf->{stream} .= "f\n"; 
    } 
1

Cả hai câu trả lời khác ở đây là hoàn hảo, nhưng tôi chỉ muốn thêm một hack nhỏ đối với trường hợp cụ thể của một chất rắn điền vòng tròn (do đó không có đột quỵ).

Chỉ cần vẽ một đường có độ dài bằng không với độ dày đường kính của đường tròn, nhưng đặt "giới hạn dòng" thành rounded.

Điều này rõ ràng không phải là giải pháp tuyệt vời cho hình elip, vòng cung, phân đoạn và nhiều hình dạng liên quan khác ... nhưng đó là một mẹo hay.

Các vấn đề liên quan