मान लीजिए कि हमारे पास दो UIBezierPaths, path1 और path2... (जो पहले से ही रनटाइम पर सीमा देखने के सापेक्ष परिभाषित किए गए हैं और पहले से ही एक ही दृश्य के गुणों के रूप में मौजूद हैं)।

हम UIBezierPath, पथ 3 का एक नया पथ प्राप्त करना चाहते हैं, जो पथ 1 से पथ 2 घटाने का परिणाम है:

enter image description here

इसे करने का तरीका (जैसा कि यहां देखा गया है) यह करना है:

path1.append(path2.reversing())

लेकिन, यह केवल उन परिस्थितियों के लिए काम करता प्रतीत होता है जहां पथ 1 पूरी तरह से पथ 2 को शामिल करता है।

उदाहरण के लिए, उस मामले पर विचार करें जहां केवल एक आंशिक प्रतिच्छेदन है - पथ 1 पथ 2 को पूरी तरह से शामिल नहीं करता है। यदि हम ऊपर दी गई विधि को लागू करते हैं तो ऐसा होता है:

enter image description here

Android में, उत्तर है:

path1.op(path2, Path.Op.DIFFERENCE);

तो ... क्या आईओएस में एक समान सरल ऑपरेशन है?

यदि नहीं, तो क्या कोई ऐसा कार्य है जिसे इस प्रकार लिखा जा सकता है:

func returnPath2CutOutOfPath1(path1: UIBezierPath, path2: UiBezierPath) -> UIBezierPath {

// the mystery lies within these here parts. :)

}
2
Nerdy Bunz 15 पद 2018, 09:46

2 जवाब

सबसे बढ़िया उत्तर

आईओएस पर एक नए पथ के रूप में UIBezierPaths के अंतर प्राप्त करने का कोई सीधा तरीका नहीं है।

टेस्टकेस

private func path2() -> UIBezierPath {
    return UIBezierPath(rect: CGRect(x: 100, y: 50, width: 200, height: 200))
}

private func path1() -> UIBezierPath {
    return UIBezierPath(rect: CGRect(x: 50, y: 100, width: 200, height: 200))
}

प्रारंभिक बिंदु: केवल यह दिखाने के लिए कि कौन सा पथ किसका प्रतिनिधित्व करता है: पथ 1 पीला है और पथ 2 हरा है:

starting point

संभावना 1

आप शायद इस संभावना को पहले ही देख चुके हैं: आपने अपने प्रश्न में जिस लिंक का उल्लेख किया है, उसमें एक चतुर समाधान भी है यदि आपको केवल एक भरण ऑपरेशन करना है।

कोड इस उत्तर से लिया गया था (आपके द्वारा पोस्ट किए गए लिंक से) https://stackoverflow.com/a/8860341 - केवल रूपांतरित स्विफ्ट करने के लिए:

func fillDifference(path2: UIBezierPath, path1: UIBezierPath) {
    let clipPath = UIBezierPath.init(rect: .infinite)
    clipPath.append(path2)
    clipPath.usesEvenOddFillRule = true

    UIGraphicsGetCurrentContext()?.saveGState()
    clipPath.addClip()
    path1.fill()
    UIGraphicsGetCurrentContext()?.restoreGState()
}

तो यह एक पथ भरता है, लेकिन UIBezierPath वापस नहीं करता है, जिसका अर्थ है कि आप रूपरेखा, पृष्ठभूमि, समोच्च चौड़ाई इत्यादि लागू नहीं कर सकते हैं, क्योंकि परिणाम UIBezierPath नहीं है।

यह इस तरह दिख रहा है:

fill only

संभावना 2

आप किसी तृतीय-पक्ष लाइब्रेरी का उपयोग कर सकते हैं, उदा। एडम वूल्फ़ नाम के एक लेखक से एक यहाँ: https://github.com/adamwulf/ClippingBezier

पुस्तकालय उद्देश्य-सी में लिखा गया है, लेकिन इसे स्विफ्ट से बुलाया जा सकता है।

स्विफ्ट में, यह इस तरह दिखेगा:

