first commit -push

This commit is contained in:
dungtt
2025-10-15 15:15:53 +07:00
parent 674ae395be
commit a9577c5756
885 changed files with 74595 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
using System.Text.Json;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ActionsController(MapEditorDbContext MapDb, LoggerController<ActionsController> Logger) : ControllerBase
{
[HttpPost]
public async Task<MessageResult<ActionDto>> CreateAction([FromBody] ActionCreateModel model)
{
try
{
var map = await MapDb.Maps.FindAsync(model.MapId);
if (map == null) return new(false, $"Không tồn tại map id = {model.MapId}");
if (MapDb.Actions.Any(action => action.Name == model.Name && action.MapId == model.MapId)) return new(false, $"Tên Action {model.Name} đã tồn tại");
var entity = await MapDb.Actions.AddAsync(new()
{
MapId = model.MapId,
Name = model.Name,
Content = model.Content,
});
await MapDb.SaveChangesAsync();
return new(true)
{
Data = new()
{
Id = entity.Entity.Id,
MapId = entity.Entity.MapId,
Name = entity.Entity.Name,
Content = entity.Entity.Content,
}
};
}
catch(Exception ex)
{
Logger.Warning($"CreateAction: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"CreateAction: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpGet]
[Route("{id}")]
public async Task<IEnumerable<ActionDto>> GetActions(Guid id)
{
return await MapDb.Actions.Where(action => action.MapId == id).Select(action => new ActionDto()
{
Id = action.Id,
MapId = action.MapId,
Name = action.Name,
Content = action.Content,
}).ToListAsync();
}
[HttpPut]
public async Task<MessageResult> UpdateAction([FromBody] ActionDto model)
{
try
{
var action = await MapDb.Actions.FindAsync(model.Id);
if (action is not null)
{
action.Name = model.Name;
action.Content = model.Content;
MapDb.Actions.Update(action);
await MapDb.SaveChangesAsync();
return new(true);
}
return new(false, $"Hệ thống không tìm thấy Action {model.Name} này");
}
catch (Exception ex)
{
Logger.Warning($"UpdateAction: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"UpdateAction: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpDelete]
[Route("{id}")]
public async Task<MessageResult> DeleteAction(Guid id)
{
try
{
var action = await MapDb.Actions.FindAsync(id);
if (action is not null)
{
foreach (var node in MapDb.Nodes)
{
var actionIds = JsonSerializer.Deserialize<Guid[]>(node.Actions);
if (actionIds is not null && actionIds.Any(a => a == action.Id))
{
var acitonIdsAfter = actionIds.ToList();
acitonIdsAfter.Remove(action.Id);
node.Actions = JsonSerializer.Serialize(acitonIdsAfter.Count > 0 ? acitonIdsAfter : []);
}
}
foreach (var edge in MapDb.Edges)
{
var actionIds = JsonSerializer.Deserialize<Guid[]>(edge.Actions);
if (actionIds is not null && actionIds.Any(a => a == action.Id))
{
var acitonIdsAfter = actionIds.ToList();
acitonIdsAfter.Remove(action.Id);
edge.Actions = JsonSerializer.Serialize(acitonIdsAfter.Count > 0 ? acitonIdsAfter : []);
}
}
MapDb.Actions.Remove(action);
await MapDb.SaveChangesAsync();
return new(true) ;
}
return new(false, $"Hệ thống không tìm thấy Action {id} này");
}
catch (Exception ex)
{
Logger.Warning($"DeleteAction {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"DeleteAction {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
}

View File

@@ -0,0 +1,269 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares;
using RobotNet.MapShares.Dtos;
using RobotNet.MapShares.Enums;
using RobotNet.Shares;
using System.Text.Json;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class EdgesController(MapEditorDbContext MapDb, LoggerController<EdgesController> Logger) : ControllerBase
{
[HttpPost]
[Route("")]
public async Task<MessageResult<EdgeCreateDto>> CreateEdge([FromBody] EdgeCreateModel model)
{
try
{
var map = await MapDb.Maps.FindAsync(model.MapId);
if (map == null) return new(false, $"Không tồn tại map id = {model.MapId}");
if (Math.Sqrt(Math.Pow(model.X1 - model.X2, 2) + Math.Pow(model.Y1 - model.Y2, 2)) < map.EdgeMinLengthDefault) return new(false, "Độ dài edge quá nhỏ");
var nodes = await MapDb.Nodes.Where(n => n.MapId == model.MapId).ToListAsync();
var edges = await MapDb.Edges.Where(e => e.MapId == model.MapId && e.TrajectoryDegree == TrajectoryDegree.One).ToListAsync();
var closesStartNode = MapEditorHelper.GetClosesNode(model.X1, model.Y1, [.. nodes.Select(node => new NodeDto()
{
MapId = node.MapId,
X = node.X,
Y = node.Y,
Theta = node.Theta,
Actions = node.Actions,
Id = node.Id,
Name = node.Name,
AllowedDeviationTheta = node.AllowedDeviationTheta,
AllowedDeviationXy = node.AllowedDeviationXy
})]);
var closesEndNode = MapEditorHelper.GetClosesNode(model.X2, model.Y2, [.. nodes.Select(node => new NodeDto()
{
MapId = node.MapId,
X = node.X,
Y = node.Y,
Theta = node.Theta,
Actions = node.Actions,
Id = node.Id,
Name = node.Name,
AllowedDeviationTheta = node.AllowedDeviationTheta,
AllowedDeviationXy = node.AllowedDeviationXy
})]);
Node? startNode = await MapDb.Nodes.FindAsync(closesStartNode?.Id);
Node? endNode = await MapDb.Nodes.FindAsync(closesEndNode?.Id);
List<Guid> RemoveEdge = [];
List<EdgeDto> AddEdgeDto = [];
if (startNode is null)
{
startNode = ServerHelper.CreateNode(map, model.X1, model.Y1);
await MapDb.Nodes.AddAsync(startNode);
var closesEdge = ServerHelper.GetClosesEdge(model.X1, model.Y1, nodes, edges, 0.1);
if (closesEdge is not null)
{
var closesEdgeStartNode = await MapDb.Nodes.FirstOrDefaultAsync(n => n.Id == closesEdge.StartNodeId);
var closesEdgeEndNode = await MapDb.Nodes.FirstOrDefaultAsync(n => n.Id == closesEdge.EndNodeId);
if (closesEdgeStartNode is not null && closesEdgeEndNode is not null)
{
var startEdge = ServerHelper.CreateEdge(map, closesEdgeStartNode.Id, startNode.Id, TrajectoryDegree.One);
var endEdge = ServerHelper.CreateEdge(map, startNode.Id, closesEdgeEndNode.Id, TrajectoryDegree.One);
await MapDb.Edges.AddAsync(startEdge);
await MapDb.Edges.AddAsync(endEdge);
MapDb.Edges.Remove(closesEdge);
edges.Remove(closesEdge);
RemoveEdge.Add(closesEdge.Id);
edges.Add(startEdge);
edges.Add(endEdge);
nodes.Add(startNode);
AddEdgeDto.Add(ServerHelper.CreateEdgeDto(startEdge, closesEdgeStartNode, startNode));
AddEdgeDto.Add(ServerHelper.CreateEdgeDto(endEdge, startNode, closesEdgeEndNode));
}
}
}
await MapDb.SaveChangesAsync();
if (endNode is null)
{
endNode = ServerHelper.CreateNode(map, model.X2, model.Y2);
await MapDb.Nodes.AddAsync(endNode);
var closesEdge = ServerHelper.GetClosesEdge(model.X2, model.Y2, nodes, edges, 0.1);
if (closesEdge is not null)
{
var closesEdgeStartNode = await MapDb.Nodes.FirstOrDefaultAsync(n => n.Id == closesEdge.StartNodeId);
var closesEdgeEndNode = await MapDb.Nodes.FirstOrDefaultAsync(n => n.Id == closesEdge.EndNodeId);
if (closesEdgeStartNode is not null && closesEdgeEndNode is not null)
{
var startEdge = ServerHelper.CreateEdge(map, closesEdgeStartNode.Id, endNode.Id, TrajectoryDegree.One);
var endEdge = ServerHelper.CreateEdge(map, endNode.Id, closesEdgeEndNode.Id, TrajectoryDegree.One);
await MapDb.Edges.AddAsync(startEdge);
await MapDb.Edges.AddAsync(endEdge);
MapDb.Edges.Remove(closesEdge);
RemoveEdge.Add(closesEdge.Id);
AddEdgeDto.Add(ServerHelper.CreateEdgeDto(startEdge, closesEdgeStartNode, endNode));
AddEdgeDto.Add(ServerHelper.CreateEdgeDto(endEdge, endNode, closesEdgeEndNode));
}
}
}
var edge = ServerHelper.CreateEdge(map, startNode.Id, endNode.Id, model.TrajectoryDegree, model.ControlPoint1X, model.ControlPoint1Y, model.ControlPoint2X, model.ControlPoint2Y);
await MapDb.Edges.AddAsync(edge);
await MapDb.SaveChangesAsync();
AddEdgeDto.Add(ServerHelper.CreateEdgeDto(edge, startNode, endNode));
return new(true)
{
Data = new EdgeCreateDto()
{
EdgesDto = AddEdgeDto,
RemoveEdge = RemoveEdge,
}
};
}
catch (Exception ex)
{
Logger.Warning($"CreateEdge: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"CreateEdge: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpDelete]
[Route("{id}")]
public async Task<MessageResult> DeleteEdge(Guid id)
{
using var transaction = await MapDb.Database.BeginTransactionAsync();
try
{
var edge = await MapDb.Edges.FindAsync(id);
if (edge == null) return new(false, $"Không tồn tại edge id = {id}");
MapDb.Edges.Remove(edge);
if (!MapDb.Edges.Any(e => (e.StartNodeId == edge.StartNodeId || e.EndNodeId == edge.StartNodeId) && e.Id != edge.Id))
{
var node = await MapDb.Nodes.FindAsync(edge.StartNodeId);
if (node != null)
{
var element = await MapDb.Elements.FirstOrDefaultAsync(e => e.NodeId == node.Id);
if (element is not null) MapDb.Elements.Remove(element);
MapDb.Nodes.Remove(node);
}
}
if (!MapDb.Edges.Any(e => (e.StartNodeId == edge.EndNodeId || e.EndNodeId == edge.EndNodeId) && e.Id != edge.Id))
{
var node = await MapDb.Nodes.FindAsync(edge.EndNodeId);
if (node != null)
{
var element = await MapDb.Elements.FirstOrDefaultAsync(e => e.NodeId == node.Id);
if (element is not null) MapDb.Elements.Remove(element);
MapDb.Nodes.Remove(node);
}
}
await MapDb.SaveChangesAsync();
await transaction.CommitAsync();
return new(true);
}
catch (Exception ex)
{
await transaction.RollbackAsync();
Logger.Warning($"DeleteEdge {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"DeleteEdge {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpDelete]
[Route("")]
public async Task<MessageResult> DeleteEdges([FromBody] IEnumerable<Guid> DeleteEdgesId)
{
try
{
List<Edge> deleteEdges = [];
List<Node> deleteNodes = [];
foreach (var edgeId in DeleteEdgesId)
{
var edge = await MapDb.Edges.FindAsync(edgeId);
if (edge == null) continue;
MapDb.Edges.Remove(edge);
if (!MapDb.Edges.Any(e => (e.StartNodeId == edge.StartNodeId || e.EndNodeId == edge.StartNodeId) && e.Id != edge.Id))
{
var node = await MapDb.Nodes.FindAsync(edge.StartNodeId);
if (node != null)
{
var element = await MapDb.Elements.FirstOrDefaultAsync(e => e.NodeId == node.Id);
if (element is not null) MapDb.Elements.Remove(element);
MapDb.Nodes.Remove(node);
}
}
if (!MapDb.Edges.Any(e => (e.StartNodeId == edge.EndNodeId || e.EndNodeId == edge.EndNodeId) && e.Id != edge.Id))
{
var node = await MapDb.Nodes.FindAsync(edge.EndNodeId);
if (node != null)
{
var element = await MapDb.Elements.FirstOrDefaultAsync(e => e.NodeId == node.Id);
if (element is not null) MapDb.Elements.Remove(element);
MapDb.Nodes.Remove(node);
}
}
await MapDb.SaveChangesAsync();
}
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"DeleteEdges: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"DeleteEdges: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPut]
[Route("")]
public async Task<MessageResult> UpdateEdge([FromBody] EdgeUpdateModel model)
{
try
{
var edge = await MapDb.Edges.FindAsync(model.Id);
if (edge == null) return new(false, $"Không tồn tại edge id = {model.Id}");
edge.MaxSpeed = model.MaxSpeed;
edge.MaxHeight = model.MaxHeight;
edge.MinHeight = model.MinHeight;
edge.ControlPoint1X = model.ControlPoint1X;
edge.ControlPoint1Y = model.ControlPoint1Y;
edge.ControlPoint2X = model.ControlPoint2X;
edge.ControlPoint2Y = model.ControlPoint2Y;
edge.DirectionAllowed = model.DirectionAllowed;
edge.RotationAllowed = model.RotationAllowed;
edge.MaxRotationSpeed = model.MaxRotationSpeed;
edge.Actions = JsonSerializer.Serialize(model.Actions ?? []);
edge.AllowedDeviationXy = model.AllowedDeviationXy;
edge.AllowedDeviationTheta = model.AllowedDeviationTheta;
await MapDb.SaveChangesAsync();
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"UpdateEdge: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"UpdateEdge: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
}

View File

@@ -0,0 +1,258 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ElementModelsController(MapEditorDbContext MapDb, MapEditorStorageRepository MapStorage, LoggerController<ElementModelsController> Logger) : ControllerBase
{
[HttpGet]
[Route("map/{mapId}")]
public async Task<MessageResult<IEnumerable<ElementModelDto>>> Gets(Guid mapId)
{
try
{
return new(true)
{
Data = await (from elm in MapDb.ElementModels
where !string.IsNullOrEmpty(elm.Name) && elm.MapId == mapId
select new ElementModelDto()
{
Id = elm.Id,
MapId = elm.MapId,
Name = elm.Name,
Height = elm.Height,
Width = elm.Width,
Image1Height = elm.Image1Height,
Image2Height = elm.Image2Height,
Image1Width = elm.Image1Width,
Image2Width = elm.Image2Width,
Content = elm.Content,
}).ToListAsync()
};
}
catch (Exception ex)
{
Logger.Warning($"Gets: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Gets: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpGet]
[Route("{id}")]
public async Task<MessageResult<ElementModelDto>> Get(Guid id)
{
try
{
var elmodel = await MapDb.ElementModels.FindAsync(id);
if (elmodel is null) return new(false, $"Element Model {id} không tồn tại");
return new(true)
{
Data = new ElementModelDto()
{
Id = elmodel.Id,
Name = elmodel.Name,
MapId = elmodel.MapId,
Height = elmodel.Height,
Width = elmodel.Width,
Content = elmodel.Content,
}
};
}
catch (Exception ex)
{
Logger.Warning($"Get {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Get {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPost]
public async Task<MessageResult<ElementModelDto>> CreateElementModel([FromForm] ElementModelCreateModel model, [FromForm(Name = "imageOpen")] IFormFile imageOpen, [FromForm(Name = "imageClose")] IFormFile imageClose)
{
try
{
if (model == null || imageOpen == null || imageClose == null) return new(false, "Dữ liệu đầu vào không hợp lệ");
var map = await MapDb.Maps.FindAsync(model.MapId);
if (map == null) return new(false, $"Không tồn tại map id = {model.MapId}");
if (MapDb.ElementModels.Any(elm => elm.Name == model.Name && elm.MapId == model.MapId)) return new(false, $"Tên Model {model.Name} đã tồn tại");
var image1 = SixLabors.ImageSharp.Image.Load(imageOpen.OpenReadStream());
var image2 = SixLabors.ImageSharp.Image.Load(imageClose.OpenReadStream());
var entity = MapDb.ElementModels.Add(new()
{
Name = model.Name,
MapId = model.MapId,
Width = model.Width,
Height = model.Height,
Image1Height = (ushort)image1.Height,
Image1Width = (ushort)image1.Width,
Image2Height = (ushort)image2.Height,
Image2Width = (ushort)image2.Width,
Content = "",
});
await MapDb.SaveChangesAsync();
var (isSuccess, message) = await MapStorage.UploadAsync("ElementOpenModels", $"{entity.Entity.Id}", imageOpen.OpenReadStream(), imageOpen.Length, imageOpen.ContentType, CancellationToken.None);
if (!isSuccess)
{
MapDb.ElementModels.Remove(entity.Entity);
await MapDb.SaveChangesAsync();
return new(false, message);
}
(isSuccess, message) = await MapStorage.UploadAsync("ElementCloseModels", $"{entity.Entity.Id}", imageClose.OpenReadStream(), imageClose.Length, imageClose.ContentType, CancellationToken.None);
if (!isSuccess)
{
MapDb.ElementModels.Remove(entity.Entity);
await MapDb.SaveChangesAsync();
await MapStorage.DeleteAsync("ElementOpenModels", $"{entity.Entity.Id}", CancellationToken.None);
return new(false, message);
}
return new(true)
{
Data = new()
{
Id = entity.Entity.Id,
Name = entity.Entity.Name,
MapId = entity.Entity.MapId,
Width = entity.Entity.Width,
Height = entity.Entity.Height,
Image1Height = entity.Entity.Image1Height,
Image1Width = entity.Entity.Image1Width,
Image2Height = entity.Entity.Image2Height,
Image2Width = entity.Entity.Image2Width,
Content = entity.Entity.Content
}
};
}
catch (Exception ex)
{
Logger.Warning($"CreateElementModel: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"CreateElementModel: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPut]
public async Task<MessageResult<ElementModelDto>> Update([FromBody] ElementModelUpdateModel model)
{
try
{
var elModel = await MapDb.ElementModels.FindAsync(model.Id);
if (elModel is null) return new(false, $"Model {model.Id} không tồn tại");
if (MapDb.ElementModels.Any(elm => elm.Name == model.Name && elm.MapId == elModel.MapId && model.Id != elModel.Id)) return new(false, $"Tên Model {model.Name} đã tồn tại");
elModel.Name = model.Name;
elModel.Width = model.Width;
elModel.Height = model.Height;
elModel.Content = model.Content;
await MapDb.SaveChangesAsync();
return new(true)
{
Data = new()
{
Id = elModel.Id,
Name = elModel.Name,
MapId = elModel.MapId,
Width = elModel.Width,
Height = elModel.Height,
Image1Height = elModel.Image1Height,
Image1Width = elModel.Image1Width,
Image2Height = elModel.Image2Height,
Image2Width = elModel.Image2Width,
Content = elModel.Content
}
};
}
catch (Exception ex)
{
Logger.Warning($"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpDelete]
[Route("{id}")]
public async Task<MessageResult> Delete(Guid id)
{
try
{
var elModel = await MapDb.ElementModels.FindAsync(id);
if (elModel is null) return new(false, $"Model {id} không tồn tại");
await MapStorage.DeleteAsync("ElementOpenModels", id.ToString(), CancellationToken.None);
await MapStorage.DeleteAsync("ElementCloseModels", id.ToString(), CancellationToken.None);
MapDb.Elements.RemoveRange(MapDb.Elements.Where(e => e.ModelId == id));
MapDb.ElementModels.Remove(elModel);
await MapDb.SaveChangesAsync();
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"Delete {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Delete {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPut]
[Route("openimage/{id}")]
public async Task<MessageResult> UpdateOpenImage(Guid id, [FromForm(Name = "image")] IFormFile image)
{
try
{
var elModel = await MapDb.ElementModels.FindAsync(id);
if (elModel is null) return new(false, $"Model {id} không tồn tại");
var imageStream = image.OpenReadStream();
var (isSuccess, message) = await MapStorage.UploadAsync("ElementOpenModels", $"{elModel.Id}", imageStream, image.Length, image.ContentType, CancellationToken.None);
if (!isSuccess) return new(false, message);
var imageUpdate = SixLabors.ImageSharp.Image.Load(image.OpenReadStream());
elModel.Image1Width = (ushort)imageUpdate.Width;
elModel.Image1Height = (ushort)imageUpdate.Height;
await MapDb.SaveChangesAsync();
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"UpdateOpenImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"UpdateOpenImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPut]
[Route("closeimage/{id}")]
public async Task<MessageResult> UpdateCloseImage(Guid id, [FromForm(Name = "image")] IFormFile image)
{
try
{
var elModel = await MapDb.ElementModels.FindAsync(id);
if (elModel is null) return new(false, $"Model {id} không tồn tại");
var imageStream = image.OpenReadStream();
var (isSuccess, message) = await MapStorage.UploadAsync("ElementCloseModels", $"{elModel.Id}", imageStream, image.Length, image.ContentType, CancellationToken.None);
if (!isSuccess) return new(false, message);
var imageUpdate = SixLabors.ImageSharp.Image.Load(image.OpenReadStream());
elModel.Image2Width = (ushort)imageUpdate.Width;
elModel.Image2Height = (ushort)imageUpdate.Height;
await MapDb.SaveChangesAsync();
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"UpdateCloseImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"UpdateCloseImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
}

View File

@@ -0,0 +1,211 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ElementsController(MapEditorDbContext MapDb, LoggerController<ElementsController> Logger) : ControllerBase
{
[HttpGet]
public async Task<MessageResult<ElementDto>> GetElement([FromQuery] string mapName, [FromQuery] string elementName)
{
try
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == mapName);
if (map is null) return new(false, $"Không tồn tại map tên = {mapName}");
var el = await MapDb.Elements.FirstOrDefaultAsync(e => e.MapId == map.Id && e.Name == elementName);
if (el is null) return new(false, $"Không tồn tại element name = {elementName}");
var elNode = await MapDb.Nodes.FindAsync(el.NodeId);
if (elNode is null) return new(false, $"Không tồn tại node id = {el.NodeId}");
return new(true)
{
Data = new()
{
Id = el.Id,
Name = el.Name,
MapId = el.MapId,
IsOpen = el.IsOpen,
NodeId = el.NodeId,
OffsetX = el.OffsetX,
OffsetY = el.OffsetY,
ModelId = el.ModelId,
Content = el.Content,
NodeName = elNode.Name,
X = elNode.X,
Y = elNode.Y,
Theta = elNode.Theta
}
};
}
catch (Exception ex)
{
Logger.Warning($"GetElement: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"GetElement: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpGet]
[Route("{modelId}")]
public async Task<MessageResult<IEnumerable<ElementDto>>> GetElementsByModelId([FromRoute] Guid modelId)
{
try
{
var elModel = await MapDb.ElementModels.FindAsync(modelId);
if (elModel is null) return new(false, $"Không tồn tại model id = {modelId}");
return new(true)
{
Data = await (from el in MapDb.Elements
where el.ModelId == modelId
select new ElementDto()
{
Id = el.Id,
MapId = el.MapId,
Name = el.Name,
ModelId = el.ModelId,
ModelName = elModel.Name,
IsOpen = el.IsOpen,
NodeId = el.NodeId,
OffsetX = el.OffsetX,
OffsetY = el.OffsetY,
Content = el.Content,
}).ToListAsync()
};
}
catch (Exception ex)
{
Logger.Warning($"GetElementsByModelId: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"GetElementsByModelId: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPost]
public async Task<MessageResult<ElementDto>> Create([FromBody] ElementCreateModel model)
{
try
{
if (model == null || string.IsNullOrEmpty(model.Name)) return new(false, "Dữ liệu không hợp lệ");
var map = await MapDb.Maps.FindAsync(model.MapId);
if (map == null) return new(false, $"Không tồn tại map id = {model.MapId}");
var node = await MapDb.Nodes.FindAsync(model.NodeId);
if (node == null) return new(false, $"Không tồn tại node id = {model.NodeId}");
var elModel = await MapDb.ElementModels.FindAsync(model.ModelId);
if (elModel is null) return new(false, $"Không tồn tại element model id = {model.ModelId}");
if (MapDb.Elements.Any(el => el.Name == model.Name && el.MapId == model.MapId)) return new(false, $"Tên Element đã tồn tại");
if (MapDb.Elements.Any(el => el.NodeId == model.NodeId)) return new(false, $"Node này đã có Element");
var entity = await MapDb.Elements.AddAsync(new()
{
Name = model.Name,
MapId = model.MapId,
NodeId = model.NodeId,
ModelId = model.ModelId,
OffsetX = model.OffsetX,
OffsetY = model.OffsetY,
Content = elModel.Content,
});
await MapDb.SaveChangesAsync();
return new(true)
{
Data = new()
{
Id = entity.Entity.Id,
MapId = entity.Entity.MapId,
NodeId = entity.Entity.NodeId,
ModelName = elModel.Name,
Name = entity.Entity.Name,
ModelId = entity.Entity.ModelId,
OffsetX = entity.Entity.OffsetX,
OffsetY = entity.Entity.OffsetY,
Content = entity.Entity.Content,
IsOpen = entity.Entity.IsOpen,
}
};
}
catch (Exception ex)
{
Logger.Warning($"Create: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Create: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPut]
public async Task<MessageResult<ElementDto>> Update([FromBody] ElementUpdateModel model)
{
try
{
var element = await MapDb.Elements.FindAsync(model.Id);
if (element == null) return new(false, $"Không tồn tại element id = {model.Id}");
var map = await MapDb.Maps.FindAsync(element.MapId);
if (map == null) return new(false, $"Không tồn tại map id = {element.MapId}");
if (MapDb.Elements.Any(el => el.Name == model.Name && el.MapId == element.MapId && el.Id != model.Id)) return new(false, $"Tên Element đã tồn tại");
element.Name = model.Name;
element.OffsetX = model.OffsetX;
element.OffsetY = model.OffsetY;
element.Content = model.Content;
element.IsOpen = model.IsOpen;
await MapDb.SaveChangesAsync();
return new(true)
{
Data = new()
{
Id = element.Id,
MapId = element.MapId,
NodeId = element.NodeId,
Name = element.Name,
ModelId = element.ModelId,
OffsetX = element.OffsetX,
OffsetY = element.OffsetY,
Content = element.Content,
IsOpen = element.IsOpen,
}
};
}
catch (Exception ex)
{
Logger.Warning($"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpDelete]
[Route("{id}")]
public async Task<MessageResult> Delete(Guid id)
{
try
{
var element = await MapDb.Elements.FindAsync(id);
if (element == null) return new(false, $"Không tồn tại element id = {id}");
MapDb.Elements.Remove(element);
await MapDb.SaveChangesAsync();
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"Delete {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Delete {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
}

View File

@@ -0,0 +1,66 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RobotNet.MapManager.Services;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class ImagesController(MapEditorStorageRepository StorageRepo, IHttpClientFactory HttpClientFactory, LoggerController<ImagesController> Logger) : ControllerBase
{
[HttpGet]
[Route("map/{id}")]
public async Task<IActionResult> GetMapImage(Guid id)
{
try
{
var (usingLocal, url) = StorageRepo.GetUrl("MapImages", $"{id}");
if (!usingLocal)
{
var http = HttpClientFactory.CreateClient();
var imageBytes = await http.GetByteArrayAsync(url);
if (imageBytes != null && imageBytes.Length > 0) return File(imageBytes, "image/png");
else return NotFound("Không thể lấy được ảnh map.");
}
if (System.IO.File.Exists(url)) return File(System.IO.File.ReadAllBytes(url), "image/png");
else return NotFound();
}
catch(Exception ex)
{
Logger.Warning($"GetMapImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return NotFound();
}
}
[HttpGet]
[Route("elementModel/{id}")]
public async Task<IActionResult> GetElementModelImage(Guid id, [FromQuery] bool IsOpen)
{
try
{
var (usingLocal, url) = StorageRepo.GetUrl(IsOpen ? "ElementOpenModels" : "ElementCloseModels", id.ToString());
if (!usingLocal)
{
var http = HttpClientFactory.CreateClient();
var imageBytes = await http.GetByteArrayAsync(url);
if (imageBytes != null && imageBytes.Length > 0)
{
return File(imageBytes, "image/png");
}
else
{
return NotFound("Không thể lấy được ảnh element model.");
}
}
if (System.IO.File.Exists(url)) return File(System.IO.File.ReadAllBytes(url), "image/png");
else return NotFound();
}
catch (Exception ex)
{
Logger.Warning($"GetElementModelImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return NotFound();
}
}
}

View File

@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RobotNet.MapManager.Services;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class MapDesignerLoggerController(LoggerController<MapDesignerLoggerController> Logger) : ControllerBase
{
private readonly string LoggerDirectory = "mapManagerlogs";
[HttpGet]
public async Task<IEnumerable<string>> GetLogs([FromQuery(Name = "date")] DateTime date)
{
string temp = "";
try
{
string fileName = $"{date:yyyy-MM-dd}.log";
string path = Path.Combine(LoggerDirectory, fileName);
if (!Path.GetFullPath(path).StartsWith(Path.GetFullPath(LoggerDirectory)))
{
Logger.Warning($"GetLogs: phát hiện đường dẫn không hợp lệ.");
return [];
}
if (!System.IO.File.Exists(path))
{
Logger.Warning($"GetLogs: không tìm thấy file log của ngày {date.ToShortDateString()} - {path}.");
return [];
}
temp = Path.Combine(LoggerDirectory, $"{Guid.NewGuid()}.log");
System.IO.File.Copy(path, temp);
return await System.IO.File.ReadAllLinesAsync(temp);
}
catch(Exception ex)
{
Logger.Warning($"GetLogs: Hệ thống có lỗi xảy ra - {ex.Message}");
return [];
}
finally
{
if (System.IO.File.Exists(temp)) System.IO.File.Delete(temp);
}
}
}

View File

@@ -0,0 +1,249 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class MapExportController(MapEditorDbContext MapDb, MapEditorStorageRepository StorageRepo, IHttpClientFactory HttpClientFactory, LoggerController<MapExportController> Logger) : ControllerBase
{
private readonly byte[] Key = Encoding.UTF8.GetBytes("2512199802031998");
private readonly byte[] IV = Encoding.UTF8.GetBytes("2512199802031998");
[HttpGet]
[Route("encrypt/{Id}")]
public async Task<IActionResult> EncryptMap(Guid Id)
{
try
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Id == Id);
if (map is null) return NotFound($"Map {Id} không tồn tại");
var (usingLocal, url) = StorageRepo.GetUrl("MapImages", $"{Id}");
byte[] imageData = await GetImageDataAsync(usingLocal, url);
var elementModels = MapDb.ElementModels.Where(n => n.MapId == Id);
List<ElementModelExportDto> ElementModelExport = [];
foreach (var elementModel in elementModels)
{
var getImageOpen = StorageRepo.GetUrl("ElementOpenModels", elementModel.Id.ToString());
byte[] imageElementModelOpenData = await GetImageDataAsync(getImageOpen.usingLocal, getImageOpen.url);
var getImageClose = StorageRepo.GetUrl("ElementCloseModels", elementModel.Id.ToString());
byte[] imageElementModelCloseData = await GetImageDataAsync(getImageClose.usingLocal, getImageClose.url);
ElementModelExport.Add(new ElementModelExportDto()
{
Id = elementModel.Id,
Height = elementModel.Height,
Width = elementModel.Width,
Image1Height = elementModel.Image1Height,
Image2Height = elementModel.Image2Height,
Image1Width = elementModel.Image1Width,
Image2Width = elementModel.Image2Width,
Name = elementModel.Name,
Content = elementModel.Content,
ImageOpenData = imageElementModelOpenData,
ImageCloseData = imageElementModelCloseData,
});
}
var nodes = MapDb.Nodes.Where(n => n.MapId == Id);
var edges = MapDb.Edges.Where(n => n.MapId == Id);
var zones = MapDb.Zones.Where(n => n.MapId == Id);
var actions = MapDb.Actions.Where(n => n.MapId == Id);
var elements = MapDb.Elements.Where(n => n.MapId == Id);
var mapDto = new MapExportDto()
{
Id = Id,
Name = map.Name,
Description = map.Description,
Info = new()
{
OriginX = map.OriginX,
OriginY = map.OriginY,
Resolution = map.Resolution,
ViewX = map.ViewX,
ViewY = map.ViewY,
ViewWidth = map.ViewWidth,
ViewHeight = map.ViewHeight,
VDA5050 = map.VDA5050,
},
Setting = new()
{
NodeNameAutoGenerate = map.NodeNameAutoGenerate,
NodeNameTemplate = map.NodeNameTemplateDefault,
NodeAllowedDeviationXy = map.EdgeAllowedDeviationXyDefault,
NodeAllowedDeviationTheta = map.EdgeAllowedDeviationThetaDefault,
EdgeStraightMaxSpeed = map.EdgeStraightMaxSpeedDefault,
EdgeCurveMaxSpeed = map.EdgeCurveMaxSpeedDefault,
EdgeMaxRotationSpeed = map.EdgeMaxRotationSpeedDefault,
EdgeMinLength = map.EdgeMinLengthDefault,
EdgeMaxHeight = map.EdgeMaxHeightDefault,
EdgeMinHeight = map.EdgeMinHeightDefault,
EdgeRotationAllowed = map.EdgeRotationAllowedDefault,
EdgeDirectionAllowed = map.EdgeDirectionAllowedDefault,
EdgeAllowedDeviationTheta = map.EdgeAllowedDeviationThetaDefault,
EdgeAllowedDeviationXy = map.EdgeAllowedDeviationXyDefault,
ZoneMinSquare = map.ZoneMinSquareDefault,
},
Data = new()
{
NodeCount = map.NodeCount,
Nodes = [.. nodes.Select(n => new NodeDto()
{
Id = n.Id,
Name = n.Name,
X = n.X,
Y = n.Y,
Theta = n.Theta,
AllowedDeviationXy = n.AllowedDeviationXy,
AllowedDeviationTheta = n.AllowedDeviationTheta,
Actions = n.Actions,
})],
Edges = [.. edges.Select(e => new EdgeDto()
{
ControlPoint1X = e.ControlPoint1X,
ControlPoint1Y = e.ControlPoint1Y,
ControlPoint2X = e.ControlPoint2X,
ControlPoint2Y = e.ControlPoint2Y,
TrajectoryDegree = e.TrajectoryDegree,
EndNodeId = e.EndNodeId,
StartNodeId = e.StartNodeId,
DirectionAllowed = e.DirectionAllowed,
RotationAllowed = e.RotationAllowed,
AllowedDeviationTheta = e.AllowedDeviationTheta,
AllowedDeviationXy = e.AllowedDeviationXy,
MaxHeight = e.MaxHeight,
MinHeight = e.MinHeight,
MaxSpeed = e.MaxSpeed,
MaxRotationSpeed = e.MaxRotationSpeed,
Actions = e.Actions,
})],
Zones = [.. zones.Select(z => new ZoneDto()
{
Type = z.Type,
X1 = z.X1,
Y1 = z.Y1,
X2 = z.X2,
Y2 = z.Y2,
X3 = z.X3,
Y3 = z.Y3,
X4 = z.X4,
Y4 = z.Y4,
})],
Actions = [.. actions.Select(a => new ActionDto()
{
Id = a.Id,
Name = a.Name,
Content = a.Content,
})],
ElementModels = [.. ElementModelExport],
Elements = [.. elements.Select(e => new ElementDto()
{
Name = e.Name,
IsOpen = e.IsOpen,
ModelId = e.ModelId,
NodeId = e.NodeId,
OffsetX = e.OffsetX,
OffsetY = e.OffsetY,
Content = e.Content,
})],
ImageData = imageData,
}
};
var jsonData = JsonSerializer.Serialize(mapDto, JsonOptionExtends.Write);
var data = EncryptDataAES(jsonData, Key, IV);
return File(data, "application/octet-stream", $"{map.Name}.map");
}
catch (Exception ex)
{
Logger.Warning($"EncryptMap: Hệ thống có lỗi xảy ra - {ex.Message}");
return NotFound("Hệ thống có lỗi xảy ra");
}
}
[HttpPost]
[Route("decrypt")]
public async Task<MessageResult<MapExportDto>> DecryptMap([FromForm(Name = "importmap")] IFormFile file)
{
try
{
if (file == null || file.Length == 0) return new(false, "File không hợp lệ");
if (!file.FileName.EndsWith(".map", StringComparison.OrdinalIgnoreCase)) return new(false, "Định dạng file không hợp lệ, yêu cầu file .map");
using var memoryStream = new MemoryStream();
await file.CopyToAsync(memoryStream);
byte[] fileBytes = memoryStream.ToArray();
var jsonData = DecryptDataAES(fileBytes, Key, IV);
var mapData = JsonSerializer.Deserialize<MapExportDto>(jsonData, JsonOptionExtends.Read);
if (mapData is null) return new(false, "Dữ liệu không hợp lệ");
else return new(true) { Data = mapData };
}
catch (Exception ex)
{
Logger.Warning($"EncryptMap: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"EncryptMap: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
private static byte[] EncryptDataAES(string data, byte[] key, byte[] iv)
{
using Aes aesAlg = Aes.Create();
aesAlg.Key = key;
aesAlg.IV = iv;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using MemoryStream msEncrypt = new();
using CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write);
using (StreamWriter swEncrypt = new(csEncrypt))
{
swEncrypt.Write(data);
}
return msEncrypt.ToArray();
}
private static string DecryptDataAES(byte[] data, byte[] key, byte[] iv)
{
using Aes aesAlg = Aes.Create();
aesAlg.Key = key;
aesAlg.IV = iv;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using MemoryStream msDecrypt = new(data);
using CryptoStream csDecrypt = new(msDecrypt, decryptor, CryptoStreamMode.Read);
using StreamReader srDecrypt = new(csDecrypt);
return srDecrypt.ReadToEnd();
}
public async Task<byte[]> GetImageDataAsync(bool usingLocal, string url)
{
if (!usingLocal)
{
var http = HttpClientFactory.CreateClient();
var response = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
if (!response.IsSuccessStatusCode) return [];
return await response.Content.ReadAsByteArrayAsync();
}
else
{
if (System.IO.File.Exists(url)) return System.IO.File.ReadAllBytes(url);
return [];
}
}
}

View File

@@ -0,0 +1,381 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares;
using RobotNet.MapShares.Dtos;
using RobotNet.MapShares.Models;
using RobotNet.Shares;
using System.Text.Json;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class MapsDataController(MapEditorDbContext MapDb, LoggerController<MapsDataController> Logger) : ControllerBase
{
[HttpGet]
[Route("{id}")]
public async Task<MessageResult<MapDataDto>> GetMapData(Guid id)
{
var map = await MapDb.Maps.FindAsync(id);
if (map is null) return new(false, $"Không tìm thấy bản đồ: {id}");
var result = new MessageResult<MapDataDto>(true)
{
Data = new()
{
Id = map.Id,
Name = map.Name,
OriginX = map.OriginX,
OriginY = map.OriginY,
Resolution = map.Resolution,
ImageHeight = map.ImageHeight,
ImageWidth = map.ImageWidth,
Active = map.Active,
Nodes = [.. MapDb.Nodes.Where(node => node.MapId == id).Select(node => new NodeDto()
{
Id = node.Id,
MapId = node.MapId,
Name = node.Name,
Theta = node.Theta,
X = node.X,
Y = node.Y,
AllowedDeviationXy = node.AllowedDeviationXy,
AllowedDeviationTheta = node.AllowedDeviationTheta,
Actions = node.Actions,
})],
Edges = [.. MapDb.Edges.Where(edge => edge.MapId == id).Select(edge => new EdgeDto()
{
Id = edge.Id,
MapId = edge.MapId,
StartNodeId = edge.StartNodeId,
EndNodeId = edge.EndNodeId,
MaxSpeed = edge.MaxSpeed,
MaxHeight = edge.MaxHeight,
MinHeight = edge.MinHeight,
DirectionAllowed = edge.DirectionAllowed,
RotationAllowed = edge.RotationAllowed,
TrajectoryDegree = edge.TrajectoryDegree,
ControlPoint1X = edge.ControlPoint1X,
ControlPoint1Y = edge.ControlPoint1Y,
ControlPoint2X = edge.ControlPoint2X,
ControlPoint2Y = edge.ControlPoint2Y,
MaxRotationSpeed = edge.MaxRotationSpeed,
Actions = edge.Actions,
AllowedDeviationXy = edge.AllowedDeviationXy,
AllowedDeviationTheta = edge.AllowedDeviationTheta,
})],
Zones = [.. MapDb.Zones.Where(zone => zone.MapId == id).Select(zone => new ZoneDto()
{
Id = zone.Id,
MapId = zone.MapId,
Type = zone.Type,
Name = zone.Name,
X1 = zone.X1,
X2 = zone.X2,
Y1 = zone.Y1,
Y2 = zone.Y2,
X3 = zone.X3,
Y3 = zone.Y3,
X4 = zone.X4,
Y4 = zone.Y4,
}).OrderBy(z => z.Type)],
Elements = [.. MapDb.Elements.Where(el => el.MapId == id).Select(element => new ElementDto()
{
Id = element.Id,
MapId = element.MapId,
ModelId = element.ModelId,
Name = element.Name,
NodeId = element.NodeId,
OffsetX = element.OffsetX,
OffsetY = element.OffsetY,
IsOpen = element.IsOpen,
Content = element.Content,
})],
Actions = [.. MapDb.Actions.Where(a => a.MapId == id).Select(action => new ActionDto()
{
Id = action.Id,
MapId = action.MapId,
Name = action.Name,
Content = action.Content,
})]
}
};
return result;
}
[HttpPut]
[Route("{id}/updates")]
public async Task<MessageResult<IEnumerable<EdgeDto>>> Updates(Guid id, MapEditorBackupModel model)
{
if (model == null || model.Steps == null) return new(false, "Dữ liệu đầu vào không hợp lệ");
try
{
var map = await MapDb.Maps.FindAsync(id);
if (map == null) return new(false, $"Không tồn tại map id = {id}");
List<EdgeDto> EdgeDtos = [];
foreach (var step in model.Steps)
{
switch (step.Type)
{
case MapEditorBackupType.Node:
PositionBackup? nodeUpdate = JsonSerializer.Deserialize<PositionBackup>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (nodeUpdate is not null)
{
var nodeDb = await MapDb.Nodes.FindAsync(step.Id);
if (nodeDb is not null)
{
nodeDb.X = nodeUpdate.X;
nodeDb.Y = nodeUpdate.Y;
}
}
break;
case MapEditorBackupType.ControlPoint1Edge:
PositionBackup? controlPoint1 = JsonSerializer.Deserialize<PositionBackup>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (controlPoint1 is not null)
{
var edgeDb = await MapDb.Edges.FindAsync(step.Id);
if (edgeDb is not null)
{
edgeDb.ControlPoint1X = controlPoint1.X;
edgeDb.ControlPoint1Y = controlPoint1.Y;
}
}
break;
case MapEditorBackupType.ControlPoint2Edge:
PositionBackup? controlPoint2 = JsonSerializer.Deserialize<PositionBackup>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (controlPoint2 is not null)
{
var edgeDb = await MapDb.Edges.FindAsync(step.Id);
if (edgeDb is not null)
{
edgeDb.ControlPoint2X = controlPoint2.X;
edgeDb.ControlPoint2Y = controlPoint2.Y;
}
}
break;
case MapEditorBackupType.Zone:
ZoneShapeBackup? zoneUpdate = JsonSerializer.Deserialize<ZoneShapeBackup>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (zoneUpdate is not null)
{
var zoneDb = await MapDb.Zones.FindAsync(step.Id);
if (zoneDb is not null)
{
zoneDb.X1 = zoneUpdate.X1;
zoneDb.Y1 = zoneUpdate.Y1;
zoneDb.X2 = zoneUpdate.X2;
zoneDb.Y2 = zoneUpdate.Y2;
zoneDb.X3 = zoneUpdate.X3;
zoneDb.Y3 = zoneUpdate.Y3;
zoneDb.X4 = zoneUpdate.X4;
zoneDb.Y4 = zoneUpdate.Y4;
}
}
break;
case MapEditorBackupType.MoveEdge:
List<EdgeBackup>? edgesUpdate = JsonSerializer.Deserialize<List<EdgeBackup>>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (edgesUpdate is not null && edgesUpdate.Count > 0)
{
foreach (var edgeUpate in edgesUpdate)
{
var edgeDb = await MapDb.Edges.FindAsync(edgeUpate.Id);
if (edgeDb is not null)
{
var startNode = await MapDb.Nodes.FindAsync(edgeDb.StartNodeId);
var endNode = await MapDb.Nodes.FindAsync(edgeDb.EndNodeId);
if (startNode is not null && endNode is not null)
{
startNode.X = edgeUpate.StartX;
startNode.Y = edgeUpate.StartY;
endNode.X = edgeUpate.EndX;
endNode.Y = edgeUpate.EndY;
}
edgeDb.ControlPoint1X = edgeUpate.ControlPoint1X;
edgeDb.ControlPoint1Y = edgeUpate.ControlPoint1Y;
edgeDb.ControlPoint2X = edgeUpate.ControlPoint2X;
edgeDb.ControlPoint2Y = edgeUpate.ControlPoint2Y;
}
}
}
break;
case MapEditorBackupType.Copy:
List<EdgeMapCopyModel>? edgesCopy = JsonSerializer.Deserialize<List<EdgeMapCopyModel>>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (edgesCopy is not null && edgesCopy.Count > 0)
{
Dictionary<Guid, Node> CreateNewNode = [];
foreach (var edgeCopy in edgesCopy)
{
if (!CreateNewNode.TryGetValue(edgeCopy.StartNodeId, out _))
{
var startNode = await MapDb.Nodes.FindAsync(edgeCopy.StartNodeId);
var newStartNode = await MapDb.Nodes.AddAsync(new Node()
{
MapId = edgeCopy.MapId,
Name = map.NodeNameAutoGenerate ? $"{map.NodeNameTemplateDefault}{++map.NodeCount}" : string.Empty,
X = edgeCopy.X1,
Y = edgeCopy.Y1,
Theta = startNode is not null ? startNode.Theta : 0,
Actions = startNode is not null ? startNode.Actions : "",
AllowedDeviationXy = startNode is not null ? startNode.AllowedDeviationXy : map.NodeAllowedDeviationXyDefault,
AllowedDeviationTheta = startNode is not null ? startNode.AllowedDeviationTheta : map.NodeAllowedDeviationThetaDefault,
});
CreateNewNode.Add(edgeCopy.StartNodeId, newStartNode.Entity);
}
if (!CreateNewNode.TryGetValue(edgeCopy.EndNodeId, out _))
{
var endNode = await MapDb.Nodes.FindAsync(edgeCopy.EndNodeId);
var newEndNode = await MapDb.Nodes.AddAsync(new Node()
{
MapId = edgeCopy.MapId,
Name = map.NodeNameAutoGenerate ? $"{map.NodeNameTemplateDefault}{++map.NodeCount}" : string.Empty,
X = edgeCopy.X2,
Y = edgeCopy.Y2,
Theta = endNode is not null ? endNode.Theta : 0,
Actions = endNode is not null ? endNode.Actions : "",
AllowedDeviationXy = endNode is not null ? endNode.AllowedDeviationXy : map.NodeAllowedDeviationXyDefault,
AllowedDeviationTheta = endNode is not null ? endNode.AllowedDeviationTheta : map.NodeAllowedDeviationThetaDefault,
});
CreateNewNode.Add(edgeCopy.EndNodeId, newEndNode.Entity);
}
var newEdge = await MapDb.Edges.AddAsync(new Edge()
{
MapId = edgeCopy.MapId,
StartNodeId = CreateNewNode[edgeCopy.StartNodeId] is null ? Guid.Empty : CreateNewNode[edgeCopy.StartNodeId].Id,
EndNodeId = CreateNewNode[edgeCopy.EndNodeId] is null ? Guid.Empty : CreateNewNode[edgeCopy.EndNodeId].Id,
TrajectoryDegree = edgeCopy.TrajectoryDegree,
ControlPoint1X = edgeCopy.ControlPoint1X,
ControlPoint1Y = edgeCopy.ControlPoint1Y,
ControlPoint2X = edgeCopy.ControlPoint2X,
ControlPoint2Y = edgeCopy.ControlPoint2Y,
DirectionAllowed = edgeCopy.DirectionAllowed,
RotationAllowed = edgeCopy.RotationAllowed,
MaxSpeed = edgeCopy.MaxSpeed,
MaxRotationSpeed = edgeCopy.MaxRotationSpeed,
MaxHeight = edgeCopy.MaxHeight,
MinHeight = edgeCopy.MinHeight,
Actions = edgeCopy.Actions,
AllowedDeviationTheta = edgeCopy.AllowedDeviationTheta,
AllowedDeviationXy = edgeCopy.AllowedDeviationXy,
});
EdgeDtos.Add(new()
{
Id = newEdge.Entity.Id,
MapId = newEdge.Entity.MapId,
StartNodeId = newEdge.Entity.StartNodeId,
EndNodeId = newEdge.Entity.EndNodeId,
TrajectoryDegree = newEdge.Entity.TrajectoryDegree,
ControlPoint1X = newEdge.Entity.ControlPoint1X,
ControlPoint1Y = newEdge.Entity.ControlPoint1Y,
ControlPoint2X = newEdge.Entity.ControlPoint2X,
ControlPoint2Y = newEdge.Entity.ControlPoint2Y,
DirectionAllowed = newEdge.Entity.DirectionAllowed,
RotationAllowed = newEdge.Entity.RotationAllowed,
MaxSpeed = newEdge.Entity.MaxSpeed,
MaxRotationSpeed = newEdge.Entity.MaxRotationSpeed,
MaxHeight = newEdge.Entity.MaxHeight,
MinHeight = newEdge.Entity.MinHeight,
Actions = newEdge.Entity.Actions,
AllowedDeviationXy = newEdge.Entity.AllowedDeviationXy,
AllowedDeviationTheta = newEdge.Entity.AllowedDeviationTheta,
StartNode = new NodeDto()
{
Id = CreateNewNode[edgeCopy.StartNodeId].Id,
Name = CreateNewNode[edgeCopy.StartNodeId].Name,
MapId = CreateNewNode[edgeCopy.StartNodeId].MapId,
Theta = CreateNewNode[edgeCopy.StartNodeId].Theta,
X = CreateNewNode[edgeCopy.StartNodeId].X,
Y = CreateNewNode[edgeCopy.StartNodeId].Y,
AllowedDeviationXy = CreateNewNode[edgeCopy.StartNodeId].AllowedDeviationXy,
AllowedDeviationTheta = CreateNewNode[edgeCopy.StartNodeId].AllowedDeviationTheta,
Actions = CreateNewNode[edgeCopy.StartNodeId].Actions,
},
EndNode = new NodeDto()
{
Id = CreateNewNode[edgeCopy.EndNodeId].Id,
Name = CreateNewNode[edgeCopy.EndNodeId].Name,
MapId = CreateNewNode[edgeCopy.EndNodeId].MapId,
Theta = CreateNewNode[edgeCopy.EndNodeId].Theta,
X = CreateNewNode[edgeCopy.EndNodeId].X,
Y = CreateNewNode[edgeCopy.EndNodeId].Y,
AllowedDeviationXy = CreateNewNode[edgeCopy.EndNodeId].AllowedDeviationXy,
AllowedDeviationTheta = CreateNewNode[edgeCopy.EndNodeId].AllowedDeviationTheta,
Actions = CreateNewNode[edgeCopy.EndNodeId].Actions,
},
});
}
}
break;
case MapEditorBackupType.SplitNode:
var nodeSplit = await MapDb.Nodes.FindAsync(step.Id);
if (nodeSplit is not null)
{
SplitNodeBackup? SplitNodeUpdate = JsonSerializer.Deserialize<SplitNodeBackup>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (SplitNodeUpdate is not null)
{
foreach (var data in SplitNodeUpdate.EdgeSplit)
{
var edge = await MapDb.Edges.FindAsync(data.Key);
if (edge is not null)
{
var newNode = new Node()
{
Id = data.Value.Id,
Name = data.Value.Name,
X = data.Value.X,
Y = data.Value.Y,
Theta = data.Value.Theta,
MapId = data.Value.MapId,
AllowedDeviationXy = data.Value.AllowedDeviationXy,
AllowedDeviationTheta = data.Value.AllowedDeviationTheta,
Actions = data.Value.Actions,
};
if (edge.StartNodeId == nodeSplit.Id) edge.StartNodeId = newNode.Id;
else if (edge.EndNodeId == nodeSplit.Id) edge.EndNodeId = newNode.Id;
else continue;
await MapDb.Nodes.AddAsync(newNode);
}
}
}
}
break;
case MapEditorBackupType.MergeNode:
var nodemerge = await MapDb.Nodes.FindAsync(step.Id);
if (nodemerge is not null)
{
MergeNodeUpdate? MergeNodeUpdate = JsonSerializer.Deserialize<MergeNodeUpdate>(step.Obj.ToString() ?? "", JsonOptionExtends.Read);
if (MergeNodeUpdate is not null)
{
foreach (var data in MergeNodeUpdate.EdgesMerge)
{
var edge = await MapDb.Edges.FindAsync(data.Key);
if (edge is not null)
{
var rmNode = await MapDb.Nodes.FindAsync(data.Value);
if (edge.StartNodeId == data.Value) edge.StartNodeId = nodemerge.Id;
else if (edge.EndNodeId == data.Value) edge.EndNodeId = nodemerge.Id;
if (rmNode is not null) MapDb.Nodes.Remove(rmNode);
}
}
}
}
break;
}
}
await MapDb.SaveChangesAsync();
Logger.Info($"User {HttpContext.User.Identity?.Name} đã cập nhật dữ liệu cho bản đồ: {map.Name} - {map.Id}");
return new(true) { Data = EdgeDtos };
}
catch (Exception ex)
{
Logger.Warning($"Updates: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, "Hệ thống có lỗi xảy ra");
}
}
}

View File

@@ -0,0 +1,571 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Hubs;
using RobotNet.MapManager.Services;
using RobotNet.MapShares.Dtos;
using RobotNet.MapShares.Enums;
using RobotNet.Shares;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class MapsManagerController(MapEditorDbContext MapDb, MapEditorStorageRepository StorageRepo, IHubContext<MapHub> MapHub, LoggerController<MapsManagerController> Logger) : ControllerBase
{
[HttpGet]
public async Task<IEnumerable<MapInfoDto>> GetMapInfos([FromQuery(Name = "txtSearch")] string? txtSearch)
{
try
{
if (string.IsNullOrWhiteSpace(txtSearch))
{
return await (from map in MapDb.Maps
select new MapInfoDto()
{
Id = map.Id,
VersionId = map.VersionId,
Name = map.Name,
Description = map.Description,
Active = map.Active,
OriginX = map.OriginX,
OriginY = map.OriginY,
Width = Math.Round(map.ImageWidth * map.Resolution, 2),
Height = Math.Round(map.ImageHeight * map.Resolution, 2),
Resolution = map.Resolution,
VDA5050 = map.VDA5050,
}).ToListAsync();
}
else
{
return await (from map in MapDb.Maps
where !string.IsNullOrEmpty(map.Name) && map.Name.Contains(txtSearch)
select new MapInfoDto()
{
Id = map.Id,
VersionId = map.VersionId,
Name = map.Name,
Description = map.Description,
Active = map.Active,
OriginX = map.OriginX,
OriginY = map.OriginY,
Width = Math.Round(map.ImageWidth * map.Resolution, 2),
Height = Math.Round(map.ImageHeight * map.Resolution, 2),
Resolution = map.Resolution,
VDA5050 = map.VDA5050,
}).ToListAsync();
}
}
catch (Exception ex)
{
Logger.Warning($"GetMapInfos: Hệ thống có lỗi xảy ra - {ex.Message}");
return [];
}
}
[HttpGet]
[Route("{id}")]
public async Task<MessageResult<MapInfoDto>> GetMapInfoId(Guid id)
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Id == id);
if (map == null) return new MessageResult<MapInfoDto>(false, $"Không tìm thấy map {id}");
return new(true)
{
Data = new MapInfoDto()
{
Id = map.Id,
Name = map.Name,
Active = map.Active,
OriginX = map.OriginX,
OriginY = map.OriginY,
Width = Math.Round(map.ImageWidth * map.Resolution, 2),
Height = Math.Round(map.ImageHeight * map.Resolution, 2),
Resolution = map.Resolution,
},
};
}
[HttpGet]
[Route("info")]
public async Task<MessageResult<MapInfoDto>> GetMapInfoName([FromQuery(Name = "name")] string name)
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == name);
if (map == null) return new MessageResult<MapInfoDto>(false, $"Không tìm thấy map {name}");
return new(true)
{
Data = new MapInfoDto()
{
Id = map.Id,
Name = map.Name,
Active = map.Active,
OriginX = map.OriginX,
OriginY = map.OriginY,
Width = Math.Round(map.ImageWidth * map.Resolution, 2),
Height = Math.Round(map.ImageHeight * map.Resolution, 2),
Resolution = map.Resolution,
},
};
}
[HttpPost]
[Route("")]
public async Task<MessageResult<MapInfoDto>> CreateMap([FromForm] MapCreateModel model, [FromForm(Name = "Image")] IFormFile imageUpload)
{
try
{
if (imageUpload is null) return new(false, "Dữ liệu không hợp lệ");
if (imageUpload.ContentType != "image/png") return new(false, "Ảnh map chỉ hỗ trợ định dạng image/png");
if (await MapDb.Maps.AnyAsync(map => map.Name == model.Name)) return new(false, "Tên của map đã tồn tại. Hãy đặt tên khác!");
var image = SixLabors.ImageSharp.Image.Load(imageUpload.OpenReadStream());
var entityMap = await MapDb.Maps.AddAsync(new Map()
{
Name = model.Name,
OriginX = model.OriginX,
OriginY = model.OriginY,
Resolution = model.Resolution,
ImageHeight = (ushort)image.Height,
ImageWidth = (ushort)image.Width,
Active = false,
NodeCount = 0,
NodeNameAutoGenerate = true,
NodeNameTemplateDefault = "Node",
NodeAllowedDeviationXyDefault = 0.1,
NodeAllowedDeviationThetaDefault = 0,
EdgeMinLengthDefault = 1,
EdgeMaxHeightDefault = 1,
EdgeMinHeightDefault = 0.1,
EdgeStraightMaxSpeedDefault = 1,
EdgeCurveMaxSpeedDefault = 0.3,
EdgeMaxRotationSpeedDefault = 0.5,
EdgeAllowedDeviationXyDefault = 0.1,
EdgeAllowedDeviationThetaDefault = 0,
EdgeRotationAllowedDefault = true,
EdgeDirectionAllowedDefault = DirectionAllowed.Both,
ZoneMinSquareDefault = 0.25,
});
await MapDb.SaveChangesAsync();
var (isSuccess, message) = await StorageRepo.UploadAsync("MapImages", $"{entityMap.Entity.Id}", imageUpload.OpenReadStream(), imageUpload.Length, imageUpload.ContentType, CancellationToken.None);
if (!isSuccess)
{
MapDb.Maps.Remove(entityMap.Entity);
await MapDb.SaveChangesAsync();
return new(false, message);
}
await MapDb.SaveChangesAsync();
Logger.Info($"User {HttpContext.User.Identity?.Name} đã tạo bản đồ mới với tên: {model.Name}");
return new(true)
{
Data = new MapInfoDto()
{
Id = entityMap.Entity.Id,
Name = entityMap.Entity.Name,
Active = entityMap.Entity.Active,
OriginX = entityMap.Entity.OriginX,
OriginY = entityMap.Entity.OriginY,
Width = entityMap.Entity.ImageWidth * entityMap.Entity.Resolution,
Height = entityMap.Entity.ImageHeight * entityMap.Entity.Resolution,
Resolution = entityMap.Entity.Resolution,
},
};
}
catch (Exception ex)
{
Logger.Warning($"CreateMap: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"CreateMap: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPut]
[Route("{id}")]
public async Task<MessageResult<MapInfoDto>> UpdateMap(Guid id, [FromBody] MapUpdateModel model)
{
try
{
if (id != model.Id) return new(false, "Dữ liệu gửi không chính xác");
var map = await MapDb.Maps.FindAsync(id);
if (map == null) return new(false, $"Không tồn tại map id = {id}");
if (map.Name != model.Name && await MapDb.Maps.AnyAsync(m => m.Name == model.Name))
{
return new(false, "Tên của map đã tồn tại, Hãy đặt tên khác!");
}
if (model.Resolution <= 0)
{
return new(false, "Độ phân giải của bản đồ phải lớn hơn 0");
}
map.Name = model.Name;
bool originChange = map.OriginX != model.OriginX || map.OriginY != model.OriginY;
if (originChange)
{
map.OriginX = model.OriginX;
map.OriginY = model.OriginY;
}
if (map.Resolution != model.Resolution)
{
var scale = model.Resolution / map.Resolution;
map.Resolution = model.Resolution;
if (originChange)
{
map.OriginX *= scale;
map.OriginY *= scale;
}
var nodes = await MapDb.Nodes.Where(n => n.MapId == map.Id).ToListAsync();
foreach (var node in nodes)
{
node.X *= scale;
node.Y *= scale;
}
var edges = await MapDb.Edges.Where(e => e.MapId == map.Id).ToListAsync();
foreach (var edge in edges)
{
edge.ControlPoint1X *= scale;
edge.ControlPoint1Y *= scale;
edge.ControlPoint2X *= scale;
edge.ControlPoint2Y *= scale;
}
}
await MapDb.SaveChangesAsync();
Logger.Info($"User {HttpContext.User.Identity?.Name} đã cập nhật thông tin bản đồ : {model.Id} - {map.Name}");
return new(true)
{
Data = new()
{
Id = id,
Name = map.Name,
OriginX = map.OriginX,
OriginY = map.OriginY,
Resolution = model.Resolution,
Width = Math.Round(map.ImageWidth * map.Resolution, 2),
Height = Math.Round(map.ImageHeight * map.Resolution, 2),
},
};
}
catch (Exception ex)
{
Logger.Warning($"UpdateMap {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"UpdateMap {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpDelete]
[Route("{id}")]
public async Task<MessageResult> DeleteMap(Guid id)
{
try
{
var map = await MapDb.Maps.FindAsync(id);
if (map == null) return new(false, $"Không tồn tại map id = {id}");
MapDb.Elements.RemoveRange(MapDb.Elements.Where(e => e.MapId == map.Id));
MapDb.ElementModels.RemoveRange(MapDb.ElementModels.Where(em => em.MapId == map.Id));
MapDb.Edges.RemoveRange(MapDb.Edges.Where(edge => edge.MapId == map.Id));
MapDb.Nodes.RemoveRange(MapDb.Nodes.Where(node => node.MapId == map.Id));
MapDb.Zones.RemoveRange(MapDb.Zones.Where(zone => zone.MapId == map.Id));
MapDb.Actions.RemoveRange(MapDb.Actions.Where(action => action.MapId == map.Id));
MapDb.Maps.Remove(map);
await MapDb.SaveChangesAsync();
await StorageRepo.DeleteAsync("MapImages", $"{id}", CancellationToken.None);
Logger.Info($"User {HttpContext.User.Identity?.Name} đã xóa bản đồ {map.Name}");
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"DeleteMap {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"DeleteMap {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPut]
[Route("active")]
public async Task<MessageResult> ActiveToggle([FromBody] MapActiveModel model)
{
var map = await MapDb.Maps.FindAsync(model.Id);
if (map == null) return new(false, $"Không tồn tại map id = {model.Id}");
map.Active = model.Active;
await MapDb.SaveChangesAsync();
await MapHub.Clients.All.SendAsync("MapUpdated", model.Id);
Logger.Info($"User {HttpContext.User.Identity?.Name} đã thay đổi trạng thái active bản đồ {map.Name}: {model.Active}");
return new(true);
}
[HttpPut]
[Route("image/{id}")]
public async Task<MessageResult> UpdateImage(Guid id, [FromForm(Name = "image")] IFormFile image)
{
try
{
var map = await MapDb.Maps.FindAsync(id);
if (map == null) return new(false, $"Không tồn tại map id = {id}");
var imageStream = image.OpenReadStream();
var imageUpdate = SixLabors.ImageSharp.Image.Load(imageStream);
map.ImageWidth = (ushort)imageUpdate.Width;
map.ImageHeight = (ushort)imageUpdate.Height;
await MapDb.SaveChangesAsync();
var (isSuccess, message) = await StorageRepo.UploadAsync("MapImages", $"{id}", image.OpenReadStream(), image.Length, image.ContentType, CancellationToken.None);
Logger.Info($"User {HttpContext.User.Identity?.Name} đã thay đổi ảnh của bản đồ {map.Name}");
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"UpdateImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"UpdateImage {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPost]
[Route("import")]
public async Task<MessageResult<MapInfoDto>> ImportNewMap([FromBody] MapExportDto model)
{
if (model == null || model.Data == null || model.Data.ImageData == null || model.Data.ImageData.Length == 0)
{
return new(false, "Dữ liệu đầu vào không hợp lệ");
}
using var transaction = await MapDb.Database.BeginTransactionAsync();
try
{
if (await MapDb.Maps.AnyAsync(map => map.Name == model.Name)) return new(false, "Tên của map đã tồn tại, Hãy đặt tên khác!");
using var stream = new MemoryStream(model.Data.ImageData);
var imageFile = new FormFile(stream, 0, model.Data.ImageData.Length, "", $"{model.Name}.png")
{
Headers = new HeaderDictionary(),
ContentType = "image/png",
};
var image = SixLabors.ImageSharp.Image.Load(imageFile.OpenReadStream());
var entityMap = await MapDb.Maps.AddAsync(new Map()
{
Name = model.Name,
Description = model.Description,
OriginX = model.Info.OriginX,
OriginY = model.Info.OriginY,
Resolution = model.Info.Resolution,
ImageHeight = (ushort)image.Height,
ImageWidth = (ushort)image.Width,
Active = false,
ViewX = model.Info.ViewX,
ViewY = model.Info.ViewY,
ViewWidth = model.Info.ViewWidth,
ViewHeight = model.Info.ViewHeight,
VDA5050 = model.Info.VDA5050,
NodeCount = model.Data.NodeCount,
NodeNameAutoGenerate = model.Setting.NodeNameAutoGenerate,
NodeNameTemplateDefault = model.Setting.NodeNameTemplate,
NodeAllowedDeviationXyDefault = model.Setting.NodeAllowedDeviationXy,
NodeAllowedDeviationThetaDefault = model.Setting.NodeAllowedDeviationTheta,
EdgeMinLengthDefault = model.Setting.EdgeMinLength,
EdgeMaxHeightDefault = model.Setting.EdgeMaxHeight,
EdgeMinHeightDefault = model.Setting.EdgeMinHeight,
EdgeStraightMaxSpeedDefault = model.Setting.EdgeStraightMaxSpeed,
EdgeCurveMaxSpeedDefault = model.Setting.EdgeCurveMaxSpeed,
EdgeMaxRotationSpeedDefault = model.Setting.EdgeMaxRotationSpeed,
EdgeAllowedDeviationXyDefault = model.Setting.EdgeAllowedDeviationXy,
EdgeAllowedDeviationThetaDefault = model.Setting.EdgeAllowedDeviationTheta,
EdgeRotationAllowedDefault = model.Setting.EdgeRotationAllowed,
EdgeDirectionAllowedDefault = model.Setting.EdgeDirectionAllowed,
ZoneMinSquareDefault = model.Setting.ZoneMinSquare,
});
var (isSuccess, message) = await StorageRepo.UploadAsync("MapImages", $"{entityMap.Entity.Id}", imageFile.OpenReadStream(), imageFile.Length, imageFile.ContentType, CancellationToken.None);
if (!isSuccess)
{
await transaction.RollbackAsync();
return new(false, message);
}
Dictionary<Guid, Guid> actionSwap = [];
foreach (var action in model.Data.Actions)
{
var actionDb = await MapDb.Actions.AddAsync(new Data.Action()
{
MapId = entityMap.Entity.Id,
Name = action.Name,
Content = action.Content,
});
actionSwap.Add(action.Id, actionDb.Entity.Id);
}
Dictionary<Guid, Guid> nodeSwap = [];
foreach (var node in model.Data.Nodes)
{
var actions = System.Text.Json.JsonSerializer.Deserialize<Guid[]>(node.Actions ?? "");
List<Guid> newActions = [];
if (actions is not null && actions.Length > 0)
{
foreach (var actionId in actions)
{
if (actionSwap.TryGetValue(actionId, out Guid newActionId) && newActionId != Guid.Empty) newActions.Add(newActionId);
}
}
var nodeDb = await MapDb.Nodes.AddAsync(new Node()
{
Name = node.Name,
MapId = entityMap.Entity.Id,
X = node.X,
Y = node.Y,
Theta = node.Theta,
AllowedDeviationXy = node.AllowedDeviationXy,
AllowedDeviationTheta = node.AllowedDeviationTheta,
Actions = System.Text.Json.JsonSerializer.Serialize(newActions),
});
nodeSwap.Add(node.Id, nodeDb.Entity.Id);
}
var Edges = model.Data.Edges.Select(e => new Edge()
{
MapId = entityMap.Entity.Id,
StartNodeId = nodeSwap[e.StartNodeId],
EndNodeId = nodeSwap[e.EndNodeId],
ControlPoint1X = e.ControlPoint1X,
ControlPoint1Y = e.ControlPoint1Y,
ControlPoint2X = e.ControlPoint2X,
ControlPoint2Y = e.ControlPoint2Y,
TrajectoryDegree = e.TrajectoryDegree,
MaxHeight = e.MaxHeight,
MinHeight = e.MinHeight,
MaxSpeed = e.MaxSpeed,
MaxRotationSpeed = e.MaxRotationSpeed,
AllowedDeviationXy = e.AllowedDeviationXy,
AllowedDeviationTheta = e.AllowedDeviationTheta,
DirectionAllowed = e.DirectionAllowed,
RotationAllowed = e.RotationAllowed,
Actions = e.Actions,
}).ToList();
var Zones = model.Data.Zones.Select(z => new Zone()
{
MapId = entityMap.Entity.Id,
Type = z.Type,
X1 = z.X1,
X2 = z.X2,
Y1 = z.Y1,
Y2 = z.Y2,
X3 = z.X3,
X4 = z.X4,
Y3 = z.Y3,
Y4 = z.Y4,
}).ToList();
Dictionary<Guid, Guid> elementModelSwap = [];
foreach (var elementModel in model.Data.ElementModels)
{
var elementModelDb = await MapDb.ElementModels.AddAsync(new ElementModel()
{
MapId = entityMap.Entity.Id,
Name = elementModel.Name,
Height = elementModel.Height,
Width = elementModel.Width,
Image1Height = elementModel.Image1Height,
Image1Width = elementModel.Image1Width,
Image2Height = elementModel.Image2Height,
Image2Width = elementModel.Image2Width,
Content = elementModel.Content,
});
elementModelSwap.Add(elementModel.Id, elementModelDb.Entity.Id);
using var openStream = new MemoryStream(elementModel.ImageOpenData);
var imageOpenFile = new FormFile(openStream, 0, elementModel.ImageOpenData.Length, "", $"{elementModel.Name}O.png")
{
Headers = new HeaderDictionary(),
ContentType = "image/png",
};
await StorageRepo.UploadAsync("ElementOpenModels", $"{elementModelDb.Entity.Id}", imageOpenFile.OpenReadStream(), imageOpenFile.Length, imageOpenFile.ContentType, CancellationToken.None);
using var closeStream = new MemoryStream(elementModel.ImageCloseData);
var imageCloseFile = new FormFile(closeStream, 0, elementModel.ImageCloseData.Length, "", $"{elementModel.Name}C.png")
{
Headers = new HeaderDictionary(),
ContentType = "image/png",
};
await StorageRepo.UploadAsync("ElementCloseModels", $"{elementModelDb.Entity.Id}", imageCloseFile.OpenReadStream(), imageCloseFile.Length, imageCloseFile.ContentType, CancellationToken.None);
}
var Elements = model.Data.Elements.Select(e => new Data.Element()
{
MapId = entityMap.Entity.Id,
Name = e.Name,
IsOpen = e.IsOpen,
ModelId = elementModelSwap[e.ModelId],
Content = e.Content,
NodeId = nodeSwap[e.NodeId],
OffsetX = e.OffsetX,
OffsetY = e.OffsetY,
}).ToList();
if (Edges.Count > 0) await MapDb.Edges.AddRangeAsync(Edges);
if (Zones.Count > 0) await MapDb.Zones.AddRangeAsync(Zones);
if (Elements.Count > 0) await MapDb.Elements.AddRangeAsync(Elements);
await MapDb.SaveChangesAsync();
await transaction.CommitAsync();
return new(true)
{
Data = new MapInfoDto()
{
Id = entityMap.Entity.Id,
Name = entityMap.Entity.Name,
Active = entityMap.Entity.Active,
OriginX = entityMap.Entity.OriginX,
OriginY = entityMap.Entity.OriginY,
Width = entityMap.Entity.ImageWidth * entityMap.Entity.Resolution,
Height = entityMap.Entity.ImageHeight * entityMap.Entity.Resolution,
Resolution = entityMap.Entity.Resolution,
}
};
}
catch (IOException ex)
{
await transaction.RollbackAsync();
Logger.Warning($"ImportNewMap: Lỗi khi xử lý hình ảnh: {ex.Message}");
return new(false, $"ImportNewMap: Lỗi khi xử lý hình ảnh: {ex.Message}");
}
catch (DbUpdateException ex)
{
await transaction.RollbackAsync();
Logger.Warning($"ImportNewMap: Lỗi khi lưu vào database: {ex.Message}");
return new(false, $"ImportNewMap: Lỗi khi lưu vào database: {ex.Message}");
}
catch (Exception ex)
{
await transaction.RollbackAsync();
Logger.Warning($"ImportNewMap: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"ImportNewMap: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
}

View File

@@ -0,0 +1,79 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class MapsSettingController(MapEditorDbContext MapDb) : ControllerBase
{
[HttpGet]
[Route("{id}")]
public async Task<MessageResult<MapSettingDefaultDto>> GetMapSetting(Guid id)
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Id == id);
if (map == null) return new(false, $"Không tìm thấy map {id}");
return new(true)
{
Data = new MapSettingDefaultDto()
{
Id = map.Id,
EdgeStraightMaxSpeed = map.EdgeStraightMaxSpeedDefault,
EdgeCurveMaxSpeed = map.EdgeCurveMaxSpeedDefault,
EdgeMaxHeight = map.EdgeMaxHeightDefault,
EdgeMinHeight = map.EdgeMinHeightDefault,
EdgeMinLength = map.EdgeMinLengthDefault,
EdgeDirectionAllowed = map.EdgeDirectionAllowedDefault,
EdgeMaxRotationSpeed = map.EdgeMaxRotationSpeedDefault,
EdgeRotationAllowed = map.EdgeRotationAllowedDefault,
EdgeAllowedDeviationXy = map.EdgeAllowedDeviationXyDefault,
EdgeAllowedDeviationTheta = map.EdgeAllowedDeviationThetaDefault,
NodeAllowedDeviationTheta = map.NodeAllowedDeviationThetaDefault,
NodeAllowedDeviationXy = map.NodeAllowedDeviationXyDefault,
NodeNameAutoGenerate = map.NodeNameAutoGenerate,
NodeNameTemplate = map.NodeNameTemplateDefault,
ZoneMinSquare = map.ZoneMinSquareDefault,
},
};
}
[HttpPut]
[Route("")]
public async Task<MessageResult> Update([FromBody] MapSettingDefaultDto mapSetting)
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Id == mapSetting.Id);
if (map == null) return new(false, $"Không tìm thấy map {mapSetting.Id}");
map.EdgeStraightMaxSpeedDefault = mapSetting.EdgeStraightMaxSpeed;
map.EdgeCurveMaxSpeedDefault = mapSetting.EdgeCurveMaxSpeed;
map.EdgeMaxHeightDefault = mapSetting.EdgeMaxHeight;
map.EdgeMinHeightDefault = mapSetting.EdgeMinHeight;
map.EdgeMinLengthDefault = mapSetting.EdgeMinLength;
map.EdgeDirectionAllowedDefault = mapSetting.EdgeDirectionAllowed;
map.EdgeMaxRotationSpeedDefault = mapSetting.EdgeMaxRotationSpeed;
map.EdgeRotationAllowedDefault = mapSetting.EdgeRotationAllowed;
map.EdgeAllowedDeviationXyDefault = mapSetting.EdgeAllowedDeviationXy;
map.EdgeAllowedDeviationThetaDefault = mapSetting.EdgeAllowedDeviationTheta;
map.NodeAllowedDeviationThetaDefault = mapSetting.NodeAllowedDeviationTheta;
map.NodeAllowedDeviationXyDefault = mapSetting.NodeAllowedDeviationXy;
map.NodeNameAutoGenerate = mapSetting.NodeNameAutoGenerate;
map.NodeNameTemplateDefault = mapSetting.NodeNameTemplate;
map.ZoneMinSquareDefault = mapSetting.ZoneMinSquare;
MapDb.Maps.Update(map);
await MapDb.SaveChangesAsync();
return new(true);
}
}

View File

@@ -0,0 +1,58 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class NodesController(MapEditorDbContext MapDb) : ControllerBase
{
[HttpGet]
[Route("{mapId}")]
public async Task<NodeDto[]> GetNodes(Guid mapId)
{
return await (from node in MapDb.Nodes
where node.MapId == mapId
select new NodeDto()
{
Id = node.Id,
Name = node.Name,
MapId = mapId,
X = node.X,
Y = node.Y,
Theta = node.Theta,
AllowedDeviationXy = node.AllowedDeviationXy,
AllowedDeviationTheta = node.AllowedDeviationTheta,
Actions = node.Actions,
}).ToArrayAsync();
}
[HttpPut]
[Route("")]
public async Task<MessageResult> Update([FromBody] NodeUpdateModel model)
{
var node = await MapDb.Nodes.FindAsync(model.Id);
if (node == null) return new(false, $"Không tồn tại node id = {model.Id}");
if (node.Name != model.Name && !string.IsNullOrWhiteSpace(model.Name) && await MapDb.Nodes.AnyAsync(n => n.Name == model.Name && n.MapId == node.MapId))
{
return new(false, $"Tên node {model.Name} đã tồn tại trong map");
}
node.Name = model.Name;
node.X = model.X;
node.Y = model.Y;
node.Theta = model.Theta;
node.AllowedDeviationXy = model.AllowedDeviationXy;
node.AllowedDeviationTheta = model.AllowedDeviationTheta;
node.Actions = System.Text.Json.JsonSerializer.Serialize(model.Actions ?? []);
await MapDb.SaveChangesAsync();
return new(true);
}
}

View File

@@ -0,0 +1,232 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares;
using RobotNet.MapShares.Dtos;
using RobotNet.MapShares.Models;
using RobotNet.MapShares.Property;
using RobotNet.Shares;
using Serialize.Linq.Serializers;
using System.Linq.Expressions;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ScriptElementsController(MapEditorDbContext MapDb, LoggerController<ScriptElementsController> Logger) : ControllerBase
{
private static readonly ExpressionSerializer expressionSerializer;
static ScriptElementsController()
{
var jss = new Serialize.Linq.Serializers.JsonSerializer();
expressionSerializer = new ExpressionSerializer(jss);
expressionSerializer.AddKnownType(typeof(Script.Expressions.ElementProperties));
}
[HttpPost]
public async Task<MessageResult<IEnumerable<ElementDto>>> GetElementsWithCondition([FromBody] ElementExpressionModel model)
{
try
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == model.MapName);
if (map is null) return new(false, $"Không tồn tại map tên = {model.MapName}");
var elModel = await MapDb.ElementModels.FirstOrDefaultAsync(m => m.MapId == map.Id && m.Name == model.ModelName);
if (elModel is null) return new(false, $"Không tồn tại element model tên = {model.ModelName}");
var modelProperties = System.Text.Json.JsonSerializer.Deserialize<List<ElementProperty>>(elModel.Content, JsonOptionExtends.Read);
if (modelProperties is null || modelProperties.Count == 0)
return new(false, $"Không tồn tại property nào trong element model tên = {model.ModelName}");
var expr = expressionSerializer.DeserializeText(model.Expression);
var lambda = (Expression<Func<Script.Expressions.ElementProperties, bool>>)expr;
// Compile và chạy:
var func = lambda.Compile();
var elements = await MapDb.Elements.Where(e => e.MapId == map.Id && e.ModelId == elModel.Id).ToListAsync();
List<ElementDto> elementSatisfies = [];
foreach (var element in elements)
{
var properties = MapManagerExtensions.GetElementProperties(element.IsOpen, element.Content);
if (func.Invoke(properties))
{
var elNode = await MapDb.Nodes.FindAsync(element.NodeId);
if (elNode is null) continue; // Bỏ qua nếu không tìm thấy node
elementSatisfies.Add(new ElementDto()
{
Id = element.Id,
Name = element.Name,
MapId = element.MapId,
IsOpen = element.IsOpen,
NodeId = element.NodeId,
OffsetX = element.OffsetX,
OffsetY = element.OffsetY,
ModelId = element.ModelId,
Content = element.Content,
NodeName = elNode.Name,
ModelName = elModel.Name,
X = elNode.X,
Y = elNode.Y,
Theta = elNode.Theta
});
}
}
return new(true)
{
Data = elementSatisfies
};
}
catch (Exception ex)
{
Logger.Warning($"GetElement: Hệ thống có lỗi xảy ra - {ex}");
return new(false, $"Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpGet]
[Route("{mapName}/node/{nodeName}")]
public async Task<MessageResult<NodeDto>> GetNode([FromRoute] string mapName, [FromRoute] string nodeName)
{
try
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == mapName);
if (map is null) return new(false, $"Không tồn tại map tên = {mapName}");
var node = await MapDb.Nodes.FirstOrDefaultAsync(n => n.MapId == map.Id && n.Name == nodeName);
if (node is null) return new(false, $"Không tồn tại node {nodeName} trong map {mapName}");
return new(true)
{
Data = new NodeDto()
{
Id = node.Id,
Name = node.Name,
MapId = node.MapId,
X = node.X,
Y = node.Y,
Theta = node.Theta,
AllowedDeviationXy = node.AllowedDeviationXy,
AllowedDeviationTheta = node.AllowedDeviationTheta,
Actions = node.Actions,
}
};
}
catch (Exception ex)
{
Logger.Warning($"GetElement: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"GetElement: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpGet]
[Route("{mapName}/element/{elementName}")]
public async Task<MessageResult<ElementDto>> GetElement([FromRoute] string mapName, [FromRoute] string elementName)
{
try
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == mapName);
if (map is null) return new(false, $"Không tồn tại map tên = {mapName}");
var el = await MapDb.Elements.FirstOrDefaultAsync(e => e.MapId == map.Id && e.Name == elementName);
if (el is null) return new(false, $"Không tồn tại element name = {elementName}");
var elModel = await MapDb.ElementModels.FindAsync(el.ModelId);
if (elModel == null) return new(false, $"Không tồn tại element model id = {el.ModelId}");
var elNode = await MapDb.Nodes.FindAsync(el.NodeId);
if (elNode is null) return new(false, $"Không tồn tại node id = {el.NodeId}");
return new(true)
{
Data = new()
{
Id = el.Id,
Name = el.Name,
MapId = el.MapId,
IsOpen = el.IsOpen,
NodeId = el.NodeId,
OffsetX = el.OffsetX,
OffsetY = el.OffsetY,
ModelId = el.ModelId,
Content = el.Content,
NodeName = elNode.Name,
ModelName = elModel.Name,
X = elNode.X,
Y = elNode.Y,
Theta = elNode.Theta
}
};
}
catch (Exception ex)
{
Logger.Warning($"GetElement: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"GetElement: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPatch]
[Route("{mapName}/element/{elementName}")]
public async Task<MessageResult> UpdateElementProperty([FromRoute] string mapName, [FromRoute] string elementName, [FromBody] ElementPropertyUpdateModel model)
{
try
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == mapName);
if (map is null) return new(false, $"Không tồn tại map tên = {mapName}");
var element = await MapDb.Elements.FirstOrDefaultAsync(m => m.Name == elementName && m.MapId == map.Id);
if (element == null) return new(false, $"Không tồn tại element tên = {elementName} trong map tên = {mapName}");
var properties = System.Text.Json.JsonSerializer.Deserialize<List<ElementProperty>>(element.Content, JsonOptionExtends.Read);
foreach (var property in model.Properties)
{
var existingProperty = properties?.FirstOrDefault(p => p.Name == property.Name);
if (existingProperty != null)
{
existingProperty.DefaultValue = property.DefaultValue;
}
else return new(false, $"Không tồn tại property name = {property.Name} trong element");
}
var content = System.Text.Json.JsonSerializer.Serialize(properties, JsonOptionExtends.Write);
element.Content = content;
await MapDb.SaveChangesAsync();
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
[HttpPatch]
[Route("{mapName}/element/{elementName}/IsOpen")]
public async Task<MessageResult> UpdateOpenOfElement([FromRoute] string mapName, [FromRoute] string elementName, [FromQuery] bool isOpen)
{
try
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == mapName);
if (map is null) return new(false, $"Không tồn tại map tên = {mapName}");
var element = await MapDb.Elements.FirstOrDefaultAsync(m => m.Name == elementName && m.MapId == map.Id);
if (element == null) return new(false, $"Không tồn tại element tên = {elementName} trong map tên = {mapName}");
element.IsOpen = isOpen;
await MapDb.SaveChangesAsync();
return new(true);
}
catch (Exception ex)
{
Logger.Warning($"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
}

View File

@@ -0,0 +1,114 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Services;
using RobotNet.MapShares;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
namespace RobotNet.MapManager.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ZonesController(MapEditorDbContext MapDb, LoggerController<ZonesController> Logger) : ControllerBase
{
[HttpPost]
[Route("")]
public async Task<MessageResult<ZoneDto>> Create([FromBody] ZoneCreateModel zone)
{
try
{
var map = await MapDb.Maps.FindAsync(zone.MapId);
if (map == null) return new(false, $"Không tồn tại map id = {zone.MapId}");
if (MapEditorHelper.CalculateQuadrilateralArea(zone.X1, zone.Y1, zone.X2, zone.Y2, zone.X3, zone.Y3, zone.X4, zone.Y4) < map.ZoneMinSquareDefault)
return new(false, "Kích thước Zone quá nhỏ");
var entity = await MapDb.Zones.AddAsync(new()
{
MapId = zone.MapId,
Type = zone.Type,
Name = "",
X1 = zone.X1,
X2 = zone.X2,
X3 = zone.X3,
X4 = zone.X4,
Y1 = zone.Y1,
Y2 = zone.Y2,
Y3 = zone.Y3,
Y4 = zone.Y4,
});
await MapDb.SaveChangesAsync();
return new(true)
{
Data = new ZoneDto() { Id = entity.Entity.Id, MapId = entity.Entity.MapId, Type = entity.Entity.Type, X1 = entity.Entity.X1, X2 = entity.Entity.X2, X3 = entity.Entity.X3, X4 = entity.Entity.X4, Y1 = entity.Entity.Y1, Y2 = entity.Entity.Y2, Y3 = entity.Entity.Y3, Y4 = entity.Entity.Y4 }
};
}
catch (Exception ex)
{
Logger.Warning($"Create: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, "Hệ thống có lỗi xảy ra");
}
}
[HttpDelete]
[Route("{id}")]
public async Task<MessageResult> Delete(Guid id)
{
try
{
var zoneExisted = await MapDb.Zones.FindAsync(id);
if (zoneExisted is not null)
{
MapDb.Zones.Remove(zoneExisted);
await MapDb.SaveChangesAsync();
return new(true);
}
return new(false, "Hệ thống không tìm thấy khu vực Zone này");
}
catch (Exception ex)
{
Logger.Warning($"Delete {id}: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, "Hệ thống có lỗi xảy ra");
}
}
[HttpPut]
[Route("")]
public async Task<MessageResult> Update([FromBody] ZoneUpdateModel zone)
{
try
{
var zoneExisted = await MapDb.Zones.FindAsync(zone.Id);
if (zoneExisted is not null)
{
if (zoneExisted.Name != zone.Name && !string.IsNullOrWhiteSpace(zone.Name) && await MapDb.Zones.AnyAsync(z => z.Name == zone.Name && z.MapId == zoneExisted.MapId))
{
return new(false, $"Tên zone {zone.Name} đã tồn tại trong map");
}
zoneExisted.Type = zone.Type;
zoneExisted.Name = zone.Name;
zoneExisted.X1 = zone.X1;
zoneExisted.X2 = zone.X2;
zoneExisted.X3 = zone.X3;
zoneExisted.X4 = zone.X4;
zoneExisted.Y1 = zone.Y1;
zoneExisted.Y2 = zone.Y2;
zoneExisted.Y3 = zone.Y3;
zoneExisted.Y4 = zone.Y4;
MapDb.Zones.Update(zoneExisted);
await MapDb.SaveChangesAsync();
return new(true);
}
return new(false, "Hệ thống không tìm thấy khu vực Zone này");
}
catch (Exception ex)
{
Logger.Warning($"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
return new(false, $"Update: Hệ thống có lỗi xảy ra - {ex.Message}");
}
}
}

View File

@@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace RobotNet.MapManager.Data;
#nullable disable
[Table("Actions")]
[Index(nameof(MapId), nameof(Name), Name = "IX_Action_MapId_Name")]
public class Action
{
[Column("Id", TypeName = "uniqueidentifier")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Required]
public Guid Id { get; set; }
[Column("MapId", TypeName = "uniqueidentifier")]
[Required]
public Guid MapId { get; set; }
[Column("Name", TypeName = "nvarchar(64)")]
public string Name { get; set; }
[Column("Content", TypeName = "nvarchar(max)")]
public string Content { get; set; }
public Map Map { get; set; }
}

View File

@@ -0,0 +1,77 @@
using Microsoft.EntityFrameworkCore;
using RobotNet.MapShares.Enums;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace RobotNet.MapManager.Data;
#nullable disable
[Table("Edges")]
[Index(nameof(MapId), Name = "IX_Edge_MapId")]
public class Edge
{
[Column("Id", TypeName = "uniqueidentifier")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Required]
public Guid Id { get; set; }
[Column("MapId", TypeName = "uniqueidentifier")]
[Required]
public Guid MapId { get; set; }
[Column("StartNodeId", TypeName = "uniqueidentifier")]
[Required]
public Guid StartNodeId { get; set; }
[Column("EndNodeId", TypeName = "uniqueidentifier")]
[Required]
public Guid EndNodeId { get; set; }
[Column("ControlPoint1X", TypeName = "float")]
public double ControlPoint1X { get; set; }
[Column("ControlPoint1Y", TypeName = "float")]
public double ControlPoint1Y { get; set; }
[Column("ControlPoint2X", TypeName = "float")]
public double ControlPoint2X { get; set; }
[Column("ControlPoint2Y", TypeName = "float")]
public double ControlPoint2Y { get; set; }
[Column("TrajectoryDegree", TypeName = "tinyint")]
public TrajectoryDegree TrajectoryDegree { get; set; }
[Column("MaxHeight", TypeName = "float")]
public double MaxHeight { get; set; }
[Column("MinHeight", TypeName = "float")]
public double MinHeight { get; set; }
[Column("DirectionAllowed", TypeName = "tinyint")]
public DirectionAllowed DirectionAllowed { get; set; }
[Column("RotationAllowed", TypeName = "bit")]
public bool RotationAllowed { get; set; }
[Column("MaxRotationSpeed", TypeName = "float")]
public double MaxRotationSpeed { get; set; }
[Column("MaxSpeed", TypeName = "float")]
public double MaxSpeed { get; set; }
[Column("AllowedDeviationXy", TypeName = "float")]
public double AllowedDeviationXy { get; set; }
[Column("AllowedDeviationTheta", TypeName = "float")]
public double AllowedDeviationTheta { get; set; }
[Column("Actions", TypeName = "nvarchar(max)")]
public string Actions { get; set; }
public Map Map { get; set; }
public virtual Node StartNode { get; set; }
public virtual Node EndNode { get; set; }
}

View File

@@ -0,0 +1,49 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace RobotNet.MapManager.Data;
#nullable disable
[Table("Elements")]
[Index(nameof(MapId), nameof(ModelId), Name = "IX_Element_MapId_ModelId")]
public class Element
{
[Column("Id", TypeName = "uniqueidentifier")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Required]
public Guid Id { get; set; }
[Column("MapId", TypeName = "uniqueidentifier")]
[Required]
public Guid MapId { get; set; }
[Column("ModelId", TypeName = "uniqueidentifier")]
[Required]
public Guid ModelId { get; set; }
[Column("NodeId", TypeName = "uniqueidentifier")]
[Required]
public Guid NodeId { get; set; }
[Column("Name", TypeName = "nvarchar(64)")]
public string Name { get; set; }
[Column("IsOpen", TypeName = "bit")]
public bool IsOpen { get; set; }
[Column("OffsetX", TypeName = "float")]
public double OffsetX { get; set; }
[Column("OffsetY", TypeName = "float")]
public double OffsetY { get; set; }
[Column("Content", TypeName = "nvarchar(max)")]
public string Content { get; set; }
public Map Map { get; set; }
public ElementModel Model { get; set; }
public Node Node { get; set; }
}

View File

@@ -0,0 +1,55 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace RobotNet.MapManager.Data;
#nullable disable
[Table("ElementModels")]
[Index(nameof(MapId), nameof(Name), Name = "IX_ElementModel_MapId_Name")]
public class ElementModel
{
[Column("Id", TypeName = "uniqueidentifier")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Required]
public Guid Id { get; set; }
[Column("MapId", TypeName = "uniqueidentifier")]
[Required]
public Guid MapId { get; set; }
[Column("Name", TypeName = "nvarchar(64)")]
public string Name { get; set; }
[Column("Width", TypeName = "float")]
[Required]
public double Width { get; set; }
[Column("Height", TypeName = "float")]
[Required]
public double Height { get; set; }
[Column("Image1Width", TypeName = "int")]
[Required]
public int Image1Width { get; set; }
[Column("Image1Height", TypeName = "int")]
[Required]
public int Image1Height { get; set; }
[Column("Image2Width", TypeName = "int")]
[Required]
public int Image2Width { get; set; }
[Column("Image2Height", TypeName = "int")]
[Required]
public int Image2Height { get; set; }
[Column("Content", TypeName = "nvarchar(max)")]
public string Content { get; set; }
public virtual ICollection<Element> Elements { get; } = [];
public Map Map { get; set; }
}

View File

@@ -0,0 +1,125 @@
using RobotNet.MapShares.Enums;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace RobotNet.MapManager.Data;
#nullable disable
[Table("Maps")]
public class Map
{
[Column("Id", TypeName = "uniqueidentifier")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Required]
public Guid Id { get; set; }
[Column("Name", TypeName = "nvarchar(64)")]
[Required]
public string Name { get; set; }
[Column("Description", TypeName = "ntext")]
public string Description { get; set; } = "";
[Column("VersionId", TypeName = "uniqueidentifier")]
[Required]
public Guid VersionId { get; set; }
[Column("OriginX", TypeName = "float")]
[Required]
public double OriginX { get; set; }
[Column("OriginY", TypeName = "float")]
[Required]
public double OriginY { get; set; }
[Column("Resolution", TypeName = "float")]
[Required]
public double Resolution { get; set; }
[Column("ViewX", TypeName = "float")]
[Required]
public double ViewX { get; set; }
[Column("ViewY", TypeName = "float")]
[Required]
public double ViewY { get; set; }
[Column("ViewWidth", TypeName = "float")]
[Required]
public double ViewWidth { get; set; }
[Column("ViewHeight", TypeName = "float")]
[Required]
public double ViewHeight { get; set; }
[Column("ImageWidth", TypeName = "float")]
[Required]
public double ImageWidth { get; set; }
[Column("ImageHeight", TypeName = "float")]
[Required]
public double ImageHeight { get; set; }
[Column("NodeCount", TypeName = "BigInt")]
public Int64 NodeCount { get; set; }
[Column("Active", TypeName = "bit")]
public bool Active { get; set; }
[Column("VDA5050", TypeName = "nvarchar(max)")]
public string VDA5050 { get; set; } = ""; //AdditionalAttributes
[Column("NodeNameAutoGenerate", TypeName = "bit")]
public bool NodeNameAutoGenerate { get; set; }
[Column("NodeNameTemplateDefault", TypeName = "nvarchar(64)")]
public string NodeNameTemplateDefault { get; set; }
[Column("NodeAllowedDeviationXyDefault", TypeName = "float")]
public double NodeAllowedDeviationXyDefault { get; set; }
[Column("NodeAllowedDeviationThetaDefault", TypeName = "float")]
public double NodeAllowedDeviationThetaDefault { get; set; }
[Column("EdgeMinLengthDefault", TypeName = "float")]
public double EdgeMinLengthDefault { get; set; }
[Column("EdgeStraightMaxSpeedDefault", TypeName = "float")]
public double EdgeStraightMaxSpeedDefault { get; set; }
[Column("EdgeCurveMaxSpeedDefault", TypeName = "float")]
public double EdgeCurveMaxSpeedDefault { get; set; }
[Column("EdgeMaxHeightDefault", TypeName = "float")]
public double EdgeMaxHeightDefault { get; set; }
[Column("EdgeMinHeightDefault", TypeName = "float")]
public double EdgeMinHeightDefault { get; set; }
[Column("EdgeMaxRoataionSpeedDefault", TypeName = "float")]
public double EdgeMaxRotationSpeedDefault { get; set; }
[Column("EdgeDirectionAllowedDefault", TypeName = "tinyint")]
public DirectionAllowed EdgeDirectionAllowedDefault { get; set; }
[Column("EdgeRotationAllowedDefault", TypeName = "bit")]
public bool EdgeRotationAllowedDefault { get; set; }
[Column("EdgeAllowedDeviationXyDefault", TypeName = "float")]
public double EdgeAllowedDeviationXyDefault { get; set; }
[Column("EdgeAllowedDeviationThetaDefault", TypeName = "float")]
public double EdgeAllowedDeviationThetaDefault { get; set; }
[Column("ZoneMinSquareDefault", TypeName = "float")]
public double ZoneMinSquareDefault { get; set; }
public virtual ICollection<Node> Nodes { get; } = [];
public virtual ICollection<Edge> Edges { get; } = [];
public virtual ICollection<Action> Actions { get; } = [];
public virtual ICollection<Zone> Zones { get; } = [];
public virtual ICollection<ElementModel> ElementModels { get; } = [];
public virtual ICollection<Element> Elements { get; } = [];
}

View File

@@ -0,0 +1,90 @@
using Microsoft.EntityFrameworkCore;
namespace RobotNet.MapManager.Data;
public class MapEditorDbContext(DbContextOptions<MapEditorDbContext> options) : DbContext(options)
{
public DbSet<Map> Maps { get; private set; }
public DbSet<Node> Nodes { get; private set; }
public DbSet<Edge> Edges { get; private set; }
public DbSet<Zone> Zones { get; private set; }
public DbSet<Action> Actions { get; private set; }
public DbSet<ElementModel> ElementModels { get; private set; }
public DbSet<Element> Elements { get; private set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Map>()
.HasMany(e => e.Actions)
.WithOne(e => e.Map)
.HasForeignKey(e => e.MapId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Map>()
.HasMany(e => e.Edges)
.WithOne(e => e.Map)
.HasForeignKey(e => e.MapId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Map>()
.HasMany(e => e.Nodes)
.WithOne(e => e.Map)
.HasForeignKey(e => e.MapId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Map>()
.HasMany(e => e.Zones)
.WithOne(e => e.Map)
.HasForeignKey(e => e.MapId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Edge>()
.HasOne(e => e.StartNode)
.WithMany(n => n.StartEdges)
.HasForeignKey(e => e.StartNodeId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Edge>()
.HasOne(e => e.EndNode)
.WithMany(n => n.EndEdges)
.HasForeignKey(e => e.EndNodeId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Map>()
.HasMany(e => e.ElementModels)
.WithOne(e => e.Map)
.HasForeignKey(e => e.MapId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Map>()
.HasMany(e => e.Elements)
.WithOne(e => e.Map)
.HasForeignKey(e => e.MapId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Node>()
.HasOne(n => n.Element)
.WithOne(e => e.Node)
.HasForeignKey<Element>(e => e.NodeId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<ElementModel>()
.HasMany(e => e.Elements)
.WithOne(e => e.Model)
.HasForeignKey(e => e.ModelId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
base.OnModelCreating(modelBuilder);
}
}

View File

@@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore;
namespace RobotNet.MapManager.Data;
public static class MapManagerDbExtensions
{
public static async Task SeedMapManagerDbAsync(this IServiceProvider serviceProvider)
{
using var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
using var appDb = scope.ServiceProvider.GetRequiredService<MapEditorDbContext>();
await appDb.Database.MigrateAsync();
//await appDb.Database.EnsureCreatedAsync();
await appDb.SaveChangesAsync();
}
}

View File

@@ -0,0 +1,603 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RobotNet.MapManager.Data;
#nullable disable
namespace RobotNet.MapManager.Data.Migrations
{
[DbContext(typeof(MapEditorDbContext))]
[Migration("20250425030649_AddMapdb")]
partial class AddMapdb
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("RobotNet.MapManager.Data.Action", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_Action_MapId_Name");
b.ToTable("Actions");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Edge", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Actions")
.HasColumnType("nvarchar(max)")
.HasColumnName("Actions");
b.Property<double>("AllowedDeviationTheta")
.HasColumnType("float")
.HasColumnName("AllowedDeviationTheta");
b.Property<double>("AllowedDeviationXy")
.HasColumnType("float")
.HasColumnName("AllowedDeviationXy");
b.Property<double>("ControlPoint1X")
.HasColumnType("float")
.HasColumnName("ControlPoint1X");
b.Property<double>("ControlPoint1Y")
.HasColumnType("float")
.HasColumnName("ControlPoint1Y");
b.Property<double>("ControlPoint2X")
.HasColumnType("float")
.HasColumnName("ControlPoint2X");
b.Property<double>("ControlPoint2Y")
.HasColumnType("float")
.HasColumnName("ControlPoint2Y");
b.Property<byte>("DirectionAllowed")
.HasColumnType("tinyint")
.HasColumnName("DirectionAllowed");
b.Property<Guid>("EndNodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("EndNodeId");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<double>("MaxHeight")
.HasColumnType("float")
.HasColumnName("MaxHeight");
b.Property<double>("MaxRotationSpeed")
.HasColumnType("float")
.HasColumnName("MaxRotationSpeed");
b.Property<double>("MaxSpeed")
.HasColumnType("float")
.HasColumnName("MaxSpeed");
b.Property<double>("MinHeight")
.HasColumnType("float")
.HasColumnName("MinHeight");
b.Property<bool>("RotationAllowed")
.HasColumnType("bit")
.HasColumnName("RotationAllowed");
b.Property<Guid>("StartNodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("StartNodeId");
b.Property<byte>("TrajectoryDegree")
.HasColumnType("tinyint")
.HasColumnName("TrajectoryDegree");
b.HasKey("Id");
b.HasIndex("EndNodeId");
b.HasIndex("StartNodeId");
b.HasIndex(new[] { "MapId" }, "IX_Edge_MapId");
b.ToTable("Edges");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Element", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<bool>("IsOpen")
.HasColumnType("bit")
.HasColumnName("IsOpen");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<Guid>("ModelId")
.HasColumnType("uniqueidentifier")
.HasColumnName("ModelId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<Guid>("NodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("NodeId");
b.Property<double>("OffsetX")
.HasColumnType("float")
.HasColumnName("OffsetX");
b.Property<double>("OffsetY")
.HasColumnType("float")
.HasColumnName("OffsetY");
b.HasKey("Id");
b.HasIndex("ModelId");
b.HasIndex("NodeId")
.IsUnique();
b.HasIndex(new[] { "MapId", "ModelId" }, "IX_Element_MapId_ModelId");
b.ToTable("Elements");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<double>("Height")
.HasColumnType("float")
.HasColumnName("Height");
b.Property<int>("Image1Height")
.HasColumnType("int")
.HasColumnName("Image1Height");
b.Property<int>("Image1Width")
.HasColumnType("int")
.HasColumnName("Image1Width");
b.Property<int>("Image2Height")
.HasColumnType("int")
.HasColumnName("Image2Height");
b.Property<int>("Image2Width")
.HasColumnType("int")
.HasColumnName("Image2Width");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("Width")
.HasColumnType("float")
.HasColumnName("Width");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_ElementModel_MapId_Name");
b.ToTable("ElementModels");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Map", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<bool>("Active")
.HasColumnType("bit")
.HasColumnName("Active");
b.Property<string>("Description")
.HasColumnType("ntext")
.HasColumnName("Description");
b.Property<double>("EdgeAllowedDeviationThetaDefault")
.HasColumnType("float")
.HasColumnName("EdgeAllowedDeviationThetaDefault");
b.Property<double>("EdgeAllowedDeviationXyDefault")
.HasColumnType("float")
.HasColumnName("EdgeAllowedDeviationXyDefault");
b.Property<double>("EdgeCurveMaxSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeCurveMaxSpeedDefault");
b.Property<byte>("EdgeDirectionAllowedDefault")
.HasColumnType("tinyint")
.HasColumnName("EdgeDirectionAllowedDefault");
b.Property<double>("EdgeMaxHeightDefault")
.HasColumnType("float")
.HasColumnName("EdgeMaxHeightDefault");
b.Property<double>("EdgeMaxRotationSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeMaxRoataionSpeedDefault");
b.Property<double>("EdgeMinHeightDefault")
.HasColumnType("float")
.HasColumnName("EdgeMinHeightDefault");
b.Property<double>("EdgeMinLengthDefault")
.HasColumnType("float")
.HasColumnName("EdgeMinLengthDefault");
b.Property<bool>("EdgeRotationAllowedDefault")
.HasColumnType("bit")
.HasColumnName("EdgeRotationAllowedDefault");
b.Property<double>("EdgeStraightMaxSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeStraightMaxSpeedDefault");
b.Property<double>("ImageHeight")
.HasColumnType("float")
.HasColumnName("ImageHeight");
b.Property<double>("ImageWidth")
.HasColumnType("float")
.HasColumnName("ImageWidth");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("NodeAllowedDeviationThetaDefault")
.HasColumnType("float")
.HasColumnName("NodeAllowedDeviationThetaDefault");
b.Property<double>("NodeAllowedDeviationXyDefault")
.HasColumnType("float")
.HasColumnName("NodeAllowedDeviationXyDefault");
b.Property<long>("NodeCount")
.HasColumnType("BigInt")
.HasColumnName("NodeCount");
b.Property<bool>("NodeNameAutoGenerate")
.HasColumnType("bit")
.HasColumnName("NodeNameAutoGenerate");
b.Property<string>("NodeNameTemplateDefault")
.HasColumnType("nvarchar(64)")
.HasColumnName("NodeNameTemplateDefault");
b.Property<double>("OriginX")
.HasColumnType("float")
.HasColumnName("OriginX");
b.Property<double>("OriginY")
.HasColumnType("float")
.HasColumnName("OriginY");
b.Property<double>("Resolution")
.HasColumnType("float")
.HasColumnName("Resolution");
b.Property<string>("VDA5050")
.HasColumnType("nvarchar(max)")
.HasColumnName("VDA5050");
b.Property<Guid>("VersionId")
.HasColumnType("uniqueidentifier")
.HasColumnName("VersionId");
b.Property<double>("ViewHeight")
.HasColumnType("float")
.HasColumnName("ViewHeight");
b.Property<double>("ViewWidth")
.HasColumnType("float")
.HasColumnName("ViewWidth");
b.Property<double>("ViewX")
.HasColumnType("float")
.HasColumnName("ViewX");
b.Property<double>("ViewY")
.HasColumnType("float")
.HasColumnName("ViewY");
b.Property<double>("ZoneMinSquareDefault")
.HasColumnType("float")
.HasColumnName("ZoneMinSquareDefault");
b.HasKey("Id");
b.ToTable("Maps");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Actions")
.HasColumnType("nvarchar(max)")
.HasColumnName("Actions");
b.Property<double>("AllowedDeviationTheta")
.HasColumnType("float")
.HasColumnName("AllowedDeviationTheta");
b.Property<double>("AllowedDeviationXy")
.HasColumnType("float")
.HasColumnName("AllowedDeviationXy");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("Theta")
.HasColumnType("float")
.HasColumnName("Theta");
b.Property<double>("X")
.HasColumnType("float")
.HasColumnName("X");
b.Property<double>("Y")
.HasColumnType("float")
.HasColumnName("Y");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_Node_MapId_Name");
b.ToTable("Nodes");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Zone", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<int>("Type")
.HasColumnType("int")
.HasColumnName("Type");
b.Property<double>("X1")
.HasColumnType("float")
.HasColumnName("X1");
b.Property<double>("X2")
.HasColumnType("float")
.HasColumnName("X2");
b.Property<double>("X3")
.HasColumnType("float")
.HasColumnName("X3");
b.Property<double>("X4")
.HasColumnType("float")
.HasColumnName("X4");
b.Property<double>("Y1")
.HasColumnType("float")
.HasColumnName("Y1");
b.Property<double>("Y2")
.HasColumnType("float")
.HasColumnName("Y2");
b.Property<double>("Y3")
.HasColumnType("float")
.HasColumnName("Y3");
b.Property<double>("Y4")
.HasColumnType("float")
.HasColumnName("Y4");
b.HasKey("Id");
b.HasIndex(new[] { "MapId" }, "IX_Zone_MapId");
b.ToTable("Zones");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Action", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Actions")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Edge", b =>
{
b.HasOne("RobotNet.MapManager.Data.Node", "EndNode")
.WithMany("EndEdges")
.HasForeignKey("EndNodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Edges")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Node", "StartNode")
.WithMany("StartEdges")
.HasForeignKey("StartNodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("EndNode");
b.Navigation("Map");
b.Navigation("StartNode");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Element", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Elements")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.ElementModel", "Model")
.WithMany("Elements")
.HasForeignKey("ModelId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Node", "Node")
.WithOne("Element")
.HasForeignKey("RobotNet.MapManager.Data.Element", "NodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
b.Navigation("Model");
b.Navigation("Node");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("ElementModels")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Nodes")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Zone", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Zones")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.Navigation("Elements");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Map", b =>
{
b.Navigation("Actions");
b.Navigation("Edges");
b.Navigation("ElementModels");
b.Navigation("Elements");
b.Navigation("Nodes");
b.Navigation("Zones");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.Navigation("Element");
b.Navigation("EndEdges");
b.Navigation("StartEdges");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,313 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace RobotNet.MapManager.Data.Migrations
{
/// <inheritdoc />
public partial class AddMapdb : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Maps",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", nullable: false),
Description = table.Column<string>(type: "ntext", nullable: true),
VersionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
OriginX = table.Column<double>(type: "float", nullable: false),
OriginY = table.Column<double>(type: "float", nullable: false),
Resolution = table.Column<double>(type: "float", nullable: false),
ViewX = table.Column<double>(type: "float", nullable: false),
ViewY = table.Column<double>(type: "float", nullable: false),
ViewWidth = table.Column<double>(type: "float", nullable: false),
ViewHeight = table.Column<double>(type: "float", nullable: false),
ImageWidth = table.Column<double>(type: "float", nullable: false),
ImageHeight = table.Column<double>(type: "float", nullable: false),
NodeCount = table.Column<long>(type: "BigInt", nullable: false),
Active = table.Column<bool>(type: "bit", nullable: false),
VDA5050 = table.Column<string>(type: "nvarchar(max)", nullable: true),
NodeNameAutoGenerate = table.Column<bool>(type: "bit", nullable: false),
NodeNameTemplateDefault = table.Column<string>(type: "nvarchar(64)", nullable: true),
NodeAllowedDeviationXyDefault = table.Column<double>(type: "float", nullable: false),
NodeAllowedDeviationThetaDefault = table.Column<double>(type: "float", nullable: false),
EdgeMinLengthDefault = table.Column<double>(type: "float", nullable: false),
EdgeStraightMaxSpeedDefault = table.Column<double>(type: "float", nullable: false),
EdgeCurveMaxSpeedDefault = table.Column<double>(type: "float", nullable: false),
EdgeMaxHeightDefault = table.Column<double>(type: "float", nullable: false),
EdgeMinHeightDefault = table.Column<double>(type: "float", nullable: false),
EdgeMaxRoataionSpeedDefault = table.Column<double>(type: "float", nullable: false),
EdgeDirectionAllowedDefault = table.Column<byte>(type: "tinyint", nullable: false),
EdgeRotationAllowedDefault = table.Column<bool>(type: "bit", nullable: false),
EdgeAllowedDeviationXyDefault = table.Column<double>(type: "float", nullable: false),
EdgeAllowedDeviationThetaDefault = table.Column<double>(type: "float", nullable: false),
ZoneMinSquareDefault = table.Column<double>(type: "float", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Maps", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Actions",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MapId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", nullable: true),
Content = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Actions", x => x.Id);
table.ForeignKey(
name: "FK_Actions_Maps_MapId",
column: x => x.MapId,
principalTable: "Maps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "ElementModels",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MapId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", nullable: true),
Width = table.Column<double>(type: "float", nullable: false),
Height = table.Column<double>(type: "float", nullable: false),
Image1Width = table.Column<int>(type: "int", nullable: false),
Image1Height = table.Column<int>(type: "int", nullable: false),
Image2Width = table.Column<int>(type: "int", nullable: false),
Image2Height = table.Column<int>(type: "int", nullable: false),
Content = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ElementModels", x => x.Id);
table.ForeignKey(
name: "FK_ElementModels_Maps_MapId",
column: x => x.MapId,
principalTable: "Maps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Nodes",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MapId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", nullable: true),
X = table.Column<double>(type: "float", nullable: false),
Y = table.Column<double>(type: "float", nullable: false),
Theta = table.Column<double>(type: "float", nullable: false),
AllowedDeviationXy = table.Column<double>(type: "float", nullable: false),
AllowedDeviationTheta = table.Column<double>(type: "float", nullable: false),
Actions = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Nodes", x => x.Id);
table.ForeignKey(
name: "FK_Nodes_Maps_MapId",
column: x => x.MapId,
principalTable: "Maps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Zones",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MapId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Type = table.Column<int>(type: "int", nullable: false),
X1 = table.Column<double>(type: "float", nullable: false),
Y1 = table.Column<double>(type: "float", nullable: false),
X2 = table.Column<double>(type: "float", nullable: false),
Y2 = table.Column<double>(type: "float", nullable: false),
X3 = table.Column<double>(type: "float", nullable: false),
Y3 = table.Column<double>(type: "float", nullable: false),
X4 = table.Column<double>(type: "float", nullable: false),
Y4 = table.Column<double>(type: "float", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Zones", x => x.Id);
table.ForeignKey(
name: "FK_Zones_Maps_MapId",
column: x => x.MapId,
principalTable: "Maps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Edges",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MapId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
StartNodeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
EndNodeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ControlPoint1X = table.Column<double>(type: "float", nullable: false),
ControlPoint1Y = table.Column<double>(type: "float", nullable: false),
ControlPoint2X = table.Column<double>(type: "float", nullable: false),
ControlPoint2Y = table.Column<double>(type: "float", nullable: false),
TrajectoryDegree = table.Column<byte>(type: "tinyint", nullable: false),
MaxHeight = table.Column<double>(type: "float", nullable: false),
MinHeight = table.Column<double>(type: "float", nullable: false),
DirectionAllowed = table.Column<byte>(type: "tinyint", nullable: false),
RotationAllowed = table.Column<bool>(type: "bit", nullable: false),
MaxRotationSpeed = table.Column<double>(type: "float", nullable: false),
MaxSpeed = table.Column<double>(type: "float", nullable: false),
AllowedDeviationXy = table.Column<double>(type: "float", nullable: false),
AllowedDeviationTheta = table.Column<double>(type: "float", nullable: false),
Actions = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Edges", x => x.Id);
table.ForeignKey(
name: "FK_Edges_Maps_MapId",
column: x => x.MapId,
principalTable: "Maps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Edges_Nodes_EndNodeId",
column: x => x.EndNodeId,
principalTable: "Nodes",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Edges_Nodes_StartNodeId",
column: x => x.StartNodeId,
principalTable: "Nodes",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Elements",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MapId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ModelId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
NodeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", nullable: true),
IsOpen = table.Column<bool>(type: "bit", nullable: false),
OffsetX = table.Column<double>(type: "float", nullable: false),
OffsetY = table.Column<double>(type: "float", nullable: false),
Content = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Elements", x => x.Id);
table.ForeignKey(
name: "FK_Elements_ElementModels_ModelId",
column: x => x.ModelId,
principalTable: "ElementModels",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Elements_Maps_MapId",
column: x => x.MapId,
principalTable: "Maps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Elements_Nodes_NodeId",
column: x => x.NodeId,
principalTable: "Nodes",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_Action_MapId_Name",
table: "Actions",
columns: new[] { "MapId", "Name" });
migrationBuilder.CreateIndex(
name: "IX_Edge_MapId",
table: "Edges",
column: "MapId");
migrationBuilder.CreateIndex(
name: "IX_Edges_EndNodeId",
table: "Edges",
column: "EndNodeId");
migrationBuilder.CreateIndex(
name: "IX_Edges_StartNodeId",
table: "Edges",
column: "StartNodeId");
migrationBuilder.CreateIndex(
name: "IX_ElementModel_MapId_Name",
table: "ElementModels",
columns: new[] { "MapId", "Name" });
migrationBuilder.CreateIndex(
name: "IX_Element_MapId_ModelId",
table: "Elements",
columns: new[] { "MapId", "ModelId" });
migrationBuilder.CreateIndex(
name: "IX_Elements_ModelId",
table: "Elements",
column: "ModelId");
migrationBuilder.CreateIndex(
name: "IX_Elements_NodeId",
table: "Elements",
column: "NodeId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Node_MapId_Name",
table: "Nodes",
columns: new[] { "MapId", "Name" });
migrationBuilder.CreateIndex(
name: "IX_Zone_MapId",
table: "Zones",
column: "MapId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Actions");
migrationBuilder.DropTable(
name: "Edges");
migrationBuilder.DropTable(
name: "Elements");
migrationBuilder.DropTable(
name: "Zones");
migrationBuilder.DropTable(
name: "ElementModels");
migrationBuilder.DropTable(
name: "Nodes");
migrationBuilder.DropTable(
name: "Maps");
}
}
}

View File

@@ -0,0 +1,608 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RobotNet.MapManager.Data;
#nullable disable
namespace RobotNet.MapManager.Data.Migrations
{
[DbContext(typeof(MapEditorDbContext))]
[Migration("20250812041834_AddZoneName")]
partial class AddZoneName
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("RobotNet.MapManager.Data.Action", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_Action_MapId_Name");
b.ToTable("Actions");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Edge", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Actions")
.HasColumnType("nvarchar(max)")
.HasColumnName("Actions");
b.Property<double>("AllowedDeviationTheta")
.HasColumnType("float")
.HasColumnName("AllowedDeviationTheta");
b.Property<double>("AllowedDeviationXy")
.HasColumnType("float")
.HasColumnName("AllowedDeviationXy");
b.Property<double>("ControlPoint1X")
.HasColumnType("float")
.HasColumnName("ControlPoint1X");
b.Property<double>("ControlPoint1Y")
.HasColumnType("float")
.HasColumnName("ControlPoint1Y");
b.Property<double>("ControlPoint2X")
.HasColumnType("float")
.HasColumnName("ControlPoint2X");
b.Property<double>("ControlPoint2Y")
.HasColumnType("float")
.HasColumnName("ControlPoint2Y");
b.Property<byte>("DirectionAllowed")
.HasColumnType("tinyint")
.HasColumnName("DirectionAllowed");
b.Property<Guid>("EndNodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("EndNodeId");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<double>("MaxHeight")
.HasColumnType("float")
.HasColumnName("MaxHeight");
b.Property<double>("MaxRotationSpeed")
.HasColumnType("float")
.HasColumnName("MaxRotationSpeed");
b.Property<double>("MaxSpeed")
.HasColumnType("float")
.HasColumnName("MaxSpeed");
b.Property<double>("MinHeight")
.HasColumnType("float")
.HasColumnName("MinHeight");
b.Property<bool>("RotationAllowed")
.HasColumnType("bit")
.HasColumnName("RotationAllowed");
b.Property<Guid>("StartNodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("StartNodeId");
b.Property<byte>("TrajectoryDegree")
.HasColumnType("tinyint")
.HasColumnName("TrajectoryDegree");
b.HasKey("Id");
b.HasIndex("EndNodeId");
b.HasIndex("StartNodeId");
b.HasIndex(new[] { "MapId" }, "IX_Edge_MapId");
b.ToTable("Edges");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Element", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<bool>("IsOpen")
.HasColumnType("bit")
.HasColumnName("IsOpen");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<Guid>("ModelId")
.HasColumnType("uniqueidentifier")
.HasColumnName("ModelId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<Guid>("NodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("NodeId");
b.Property<double>("OffsetX")
.HasColumnType("float")
.HasColumnName("OffsetX");
b.Property<double>("OffsetY")
.HasColumnType("float")
.HasColumnName("OffsetY");
b.HasKey("Id");
b.HasIndex("ModelId");
b.HasIndex("NodeId")
.IsUnique();
b.HasIndex(new[] { "MapId", "ModelId" }, "IX_Element_MapId_ModelId");
b.ToTable("Elements");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<double>("Height")
.HasColumnType("float")
.HasColumnName("Height");
b.Property<int>("Image1Height")
.HasColumnType("int")
.HasColumnName("Image1Height");
b.Property<int>("Image1Width")
.HasColumnType("int")
.HasColumnName("Image1Width");
b.Property<int>("Image2Height")
.HasColumnType("int")
.HasColumnName("Image2Height");
b.Property<int>("Image2Width")
.HasColumnType("int")
.HasColumnName("Image2Width");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("Width")
.HasColumnType("float")
.HasColumnName("Width");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_ElementModel_MapId_Name");
b.ToTable("ElementModels");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Map", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<bool>("Active")
.HasColumnType("bit")
.HasColumnName("Active");
b.Property<string>("Description")
.HasColumnType("ntext")
.HasColumnName("Description");
b.Property<double>("EdgeAllowedDeviationThetaDefault")
.HasColumnType("float")
.HasColumnName("EdgeAllowedDeviationThetaDefault");
b.Property<double>("EdgeAllowedDeviationXyDefault")
.HasColumnType("float")
.HasColumnName("EdgeAllowedDeviationXyDefault");
b.Property<double>("EdgeCurveMaxSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeCurveMaxSpeedDefault");
b.Property<byte>("EdgeDirectionAllowedDefault")
.HasColumnType("tinyint")
.HasColumnName("EdgeDirectionAllowedDefault");
b.Property<double>("EdgeMaxHeightDefault")
.HasColumnType("float")
.HasColumnName("EdgeMaxHeightDefault");
b.Property<double>("EdgeMaxRotationSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeMaxRoataionSpeedDefault");
b.Property<double>("EdgeMinHeightDefault")
.HasColumnType("float")
.HasColumnName("EdgeMinHeightDefault");
b.Property<double>("EdgeMinLengthDefault")
.HasColumnType("float")
.HasColumnName("EdgeMinLengthDefault");
b.Property<bool>("EdgeRotationAllowedDefault")
.HasColumnType("bit")
.HasColumnName("EdgeRotationAllowedDefault");
b.Property<double>("EdgeStraightMaxSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeStraightMaxSpeedDefault");
b.Property<double>("ImageHeight")
.HasColumnType("float")
.HasColumnName("ImageHeight");
b.Property<double>("ImageWidth")
.HasColumnType("float")
.HasColumnName("ImageWidth");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("NodeAllowedDeviationThetaDefault")
.HasColumnType("float")
.HasColumnName("NodeAllowedDeviationThetaDefault");
b.Property<double>("NodeAllowedDeviationXyDefault")
.HasColumnType("float")
.HasColumnName("NodeAllowedDeviationXyDefault");
b.Property<long>("NodeCount")
.HasColumnType("BigInt")
.HasColumnName("NodeCount");
b.Property<bool>("NodeNameAutoGenerate")
.HasColumnType("bit")
.HasColumnName("NodeNameAutoGenerate");
b.Property<string>("NodeNameTemplateDefault")
.HasColumnType("nvarchar(64)")
.HasColumnName("NodeNameTemplateDefault");
b.Property<double>("OriginX")
.HasColumnType("float")
.HasColumnName("OriginX");
b.Property<double>("OriginY")
.HasColumnType("float")
.HasColumnName("OriginY");
b.Property<double>("Resolution")
.HasColumnType("float")
.HasColumnName("Resolution");
b.Property<string>("VDA5050")
.HasColumnType("nvarchar(max)")
.HasColumnName("VDA5050");
b.Property<Guid>("VersionId")
.HasColumnType("uniqueidentifier")
.HasColumnName("VersionId");
b.Property<double>("ViewHeight")
.HasColumnType("float")
.HasColumnName("ViewHeight");
b.Property<double>("ViewWidth")
.HasColumnType("float")
.HasColumnName("ViewWidth");
b.Property<double>("ViewX")
.HasColumnType("float")
.HasColumnName("ViewX");
b.Property<double>("ViewY")
.HasColumnType("float")
.HasColumnName("ViewY");
b.Property<double>("ZoneMinSquareDefault")
.HasColumnType("float")
.HasColumnName("ZoneMinSquareDefault");
b.HasKey("Id");
b.ToTable("Maps");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Actions")
.HasColumnType("nvarchar(max)")
.HasColumnName("Actions");
b.Property<double>("AllowedDeviationTheta")
.HasColumnType("float")
.HasColumnName("AllowedDeviationTheta");
b.Property<double>("AllowedDeviationXy")
.HasColumnType("float")
.HasColumnName("AllowedDeviationXy");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("Theta")
.HasColumnType("float")
.HasColumnName("Theta");
b.Property<double>("X")
.HasColumnType("float")
.HasColumnName("X");
b.Property<double>("Y")
.HasColumnType("float")
.HasColumnName("Y");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_Node_MapId_Name");
b.ToTable("Nodes");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Zone", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<int>("Type")
.HasColumnType("int")
.HasColumnName("Type");
b.Property<double>("X1")
.HasColumnType("float")
.HasColumnName("X1");
b.Property<double>("X2")
.HasColumnType("float")
.HasColumnName("X2");
b.Property<double>("X3")
.HasColumnType("float")
.HasColumnName("X3");
b.Property<double>("X4")
.HasColumnType("float")
.HasColumnName("X4");
b.Property<double>("Y1")
.HasColumnType("float")
.HasColumnName("Y1");
b.Property<double>("Y2")
.HasColumnType("float")
.HasColumnName("Y2");
b.Property<double>("Y3")
.HasColumnType("float")
.HasColumnName("Y3");
b.Property<double>("Y4")
.HasColumnType("float")
.HasColumnName("Y4");
b.HasKey("Id");
b.HasIndex(new[] { "MapId" }, "IX_Zone_MapId");
b.ToTable("Zones");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Action", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Actions")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Edge", b =>
{
b.HasOne("RobotNet.MapManager.Data.Node", "EndNode")
.WithMany("EndEdges")
.HasForeignKey("EndNodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Edges")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Node", "StartNode")
.WithMany("StartEdges")
.HasForeignKey("StartNodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("EndNode");
b.Navigation("Map");
b.Navigation("StartNode");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Element", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Elements")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.ElementModel", "Model")
.WithMany("Elements")
.HasForeignKey("ModelId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Node", "Node")
.WithOne("Element")
.HasForeignKey("RobotNet.MapManager.Data.Element", "NodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
b.Navigation("Model");
b.Navigation("Node");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("ElementModels")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Nodes")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Zone", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Zones")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.Navigation("Elements");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Map", b =>
{
b.Navigation("Actions");
b.Navigation("Edges");
b.Navigation("ElementModels");
b.Navigation("Elements");
b.Navigation("Nodes");
b.Navigation("Zones");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.Navigation("Element");
b.Navigation("EndEdges");
b.Navigation("StartEdges");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace RobotNet.MapManager.Data.Migrations
{
/// <inheritdoc />
public partial class AddZoneName : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Name",
table: "Zones",
type: "nvarchar(64)",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Name",
table: "Zones");
}
}
}

View File

@@ -0,0 +1,605 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RobotNet.MapManager.Data;
#nullable disable
namespace RobotNet.MapManager.Data.Migrations
{
[DbContext(typeof(MapEditorDbContext))]
partial class MapEditorDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("RobotNet.MapManager.Data.Action", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_Action_MapId_Name");
b.ToTable("Actions");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Edge", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Actions")
.HasColumnType("nvarchar(max)")
.HasColumnName("Actions");
b.Property<double>("AllowedDeviationTheta")
.HasColumnType("float")
.HasColumnName("AllowedDeviationTheta");
b.Property<double>("AllowedDeviationXy")
.HasColumnType("float")
.HasColumnName("AllowedDeviationXy");
b.Property<double>("ControlPoint1X")
.HasColumnType("float")
.HasColumnName("ControlPoint1X");
b.Property<double>("ControlPoint1Y")
.HasColumnType("float")
.HasColumnName("ControlPoint1Y");
b.Property<double>("ControlPoint2X")
.HasColumnType("float")
.HasColumnName("ControlPoint2X");
b.Property<double>("ControlPoint2Y")
.HasColumnType("float")
.HasColumnName("ControlPoint2Y");
b.Property<byte>("DirectionAllowed")
.HasColumnType("tinyint")
.HasColumnName("DirectionAllowed");
b.Property<Guid>("EndNodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("EndNodeId");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<double>("MaxHeight")
.HasColumnType("float")
.HasColumnName("MaxHeight");
b.Property<double>("MaxRotationSpeed")
.HasColumnType("float")
.HasColumnName("MaxRotationSpeed");
b.Property<double>("MaxSpeed")
.HasColumnType("float")
.HasColumnName("MaxSpeed");
b.Property<double>("MinHeight")
.HasColumnType("float")
.HasColumnName("MinHeight");
b.Property<bool>("RotationAllowed")
.HasColumnType("bit")
.HasColumnName("RotationAllowed");
b.Property<Guid>("StartNodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("StartNodeId");
b.Property<byte>("TrajectoryDegree")
.HasColumnType("tinyint")
.HasColumnName("TrajectoryDegree");
b.HasKey("Id");
b.HasIndex("EndNodeId");
b.HasIndex("StartNodeId");
b.HasIndex(new[] { "MapId" }, "IX_Edge_MapId");
b.ToTable("Edges");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Element", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<bool>("IsOpen")
.HasColumnType("bit")
.HasColumnName("IsOpen");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<Guid>("ModelId")
.HasColumnType("uniqueidentifier")
.HasColumnName("ModelId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<Guid>("NodeId")
.HasColumnType("uniqueidentifier")
.HasColumnName("NodeId");
b.Property<double>("OffsetX")
.HasColumnType("float")
.HasColumnName("OffsetX");
b.Property<double>("OffsetY")
.HasColumnType("float")
.HasColumnName("OffsetY");
b.HasKey("Id");
b.HasIndex("ModelId");
b.HasIndex("NodeId")
.IsUnique();
b.HasIndex(new[] { "MapId", "ModelId" }, "IX_Element_MapId_ModelId");
b.ToTable("Elements");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Content")
.HasColumnType("nvarchar(max)")
.HasColumnName("Content");
b.Property<double>("Height")
.HasColumnType("float")
.HasColumnName("Height");
b.Property<int>("Image1Height")
.HasColumnType("int")
.HasColumnName("Image1Height");
b.Property<int>("Image1Width")
.HasColumnType("int")
.HasColumnName("Image1Width");
b.Property<int>("Image2Height")
.HasColumnType("int")
.HasColumnName("Image2Height");
b.Property<int>("Image2Width")
.HasColumnType("int")
.HasColumnName("Image2Width");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("Width")
.HasColumnType("float")
.HasColumnName("Width");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_ElementModel_MapId_Name");
b.ToTable("ElementModels");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Map", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<bool>("Active")
.HasColumnType("bit")
.HasColumnName("Active");
b.Property<string>("Description")
.HasColumnType("ntext")
.HasColumnName("Description");
b.Property<double>("EdgeAllowedDeviationThetaDefault")
.HasColumnType("float")
.HasColumnName("EdgeAllowedDeviationThetaDefault");
b.Property<double>("EdgeAllowedDeviationXyDefault")
.HasColumnType("float")
.HasColumnName("EdgeAllowedDeviationXyDefault");
b.Property<double>("EdgeCurveMaxSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeCurveMaxSpeedDefault");
b.Property<byte>("EdgeDirectionAllowedDefault")
.HasColumnType("tinyint")
.HasColumnName("EdgeDirectionAllowedDefault");
b.Property<double>("EdgeMaxHeightDefault")
.HasColumnType("float")
.HasColumnName("EdgeMaxHeightDefault");
b.Property<double>("EdgeMaxRotationSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeMaxRoataionSpeedDefault");
b.Property<double>("EdgeMinHeightDefault")
.HasColumnType("float")
.HasColumnName("EdgeMinHeightDefault");
b.Property<double>("EdgeMinLengthDefault")
.HasColumnType("float")
.HasColumnName("EdgeMinLengthDefault");
b.Property<bool>("EdgeRotationAllowedDefault")
.HasColumnType("bit")
.HasColumnName("EdgeRotationAllowedDefault");
b.Property<double>("EdgeStraightMaxSpeedDefault")
.HasColumnType("float")
.HasColumnName("EdgeStraightMaxSpeedDefault");
b.Property<double>("ImageHeight")
.HasColumnType("float")
.HasColumnName("ImageHeight");
b.Property<double>("ImageWidth")
.HasColumnType("float")
.HasColumnName("ImageWidth");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("NodeAllowedDeviationThetaDefault")
.HasColumnType("float")
.HasColumnName("NodeAllowedDeviationThetaDefault");
b.Property<double>("NodeAllowedDeviationXyDefault")
.HasColumnType("float")
.HasColumnName("NodeAllowedDeviationXyDefault");
b.Property<long>("NodeCount")
.HasColumnType("BigInt")
.HasColumnName("NodeCount");
b.Property<bool>("NodeNameAutoGenerate")
.HasColumnType("bit")
.HasColumnName("NodeNameAutoGenerate");
b.Property<string>("NodeNameTemplateDefault")
.HasColumnType("nvarchar(64)")
.HasColumnName("NodeNameTemplateDefault");
b.Property<double>("OriginX")
.HasColumnType("float")
.HasColumnName("OriginX");
b.Property<double>("OriginY")
.HasColumnType("float")
.HasColumnName("OriginY");
b.Property<double>("Resolution")
.HasColumnType("float")
.HasColumnName("Resolution");
b.Property<string>("VDA5050")
.HasColumnType("nvarchar(max)")
.HasColumnName("VDA5050");
b.Property<Guid>("VersionId")
.HasColumnType("uniqueidentifier")
.HasColumnName("VersionId");
b.Property<double>("ViewHeight")
.HasColumnType("float")
.HasColumnName("ViewHeight");
b.Property<double>("ViewWidth")
.HasColumnType("float")
.HasColumnName("ViewWidth");
b.Property<double>("ViewX")
.HasColumnType("float")
.HasColumnName("ViewX");
b.Property<double>("ViewY")
.HasColumnType("float")
.HasColumnName("ViewY");
b.Property<double>("ZoneMinSquareDefault")
.HasColumnType("float")
.HasColumnName("ZoneMinSquareDefault");
b.HasKey("Id");
b.ToTable("Maps");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<string>("Actions")
.HasColumnType("nvarchar(max)")
.HasColumnName("Actions");
b.Property<double>("AllowedDeviationTheta")
.HasColumnType("float")
.HasColumnName("AllowedDeviationTheta");
b.Property<double>("AllowedDeviationXy")
.HasColumnType("float")
.HasColumnName("AllowedDeviationXy");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<double>("Theta")
.HasColumnType("float")
.HasColumnName("Theta");
b.Property<double>("X")
.HasColumnType("float")
.HasColumnName("X");
b.Property<double>("Y")
.HasColumnType("float")
.HasColumnName("Y");
b.HasKey("Id");
b.HasIndex(new[] { "MapId", "Name" }, "IX_Node_MapId_Name");
b.ToTable("Nodes");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Zone", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasColumnName("Id");
b.Property<Guid>("MapId")
.HasColumnType("uniqueidentifier")
.HasColumnName("MapId");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(64)")
.HasColumnName("Name");
b.Property<int>("Type")
.HasColumnType("int")
.HasColumnName("Type");
b.Property<double>("X1")
.HasColumnType("float")
.HasColumnName("X1");
b.Property<double>("X2")
.HasColumnType("float")
.HasColumnName("X2");
b.Property<double>("X3")
.HasColumnType("float")
.HasColumnName("X3");
b.Property<double>("X4")
.HasColumnType("float")
.HasColumnName("X4");
b.Property<double>("Y1")
.HasColumnType("float")
.HasColumnName("Y1");
b.Property<double>("Y2")
.HasColumnType("float")
.HasColumnName("Y2");
b.Property<double>("Y3")
.HasColumnType("float")
.HasColumnName("Y3");
b.Property<double>("Y4")
.HasColumnType("float")
.HasColumnName("Y4");
b.HasKey("Id");
b.HasIndex(new[] { "MapId" }, "IX_Zone_MapId");
b.ToTable("Zones");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Action", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Actions")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Edge", b =>
{
b.HasOne("RobotNet.MapManager.Data.Node", "EndNode")
.WithMany("EndEdges")
.HasForeignKey("EndNodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Edges")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Node", "StartNode")
.WithMany("StartEdges")
.HasForeignKey("StartNodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("EndNode");
b.Navigation("Map");
b.Navigation("StartNode");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Element", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Elements")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.ElementModel", "Model")
.WithMany("Elements")
.HasForeignKey("ModelId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("RobotNet.MapManager.Data.Node", "Node")
.WithOne("Element")
.HasForeignKey("RobotNet.MapManager.Data.Element", "NodeId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
b.Navigation("Model");
b.Navigation("Node");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("ElementModels")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Nodes")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Zone", b =>
{
b.HasOne("RobotNet.MapManager.Data.Map", "Map")
.WithMany("Zones")
.HasForeignKey("MapId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Map");
});
modelBuilder.Entity("RobotNet.MapManager.Data.ElementModel", b =>
{
b.Navigation("Elements");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Map", b =>
{
b.Navigation("Actions");
b.Navigation("Edges");
b.Navigation("ElementModels");
b.Navigation("Elements");
b.Navigation("Nodes");
b.Navigation("Zones");
});
modelBuilder.Entity("RobotNet.MapManager.Data.Node", b =>
{
b.Navigation("Element");
b.Navigation("EndEdges");
b.Navigation("StartEdges");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,51 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace RobotNet.MapManager.Data;
#nullable disable
[Table("Nodes")]
[Index(nameof(MapId), nameof(Name), Name = "IX_Node_MapId_Name")]
public class Node
{
[Column("Id", TypeName = "uniqueidentifier")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Required]
public Guid Id { get; set; }
[Column("MapId", TypeName = "uniqueidentifier")]
[Required]
public Guid MapId { get; set; }
[Column("Name", TypeName = "nvarchar(64)")]
public string Name { get; set; }
[Column("X", TypeName = "float")]
[Required]
public double X { get; set; }
[Column("Y", TypeName = "float")]
[Required]
public double Y { get; set; }
[Column("Theta", TypeName = "float")]
[Required]
public double Theta { get; set; }
[Column("AllowedDeviationXy", TypeName = "float")]
public double AllowedDeviationXy { get; set; }
[Column("AllowedDeviationTheta", TypeName = "float")]
public double AllowedDeviationTheta { get; set; }
[Column("Actions", TypeName = "nvarchar(max)")]
public string Actions { get; set; }
public Map Map { get; set; }
public Element Element { get; set; }
public ICollection<Edge> StartEdges { get; } = [];
public ICollection<Edge> EndEdges { get; } = [];
}

View File

@@ -0,0 +1,61 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapShares.Enums;
namespace RobotNet.MapManager.Data;
[Table("Zones")]
[Index(nameof(MapId), Name = "IX_Zone_MapId")]
public class Zone
{
[Column("Id", TypeName = "uniqueidentifier")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Required]
public Guid Id { get; set; }
[Column("MapId", TypeName = "uniqueidentifier")]
[Required]
public Guid MapId { get; set; }
[Column("Type", TypeName = "int")]
[Required]
public ZoneType Type { get; set; }
[Column("Name", TypeName = "nvarchar(64)")]
[Required]
public string Name { get; set; } = "";
[Column("X1", TypeName = "float")]
[Required]
public double X1 { get; set; }
[Column("Y1", TypeName = "float")]
[Required]
public double Y1 { get; set; }
[Column("X2", TypeName = "float")]
[Required]
public double X2 { get; set; }
[Column("Y2", TypeName = "float")]
[Required]
public double Y2 { get; set; }
[Column("X3", TypeName = "float")]
[Required]
public double X3 { get; set; }
[Column("Y3", TypeName = "float")]
[Required]
public double Y3 { get; set; }
[Column("X4", TypeName = "float")]
public double X4 { get; set; }
[Column("Y4", TypeName = "float")]
public double Y4 { get; set; }
public Map Map { get; set; } = default!;
}

View File

@@ -0,0 +1,65 @@
FROM alpine:3.22 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["RobotNet.MapManager/RobotNet.MapManager.csproj", "RobotNet.MapManager/"]
COPY ["RobotNet.MapShares/RobotNet.MapShares.csproj", "RobotNet.MapShares/"]
COPY ["RobotNet.Script/RobotNet.Script.csproj", "RobotNet.Script/"]
COPY ["RobotNet.Script.Expressions/RobotNet.Script.Expressions.csproj", "RobotNet.Script.Expressions/"]
COPY ["RobotNet.Shares/RobotNet.Shares.csproj", "RobotNet.Shares/"]
COPY ["RobotNet.OpenIddictClient/RobotNet.OpenIddictClient.csproj", "RobotNet.OpenIddictClient/"]
# RUN dotnet package remove "Microsoft.EntityFrameworkCore.Tools" --project "RobotNet.MapManager/RobotNet.MapManager.csproj"
RUN dotnet restore "RobotNet.MapManager/RobotNet.MapManager.csproj"
COPY RobotNet.MapManager/ RobotNet.MapManager/
COPY RobotNet.MapShares/ RobotNet.MapShares/
COPY RobotNet.Script/ RobotNet.Script/
COPY RobotNet.Script.Expressions/ RobotNet.Script.Expressions/
COPY RobotNet.Shares/ RobotNet.Shares/
COPY RobotNet.OpenIddictClient/ RobotNet.OpenIddictClient/
RUN rm -rf ./RobotNet.MapManager/bin
RUN rm -rf ./RobotNet.MapManager/obj
RUN rm -rf ./RobotNet.MapShares/bin
RUN rm -rf ./RobotNet.MapShares/obj
RUN rm -rf ./RobotNet.Script/bin
RUN rm -rf ./RobotNet.Script/obj
RUN rm -rf ./RobotNet.Script.Expressions/bin
RUN rm -rf ./RobotNet.Script.Expressions/obj
RUN rm -rf ./RobotNet.Shares/bin
RUN rm -rf ./RobotNet.Shares/obj
RUN rm -rf ./RobotNet.OpenIddictClient/bin
RUN rm -rf ./RobotNet.OpenIddictClient/obj
WORKDIR "/src/RobotNet.MapManager"
RUN dotnet build "RobotNet.MapManager.csproj" -c Release -o /app/build
FROM build AS publish
WORKDIR /src/RobotNet.MapManager
RUN dotnet publish "RobotNet.MapManager.csproj" \
-c Release \
-o /app/publish \
--runtime linux-musl-x64 \
--self-contained true \
/p:PublishTrimmed=false \
/p:PublishReadyToRun=true
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish ./
RUN apk add --no-cache icu-libs tzdata ca-certificates
RUN echo '#!/bin/sh' >> ./start.sh
RUN echo 'update-ca-certificates' >> ./start.sh
RUN echo 'exec ./RobotNet.MapManager' >> ./start.sh
RUN chmod +x ./RobotNet.MapManager
RUN chmod +x ./start.sh
# Use the start script to ensure certificates are updated before starting the application
EXPOSE 443
ENTRYPOINT ["./start.sh"]

View File

@@ -0,0 +1,165 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using RobotNet.MapManager.Data;
using RobotNet.MapShares.Dtos;
using RobotNet.Shares;
namespace RobotNet.MapManager.Hubs;
[Authorize]
public class MapHub(MapEditorDbContext MapDb) : Hub
{
public async Task<MessageResult<MapDataDto>> GetMapData(Guid mapId)
{
var map = await MapDb.Maps.FindAsync(mapId);
if (map is null) return new(false, $"Không tìm thấy bản đồ: {mapId}");
return new(true)
{
Data = new()
{
Id = map.Id,
Name = map.Name,
OriginX = map.OriginX,
OriginY = map.OriginY,
Resolution = map.Resolution,
ImageHeight = map.ImageHeight,
ImageWidth = map.ImageWidth,
Active = map.Active,
Nodes = [.. MapDb.Nodes.Where(node => node.MapId == mapId).Select(node => new NodeDto()
{
Id = node.Id,
MapId = node.MapId,
Name = node.Name,
Theta = node.Theta,
X = node.X,
Y = node.Y,
AllowedDeviationXy = node.AllowedDeviationXy,
AllowedDeviationTheta = node.AllowedDeviationTheta,
Actions = node.Actions,
})],
Edges = [.. MapDb.Edges.Where(edge => edge.MapId == mapId).Select(edge => new EdgeDto()
{
Id = edge.Id,
MapId = edge.MapId,
StartNodeId = edge.StartNodeId,
EndNodeId = edge.EndNodeId,
MaxSpeed = edge.MaxSpeed,
MaxHeight = edge.MaxHeight,
MinHeight = edge.MinHeight,
DirectionAllowed = edge.DirectionAllowed,
RotationAllowed = edge.RotationAllowed,
TrajectoryDegree = edge.TrajectoryDegree,
ControlPoint1X = edge.ControlPoint1X,
ControlPoint1Y = edge.ControlPoint1Y,
ControlPoint2X = edge.ControlPoint2X,
ControlPoint2Y = edge.ControlPoint2Y,
MaxRotationSpeed = edge.MaxRotationSpeed,
Actions = edge.Actions,
AllowedDeviationXy = edge.AllowedDeviationXy,
AllowedDeviationTheta = edge.AllowedDeviationTheta,
})],
Zones = [.. MapDb.Zones.Where(zone => zone.MapId == mapId).Select(zone => new ZoneDto()
{
Id = zone.Id,
MapId = zone.MapId,
Type = zone.Type,
Name = zone.Name,
X1 = zone.X1,
X2 = zone.X2,
Y1 = zone.Y1,
Y2 = zone.Y2,
X3 = zone.X3,
Y3 = zone.Y3,
X4 = zone.X4,
Y4 = zone.Y4,
}).OrderBy(z => z.Type)],
Elements = [.. MapDb.Elements.Where(el => el.MapId == mapId).Select(element => new ElementDto()
{
Id = element.Id,
MapId = element.MapId,
ModelId = element.ModelId,
Name = element.Name,
NodeId = element.NodeId,
OffsetX = element.OffsetX,
OffsetY = element.OffsetY,
IsOpen = element.IsOpen,
Content = element.Content,
})],
Actions = [.. MapDb.Actions.Where(a => a.MapId == mapId).Select(action => new ActionDto()
{
Id = action.Id,
MapId = action.MapId,
Name = action.Name,
Content = action.Content,
})]
}
};
}
public async Task<MessageResult<ElementDto[]>> GetElementsState(Guid mapId)
{
var map = await MapDb.Maps.FindAsync(mapId);
if (map is null) return new(false, $"Không tìm thấy bản đồ: {mapId}");
var elements = MapDb.Elements
.Where(el => el.MapId == mapId)
.Select(element => new ElementDto()
{
Id = element.Id,
MapId = element.MapId,
ModelId = element.ModelId,
Name = element.Name,
NodeId = element.NodeId,
OffsetX = element.OffsetX,
OffsetY = element.OffsetY,
IsOpen = element.IsOpen,
Content = element.Content
});
return new(true, "") { Data = [..elements] };
}
public async Task<MessageResult<MapInfoDto>> GetMapInfoByName(string name)
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Name == name);
if (map == null) return new MessageResult<MapInfoDto>(false, $"Không tìm thấy map {name}");
return new(true)
{
Data = new MapInfoDto()
{
Id = map.Id,
Name = map.Name,
Active = map.Active,
OriginX = map.OriginX,
OriginY = map.OriginY,
Width = Math.Round(map.ImageWidth * map.Resolution, 2),
Height = Math.Round(map.ImageHeight * map.Resolution, 2),
Resolution = map.Resolution,
},
};
}
public async Task<MessageResult<MapInfoDto>> GetMapInfoById(Guid id)
{
var map = await MapDb.Maps.FirstOrDefaultAsync(m => m.Id == id);
if (map == null) return new MessageResult<MapInfoDto>(false, $"Không tìm thấy map {id}");
return new(true)
{
Data = new MapInfoDto()
{
Id = map.Id,
Name = map.Name,
Active = map.Active,
OriginX = map.OriginX,
OriginY = map.OriginY,
Width = Math.Round(map.ImageWidth * map.Resolution, 2),
Height = Math.Round(map.ImageHeight * map.Resolution, 2),
Resolution = map.Resolution,
},
};
}
}

View File

@@ -0,0 +1,94 @@
using Microsoft.EntityFrameworkCore;
using NLog.Web;
using OpenIddict.Validation.AspNetCore;
using RobotNet.MapManager.Data;
using RobotNet.MapManager.Hubs;
using RobotNet.MapManager.Services;
using RobotNet.OpenIddictClient;
using System.Globalization;
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseNLog();
// builder.AddServiceDefaults();
// Add services to the container.
var openIddictOption = builder.Configuration.GetSection(nameof(OpenIddictClientProviderOptions)).Get<OpenIddictClientProviderOptions>()
?? throw new InvalidOperationException("OpenID configuration not found or invalid format.");
builder.Services.AddControllers();
builder.Services.AddSignalR();
builder.Services.AddOpenIddict()
.AddValidation(options =>
{
// Note: the validation handler uses OpenID Connect discovery
// to retrieve the address of the introspection endpoint.
options.SetIssuer(openIddictOption.Issuer);
options.AddAudiences(openIddictOption.Audiences);
// Configure the validation handler to use introspection and register the client
// credentials used when communicating with the remote introspection endpoint.
options.UseIntrospection()
.SetClientId(openIddictOption.ClientId)
.SetClientSecret(openIddictOption.ClientSecret);
// Register the System.Net.Http integration.
if (builder.Environment.IsDevelopment())
{
options.UseSystemNetHttp(httpOptions =>
{
httpOptions.ConfigureHttpClientHandler(context =>
{
context.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true;
});
});
}
else
{
options.UseSystemNetHttp();
}
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
builder.Services.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
builder.Services.AddAuthorization();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
Action<DbContextOptionsBuilder> appDbOptions = options => options.UseSqlServer(connectionString, b => b.MigrationsAssembly("RobotNet.MapManager"));
builder.Services.AddDbContext<MapEditorDbContext>(appDbOptions);
builder.Services.AddSingleton<MapEditorStorageRepository>();
builder.Services.AddSingleton(typeof(LoggerController<>));
var app = builder.Build();
await app.Services.SeedMapManagerDbAsync();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapHub<MapHub>("/hubs/map/data");
app.Run();

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"workingDirectory": "$(TargetDir)",
"applicationUrl": "https://localhost:7177",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NLog" Version="6.0.3" />
<PackageReference Include="NLog.Web.AspNetCore" Version="6.0.3" />
<PackageReference Include="OpenIddict.Validation.AspNetCore" Version="7.0.0" />
<PackageReference Include="OpenIddict.Validation.SystemNetHttp" Version="7.0.0" />
<PackageReference Include="Minio" Version="6.0.5" />
<PackageReference Include="Serialize.Linq" Version="4.0.167" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RobotNet.MapShares\RobotNet.MapShares.csproj" />
<ProjectReference Include="..\RobotNet.OpenIddictClient\RobotNet.OpenIddictClient.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
@RobotNet.MapManager_HostAddress = http://localhost:5082
GET {{RobotNet.MapManager_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@@ -0,0 +1,108 @@
namespace RobotNet.MapManager.Services;
public class LoggerController<T>(ILogger<T> Logger)
{
public event Action? LoggerUpdate;
public void Write(string message, LogLevel level)
{
switch (level)
{
case LogLevel.Trace:
Logger.LogTrace("{mes}", message);
break;
case LogLevel.Debug:
Logger.LogDebug("{mes}", message);
break;
case LogLevel.Information:
Logger.LogInformation("{mes}", message);
break;
case LogLevel.Warning:
Logger.LogWarning("{mes}", message);
break;
case LogLevel.Error:
Logger.LogError("{mes}", message);
break;
case LogLevel.Critical:
Logger.LogCritical("{mes}", message);
break;
}
LoggerUpdate?.Invoke();
}
public void Write(string message)
{
Write(message, LogLevel.Information);
}
public async Task WriteAsync(string message)
{
var write = Task.Run(() => Write(message));
await write.WaitAsync(CancellationToken.None);
}
public async Task TraceAsync(string message)
{
var write = Task.Run(() => Write(message, LogLevel.Trace));
await write.WaitAsync(CancellationToken.None);
}
public async Task DebugAsync(string message)
{
var write = Task.Run(() => Write(message, LogLevel.Debug));
await write.WaitAsync(CancellationToken.None);
}
public async Task InfoAsync(string message)
{
var write = Task.Run(() => Write(message, LogLevel.Information));
await write.WaitAsync(CancellationToken.None);
}
public async Task WarningAsync(string message)
{
var write = Task.Run(() => Write(message, LogLevel.Warning));
await write.WaitAsync(CancellationToken.None);
}
public async Task ErrorAsync(string message)
{
var write = Task.Run(() => Write(message, LogLevel.Error));
await write.WaitAsync(CancellationToken.None);
}
public async Task CriticalAsync(string message)
{
var write = Task.Run(() => Write(message, LogLevel.Critical));
await write.WaitAsync(CancellationToken.None);
}
public void Trace(string message)
{
Write(message, LogLevel.Trace);
}
public void Debug(string message)
{
Write(message, LogLevel.Debug);
}
public void Info(string message)
{
Write(message, LogLevel.Information);
}
public void Warning(string message)
{
Write(message, LogLevel.Warning);
}
public void Error(string message)
{
Write(message, LogLevel.Error);
}
public void Critical(string message)
{
Write(message, LogLevel.Critical);
}
}

View File

@@ -0,0 +1,140 @@
using Minio;
using Minio.DataModel.Args;
using Minio.Exceptions;
namespace RobotNet.MapManager.Services;
public class MapEditorStorageRepository
{
private class MinioOption
{
public bool UsingLocal { get; set; }
public string? Endpoint { get; set; }
public string? User { get; set; }
public string? Password { get; set; }
public string? Bucket { get; set; }
}
private readonly IMinioClient MinioClient;
private readonly MinioOption MinioOptions = new();
public MapEditorStorageRepository(IConfiguration configuration)
{
configuration.Bind("MinIO", MinioOptions);
MinioClient = new MinioClient()
.WithEndpoint(MinioOptions.Endpoint)
.WithCredentials(MinioOptions.User, MinioOptions.Password)
.WithSSL(false)
.Build();
}
public async Task<(bool, string)> UploadAsync(string path, string objectName, Stream data, long size, string contentType, CancellationToken cancellationToken)
{
try
{
if (!MinioOptions.UsingLocal)
{
var beArgs = new BucketExistsArgs().WithBucket(MinioOptions.Bucket);
bool found = await MinioClient.BucketExistsAsync(beArgs, cancellationToken).ConfigureAwait(false);
if (!found)
{
var mbArgs = new MakeBucketArgs()
.WithBucket(MinioOptions.Bucket);
await MinioClient.MakeBucketAsync(mbArgs, cancellationToken).ConfigureAwait(false);
}
var getListBucketsTask = await MinioClient.ListBucketsAsync(cancellationToken);
var putObjectArgs = new PutObjectArgs()
.WithBucket(MinioOptions.Bucket)
.WithObject($"{path}/{objectName}")
.WithObjectSize(size)
.WithStreamData(data)
.WithContentType(contentType);
await MinioClient.PutObjectAsync(putObjectArgs, cancellationToken).ConfigureAwait(false);
return (true, "");
}
var mapImageFolder = string.IsNullOrEmpty(MinioOptions.Bucket) ? "MapImages" : MinioOptions.Bucket;
if (!Directory.Exists(mapImageFolder)) Directory.CreateDirectory(mapImageFolder);
var folderPath = Path.Combine(mapImageFolder, path);
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
var pathLocal = Path.Combine(folderPath, $"{objectName}.png");
if (File.Exists($"{pathLocal}.bk")) File.Delete($"{pathLocal}.bk");
if (File.Exists(pathLocal)) File.Move(pathLocal, $"{pathLocal}.bk");
using (Stream fileStream = new FileStream(pathLocal, FileMode.Create))
{
await data.CopyToAsync(fileStream, cancellationToken);
}
return (true, "");
}
catch (MinioException ex)
{
return (false, ex.Message);
}
}
public (bool usingLocal, string url) GetUrl(string path, string objectName)
{
try
{
if (!MinioOptions.UsingLocal)
{
var presignedGetObjectArgs = new PresignedGetObjectArgs()
.WithBucket(MinioOptions.Bucket)
.WithObject($"{path}/{objectName}")
.WithExpiry(60 * 60 * 24);
var url = MinioClient.PresignedGetObjectAsync(presignedGetObjectArgs);
url.Wait();
return (false, url.Result);
}
var mapImageFolder = string.IsNullOrEmpty(MinioOptions.Bucket) ? "MapImages" : MinioOptions.Bucket;
if (Directory.Exists(mapImageFolder))
{
var folderPath = Path.Combine(mapImageFolder, path);
if (Directory.Exists(folderPath))
{
var pathLocal = Path.Combine(folderPath, $"{objectName}.png");
if (File.Exists(pathLocal))
{
return (true, pathLocal);
}
}
}
return (true, "");
}
catch (MinioException ex)
{
return (false, ex.Message);
}
}
public async Task<(bool, string)> DeleteAsync(string path, string objectName, CancellationToken cancellationToken)
{
try
{
if (!MinioOptions.UsingLocal)
{
var removeObjectArgs = new RemoveObjectArgs()
.WithBucket(MinioOptions.Bucket)
.WithObject($"{path}/{objectName}");
await MinioClient.RemoveObjectAsync(removeObjectArgs, cancellationToken).ConfigureAwait(false);
return (true, "");
}
var mapImageFolder = string.IsNullOrEmpty(MinioOptions.Bucket) ? "MapImages" : MinioOptions.Bucket;
if (Directory.Exists(mapImageFolder))
{
var folderPath = Path.Combine(mapImageFolder, path);
if (Directory.Exists(folderPath))
{
var pathLocal = Path.Combine(folderPath, $"{objectName}.png");
if (File.Exists(pathLocal)) File.Delete(pathLocal);
if (File.Exists($"{pathLocal}.bk")) File.Delete($"{pathLocal}.bk");
}
}
return (true, "");
}
catch (MinioException ex)
{
return (false, ex.Message);
}
}
}

View File

@@ -0,0 +1,161 @@
using RobotNet.MapManager.Data;
using RobotNet.MapShares.Dtos;
using RobotNet.MapShares.Enums;
namespace RobotNet.MapManager.Services;
public class ServerHelper
{
public static Edge CreateEdge(Map map, Guid startNodeId, Guid endNodeId, TrajectoryDegree trajectoryDegree, double cpX1 = 0, double cpY1 = 0, double cpX2 = 0, double cpY2 = 0)
{
return new Edge()
{
MapId = map.Id,
StartNodeId = startNodeId,
EndNodeId = endNodeId,
TrajectoryDegree = trajectoryDegree,
DirectionAllowed = map.EdgeDirectionAllowedDefault,
RotationAllowed = map.EdgeRotationAllowedDefault,
MaxSpeed = trajectoryDegree == TrajectoryDegree.One ? map.EdgeStraightMaxSpeedDefault : map.EdgeCurveMaxSpeedDefault,
MaxRotationSpeed = map.EdgeMaxRotationSpeedDefault,
MaxHeight = map.EdgeMaxHeightDefault,
MinHeight = map.EdgeMinHeightDefault,
Actions = "[]",
AllowedDeviationXy = map.EdgeAllowedDeviationXyDefault,
AllowedDeviationTheta = map.EdgeAllowedDeviationThetaDefault,
ControlPoint1X = cpX1,
ControlPoint1Y = cpY1,
ControlPoint2X = cpX2,
ControlPoint2Y = cpY2,
};
}
public static Node CreateNode(Map map, double x, double y)
{
return new Node()
{
MapId = map.Id,
Name = map.NodeNameAutoGenerate ? $"{map.NodeNameTemplateDefault}{++map.NodeCount}" : string.Empty,
X = x,
Y = y,
Theta = 0,
AllowedDeviationXy = map.NodeAllowedDeviationXyDefault,
AllowedDeviationTheta = map.NodeAllowedDeviationThetaDefault,
Actions = "[]",
};
}
public static EdgeDto CreateEdgeDto(Edge edge, Node startNode, Node endNode)
{
return new EdgeDto()
{
Id = edge.Id,
MapId = edge.MapId,
StartNodeId = edge.StartNodeId,
EndNodeId = edge.EndNodeId,
TrajectoryDegree = edge.TrajectoryDegree,
ControlPoint1X = edge.ControlPoint1X,
ControlPoint1Y = edge.ControlPoint1Y,
ControlPoint2X = edge.ControlPoint2X,
ControlPoint2Y = edge.ControlPoint2Y,
DirectionAllowed = edge.DirectionAllowed,
RotationAllowed = edge.RotationAllowed,
MaxSpeed = edge.MaxSpeed,
MaxRotationSpeed = edge.MaxRotationSpeed,
MaxHeight = edge.MaxHeight,
MinHeight = edge.MinHeight,
Actions = edge.Actions,
AllowedDeviationXy = edge.AllowedDeviationXy,
AllowedDeviationTheta = edge.AllowedDeviationTheta,
StartNode = new NodeDto()
{
Id = startNode.Id,
Name = startNode.Name,
MapId = startNode.MapId,
Theta = startNode.Theta,
X = startNode.X,
Y = startNode.Y,
Actions = startNode.Actions,
AllowedDeviationXy = startNode.AllowedDeviationXy,
AllowedDeviationTheta = startNode.AllowedDeviationTheta,
},
EndNode = new NodeDto()
{
Id = endNode.Id,
Name = endNode.Name,
MapId = endNode.MapId,
Theta = endNode.Theta,
X = endNode.X,
Y = endNode.Y,
AllowedDeviationXy = endNode.AllowedDeviationXy,
AllowedDeviationTheta = endNode.AllowedDeviationTheta,
Actions = endNode.Actions,
},
};
}
public static NodeDto CreateNodeDto(Node node)
{
return new NodeDto()
{
Id = node.Id,
Name = node.Name,
MapId = node.MapId,
Theta = node.Theta,
X = node.X,
Y = node.Y,
AllowedDeviationXy = node.AllowedDeviationXy,
AllowedDeviationTheta = node.AllowedDeviationTheta,
Actions = node.Actions,
};
}
public static Edge? GetClosesEdge(double x, double y, IEnumerable<Node> nodes, IEnumerable<Edge> edges, double allowDistance)
{
double minDistance = double.MaxValue;
Edge? edgeResult = null;
foreach (var edge in edges)
{
if (edge is not null)
{
var startNode = nodes.FirstOrDefault(n => n.Id == edge.StartNodeId);
var endNode = nodes.FirstOrDefault(n => n.Id == edge.EndNodeId);
if (startNode is null || endNode is null) continue;
var distance = DistanceToSegment(x, y, startNode.X, startNode.Y, endNode.X, endNode.Y);
if (distance < minDistance)
{
minDistance = distance;
edgeResult = edge;
}
}
}
if (minDistance > allowDistance) return null;
return edgeResult;
}
private static double DistanceToSegment(double x, double y, double x1, double y1, double x2, double y2)
{
double dx = x2 - x1;
double dy = y2 - y1;
double segmentLengthSquared = dx * dx + dy * dy;
double t;
if (segmentLengthSquared == 0)
{
t = 0;
}
else
{
t = ((x - x1) * dx + (y - y1) * dy) / segmentLengthSquared;
t = Math.Max(0, Math.Min(1, t));
}
double nearestX = x1 + t * dx;
double nearestY = y1 + t * dy;
double distanceSquared = (x - nearestX) * (x - nearestX) + (y - nearestY) * (y - nearestY);
return Math.Sqrt(distanceSquared);
}
}

View File

@@ -0,0 +1,31 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=172.20.235.170;Database=RobotNet.MapEditor;User Id=sa;Password=robotics@2022;TrustServerCertificate=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"System.Net.Http.HttpClient": "Warning",
"OpenIddict.Validation.OpenIddictValidationDispatcher": "Warning",
"Microsoft.EntityFrameworkCore.Database": "Warning"
}
},
"AllowedHosts": "*",
"MinIO": {
"UsingLocal": false,
"Endpoint": "172.20.235.170:9000",
"Bucket": "mapeditor",
"User": "minio",
"Password": "robotics"
},
"OpenIddictClientProviderOptions": {
"Issuer": "https://localhost:7061/",
"Audiences": [
"robotnet-map-manager"
],
"ClientId": "robotnet-map-manager",
"ClientSecret": "72B36E68-2F2B-455B-858A-77B1DCC79979",
"Scopes": [ ]
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target xsi:type="File" name="mapManagerLogFile" fileName="${basedir}/mapManagerlogs/${shortdate}.log" maxArchiveFiles="90" archiveEvery="Day" >
<layout type='JsonLayout'>
<attribute name='time' layout='${date:format=HH\:mm\:ss.ffff}' />
<attribute name='level' layout='${level:upperCase=true}'/>
<attribute name='logger' layout='${logger}' />
<attribute name='message' layout='${message}' />
<attribute name='exception' layout='${exception:format=tostring}' />
</layout>
</target>
</targets>
<rules>
<logger name="RobotNet.MapManager.*" minlevel="Debug" writeto="mapManagerLogFile" />
</rules>
</nlog>