How would I draw a filled polygon connecting points touched by user on a detected horizontal plane in ARKit world.
I went on to do this by keeping hit points on an array...
let position = SCNVector3.positionFrom(matrix: result.worldTransform)
let sphere = SphereNode(position: position)
nodes.append(position)
... and then trying to draw a bezier path
let bezierPath = UIBezierPath()
bezierPath.lineWidth = 0.1
for index in 0..<nodes.count {
let node = nodes[index] as SphereNode
if (index == 0) {
let point = CGPoint(x: CGFloat(node.position.x), y: CGFloat(node.position.z))
bezeierPath.move(to: point)
} else {
let point = CGPoint(x: CGFloat(node.position.x), y: CGFloat(node.position.z))
bezeierPath.addLine(to: point)
}
}
bezeierPath.close()
bezeierPath.fill()
bezeierPath.stroke()
let shape = SCNShape(path: bezeierPath, extrusionDepth: 0.03)
shape.firstMaterial?.diffuse.contents = UIColor.red
let node = SCNNode.init(geometry: shape)
sceneView.scene.rootNode.addChildNode(node)
But this doesn't draw the polygon on the correct place. it draw it behind the camera vertically angled.
2D geometries like SCNPlane, SCNText and SCNShape are vertical by nature because they work on the xy plane. In your example, you're using the z 3D coordinate as the y 2X coordinate.
Try setting node.eulerAngles.x to -.pi / 2 (if that doesn't work try without the -), and your node will be horizontal instead of vertical.
Related
I'm working on a simple freehand drawing app. Below is the sample code, I'm using the UIGesture class to track the scribble, i.e., pencil or finger movement, and then stroking those touch points on the UIImageView
let previousLocation = touch.previousLocation(in: self)
let location = touch.location(in: self)
var lineWidth: CGFloat = 3
UIColor.black.setStroke()
context?.setLineWidth(lineWidth)
context?.setLineCap(.round)
context?.move(to: previousLocation)
context?.addLine(to: location)
context?.strokePath()
the strokes are blurry on the edges and the result looks like this:
Few other things I have tried:
1)Stroking bezier pathh
2)Using view instead of image view
3)Increasing scale here -> UIGraphicsBeginImageContextWithOptions, this does increase the sharpness but the overall writing lags
How do I get sharp annotations?
Anyone familiar with using curved UIBezierPaths to create a SCNShape in ARKit? I'm creating a closed circle path, but I get a diamond shape in my ARKit scene.
Here is the code I use to create the bezier path and SCNShape:
let radius : CGFloat = 1.0
let outerPath = UIBezierPath(ovalIn: CGRect(x: -radius, y: -radius, width: 2* radius, height: 2* radius))
let material = SCNMaterial()
material.diffuse.contents = UIColor.blue
material.isDoubleSided = true
material.ambient.contents = UIColor.black
material.lightingModel = .constant
material.emission.contents = UIColor.blue
let shape = SCNShape(path: outerPath, extrusionDepth: 0.01)
shape.materials = [material]
let shapeNode = SCNNode(geometry: shape)
positioningNode.addChildNode(shapeNode)
I've successfully tested a rectangular bezier path, but even had issues with a rounded rect bezier path (using UIBezierPath(roundedRect:). For the rounded rect bezier path, ARKit shows the curved corners with 45 degree lines.
Thanks in advance!
UPDATE:
On the left is the initial SCNShape with UIBezierPath flatness set to 0.6. On the right is the same SCNShape with flatness set to 0.001.
I was able to find a solution. Basically the UIBezierPath's flatness variable is used to control curvature. The default value of 0.6 was too large in my case. I ended up using a flatness of 0.001
https://developer.apple.com/documentation/scenekit/scnshape/1523432-init
I am trying to draw a wedge of a circle using UIBezierPath, but when drawing it it shows a triangle and instead of drawing a curve through my points, it draws a straight line.
I am constructing the SCNNode Like so:
let path = UiBezierPath()
path.move(to: CGPoint.zero)
path.addArc(withCenter: CGPoint.zero, radius: 0.5, startAngle: 0, endAngle: .pi/2, clockwise: true)
path.close()
let shape = SCNShape(path: path, extrusionDepth: 0.1)
let mat = SCNMaterial()
mat.diffuse.contents = UIColor.orange
shape.materials = [mat]
let node = SCNNode(geometry: shape)
When I position this node in the world, and add it to the scene it draws a triangle. How can I make it so there is a curve instead of just a straight line?
Setting the flatness of the path to 0 fixed this issue:
path.flatness = 0
I'm trying to draw small circles over corners of pentagon inside a circle.
I know the following information.
The radius of circle is 50.
Centre of circle is x = 100, y = 100
How can I get position of pentagon corners in x and y so that I can draw a circle there.
Thanks.
I hope you are familiar with polar coordinates. I wrote simple algorithm to calculate corners:
let center = CGPoint(x: 100, y: 100)
let numberOfCorners: Int = 5
let radius = 50.0
var angle:Double = 0.0
let startAngle = M_PI_2
var points: [CGPoint] = []
angle = startAngle
while angle - startAngle < 2*M_PI {
let x = radius * cos(angle) + Double(center.x) // transform polar coordinates to XY
let y = radius * sin(angle) + Double(center.y)
let point = CGPoint(x: x, y: y)
points.append(point)
let angleIncrease = Double(2.0*M_PI)/Double(numberOfCorners)
angle += angleIncrease
}
print(points)
It should works with other polygons. You only have to specify numberOfCorners and startAngle (in radians). Correct StartAngle for iOS coordinates is I think: 3/2 PI.
But for default XY plane to achieve polygon like on your picture, pi/4 it's ok.
I am tying to draw a 3d line in Scenekit iOS, i am trying below code to draw line,
func path() -> UIBezierPath
{
var bPath = UIBezierPath()
bPath.moveToPoint(CGPointMake(0, 0))
bPath.addLineToPoint(CGPointMake(10, 10))
bPath.addLineToPoint(CGPointMake(5, 5))
bPath.closePath()
return bPath
}
and the below code is to load the line in SCNNode,
let sap = SCNShape()
sap.path = path()
let carbonNode = SCNNode(geometry: sap)
carbonNode.position = SCNVector3Make(0, 0, 15)
scene.rootNode.addChildNode(carbonNode)
But, i am getting blank screen.
try changing your geometry's materials. You might have a white object on a white background.
edit:
it also turns out that the vertices of your triangle are colinear. You thus end up with a degenerate triangle.
Your path has no surface area since you start at (0,0), draw a line to (10, 10) and then a second line to (5,5) which is already on the line between (0,0) and (10, 10). Then you close the path by drawing another line to (0,0).
Changing either of the three points creates a path with a surface area.
Also, the z-axis points out of the screen. This means that depending on where your camera is positioned, you may be placing the carbonNode behind the camera. If instead you meant to position it further into the scene you should likely use a negative z value.
Here's some code I wrote to address the problem.
// Material colors
let cyanMaterial = SCNMaterial()
cyanMaterial.diffuse.contents = UIColor.cyanColor()
let anOrangeMaterial = SCNMaterial()
anOrangeMaterial.diffuse.contents = UIColor.orangeColor()
let aPurpleMaterial = SCNMaterial()
aPurpleMaterial.diffuse.contents = UIColor.purpleColor()
// A bezier path
let bezierPath = UIBezierPath()
bezierPath.moveToPoint(CGPointMake(-0.25, 0))
bezierPath.addLineToPoint(CGPointMake(0, -0.25))
bezierPath.addLineToPoint(CGPointMake(0.25, 0))
bezierPath.addLineToPoint(CGPointMake(0, 0.25))
bezierPath.closePath()
// Add shape
let shape = SCNShape(path: bezierPath, extrusionDepth: 0.75)
shape.materials = [cyanMaterial, anOrangeMaterial, aPurpleMaterial]
let shapeNode = SCNNode(geometry: shape)
shapeNode.position = SCNVector3(x: 0.2, y: 0.75, z: 0.1);
self.rootNode.addChildNode(shapeNode)
shapeNode.rotation = SCNVector4(x: -1.0, y: -1.0, z: 0.0, w: 0.0)
Keep in mind that the numbers, the Scene Kit scale, are in meters. So set the numbers similarly to those that work for the other shapes you create.