/* * Copyright (c) 2022 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora.View; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media; namespace AuroraUIComponent.UserControls { public class LWPolyLinePattern : IPattern { // DXF 의 LWPolyLine 의 데이터를 기준으로 일단 정의 // 자료를 보면, x, y, start width, end width, bulge value 로 구성되는데, // 일단은 x, y, bulge 로만 구성 (추후 필요시 수정) public class PathElement : NotifyPropertyChangedBase { public double X { get => _X; set => SetProperty(ref _X, value); } private double _X; public double Y { get => _Y; set => SetProperty(ref _Y, value); } private double _Y; public double Bulge { get => _Bulge; set => SetProperty(ref _Bulge, value); } private double _Bulge; public Brush CustomBrush = null; public PathElement() : this(0, 0, 0) { } public PathElement(PathElement org, string brush = null) { X = org.X; Y = org.Y; Bulge = org.Bulge; if (brush != null) { CustomBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(brush)); } } public PathElement(double x, double y, double r = 0, string brush = null) { X = x; Y = y; Bulge = r; if (brush != null) { CustomBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(brush)); } } } public ObservableCollection Entities { get => _ListPath; set => SetProperty(ref _ListPath, value); } private ObservableCollection _ListPath; private double minX; private double maxX; private double minY; private double maxY; public LWPolyLinePattern() { Entities = new ObservableCollection(); } public void Copy(LWPolyLinePattern copyPattern) { if (copyPattern != null) { //Entities.Clear(); //foreach (var item in copyPattern.Entities) { // Entities.Add(item); //} // ObservableCollection Clear/Add/Remove 시 매번 UI Update 발생하여 Delay -> 최대한 Element 개수는 변하지 않도록 아래와 같이 수정. // 코드 유지보수에는 위처럼 Clear/Add하는 게 심플하지만, Performance를 위해 우선 아래와 같이 적용해 봄 int i = 0; for (; i < Entities.Count && i < copyPattern.Entities.Count; i++) { Entities[i].X = copyPattern.Entities[i].X; Entities[i].Y = copyPattern.Entities[i].Y; Entities[i].Bulge = copyPattern.Entities[i].Bulge; } if (Entities.Count < copyPattern.Entities.Count) { for (; i < copyPattern.Entities.Count; i++) { Entities.Add(new PathElement(copyPattern.Entities[i])); } } if (Entities.Count > copyPattern.Entities.Count) { while (copyPattern.Entities.Count < Entities.Count) { Entities.RemoveAt(i); } } NotifyPropertyChanged("Entities"); UpdateCalculatedPath(); } } public void Clear() { Entities.Clear(); //Entities.Add(new Rect()); } public void UpdateCalculatedPath() { UpdateCalculatedPath(0, 0, 1.0); } public void UpdateCalculatedPath(double offsetX, double offsetY, double ratio) { for (int i = 0; i < Entities.Count; i++) { Entities[i].X = (Entities[i].X + offsetX) * ratio; Entities[i].Y = (Entities[i].Y + offsetY) * ratio; Entities[i].Bulge = Entities[i].Bulge; } NotifyPropertyChanged("Entities"); UpdateMinMaxXY(); } private void UpdateMinMaxXY() { if (Entities != null && Entities.Count > 0) { minX = Entities[0].X; maxX = Entities[0].X; minY = Entities[0].Y; maxY = Entities[0].Y; foreach (var item in Entities) { if (item.X < minX) minX = item.X; if (item.X > maxX) maxX = item.X; if (item.Y < minY) minY = item.Y; if (item.Y > maxY) maxY = item.Y; } } } public void FitToTPArea(double tpWidth, double tpHeight) { if (Entities.Count > 0) { UpdateMinMaxXY(); double ratio = tpWidth / (maxX - minX) < tpHeight / (maxY - minY) ? tpWidth / (maxX - minX) : tpHeight / (maxY - minY); UpdateCalculatedPath((tpWidth / ratio - minX - maxX) / 2, (tpHeight / ratio - minY - maxY) / 2, ratio); } } public void FitCenterToTPArea(double tpWidth, double tpHeight) { if (Entities.Count > 0) { double minX = Entities[0].X; double maxX = Entities[0].X; double minY = Entities[0].Y; double maxY = Entities[0].Y; foreach (var item in Entities) { if (item.X < minX) minX = item.X; if (item.X > maxX) maxX = item.X; if (item.Y < minY) minY = item.Y; if (item.Y > maxY) maxY = item.Y; } UpdateCalculatedPath((tpWidth - minX - maxX) / 2, (tpHeight - minY - maxY) / 2, 1.0); } } public void ShiftX(double delta) { UpdateCalculatedPath(delta, 0, 1.0); } public void ShiftY(double delta) { UpdateCalculatedPath(0, delta, 1.0); } public override void Shift(double x, double y) { UpdateCalculatedPath(x, y, 1.0); } public override bool GetMinMax(out double minX, out double maxX, out double minY, out double maxY) { if (Entities.Count == 0) { return base.GetMinMax(out minX, out maxX, out minY, out maxY); } minX = maxX = Entities[0].X; minY = maxY = Entities[0].Y; foreach (var item in Entities) { if (minX > item.X) minX = item.X; if (minY > item.Y) minY = item.Y; if (maxX < item.X) maxX = item.X; if (maxY < item.Y) maxY = item.Y; // TODO: Arc로 벗어나는 부분까지 계산 } return true; } } }