【问题标题】:Check UIBezierPath closed or not检查 UIBezierPath 是否关闭
【发布时间】:2016-06-07 04:43:55
【问题描述】:

如何检查UIBezierPath是否是闭合路径(闭合路径就像闭合轮廓意味着它可以创建任何形状,如三角形、正方形、多边形等),如果它是闭合的,那么只填充路径?

以下表示应该填充形状的区域;最后 2 个定义闭合轮廓和简单闭合轮廓的形状,只能填充颜色:

Image Source

以下是我的代码,里面有 4 个方块,但只填充了 3 个方块;还想知道是否可以找到以平方英尺为单位的填充区域的面积,因为我在这里得到 4 个正方形如何检查它在 4 个正方形中覆盖的总面积?

UIBezierPath *mainPath =[UIBezierPath bezierPath];
[mainPath moveToPoint:CGPointMake(50, 100)];
[mainPath addLineToPoint:CGPointMake(0, 100)];
[mainPath addLineToPoint:CGPointMake(0, 150)];
[mainPath addLineToPoint:CGPointMake(50, 150)];
[mainPath addLineToPoint:CGPointMake(50, 200)];
[mainPath addLineToPoint:CGPointMake(100, 200)];
[mainPath addLineToPoint:CGPointMake(100, 150)];
[mainPath addLineToPoint:CGPointMake(50, 150)];
[mainPath addLineToPoint:CGPointMake(50, 100)];
[mainPath addLineToPoint:CGPointMake(100, 100)];
[mainPath addLineToPoint:CGPointMake(150, 100)];
[mainPath addLineToPoint:CGPointMake(150, 150)];
[mainPath addLineToPoint:CGPointMake(100, 150)];
[mainPath addLineToPoint:CGPointMake(100, 100)];
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.lineWidth = 5.0;
shapeLayer.strokeColor = [UIColor blueColor].CGColor;
shapeLayer.path =mainPath.CGPath;
shapeLayer.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.5].CGColor;
[[self.view layer] addSublayer:shapeLayer];

【问题讨论】:

    标签: ios objective-c core-graphics uibezierpath cashapelayer


    【解决方案1】:

    你为什么不使用mainPath.closePath它会自动为你关闭路径并填充。如果你想了解更多关于自动或手动关闭路径的信息,你可以看看here,它说:

    不同的是 [closePath] 方法实际上添加了一个 支持底层 CGPath 的附加路径元素 UIBezierPath。

    如果你使用 [closePath],那么一个额外的 CGPathElement 类型 kCGPathElementCloseSubpath 将附加到路径的末尾 紧接在最后一条线段之后。

    对于所覆盖的区域,您可以获得UIBezierPath 的边界框,但我认为拥有不同的UIBezierPath(每个正方形一个)可能更简单,然后计算边界框对于每个正方形。如果您想拥有路径的边界框:

    let bounds = CGPathGetBoundingBox(yourPath.CGPath)
    

    【讨论】:

    • 好吧,所有的行都是动态添加的,我不想关闭路径;我只是想检查它是否已关闭。并计算面积,然后形状可以是三角形左右,因此可以以平方英尺为单位计算所有不同形状的面积。
    【解决方案2】:

    我已经回答了关于 CGPath here 的类似问题。因为你可以得到CGPathUIBezierPath,我认为它也适用于这里。这适用于 Swift 3.x。我从this answer 大量借用,添加了isClosed() 函数。

    func isClosed() -> Bool {
        var isClosed = false
        forEach { element in
            if element.type == .closeSubpath { isClosed = true }
        }
        return isClosed
    }
    
    func forEach( body: @convention(block) (CGPathElement) -> Void) {
        typealias Body = @convention(block) (CGPathElement) -> Void
        let callback: @convention(c) (UnsafeMutableRawPointer, UnsafePointer<CGPathElement>) -> Void = { (info, element) in
            let body = unsafeBitCast(info, to: Body.self)
            body(element.pointee)
        }
        print(MemoryLayout.size(ofValue: body))
        let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self)
        self.apply(info: unsafeBody, function: unsafeBitCast(callback, to: CGPathApplierFunction.self))
    }
    }
    

    这是你如何使用它:

    myBezierPath.cgPath.isClosed()
    

    【讨论】:

    • 必须 forEach 循环所有元素还是足以检测到 FIRST element.type == .closeSubpath 并立即返回(性能)?
    • 不错@sabiland 我已经编辑了我的答案以包含您的建议!
    • 代码无法编译。您尝试从“块”返回 true。
    猜你喜欢
    • 1970-01-01
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多