2016-12-07 46 views
2

我經歷過某些NSBezierPath s SCNShape似乎無法繪製形狀。SCNShape不繪製NSBezierPath的形狀

該路徑僅使用line(to:)創建。

//...set up scene... 

//Create path (working) 
let path = NSBezierPath() 
path.move(to: CGPoint.zero) 
path.line(to: NSMakePoint(0.000000, 0.000000)) 
path.line(to: NSMakePoint(0.011681, 0.029526)) 
// more points ... 
path.close() 

// Make a 3D shape (not working) 
let shape = SCNShape(path: path, extrusionDepth: 10) 
shape.firstMaterial?.diffuse.contents = NSColor.green 
let node = SCNNode(geometry: shape) 
root.addChildNode(node) 

用於驗證創建SCNShape的一般過程是正確的,我還畫了藍色形狀僅由具有不同的點是不同的。藍色的形狀被繪製,綠色的形狀不會。

你可以找到一個包含完整示例here的遊樂場。在示例中,您應該能夠在助理編輯器中看到綠色和藍色的形狀。但只有藍色的形狀被繪製。

你知道爲什麼沒有顯示綠色的形狀嗎?

+0

它有多好,是,如果有可能複製和粘貼Illustrator或其它矢量程序的形狀,放入SceneKit的場景編輯器?然後將其縮放......等等。或者導入一個SVG或某種其他單獨的矢量形狀。 – Confused

回答

6

小故事:你的路徑比它需要更多的點,導致你意外,很難找到幾何問題。

注意該位在documentation

擠出自相交路徑的結果是不確定的。

事實證明,在第8個左右百分點的地方,你的「曲線」賺了足夠的轉彎錯誤的方式,該行關閉的路徑(第一點之間的路徑0,0和最後一點32.366829, 29.713470)與路徑的其餘部分相交。下面是在使其可見通過排除所有,但前幾站,並從操場的最後一點渲染的嘗試(看到小小的曲折的左下角):

move zig for great justice

一些

而且至少在SceneKit版本/渲染器中,當它試圖從自相交路徑中創建一個網格時,它只會放棄並且什麼也不做。

但是,你真的不需要那麼多點讓你的路徑看起來不錯。這是,如果你使用1X,1/5倍,1/10倍儘可能多的積分:

original path path w/ every 5th point from the original path w/ every 10th point from the original

如果整體排除足夠的積分,和/或跳過開頭的少數讓你的曲線字形,它應該鋸齒,呈現SceneKit形狀就好:

first few points excluded, 1/5 as many points total


從診斷的一些技巧收口問題:

在有很多協調這樣的數據的工作,我喜歡用ExpressibleByArrayLiteral這樣我就可以輕鬆構建大量點/矢量/等陣列:

extension CGPoint: ExpressibleByArrayLiteral { 
    public init(arrayLiteral elements: CGFloat...) { 
     precondition(elements.count == 2) 
     self.init(x: elements.first!, y: elements.last!) 
    } 
} 

var points: [CGPoint] = [ 
    [0.000000, 0.000000], 
    [0.011681, 0.029526], 
    // ... 
] 

這讓我的數組(並且很少輸入諸如NSPointMake之類的內容),所以我可以對數據進行分片和分片以找出其中的錯誤。 (例如,我早期的理論之一是可能有一些關於負座標的東西,所以我做了一些mapmin()來找到最負的X和Y值,然後再做一些數據,使所有的點都被偏移通過將恆定量)

現在,使用點的陣列的路徑作,我就NSBezierPath擴展:

extension NSBezierPath { 
    convenience init(linesBetween points: [CGPoint], stride: Int = 1) { 
     precondition(points.count > 1) 
     self.init() 
     move(to: points.first!) 
     for i in Swift.stride(from: 1, to: points.count, by: stride) { 
      line(to: points[i]) 
     } 
    } 
} 

藉助於此,我可以輕鬆地創建從點不只是整個陣列的路徑,還...

  • 路徑即跳過(與stride參數)的原陣列的部分

    let path5 = NSBezierPath(linesBetween: points, stride: 5) 
    let path10 = NSBezierPath(linesBetween: points, stride: 10) 
    

    (這是非常方便用於產生操場快速預覽有點多,太)。使用一些塊

  • 路徑還是原來的陣列

    let zigzag = NSBezierPath(linesBetween: Array(points.prefix(to:10)) + [points.last!]) 
    let lopOffBothEnds = NSBezierPath(linesBetween: Array(points[1 ..< points.count < 1])) 
    

或者兩者都是,獲獎作品(在screensho切片上述t)爲:

let path = NSBezierPath(linesBetween: Array(points.suffix(from: 10)), stride: 5) 

你可以得到一個(略)更好地呈現出在你的路徑有更多的點,但更好的方法來做到線,這將是使一個路徑出來的曲線,而不是。要獲得額外的功勞,請嘗試擴展上面的NSBezierPath(linesBetween:)初始值設定項,以將每個n作爲路徑的一部分,同時使用一對中間點作爲控制手柄來添加曲線。 (這是沒有通用的自動跟蹤算法,但可能是這樣的情況下足夠好)。

+1

哇。只是哇!這是頭等文件。我代表所有沮喪的設計導向,習慣於用鋼筆,鼠標或平板電腦繪圖的觸覺插圖畫家,我感謝你! – Confused

+0

有路徑的事情是,它是由我的應用程序的用戶創建的,所以我事先不知道路徑將包含多少個點和哪個點。謝謝你這個偉大的答案! :) –

+0

爲了收集這個例子的數據,我們要求用戶在空中畫一個圓圈。顯然,結果不是一個完美的圓圈。理想情況下,我們會將其識別爲一個圓,然後更改數據以繪製一個完美的圓。但這是一個不同的問題... –

2

這與Rikster的答案沒有什麼區別,但有另一種方法來防止這種問題。這是一種商業方式,可能有類似的免費軟件應用程序,但這是我習慣使用的,這很好。

我在說什麼'這個'?

通過名爲PaintCode的應用程序將圖紙轉換爲代碼。這將讓你看到你的路徑,並確保他們沒有Rickster指出的衝突是你的問題。

看看這裏:https://www.paintcodeapp.com/

其他選項中的答案在這裏列出:How to import/parse SVG into UIBezierpaths, NSBezierpaths, CGPaths?