//
// SceneStuff.swift
// 3DTest
//
// Created by JxR on 3/15/23.
//

import Foundation
import Swift
import UIKit
import SceneKit
import SwiftUI

struct NetworkNode {
 let identifier: String
 let position: SCNVector3
 var connections: [String]
}

struct ThreeDimsView: UIViewRepresentable {
 func makeCoordinator() -> Coordinator {
 Coordinator(self)
 }
 
 func makeUIView(context: Context) -> SCNView {
 // Create an instance of ThreeDims view controller
 let threeDimsVC = ThreeDims()

 // Load its view if needed
 threeDimsVC.loadViewIfNeeded()

 // Return the scnView from the view controller
 return threeDimsVC.scnView
 }
 
 func updateUIView(\_ uiView: SCNView, context: Context) {
 // Perform any updates as needed
 }
 
 class Coordinator: NSObject {
 var parent: ThreeDimsView

 init(\_ parent: ThreeDimsView) {
 self.parent = parent
 }
 }
}
class ThreeDims: UIViewController {
 var scnView: SCNView!
 let networkNodes: [NetworkNode] = [
 NetworkNode(identifier: "A", position: SCNVector3(-1, 0, 0), connections: ["B", "C"]),
 NetworkNode(identifier: "B", position: SCNVector3(1, 1, 0), connections: ["A"]),
 NetworkNode(identifier: "C", position: SCNVector3(1, -1, 0), connections: ["A"])
 ]
 override func viewDidLoad() {
 super.viewDidLoad()
 
 // Initialize the scnView property
 scnView = SCNView(frame: view.bounds)
 scnView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
 view.addSubview(scnView)
 
 // Set up the scene
 let scene = SCNScene()
 scnView.scene = scene
 // Add a camera
 setupCamera(in: scene)
 // Add a light source
 let lightNode = SCNNode()
 lightNode.light = SCNLight()
 lightNode.light!.type = .omni
 lightNode.position = SCNVector3(0, 5, 10)
 scene.rootNode.addChildNode(lightNode)
 
 // Create nodes for the network nodes and add them to the scene
 var sphereNodes: [String: SCNNode] = [:]
 for networkNode in networkNodes {
 let sphereNode = createSphereNode(for: networkNode)
 sphereNodes[networkNode.identifier] = sphereNode
 scene.rootNode.addChildNode(sphereNode)
 }
 
 // Connect the nodes with cylinder edges
 for networkNode in networkNodes {
 let startNode = sphereNodes[networkNode.identifier]
 for connectionIdentifier in networkNode.connections {
 if let endNode = sphereNodes[connectionIdentifier], startNode != nil {
 let cylinderNode = createCylinderNode(from: startNode!, to: endNode)
 scene.rootNode.addChildNode(cylinderNode)
 }
 }
 }
 }
 func setupCamera(in scene: SCNScene) {
 let cameraNode = SCNNode()
 cameraNode.camera = SCNCamera()
 cameraNode.position = SCNVector3(0, 0, 5)
 cameraNode.name = "cameraNode" // Add this line to set the camera node's name
 
 // Create a pan gesture recognizer to rotate the camera
 let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(\_:)))
 view.addGestureRecognizer(panGestureRecognizer) // Add the gesture recognizer to the main view
 
 scene.rootNode.addChildNode(cameraNode)
 }
 @objc func handlePanGesture(\_ sender: UIPanGestureRecognizer) {
 guard let cameraNode = scnView.scene?.rootNode.childNode(withName: "cameraNode", recursively: false) else { return }

 let translation = sender.translation(in: scnView)
 let rotationSpeed: CGFloat = 0.005

 let rotationX = Float(translation.y) \* Float(rotationSpeed)
 let rotationY = Float(translation.x) \* Float(rotationSpeed)

 // Rotate the camera around the Y-axis (left and right)
 let rotationAroundY = SCNMatrix4MakeRotation(rotationY, 0, 1, 0)
 cameraNode.transform = SCNMatrix4Mult(cameraNode.transform, rotationAroundY)

 // Rotate the camera around its X-axis (up and down)
 let rotationAroundX = SCNMatrix4MakeRotation(rotationX, 1, 0, 0)
 cameraNode.transform = SCNMatrix4Mult(rotationAroundX, cameraNode.transform)

 sender.setTranslation(.zero, in: scnView)
 }

 func createSphereNode(for networkNode: NetworkNode) -> SCNNode {
 let sphereGeometry = SCNSphere(radius: 0.1)
 let material = SCNMaterial()
 material.diffuse.contents = UIColor.random() // A random color for each sphere
 sphereGeometry.materials = [material]
 
 let sphereNode = SCNNode(geometry: sphereGeometry)
 sphereNode.position = networkNode.position
 sphereNode.name = networkNode.identifier
 
 return sphereNode
 }
 func createCylinderNode(from startNode: SCNNode, to endNode: SCNNode) -> SCNNode {
 let vector = endNode.position - startNode.position
 let distance = vector.length()
 let direction = vector.normalized()
 
 let cylinderGeometry = SCNCylinder(radius: 0.02, height: CGFloat(distance))
 cylinderGeometry.firstMaterial?.diffuse.contents = UIColor.gray
 
 let cylinderNode = SCNNode(geometry: cylinderGeometry)
 cylinderNode.position = (startNode.position + endNode.position) / 2
 cylinderNode.look(at: endNode.position, up: SCNVector3(0, 1, 0), localFront: SCNVector3(0, 1, 0))
 return cylinderNode
 }
}

