/* * GNU AFFERO GENERAL PUBLIC LICENSE * Version 3, 19 November 2007 * Copyright (C) 2007 Free Software Foundation, Inc. * Everyone is permitted to copy and distribute verbatim copies * of this license document, but changing it is not allowed. */ using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text.Json.Serialization; using UVtools.Core.Extensions; namespace UVtools.Core.Layers; public class MainIssue : IReadOnlyList { public enum IssueType : byte { Island, Overhang, ResinTrap, SuctionCup, TouchingBound, PrintHeight, EmptyLayer, Debug //HoleSandwich, } public bool IsIsland => Type == IssueType.Island; public bool IsOverhang => Type == IssueType.Overhang; public bool IsResinTrap => Type == IssueType.ResinTrap; public bool IsSuctionCup => Type == IssueType.SuctionCup; public bool IsTouchingBound => Type == IssueType.TouchingBound; public bool IsPrintHeight => Type == IssueType.PrintHeight; public bool IsEmptyLayer => Type == IssueType.EmptyLayer; public bool IsDebug => Type == IssueType.Debug; /// /// Gets the issue type associated /// public IssueType Type { get; init; } /// /// Gets the layer where issue is present and starts /// [JsonIgnore] public Layer StartLayer => Childs[0].Layer; /// /// Gets the layer where issue ends /// [JsonIgnore] public Layer EndLayer => Childs[^1].Layer; /// /// Gets the layer index /// public uint StartLayerIndex => StartLayer.Index; /// /// Gets the layer index /// public uint EndLayerIndex => EndLayer.Index; /// /// Gets the number of layers in this range /// public uint LayerRangeCount => 1 + EndLayerIndex - StartLayerIndex; public string LayerInfoStr => StartLayerIndex == EndLayerIndex ? $"{StartLayerIndex}" : $"{StartLayerIndex}-{EndLayerIndex} ({LayerRangeCount})"; /// /// Gets the total height that represents this issue /// public float TotalHeight => Layer.RoundHeight(StartLayer.LayerHeight + EndLayer.PositionZ - StartLayer.PositionZ); /// /// Gets the bounding rectangle of the area /// public Rectangle BoundingRectangle { get; init; } /// /// Gets the area of the issue /// public uint PixelCount { get; init; } /// /// Gets the area of the issue /// public double Area { get; init; } /// /// Gets all issues inside this main issue /// public Issue[] Childs { get; init; } = null!; public MainIssue(IssueType type, Rectangle boundingRectangle = default) { Type = type; BoundingRectangle = boundingRectangle; Area = boundingRectangle.Area(); } public MainIssue(IssueType type, Issue issue) : this(type, issue.BoundingRectangle) { Childs = new[] { issue }; issue.Parent = this; PixelCount = issue.PixelsCount; if (issue is IssueOfPoints) Area = issue.PixelsCount; } public MainIssue(IssueType type, IEnumerable issues) : this(type) { var boundingRectangle = Rectangle.Empty; double area = 0; foreach (var issue in issues) { issue.Parent = this; area += issue.Area / issue.Layer.LayerHeight; PixelCount += issue.PixelsCount; if (issue.BoundingRectangle.IsEmpty) continue; if (boundingRectangle.IsEmpty) { boundingRectangle = issue.BoundingRectangle; continue; } boundingRectangle.Intersect(issue.BoundingRectangle); } BoundingRectangle = boundingRectangle; Area = area; Childs = issues.OrderBy(issue => issue.LayerIndex).ToArray(); Sort(); } private void Sort() { Array.Sort(Childs, (issue, issue1) => issue.LayerIndex.CompareTo(issue1.LayerIndex)); } public bool IsIssueInBetween(int layerIndex) => layerIndex >= StartLayerIndex && layerIndex <= EndLayerIndex; public bool IsIssueInBetween(uint layerIndex) => layerIndex >= StartLayerIndex && layerIndex <= EndLayerIndex; public bool IsIssueInBetween(Layer layer) => IsIssueInBetween(layer.Index); public IEnumerator GetEnumerator() { return ((IEnumerable)Childs).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return Childs.GetEnumerator(); } public int Count => Childs.Length; public Issue this[int index] => Childs[index]; protected bool Equals(MainIssue other) { return Type == other.Type && BoundingRectangle.Equals(other.BoundingRectangle) && PixelCount == other.PixelCount && Area.Equals(other.Area) && Childs.SequenceEqual(other.Childs); } public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((MainIssue)obj); } public override int GetHashCode() { return HashCode.Combine((int)Type, BoundingRectangle, PixelCount, Area, Childs); } }