如何填充Quartz 2D中路径下方的区域?

时间:2013-04-23 15:46:42

标签: ios quartz-2d fill area bezier

我在UIView对象中使用Quartz 2D来绘制几条曲线,如下例所示:

Two curves drawn using Quartz 2D with <code>CGContextStrokePath</code>

这是我现在的代码(我省略了控制点和其他东西的计算):

for (int i = 1; i < points.count; ++i) {
  CGContextMoveToPoint(context, previousXValue, previousYValue);
  CGContextAddCurveToPoint(context,
    firstControlPointXValue, firstControlPointYValue,
    secondControlPointXValue, secondControlPointYValue,
    xValue, yValue
  );

  // CGContextFillPath(context);
  CGContextStrokePath(context);
}

现在我想填充曲线下方的区域,但如果我使用CGContextFillPath,结果如下:

Two curves filled using Quartz 2D with <code>CGContextFillPath</code>

这是有道理的,因为根据Quartz 2D documentation

  

填充当前路径时,Quartz就像关闭路径中包含的每个子路径一样。然后它使用这些封闭的子路径   并计算要填充的像素。

然后我尝试将路径移动到右下角并关闭路径,但填充方法没有任何效果:

CGContextMoveToPoint(context, rect.size.width, rect.size.height);
CGContextClosePath(context);
CGContextFillPath(context);

我怎样才能填满曲线下面的整个区域而不只是填充每个子路径中的子区域?

编辑:

我找到了一个临时解决方案:使用曲线绘制形状,并在每个子路径上绘制两条垂直线:

for (int i = 1; i < points.count; ++i) {
  // Draw the curve
  CGContextMoveToPoint(context, previousXValue, previousYValue);
  CGContextAddCurveToPoint(context,
    firstControlPointXValue, firstControlPointYValue,
    secondControlPointXValue, secondControlPointYValue,
    xValue, yValue
  );
  CGContextStrokePath(context);

  // Draw a shape using curve's initial and final points
  CGContextMoveToPoint(context, previousXValue, rect.size.height);
  CGContextAddLineToPoint(context, previousXValue, previousYValue);
  CGContextAddCurveToPoint(context,
    firstControlPointXValue, firstControlPointYValue,
    secondControlPointXValue, secondControlPointYValue,
    xValue, yValue
  );
  CGContextAddLineToPoint(context, xValue, rect.size.height);
  CGContextFillPath(context);
}

我不知道这是否过度,所以也欢迎改进。此外,我得到了这个结果:

Two curves drawn using Quartz 2D with the area below them filled

请注意,由于将子区域绘制在一起,因此会显示垂直线条。如何避免这种情况?

1 个答案:

答案 0 :(得分:3)

这个想法是正确的,但你不应该填充单个曲线,而是创建一个单独的路径然后填充它。因此,从左下角的CGContextMoveToPoint开始,到第一个点的CGContextAddLineToPoint,为所有曲线执行CGContextAddCurveToPoint,最后执行CGContextAddLineToPoint在右下角(你可以做一个CGContextClosePath以获得良好的衡量标准)。

这是一个简化的例子,我只有一个点数组,但它说明了这个想法:

- (void)drawRect:(CGRect)rect
{
    if (!self.points)
        [self configurePoints];

    DataPoint *point;

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGColorRef color = [[UIColor redColor] CGColor];
    CGContextSetStrokeColorWithColor(context, color);
    CGContextSetFillColorWithColor(context, color);

    point = self.points[0];

    CGContextMoveToPoint(context, point.x, self.bounds.size.height);
    CGContextAddLineToPoint(context, point.x, point.y);

    for (point in self.points)
    {
        // you'd do your CGContextAddCurveToPoint here; I'm just adding lines
        CGContextAddLineToPoint(context, point.x, point.y);
    }

    point = [self.points lastObject];
    CGContextAddLineToPoint(context, point.x, self.bounds.size.height);
    CGContextClosePath(context);

    CGContextDrawPath(context, kCGPathFillStroke);
}