using System; using System.Collections; using System.Collections.Generic; using BITKit; using BITKit.CommandPattern; using BITKit.Entities; using BITKit.IO; using Cysharp.Threading.Tasks; using PaintIn3D; using Unity.Mathematics; using UnityEngine; namespace BITFactory.Cutting { [Serializable] public sealed class DIUnityCuttingTool : InjectFromDI,ICuttingTool { private ICuttingTool _cuttingToolImplementation => Value; public ICommand[] Commands => _cuttingToolImplementation.Commands; public event Action OnExecute { add => _cuttingToolImplementation.OnExecute += value; remove => _cuttingToolImplementation.OnExecute -= value; } public event Action OnClear { add => _cuttingToolImplementation.OnClear += value; remove => _cuttingToolImplementation.OnClear -= value; } public event Action OnUndo { add => _cuttingToolImplementation.OnUndo += value; remove => _cuttingToolImplementation.OnUndo -= value; } public event Action OnRelease { add => _cuttingToolImplementation.OnRelease += value; remove => _cuttingToolImplementation.OnRelease -= value; } public void Execute(ICommand command) { _cuttingToolImplementation.Execute(command); } public void Undo() { _cuttingToolImplementation.Undo(); } public void Undo(int count) { _cuttingToolImplementation.Undo(count); } public void Redo() { _cuttingToolImplementation.Redo(); } public void Trace(ICommand command) { _cuttingToolImplementation.Trace(command); } public void Clear() { _cuttingToolImplementation.Clear(); } public void Rebuild() => _cuttingToolImplementation.Rebuild(); public void Release() => _cuttingToolImplementation.Release(); public void CutPlanePoint(bool preview, float3 planeNormal, float3 planePoint) { _cuttingToolImplementation.CutPlanePoint(preview, planeNormal, planePoint); } public void CutPlantSphere(bool preview, float3 planeNormal, float3 planePoint, float radius) { _cuttingToolImplementation.CutPlantSphere(preview, planeNormal, planePoint, radius); } public void CutPlaneBox(bool preview, float3 planeNormal, float3 planePoint, float3 boxSize) { _cuttingToolImplementation.CutPlaneBox(preview, planeNormal, planePoint, boxSize); } public void CutPlaneLine(bool preview, float3 planeNormal, float3[] line) { _cuttingToolImplementation.CutPlaneLine(preview, planeNormal, line); } public void FillPlanePoint(bool preview, float3 planeNormal, float3 planePoint) { _cuttingToolImplementation.FillPlanePoint(preview, planeNormal, planePoint); } } [CustomType(typeof(ICuttingTool),true)] public class UnityCuttingTool : EntityBehavior,ICuttingTool { [SerializeField] private float defaultPointRadius = 0.1f; [SerializeReference, SubclassSelector] private IApplicationFile applicationFile; private P3dPaintSphere paintSphere { get { if (!_paintSphere) { _paintSphere = GetComponentInChildren(); } return _paintSphere; } } private P3dPaintSphere _paintSphere; private readonly CommandSequence _commands=new(); private readonly CommandSequence _executedCommands=new(); private void Awake() { DI.Register(this); } private void OnEnable() { applicationFile.DataHandle += OnDataHandle; applicationFile.AddListener(nameof(UnityCuttingTool),OnData); } private void OnDisable() { applicationFile.DataHandle -= OnDataHandle; applicationFile.RemoveListener(nameof(UnityCuttingTool),OnData); } private (string, byte[]) OnDataHandle() { return new(nameof(UnityCuttingTool), BITBinary.WriteAsBytes(_executedCommands)); } private async void OnData(byte[] obj) { await UniTask.NextFrame(); if (destroyCancellationToken.IsCancellationRequested) return; Clear(); var seq = BITBinary.Read(obj); _commands.AddRange(seq); _executedCommands.AddRange(seq); Rebuild(); } public void CutPlanePoint(bool preview, float3 planeNormal, float3 planePoint) { paintSphere.Radius = defaultPointRadius; paintSphere.HandleHitLine( preview, 0, 1.0f, 0, planePoint+planeNormal*1, planePoint-planeNormal*1, Quaternion.LookRotation(planeNormal),true); } public void CutPlantSphere(bool preview, float3 planeNormal, float3 planePoint, float radius) { paintSphere.Radius = radius; paintSphere.HandleHitLine( preview, 0, 1.0f, 0, planePoint+planeNormal*1, planePoint-planeNormal*1, Quaternion.LookRotation(planeNormal),true); } public void CutPlaneBox(bool preview, float3 planeNormal, float3 planePoint, float3 boxSize) { throw new System.NotImplementedException(); } public void CutPlaneLine(bool preview, float3 planeNormal, float3[] line) { paintSphere.Radius = defaultPointRadius; var lastPoint = line[0]; foreach (var pos in line) { paintSphere.HandleHitLine( preview, 0, 1.0f, 0, lastPoint, pos, Quaternion.LookRotation(planeNormal),true); lastPoint = pos; } } public void FillPlanePoint(bool preview, float3 planeNormal, float3 planePoint) { var texture = (Texture2D)_paintSphere.TargetTexture.Texture; } public ICommand[] Commands =>_executedCommands.ToArray(); public event Action OnExecute; public event Action OnClear; public event Action OnUndo; public event Action OnRelease; public void Execute(ICommand command) { _commands.Add(command); OnExecute?.Invoke(command); _executedCommands.Add(command); ExecuteInternal(command); } public void Undo() { if(_executedCommands.Count==0)return; var command = _executedCommands[^1]; command.Undo(); _executedCommands.RemoveAt(_executedCommands.Count-1); OnClear?.Invoke(null); paintSphere.TargetTexture.Clear(); foreach (var x in _executedCommands) { ExecuteInternal(x); OnExecute?.Invoke(x); } } public void Undo(int count) { throw new System.NotImplementedException(); } public void Redo() { throw new System.NotImplementedException(); } public void Trace(ICommand command) { var index = _commands.IndexOf(command); paintSphere.TargetTexture.Clear(); OnClear?.Invoke(command); _executedCommands.Clear(); _executedCommands.AddRange(_commands.GetRange(0, index)); foreach (var x in _executedCommands) { ExecuteInternal(x); OnExecute?.Invoke(x); } } public void Clear() { OnClear?.Invoke(null); _executedCommands.Clear(); _commands.Clear(); paintSphere.TargetTexture.Clear(); } public void Rebuild() { OnClear?.Invoke(null); foreach (var x in _executedCommands) { ExecuteInternal(x); OnExecute?.Invoke(x); } } public void Release() { OnRelease?.Invoke(_executedCommands.ToArray()); } private void ExecuteInternal(ICommand command) { switch (command) { case CuttingPointCommand cuttingPointCommand: CutPlanePoint(false,cuttingPointCommand.PlaneNormal,cuttingPointCommand.PlanePoint); break; case CuttingSphereCommand sphereCommand: CutPlantSphere(false,sphereCommand.PlaneNormal,sphereCommand.PlanePoint,sphereCommand.Radius); break; case CuttingLineCommand lineCommand: CutPlaneLine(false,lineCommand.PlaneNormal,lineCommand.Line); break; } } } }