override func draw(_ rect: CGRect) {
    let result = self.path1().difference(with: self.path2())

    for p in result ?? [] {
        p.stroke()
    }
}

यदि आप इस पुस्तकालय का उपयोग करना चाहते हैं, तो आपको एक छोटा संकेत नोट करना होगा: प्रोजेक्ट सेटिंग्स में अन्य लिंकर फ़्लैग्स में, जैसा कि रीडमी द्वारा वर्णित है, "-ObjC++ -lstdc++" जोड़ा जाना चाहिए, अन्यथा इसे बिना किसी शिकायत के बनाया जाएगा, लेकिन चुपचाप फ्रेमवर्क लोड नहीं करेगा और अंततः क्रैश हो जाएगा, क्योंकि UIBEzierPath श्रेणियां नहीं मिली हैं।

परिणाम इस तरह दिखता है:

real bezier path result

तो यह वास्तव में आपका वांछित परिणाम देगा, लेकिन आपको किसी तृतीय पक्ष लाइब्रेरी का उपयोग करना होगा।

2
Stephan Schlecht 27 पद 2018, 11:22

मैंने आपको वांछित समाधान प्राप्त कर लिया है, लेकिन मैंने 200x200 आकार के स्थिर दृश्य के लिए कोड बनाया है।

मैं आपको दिखाता हूं कि मैंने क्या प्रयास किया है और मुझे बताएं कि आपके लिए कितना उपयोगी है।

सबसे पहले, मैंने कस्टम व्यू का वर्ग बनाया है जहां मैंने दृश्य बनाने के लिए कोड लिखा है। निम्नलिखित कोड देखें:

class MyCustomView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    func setup() {

        // Create a CAShapeLayer
        let shapeLayer = CAShapeLayer()

        let path1 = self.path1()
        let path2 = self.path2()

        // Append path2 to path1
        path1.append(path2.reversing())

        // Set true of Even Odd Fill Rule
        path1.usesEvenOddFillRule = true

        // Call this method to add clip in path
        path1.addClip()

        shapeLayer.path = path1.cgPath

        // Apply other properties related to the path
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.black.cgColor
        shapeLayer.lineWidth = 1.0
        shapeLayer.position = CGPoint(x: 0, y: 0)

        // Add the new layer to our custom view
        self.layer.addSublayer(shapeLayer)
    }

    //-----------------------------------------------------
    // This is static code as I have already told you first.
    // Create First UIBezierPath,

    func path1() -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: 0, y: 200))
        path.addLine(to: CGPoint(x: 200, y: 200))
        path.addLine(to: CGPoint(x: 200, y: 0))
        path.close()
        return path
    }

    // Create Second UIBezierPath
    func path2() -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 50, y: -50))
        path.addLine(to: CGPoint(x: 50, y: 150))
        path.addLine(to: CGPoint(x: 250, y: 150))
        path.addLine(to: CGPoint(x: 250, y: -50))
        path.close()
        return path
    }
}

जैसा कि आपने चित्र 4 में बताया है, यह कस्टम वर्ग कोड आपके वास्तविक परिणाम के साथ साझा परत बनाएगा।

अब इस वर्ग का उपयोग करने के लिए मैंने निश्चित ऊंचाई और चौड़ाई के साथ उपरोक्त वर्ग का उदाहरण बनाया है।

override func viewDidLoad() {
    super.viewDidLoad()

    // Create a new UIView and add it to the view controller
    let myView = MyCustomView()

    // Must set clipsToBounds true to remove extra layer which are display out side of view as like your **actual** result in figure 4.
    myView.clipsToBounds = true 
    myView.frame = CGRect(x: 50, y: 100, width: 200, height: 200)
    myView.backgroundColor = UIColor.orange
    view.addSubview(myView)
}

यह अनुसरण के रूप में दृश्य प्रदर्शित करेगा जो आपका वांछित परिणाम है।

UIBezierPath चौराहा मुझे उम्मीद है कि यह आपकी मदद करेगा, अगर आपके पास कोई प्रश्न है तो मुझे अभी भी बताएं।

2
Mayur Karmur 20 पद 2018, 16:57