2016-12-07 9 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/5x, и 1/10x, как много точек:

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


Некоторые советы от DIAG совать проблемы:

При работе с большим количеством данных координат, как это, мне нравится использовать 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 снова и снова), поэтому я могу нарезать и нарезать данные, чтобы выяснить, что с ними не так. (Например, одна из моих ранних теорий заключалась в том, что может быть что-то относительно отрицательных координат, поэтому я сделал некоторые map и min(), чтобы найти наиболее отрицательные значения X и Y, затем еще несколько map, чтобы создать массив, где все точки смещены . на постоянной величину)

Теперь, чтобы сделать пути с использованием массивов точек, я делаю расширение на 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 т выше):

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

Вы можете получить (немного) лучше сделать из того, больше очков на своем пути, но еще лучший способ сделать это было бы сделать путь из кривых вместо линий , Для дополнительного кредита попробуйте расширить инициализатор NSBezierPath(linesBetween:), чтобы добавить кривые, сохранив каждую n-ю точку как часть пути, используя пару промежуточных точек в качестве управляющих ручек. (Это не универсальный алгоритм автоматической трассировки, но он может быть достаточно хорош для таких случаев.)

+1

Ничего себе. ПРОСТО ВАУ!!! Это документация первого класса. От имени всех разочарованных дизайнеров, тактильных иллюстраторов, привыкших рисовать ручкой, мышью или планшетом, я благодарю вас! – Confused

+0

Вещь с путём заключается в том, что она создана пользователем моего приложения, поэтому я заранее не знаю, сколько и в какой точке будет содержать этот путь. СПАСИБО за этот отличный ответ! :) –

+0

Чтобы собрать данные для этого примера, мы попросили пользователя нарисовать круг в воздухе. Очевидно, результат не идеальный круг. В идеале мы бы узнали его как круг, а затем изменили данные, чтобы нарисовать идеальный круг. Но это другая проблема ... –

2

Это никак не сравнится с ответом Рикстера, но есть еще один способ предотвратить эту проблему. Это коммерческий способ, и есть, вероятно, бесплатные приложения, которые делают подобное, но это тот, который я использую для использования, что делает это довольно хорошо.

Что такое «это», о котором я говорю?

Преобразование чертежей в код при помощи приложения под названием PaintCode. Это позволит вам увидеть ваши пути и убедиться, что у них нет ни одного конфликта, который указал Рикстер, - это ваша проблема.

Проверьте это здесь: https://www.paintcodeapp.com/

Других варианты перечислены в ответах здесь: How to import/parse SVG into UIBezierpaths, NSBezierpaths, CGPaths?