336 lines
11 KiB
C#
336 lines
11 KiB
C#
using System;
|
|
using System.IO;
|
|
using Newtonsoft.Json;
|
|
using PathLogic.Models;
|
|
|
|
namespace PathLogic.Core
|
|
{
|
|
/// <summary>
|
|
/// 맵 파일 로더 클래스
|
|
/// 기존 AGV 맵 에디터에서 생성한 JSON 파일을 로드
|
|
/// </summary>
|
|
public class MapLoader
|
|
{
|
|
/// <summary>
|
|
/// 파일에서 맵 데이터 로드
|
|
/// </summary>
|
|
/// <param name="filePath">맵 파일 경로</param>
|
|
/// <returns>로드된 맵 데이터</returns>
|
|
public MapData LoadFromFile(string filePath)
|
|
{
|
|
if (!File.Exists(filePath))
|
|
{
|
|
throw new FileNotFoundException($"맵 파일을 찾을 수 없습니다: {filePath}");
|
|
}
|
|
|
|
try
|
|
{
|
|
string jsonContent = File.ReadAllText(filePath);
|
|
return LoadFromJson(jsonContent);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"맵 파일 로드 중 오류 발생: {ex.Message}", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// JSON 문자열에서 맵 데이터 로드
|
|
/// </summary>
|
|
/// <param name="jsonContent">JSON 문자열</param>
|
|
/// <returns>로드된 맵 데이터</returns>
|
|
public MapData LoadFromJson(string jsonContent)
|
|
{
|
|
if (string.IsNullOrEmpty(jsonContent))
|
|
{
|
|
throw new ArgumentException("JSON 내용이 비어있습니다.");
|
|
}
|
|
|
|
try
|
|
{
|
|
// JSON 역직렬화 설정
|
|
var settings = new JsonSerializerSettings
|
|
{
|
|
DateFormatHandling = DateFormatHandling.IsoDateFormat,
|
|
NullValueHandling = NullValueHandling.Ignore,
|
|
MissingMemberHandling = MissingMemberHandling.Ignore
|
|
};
|
|
|
|
// JSON 파일 구조 분석
|
|
var jsonObject = JsonConvert.DeserializeObject<dynamic>(jsonContent, settings);
|
|
|
|
var mapData = new MapData();
|
|
|
|
// 메타데이터 로드
|
|
if (jsonObject.CreatedDate != null)
|
|
{
|
|
mapData.CreatedDate = jsonObject.CreatedDate;
|
|
}
|
|
|
|
if (jsonObject.Version != null)
|
|
{
|
|
mapData.Version = jsonObject.Version;
|
|
}
|
|
|
|
// 노드 데이터 로드
|
|
if (jsonObject.Nodes != null)
|
|
{
|
|
foreach (var nodeJson in jsonObject.Nodes)
|
|
{
|
|
var node = LoadNodeFromJson(nodeJson);
|
|
if (node != null)
|
|
{
|
|
mapData.Nodes.Add(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 맵 데이터 유효성 검증
|
|
var validationIssues = mapData.ValidateMap();
|
|
if (validationIssues.Count > 0)
|
|
{
|
|
Console.WriteLine("맵 데이터 검증 경고:");
|
|
foreach (var issue in validationIssues)
|
|
{
|
|
Console.WriteLine($" - {issue}");
|
|
}
|
|
}
|
|
|
|
Console.WriteLine($"맵 로드 완료: {mapData.GetStatistics()}");
|
|
return mapData;
|
|
}
|
|
catch (JsonException ex)
|
|
{
|
|
throw new Exception($"JSON 파싱 오류: {ex.Message}", ex);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"맵 데이터 로드 중 오류: {ex.Message}", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// JSON 객체에서 노드 데이터 로드
|
|
/// </summary>
|
|
/// <param name="nodeJson">노드 JSON 객체</param>
|
|
/// <returns>로드된 노드</returns>
|
|
private MapNode LoadNodeFromJson(dynamic nodeJson)
|
|
{
|
|
try
|
|
{
|
|
var node = new MapNode();
|
|
|
|
// 필수 필드
|
|
node.NodeId = nodeJson.NodeId ?? string.Empty;
|
|
node.Name = nodeJson.Name ?? string.Empty;
|
|
|
|
// 위치 정보 파싱
|
|
if (nodeJson.Position != null)
|
|
{
|
|
var position = nodeJson.Position.ToString();
|
|
node.Position = ParsePosition(position);
|
|
}
|
|
|
|
// 노드 타입
|
|
if (nodeJson.Type != null)
|
|
{
|
|
if (Enum.TryParse<NodeType>(nodeJson.Type.ToString(), out NodeType nodeType))
|
|
{
|
|
node.Type = nodeType;
|
|
}
|
|
}
|
|
|
|
// 도킹 방향
|
|
if (nodeJson.DockDirection != null)
|
|
{
|
|
if (Enum.TryParse<DockingDirection>(nodeJson.DockDirection.ToString(), out DockingDirection dockDirection))
|
|
{
|
|
node.DockDirection = dockDirection;
|
|
}
|
|
}
|
|
|
|
// 연결된 노드들
|
|
if (nodeJson.ConnectedNodes != null)
|
|
{
|
|
foreach (var connectedNodeId in nodeJson.ConnectedNodes)
|
|
{
|
|
if (connectedNodeId != null)
|
|
{
|
|
node.ConnectedNodes.Add(connectedNodeId.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
// 기타 속성들
|
|
if (nodeJson.CanRotate != null)
|
|
node.CanRotate = nodeJson.CanRotate;
|
|
|
|
if (nodeJson.StationId != null)
|
|
node.StationId = nodeJson.StationId;
|
|
|
|
if (nodeJson.StationType != null && Enum.TryParse<StationType>(nodeJson.StationType.ToString(), out StationType stationType))
|
|
node.StationType = stationType;
|
|
|
|
if (nodeJson.CreatedDate != null)
|
|
node.CreatedDate = nodeJson.CreatedDate;
|
|
|
|
if (nodeJson.ModifiedDate != null)
|
|
node.ModifiedDate = nodeJson.ModifiedDate;
|
|
|
|
if (nodeJson.IsActive != null)
|
|
node.IsActive = nodeJson.IsActive;
|
|
|
|
// RFID 정보
|
|
if (nodeJson.RfidId != null)
|
|
node.RfidId = nodeJson.RfidId;
|
|
|
|
if (nodeJson.RfidStatus != null)
|
|
node.RfidStatus = nodeJson.RfidStatus;
|
|
|
|
if (nodeJson.RfidDescription != null)
|
|
node.RfidDescription = nodeJson.RfidDescription;
|
|
|
|
// UI 관련 속성들 (맵 에디터 호환성을 위해)
|
|
LoadUIProperties(node, nodeJson);
|
|
|
|
// 기본 색상 설정
|
|
node.SetDefaultColorByType(node.Type);
|
|
|
|
return node;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"노드 로드 오류: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// UI 관련 속성 로드
|
|
/// </summary>
|
|
/// <param name="node">대상 노드</param>
|
|
/// <param name="nodeJson">노드 JSON 객체</param>
|
|
private void LoadUIProperties(MapNode node, dynamic nodeJson)
|
|
{
|
|
try
|
|
{
|
|
if (nodeJson.LabelText != null)
|
|
node.LabelText = nodeJson.LabelText;
|
|
|
|
if (nodeJson.FontFamily != null)
|
|
node.FontFamily = nodeJson.FontFamily;
|
|
|
|
if (nodeJson.FontSize != null)
|
|
node.FontSize = (float)nodeJson.FontSize;
|
|
|
|
if (nodeJson.ImagePath != null)
|
|
node.ImagePath = nodeJson.ImagePath;
|
|
|
|
if (nodeJson.Opacity != null)
|
|
node.Opacity = (float)nodeJson.Opacity;
|
|
|
|
if (nodeJson.Rotation != null)
|
|
node.Rotation = (float)nodeJson.Rotation;
|
|
|
|
if (nodeJson.ShowBackground != null)
|
|
node.ShowBackground = nodeJson.ShowBackground;
|
|
|
|
// Scale 파싱
|
|
if (nodeJson.Scale != null)
|
|
{
|
|
var scale = nodeJson.Scale.ToString();
|
|
node.Scale = ParseScale(scale);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"UI 속성 로드 오류: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 위치 문자열을 Point로 파싱
|
|
/// 예: "65, 229" -> Point(65, 229)
|
|
/// </summary>
|
|
/// <param name="positionString">위치 문자열</param>
|
|
/// <returns>파싱된 Point</returns>
|
|
private System.Drawing.Point ParsePosition(string positionString)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(positionString))
|
|
return System.Drawing.Point.Empty;
|
|
|
|
var parts = positionString.Split(',');
|
|
if (parts.Length >= 2)
|
|
{
|
|
int x = int.Parse(parts[0].Trim());
|
|
int y = int.Parse(parts[1].Trim());
|
|
return new System.Drawing.Point(x, y);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"위치 파싱 오류: {positionString}, {ex.Message}");
|
|
}
|
|
|
|
return System.Drawing.Point.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스케일 문자열을 SizeF로 파싱
|
|
/// 예: "1, 1" -> SizeF(1.0f, 1.0f)
|
|
/// </summary>
|
|
/// <param name="scaleString">스케일 문자열</param>
|
|
/// <returns>파싱된 SizeF</returns>
|
|
private System.Drawing.SizeF ParseScale(string scaleString)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(scaleString))
|
|
return new System.Drawing.SizeF(1.0f, 1.0f);
|
|
|
|
var parts = scaleString.Split(',');
|
|
if (parts.Length >= 2)
|
|
{
|
|
float width = float.Parse(parts[0].Trim());
|
|
float height = float.Parse(parts[1].Trim());
|
|
return new System.Drawing.SizeF(width, height);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"스케일 파싱 오류: {scaleString}, {ex.Message}");
|
|
}
|
|
|
|
return new System.Drawing.SizeF(1.0f, 1.0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 맵 데이터를 JSON 파일로 저장
|
|
/// </summary>
|
|
/// <param name="mapData">저장할 맵 데이터</param>
|
|
/// <param name="filePath">저장할 파일 경로</param>
|
|
public void SaveToFile(MapData mapData, string filePath)
|
|
{
|
|
try
|
|
{
|
|
var settings = new JsonSerializerSettings
|
|
{
|
|
DateFormatHandling = DateFormatHandling.IsoDateFormat,
|
|
NullValueHandling = NullValueHandling.Ignore,
|
|
Formatting = Formatting.Indented
|
|
};
|
|
|
|
string jsonContent = JsonConvert.SerializeObject(mapData, settings);
|
|
File.WriteAllText(filePath, jsonContent);
|
|
|
|
Console.WriteLine($"맵 데이터 저장 완료: {filePath}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"맵 파일 저장 중 오류: {ex.Message}", ex);
|
|
}
|
|
}
|
|
}
|
|
} |