在 PostScript 上绘制圆圈很容易,令我惊讶的是 PDF 显然没有继承这些相同的基元。有很多商业图书馆可以做到这一点,但它不应该比这更简单吗?
还有一些使用贝塞尔曲线的技巧,但你不会得到一个完美的圆,你必须在连接线段中绘制它们。我不需要完美的圆形,只要它看起来接近完美即可。
我这样做是作为 PDF-EasyPDF Perl 模块的补充,但该语言不是我需要帮助的部分。
情况总是如此。 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”。 我从 Don Lancaster 的精彩解释(当然是 PDF)中获取了我的数学和神奇数字。 这假设圆或椭圆将在原点绘制。 要将其移动到其他位置,请先进行平移变换或修改代码以在所需原点中减去添加。 此代码给出的最坏情况误差约为 1/1250(约 0.08%),平均值为 1/2500(约 0.04%)。
这里的其他两个答案都是完美的,但我只想为实心填充圆(因此没有笔画)的特定情况添加一个小技巧。
只需绘制一条零长度线,线宽为圆的直径,但将“线帽”设置为
rounded
。
对于椭圆、圆弧、线段和许多其他相关形状来说,这显然不是一个很好的解决方案......但它是一个很酷的技巧。
plinth的答案与我最终发现的相同。有很多棘手的数学可以简化为一个神奇的常数,并将任务细分为四个独立的贝塞尔曲线。 我需要在原始 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";
}