extension SCNVector3 {
 static func -(lhs: SCNVector3, rhs: SCNVector3) -> SCNVector3 {
 return SCNVector3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z)
 }
 
 static func +(lhs: SCNVector3, rhs: SCNVector3) -> SCNVector3 {
 return SCNVector3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z)
 }
 
 static func /(lhs: SCNVector3, rhs: Float) -> SCNVector3 {
 return SCNVector3(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs)
 }
 
 func length() -> Float {
 return sqrtf(x \* x + y \* y + z \* z)
 }
 
 func normalized() -> SCNVector3 {
 let length = self.length()
 return SCNVector3(x / length, y / length, z / length)
 }
}

extension UIColor {
 static func random() -> UIColor {
 let red = CGFloat(arc4random\_uniform(256)) / 255.0
 let green = CGFloat(arc4random\_uniform(256)) / 255.0
 let blue = CGFloat(arc4random\_uniform(256)) / 255.0
 return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
 }
}

The camera still is not moving upon dragging at all
/// SceneStuff.swift// 3DTest//// 3/15/23에 JxR에 의해 생성되었습니다.//import Foundationimport Swiftimport UIKitSceneKit importimport SwiftUI구조체 NetworkNode { let 식별자: String let 위치: SCNVector3 var 연결: [문자열]}구조체 ThreeDimsView: UIViewRepresentable { func makeCoordinator() -> Coordinator { Coordinator(self) }  func makeUIView(context: Context) -> SCNView { // ThreeDims 뷰 컨트롤러의 인스턴스를 생성합니다. let threeDimsVC = ThreeDims() // 필요한 경우 뷰를 로드합니다. threeDimsVC.loadViewIfNeeded() // 뷰 컨트롤러에서 scnView를 반환합니다. return threeDimsVC.scnView }  func updateUIView(\_ uiView: SCNView, context: Context) { // 필요에 따라 업데이트 수행 }  Coordinator 클래스: NSObject { var parent: ThreeDimsView init(\_ parent: ThreeDimsView) { self.parent = 부모 } }}ThreeDims 클래스: UIViewController { var scnView: SCNView! let networkNodes: [NetworkNode] = [ NetworkNode(identifier: "A", position: SCNVector3(-1, 0, 0), connections: ["B", "C"]), NetworkNode(식별자: "B", 위치: SCNVector3(1, 1, 0), connections: ["A"]), NetworkNode(식별자: "C", 위치: SCNVector3(1, -1, 0), connections: ["A"]) ] 재정의 함수 viewDidLoad() { super.viewDidLoad()  // scnView 프로퍼티 초기화 scnView = SCNView(frame: view.bounds) scnView.autoresizingMask = [.flexibleWidth, .flexibleHeight] = [. view.addSubview(scnView)  // 장면 설정 let scene = SCNScene() scnView.scene = 장면 // 카메라 추가 setupCamera(in: scene) // 광원 추가 let lightNode = SCNNode() lightNode.light = SCNLight() lightNode.light!.type = .omni lightNode.position = SCNVector3(0, 5, 10) scene.rootNode.addChildNode(lightNode)  // 네트워크 노드에 대한 노드를 생성하고 장면에 추가합니다. var sphereNodes: [String: SCNNode] = [:] for networkNodes in networkNode { let sphereNode = createSphereNode(for: networkNode) sphereNodes[networkNode.identifier] = sphereNode scene.rootNode.addChildNode(sphereNode) }  // 원기둥 가장자리로 노드를 연결합니다. for networkNodes in networkNode { let startNode = sphereNodes[networkNode.identifier] for connectionIdentifier in networkNode.connections { let endNode = sphereNodes[connectionIdentifier], startNode != nil { let cylinderNode = createCylinderNode(from: startNode!, to: endNode) scene.rootNode.addChildNode(cylinderNode) } } } } func setupCamera(in scene: SCNScene) { let cameraNode = SCNNode() cameraNode.camera = SCNCamera() cameraNode.position = SCNVector3(0, 0, 5) cameraNode.name = "cameraNode" // 카메라 노드의 이름을 설정하기 위해 이 줄을 추가합니다.  // 카메라를 회전시키는 팬 제스처 인식기를 생성합니다. let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(\_:))) view.addGestureRecognizer(panGestureRecognizer) // 메인 뷰에 제스처 인식기를 추가합니다.  scene.rootNode.addChildNode(cameraNode) } @objc func handlePanGesture(\_ sender: UIPanGestureRecognizer) { guard let cameraNode = scnView.scene?.rootNode.childNode(withName: "cameraNode", 재귀적으로: false) else { return } let translation = sender.translation(in: scnView) let 회전속도: CGFloat = 0.005 let rotationX = Float(translation.y) \* Float(rotationSpeed) let rotationY = Float(translation.x) \* Float(rotationSpeed) // 카메라를 Y축(왼쪽과 오른쪽)을 중심으로 회전합니다. let rotationAroundY = SCNMatrix4MakeRotation(rotationY, 0, 1, 0) cameraNode.transform = SCNMatrix4Mult(cameraNode.transform, rotationAroundY) // 카메라를 X축(위아래)을 중심으로 회전합니다. let rotationAroundX = SCNMatrix4MakeRotation(rotationX, 1, 0, 0) cameraNode.transform = SCNMatrix4Mult(rotationAroundX, cameraNode.transform) sender.setTranslation(.0, in: scnView) } func createSphereNode(for networkNode: NetworkNode) -> SCNNode { let sphereGeometry = SCNSphere(반지름: 0.1) let material = SCNMaterial() material.diffuse.contents = UIColor.random() // 각 구체에 대한 임의의 색상 sphereGeometry.materials = [material]  let sphereNode = SCNNode(지오메트리: sphereGeometry) sphereNode.position = networkNode.position sphereNode.name = networkNode.식별자  반환 구체노드 } func createCylinderNode(from startNode: SCNNode, to endNode: SCNNode) -> SCNNode { let vector = endNode.position - startNode.position let distance = vector.length() let direction = vector.normalized()  let cylinderGeometry = SCNCylinder(반지름: 0.02, 높이: CGFloat(distance)) cylinderGeometry.firstMaterial?.diffuse.contents = UIColor.gray  let cylinderNode = SCNNode(지오메트리: cylinderGeometry) cylinderNode.position = (startNode.position + endNode.position) / 2 cylinderNode.look(at: endNode.position, up: SCNVector3(0, 1, 0), localFront: SCNVector3(0, 1, 0)) 반환 실린더 노드 }}확장 SCNVector3 { static func -(lhs: SCNVector3, rhs: SCNVector3) -> SCNVector3 { return SCNVector3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z) }  정적 함수 +(lhs: SCNVector3, rhs: SCNV