How to Draw Line Node Keep Same Size in Camera as Measure App in Iphone

How to draw line node keep same size in camera as Measure App in iPhone?

I use this to update scale if even if you stay far away it still readable

func updateScaleFromCameraForNodes(_ nodes: [SCNNode], fromPointOfView pointOfView: SCNNode , useScaling: Bool){
nodes.forEach { (node) in

//1. Get The Current Position Of The Node
let positionOfNode = SCNVector3ToGLKVector3(node.worldPosition)

//2. Get The Current Position Of The Camera
let positionOfCamera = SCNVector3ToGLKVector3(pointOfView.worldPosition)

//3. Calculate The Distance From The Node To The Camera
let distanceBetweenNodeAndCamera = GLKVector3Distance(positionOfNode, positionOfCamera)

let a = distanceBetweenNodeAndCamera*1.75
if(useScaling) {
node.simdScale = simd_float3(a,a,a)

}

}
SCNTransaction.flush()
}

then called it in the renderer updateAtTime

self.updateScaleFromCameraForNodes(self.nodesAdded, fromPointOfView:
self.cameraNode, useScaling: true)

How to pin a label / UIView to a node in ARKit

I've come up with the following solution to make it work.

First, I create the UILabel and add it as a subview. Next, I convert the position of the node I want to follow to screen coordinates in renderer(_: updateAtTime:). Now the label follows the node correctly and stays fixed in scale. However, the label stays horizontal to the screen, which looks weird. To make it stay horizontal to the world, I rotate the label according to the ARCamera's yaw (z rotation).

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {

// Convert the node's position to screen coordinates
let screenCoordinate = self.sceneView.projectPoint(node.position)

DispatchQueue.main.async {
// Move the label
label.center = CGPoint(x: CGFloat(screenCoordinate.x), y: CGFloat(screenCoordinate.y))

// Hide the label if the node is "behind the screen"
label.isHidden = (screenCoordinate.z > 1)

// Rotate the label
if let rotation = sceneView.session.currentFrame?.camera.eulerAngles.z {
label.transform = CGAffineTransform(rotationAngle: CGFloat(rotation + Float.pi/2))
}
}

}

How to create a square or rectangle overlay(plane) over camera with given width and height programmatically using Scenekit(ARKit) iOS 11?

A simple way to implement your need: prepare a rectangle icon, and generate a SCNNode with the method:

func geometryNodeFromImage(named name: String, width: CGFloat, height: CGFloat, length: CGFloat) -> SCNNode {
let box = SCNBox(width: width, height: height, length: length, chamferRadius: 0)

let rectangleMaterial = SCNMaterial()
rectangleMaterial.diffuse.contents = UIImage(named: name)
box.materials = [rectangleMaterial]

return SCNNode(geometry: box)
}

remove nodes from scene after use ARSCNView

I think the issue here is that your are not actually removing the SCNNodes you have added to hierarchy.

Although you are removing the nodes from what I assume is an array of SCNNodes by calling: nodes.removeAll(), you first need to actually remove them from the scene hierarchy.

So what you need to do is call the following function on any node you wish to remove:

removeFromParentNode()

Which simply:

Removes the node from its parent’s array of child nodes.

As such you would do something like this which first removes the nodes from the hierarchy, and then removes them from the array:

for nodeAdded in nodesArray{
nodeAdded.removeFromParentNode()
}

nodesArray.removeAll()

So based on the code provided you could do the following:

if nodes.count > 2 {

for nodeAdded in nodes{
nodeAdded.removeFromParentNode()
}

nodes.removeAll()

}

For future reference, if you want to remove all SCNNodes from you hierarchy you can also call:

self.augmentedRealityView.scene.rootNode.enumerateChildNodes { (existingNode, _) in
existingNode.removeFromParentNode()
}

Whereby self.augmentedRealityView refers to the variable:

var augmentedRealityView: ARSCNView!

Here is a very basic working example based on (and modified from) the code you have provided:

/// Places A Marker Node At The Desired Tap Point
///
/// - Parameter sender: UITapGestureRecognizer
@objc func handleTap(_ sender: UITapGestureRecognizer) {

//1. Get The Current Tap Location
let currentTapLocation = sender.location(in: sceneView)

//2. Check We Have Hit A Feature Point
guard let hitTestResult = self.augmentedRealityView.hitTest(currentTapLocation, types: .featurePoint).first else { return }

//3. Get The World Position From The HitTest Result
let worldPosition = positionFromMatrix(hitTestResult.worldTransform)

//4. Create A Marker Node
createSphereNodeAt(worldPosition)

//5. If We Have Two Nodes Then Measure The Distance
if let distance = distanceBetweenNodes(){
print("Distance == \(distance)")
}

}

/// Creates A Marker Node
///
/// - Parameter position: SCNVector3
func createSphereNodeAt(_ position: SCNVector3){

//1. If We Have More Than 2 Nodes Remove Them All From The Array & Hierachy
if nodes.count >= 2{

nodes.forEach { (nodeToRemove) in
nodeToRemove.removeFromParentNode()
}

nodes.removeAll()
}

//2. Create A Marker Node With An SCNSphereGeometry & Add It To The Scene
let markerNode = SCNNode()
let markerGeometry = SCNSphere(radius: 0.01)
markerGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
markerNode.geometry = markerGeometry
markerNode.position = position
sceneView.scene.rootNode.addChildNode(markerNode)

//3. Add It To The Nodes Array
nodes.append(markerNode)
}

/// Converts A matrix_float4x4 To An SCNVector3
///
/// - Parameter matrix: matrix_float4x4
/// - Returns: SCNVector3
func positionFromMatrix(_ matrix: matrix_float4x4) -> SCNVector3{

return SCNVector3(matrix.columns.3.x, matrix.columns.3.y, matrix.columns.3.z)

}

/// Calculates The Distance Between 2 Nodes
///
/// - Returns: Float?
func distanceBetweenNodes() -> Float? {

guard let firstNode = nodes.first, let endNode = nodes.last else { return nil }
let startPoint = GLKVector3Make(firstNode.position.x, firstNode.position.y, firstNode.position.z)
let endPoint = GLKVector3Make(endNode.position.x, endNode.position.y, endNode.position.z)
let distance = GLKVector3Distance(startPoint, endPoint)
return distance
}

For an example of a measuringApp which might help your development you can look here: ARKit Measuring Example

Hope it helps...



Related Topics



Leave a reply



Submit