462 lines
15 KiB
C#
462 lines
15 KiB
C#
using Newtonsoft.Json;
|
|
using Ookii.Dialogs;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Runtime.CompilerServices;
|
|
using TriLibCore.SFB;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using XRLib;
|
|
using XED.Interfaces;
|
|
using XED.Manage;
|
|
using NUnit.Framework.Interfaces;
|
|
|
|
namespace XED.Machine
|
|
{
|
|
public enum NodeSelectMode
|
|
{
|
|
Idle,
|
|
Draw,
|
|
SelectRunNode,
|
|
Select,
|
|
Setting
|
|
}
|
|
public class AGVNodeManager : MonoBehaviour, ISingle, IModeController, IInputHandler
|
|
{
|
|
[SerializeField]
|
|
GameObject nodePrefab;
|
|
|
|
[SerializeField]
|
|
GameObject markerPrefab;
|
|
GameObject nodeTarget;
|
|
|
|
NodeSelectMode nodeSelectMode = NodeSelectMode.Idle;
|
|
|
|
public event Action<AGVNode, AGVNode> onNodeConnectionAdded;
|
|
public event Action<AGVNode, AGVNode> onNodeConnectionUpdated;
|
|
public event Action<AGVNode, AGVNode> onNodeConnectionRemoved;
|
|
|
|
public AGVNode currentlySelectedNode;
|
|
|
|
public event Action<GameObject> onNodeGizmoSelected;
|
|
public event Action<GameObject> onNodeSettingSelected;
|
|
public event Action onNodeDeselected;
|
|
public event Action<List<AGVNode>> onNodeSequenceUpdated;
|
|
public event Action<List<AGVNode>> onNodeSequenceOrdered;
|
|
|
|
public AGVNodeMap agvNodeMap;
|
|
Dictionary<string, AGVNode> nodeTable = new();
|
|
|
|
List<AGVNode> selectedNodeSequence = new List<AGVNode>();
|
|
InputHandler myHandler;
|
|
NodeGizmoController nodeGizmoController;
|
|
|
|
public ModePanel.ProgramMode mode => ModePanel.ProgramMode.AGVPathDrawing;
|
|
|
|
public override void AfterStart()
|
|
{
|
|
agvNodeMap = new AGVNodeMap();
|
|
myHandler = GetInputHandler();
|
|
nodeGizmoController = FindSingle<NodeGizmoController>();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (currentlySelectedNode)
|
|
{
|
|
foreach (var c in currentlySelectedNode.nodeClass.linkedNodID)
|
|
{
|
|
onNodeConnectionUpdated?.Invoke(currentlySelectedNode, nodeTable[c]);
|
|
}
|
|
agvNodeMap.agvNodeData.Find(n => n.id == currentlySelectedNode.nodeClass.id).x = currentlySelectedNode.transform.position.x.ToString();
|
|
agvNodeMap.agvNodeData.Find(n => n.id == currentlySelectedNode.nodeClass.id).y = currentlySelectedNode.transform.position.y.ToString();
|
|
agvNodeMap.agvNodeData.Find(n => n.id == currentlySelectedNode.nodeClass.id).z = currentlySelectedNode.transform.position.z.ToString();
|
|
}
|
|
}
|
|
|
|
public void ChangeSelectMode(NodeSelectMode selectMode)
|
|
{
|
|
if (nodeSelectMode == selectMode)
|
|
{
|
|
return;
|
|
}
|
|
nodeSelectMode = selectMode;
|
|
if (selectMode == NodeSelectMode.Draw)
|
|
{
|
|
DrawMarker(true);
|
|
}
|
|
else
|
|
{
|
|
DrawMarker(false);
|
|
}
|
|
foreach (var n in selectedNodeSequence)
|
|
{
|
|
n.DeleteColor();
|
|
}
|
|
selectedNodeSequence.Clear();
|
|
onNodeSequenceUpdated?.Invoke(selectedNodeSequence);
|
|
DeselectNode();
|
|
}
|
|
|
|
public void OnClickAGVNode(RaycastHit hit, Component comp)
|
|
{
|
|
if (nodeGizmoController.GetGizmoHover()||nodeSelectMode==NodeSelectMode.Idle)
|
|
{
|
|
return;
|
|
}
|
|
var selectnode = comp.GetComponent<AGVNode>();
|
|
if (nodeSelectMode == NodeSelectMode.SelectRunNode)
|
|
{
|
|
if (selectedNodeSequence.Contains(selectnode))
|
|
{
|
|
OrderNodeRemove(selectnode);
|
|
}
|
|
else
|
|
{
|
|
OrderNodeAdd(selectnode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (selectnode == currentlySelectedNode)
|
|
{
|
|
DeselectNode();
|
|
}
|
|
else
|
|
{
|
|
SelectNode(selectnode);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SelectNode(AGVNode node)
|
|
{
|
|
currentlySelectedNode = node;
|
|
if (nodeSelectMode == NodeSelectMode.Setting)
|
|
{
|
|
onNodeSettingSelected?.Invoke(currentlySelectedNode.gameObject);
|
|
}
|
|
else
|
|
{
|
|
onNodeGizmoSelected?.Invoke(currentlySelectedNode.gameObject);
|
|
}
|
|
}
|
|
|
|
private void DeselectNode()
|
|
{
|
|
onNodeDeselected?.Invoke();
|
|
if (currentlySelectedNode)
|
|
{
|
|
currentlySelectedNode.DeleteColor();
|
|
}
|
|
currentlySelectedNode = null;
|
|
}
|
|
|
|
public void Load()
|
|
{
|
|
ClearNodes();
|
|
string json = "";
|
|
var data = StandaloneFileBrowser.OpenFilePanel("AGV Node Dialog", "", "json", false);
|
|
if (data.Count >= 1 && !string.IsNullOrEmpty(data[0].Name))
|
|
{
|
|
json = System.IO.File.ReadAllText(data[0].Name);
|
|
try
|
|
{
|
|
agvNodeMap = JsonConvert.DeserializeObject<AGVNodeMap>(json);
|
|
} catch
|
|
{
|
|
Debug.Log("¸Â´Â json Çü½ÄÀÌ ¾Æ´Õ´Ï´Ù");
|
|
}
|
|
}
|
|
if (string.IsNullOrEmpty(json))
|
|
{
|
|
Debug.Log("File not found!");
|
|
return;
|
|
}
|
|
|
|
|
|
foreach (var nd in agvNodeMap.agvNodeData)
|
|
{
|
|
CreateNode(nd);
|
|
}
|
|
LoadNodeConnections();
|
|
}
|
|
|
|
public void Save()
|
|
{
|
|
string json = JsonConvert.SerializeObject(agvNodeMap);
|
|
var data=StandaloneFileBrowser.SaveFilePanel("AGV Node Dialog", "", "agvnodedata", "json");
|
|
if (!string.IsNullOrEmpty(data.Name))
|
|
{
|
|
FileStream f = new FileStream(data.Name, FileMode.Create, FileAccess.Write);
|
|
|
|
StreamWriter writer = new StreamWriter(f, System.Text.Encoding.Unicode);
|
|
writer.Write(json);
|
|
writer.Close();
|
|
}
|
|
}
|
|
|
|
public void DrawMarker(bool flag)
|
|
{
|
|
if (flag)
|
|
{
|
|
nodeTarget = Instantiate(markerPrefab);
|
|
}
|
|
else
|
|
{
|
|
if (nodeTarget)
|
|
{
|
|
Destroy(nodeTarget);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MoveDrawTarget(RaycastHit hit, Component comp)
|
|
{
|
|
if (nodeTarget)
|
|
{
|
|
nodeTarget.transform.position = hit.point;
|
|
}
|
|
}
|
|
|
|
void CreateNode(AGVNodeClass nodedata)
|
|
{
|
|
if (nodeTable.ContainsKey(nodedata.id))
|
|
{
|
|
return;
|
|
}
|
|
|
|
GameObject go = Instantiate(nodePrefab);
|
|
var objNode = go.GetComponent<AGVNode>();
|
|
nodeTable.Add(nodedata.id, objNode);
|
|
objNode.Initialize(nodedata);
|
|
|
|
var x = float.Parse(nodedata.x);
|
|
var y = float.Parse(nodedata.y);
|
|
var z = float.Parse(nodedata.z);
|
|
go.transform.position = new Vector3(x, y, z);
|
|
}
|
|
|
|
void LoadNodeConnections()
|
|
{
|
|
foreach (var nodedata in nodeTable.Values)
|
|
{
|
|
foreach (var c in nodedata.nodeClass.linkedNodID)
|
|
{
|
|
onNodeConnectionAdded?.Invoke(nodeTable[nodedata.nodeClass.id], nodeTable[c]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ONClickGround(RaycastHit hit, Component comp)
|
|
{
|
|
if (nodeGizmoController.GetGizmoHover() || nodeSelectMode == NodeSelectMode.Idle)
|
|
{
|
|
return;
|
|
}
|
|
DeselectNode();
|
|
if (nodeSelectMode == NodeSelectMode.Draw)
|
|
{
|
|
GameObject go = Instantiate(nodePrefab);
|
|
go.transform.position = hit.point;
|
|
var objNode = go.GetComponent<AGVNode>();
|
|
int maxid = int.Parse(agvNodeMap.maxid);
|
|
maxid++;
|
|
AGVNodeClass objNodeClass = new AGVNodeClass();
|
|
objNodeClass.id = maxid.ToString();
|
|
objNodeClass.x = hit.point.x.ToString();
|
|
objNodeClass.y = hit.point.y.ToString();
|
|
objNodeClass.z = hit.point.z.ToString();
|
|
objNode.Initialize(objNodeClass);
|
|
|
|
agvNodeMap.maxid = maxid.ToString();
|
|
agvNodeMap.agvNodeData.Add(objNode.nodeClass);
|
|
nodeTable.Add(maxid.ToString(), objNode);
|
|
}
|
|
}
|
|
|
|
public void AddNode()
|
|
{
|
|
if (!currentlySelectedNode)
|
|
{
|
|
return;
|
|
}
|
|
GameObject NewNode = Instantiate(nodePrefab, currentlySelectedNode.transform.position + Vector3.right, Quaternion.identity);
|
|
AGVNode node = NewNode.GetComponent<AGVNode>();
|
|
int maxid = int.Parse(agvNodeMap.maxid);
|
|
maxid++;
|
|
agvNodeMap.maxid = maxid.ToString();
|
|
AGVNodeClass nodeClass = new AGVNodeClass();
|
|
nodeClass.id = maxid.ToString();
|
|
nodeClass.x = (currentlySelectedNode.transform.position.x + 1f).ToString();
|
|
nodeClass.y = (currentlySelectedNode.transform.position.y).ToString();
|
|
nodeClass.z = (currentlySelectedNode.transform.position.z).ToString();
|
|
node.Initialize(nodeClass);
|
|
nodeTable.Add(maxid.ToString(), node);
|
|
|
|
currentlySelectedNode.nodeClass.linkedNodID.Add(maxid.ToString());
|
|
node.nodeClass.linkedNodID.Add(currentlySelectedNode.nodeClass.id);
|
|
|
|
agvNodeMap.agvNodeData.Add(node.nodeClass);
|
|
onNodeConnectionAdded?.Invoke(currentlySelectedNode, node);
|
|
SelectNode(node);
|
|
}
|
|
|
|
public void RemoveNode()
|
|
{
|
|
if (!currentlySelectedNode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var c in currentlySelectedNode.nodeClass.linkedNodID)
|
|
{
|
|
onNodeConnectionRemoved?.Invoke(currentlySelectedNode, nodeTable[c]);
|
|
nodeTable[c].nodeClass.linkedNodID.Remove(currentlySelectedNode.nodeClass.id);
|
|
}
|
|
|
|
agvNodeMap.agvNodeData.Remove(currentlySelectedNode.nodeClass);
|
|
|
|
foreach (var n in agvNodeMap.agvNodeData)
|
|
{
|
|
n.linkedNodID.Remove(currentlySelectedNode.nodeClass.id);
|
|
}
|
|
|
|
Destroy(currentlySelectedNode.gameObject);
|
|
DeselectNode();
|
|
}
|
|
|
|
public void NodeTypeChange(int index)
|
|
{
|
|
if (currentlySelectedNode)
|
|
{
|
|
currentlySelectedNode.nodeClass.type = (AGVNodeType)index;
|
|
nodeTable[currentlySelectedNode.nodeClass.id].nodeClass.type = (AGVNodeType)index;
|
|
agvNodeMap.agvNodeData.Find(n => n.id == currentlySelectedNode.nodeClass.id).type = (AGVNodeType)index;
|
|
}
|
|
}
|
|
|
|
public void RemoveNode(AGVNode node)
|
|
{
|
|
if (!node)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var c in node.nodeClass.linkedNodID)
|
|
{
|
|
onNodeConnectionRemoved?.Invoke(node, nodeTable[c]);
|
|
nodeTable[c].nodeClass.linkedNodID.Remove(node.nodeClass.id);
|
|
}
|
|
|
|
agvNodeMap.agvNodeData.Remove(node.nodeClass);
|
|
|
|
foreach (var n in agvNodeMap.agvNodeData)
|
|
{
|
|
n.linkedNodID.Remove(node.nodeClass.id);
|
|
}
|
|
|
|
Destroy(node.gameObject);
|
|
DeselectNode();
|
|
}
|
|
|
|
public void ClearNodes()
|
|
{
|
|
foreach (var n in nodeTable)
|
|
{
|
|
RemoveNode(n.Value);
|
|
}
|
|
nodeTable.Clear();
|
|
selectedNodeSequence.Clear();
|
|
onNodeSequenceUpdated?.Invoke(selectedNodeSequence);
|
|
}
|
|
|
|
public void ordertoAGV()
|
|
{
|
|
if (selectedNodeSequence.Count <= 1)
|
|
{
|
|
return;
|
|
}
|
|
onNodeSequenceOrdered?.Invoke(selectedNodeSequence);
|
|
for (int i = 0; i < selectedNodeSequence.Count; i++)
|
|
{
|
|
if (i < selectedNodeSequence.Count - 1)
|
|
{
|
|
selectedNodeSequence[i].nodeClass.linkedNodID.Add(selectedNodeSequence[i+1].nodeClass.id);
|
|
selectedNodeSequence[i + 1].nodeClass.linkedNodID.Add(selectedNodeSequence[i].nodeClass.id);
|
|
}
|
|
else
|
|
{
|
|
selectedNodeSequence[i].nodeClass.linkedNodID.Add(selectedNodeSequence[0].nodeClass.id);
|
|
selectedNodeSequence[0].nodeClass.linkedNodID.Add(selectedNodeSequence[i].nodeClass.id);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OrderNodeAdd(AGVNode node)
|
|
{
|
|
if (selectedNodeSequence.Contains(node))
|
|
{
|
|
return;
|
|
}
|
|
node.SetColor(new Color(0f, 0.5f, 0f));
|
|
selectedNodeSequence.Add(node);
|
|
onNodeSequenceUpdated?.Invoke(selectedNodeSequence);
|
|
}
|
|
|
|
public void OrderNodeRemove(AGVNode node)
|
|
{
|
|
if (!selectedNodeSequence.Contains(node))
|
|
{
|
|
return;
|
|
}
|
|
node.DeleteColor();
|
|
selectedNodeSequence.Remove(node);
|
|
onNodeSequenceUpdated?.Invoke(selectedNodeSequence);
|
|
}
|
|
|
|
public void StatusEnterEvent()
|
|
{
|
|
var raycaster = FindSingle<Raycaster>();
|
|
FindSingle<UserInputManager>().SetHandler(myHandler);
|
|
raycaster.AddEvent(Raycaster.EventType.FirstLeftClickOnly, typeof(AGVNode), OnClickAGVNode);
|
|
raycaster.AddEvent(Raycaster.EventType.Stay, typeof(Map), MoveDrawTarget);
|
|
raycaster.AddEvent(Raycaster.EventType.FirstLeftClickOnly, typeof(Map), ONClickGround);
|
|
}
|
|
|
|
public void StatusExitEvent()
|
|
{
|
|
var raycaster = FindSingle<Raycaster>();
|
|
FindSingle<UserInputManager>().RemoveHandler(myHandler);
|
|
raycaster.RemoveEvent(Raycaster.EventType.FirstLeftClickOnly, typeof(AGVNode), OnClickAGVNode);
|
|
raycaster.RemoveEvent(Raycaster.EventType.Stay, typeof(Map), MoveDrawTarget);
|
|
raycaster.RemoveEvent(Raycaster.EventType.FirstLeftClickOnly, typeof(Map), ONClickGround);
|
|
}
|
|
|
|
public InputHandler GetInputHandler()
|
|
{
|
|
var getKeyActions = new Dictionary<KeyCode, Action>();
|
|
var downKeyActions = new Dictionary<KeyCode, Action>();
|
|
var upKeyActions = new Dictionary<KeyCode, Action>();
|
|
|
|
|
|
getKeyActions.Add(KeyCode.Alpha1, ()=>ChangeSelectMode(NodeSelectMode.Draw));
|
|
getKeyActions.Add(KeyCode.Alpha2, () => ChangeSelectMode(NodeSelectMode.Select));
|
|
getKeyActions.Add(KeyCode.Alpha3, () => ChangeSelectMode(NodeSelectMode.Setting));
|
|
getKeyActions.Add(KeyCode.Alpha4, () => ChangeSelectMode(NodeSelectMode.SelectRunNode));
|
|
getKeyActions.Add(KeyCode.Escape, () => ChangeSelectMode(NodeSelectMode.Idle));
|
|
|
|
|
|
var handler = new InputHandler(getKeyActions, downKeyActions, upKeyActions);
|
|
return handler;
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
//vistaOpenFileDialog.Dispose();
|
|
//saveFileDialog.Dispose();
|
|
}
|
|
}
|
|
}
|