Как вы рисуете заполненные и незаполненные круги с PDF примитивами? - PullRequest
5 голосов
/ 25 декабря 2009

Рисовать круги на PostScript легко, и я удивлен, что PDF, по-видимому, не переносит те же самые примитивы. Есть много коммерческих библиотек, которые это сделают, но разве это не должно быть проще?

Есть также некоторые приемы, использующие кривые Безье, но вы не получите идеальный круг, и вам нужно нарисовать их в соединительных сегментах. Мне не нужен идеальный круг, если он выглядит близко к идеальному.

Я делаю это как дополнение к Perl-модулю PDF-EasyPDF , но язык не та часть, с которой мне нужна помощь.

Ответы [ 3 ]

5 голосов
/ 05 января 2010

Так будет всегда. У PDF нет кругов в примитивах, только Безье. Модель изображения PDF была построена на основе модели изображения PostScript, которая сама предоставляет только круги с использованием примитивов arc / arcto, которые сами по себе реализованы в терминах Безье.

Как ни странно, мне нужно было выполнить эту задачу в каком-то тестовом коде, над которым я работаю, который генерирует PDF. Вот как я это сделал:

    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);
    }

Предположим, что PdfGraphics - это класс, который выдает команды PDF, поэтому g.MoveTo(x, y) превратится в "x y m" в потоке контента. Я взял свою математику и магическое число у Дона Невероятное объяснение Ланкастера (PDF, естественно). Это предполагает, что круг или эллипс будут нарисованы в начале координат. Чтобы переместить его куда-нибудь еще, сначала выполните преобразование перевода или измените код, чтобы вычесть сложение в желаемом источнике. Этот код дает ошибку наихудшего случая примерно 1/1250 (около 0,08%) и в среднем 1/2500 (около 0,04%).

4 голосов
/ 20 января 2010

ответ плинтуса - это то же самое, что я в конце концов нашел. Есть много хитрой математики, которая сводится к магической константе и делит задачу на четыре отдельные кривые Безье. Мне нужно было сделать это в необработанных командах PDF, но процесс тот же.

  • Перейти к началу первой кривой. Это центр круга минус радиус в любом направлении, которое вам нравится.

  • Вычислите конец кривой (значения $x3 и $y3 в этом коде). Индексы взяты из меток контрольной точки кривой Безье, которые используют большинство людей.

  • Определить контрольные точки. Вот где появляется значение $magic.

  • Когда вы закончите с одним сегментом, сделайте следующий. В четырех сегментах нет ничего особенного, кроме того, что он хорошо работает в декартовых координатах с простыми сложениями и вычитаниями.

  • Если вы хотите заполнить, вы заканчиваете f, чтобы нарисовать внутреннюю часть только что созданного пути.

Есть некоторый рефакторинг, который я мог бы выполнить, но поскольку я работал с этим, было намного легче увидеть, что я правильно понял знаки, имея отдельные блоки кода. Это подпрограмма, которую я добавил в 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 голос
/ 23 октября 2017

Оба эти других ответа здесь идеальны, но я просто хотел бы добавить небольшой хак для конкретного случая сплошного заполненного круга (таким образом, без обводки) .

Просто нарисуйте линию нулевой длины с толщиной линии в диаметре круга, но установите «ограничение линии» равным rounded.

Это явно не лучшее решение для эллипсов, дуг, сегментов и многих других связанных форм ... но это крутой трюк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...