#region Header // _,-'/-'/ // . __,-; ,'( '/ // \. `-.__`-._`:_,-._ _ , . `` // `:-._,------' ` _,`--` -: `_ , ` ,' : // `---..__,,--' (C) 2023 ` -'. -' // # Vita-Nex [http://core.vita-nex.com] # // {o)xxx|===============- # -===============|xxx(o} // # # #endregion #region References using System; using System.Collections; using System.Collections.Generic; using System.Linq; using VitaNex.Collections; #endregion namespace Server { public interface IWireframe : IEnumerable { bool Intersects(IBlock3D b); bool Intersects(int x, int y, int z); bool Intersects(int x, int y, int z, int h); bool Intersects(IWireframe frame); Rectangle3D GetBounds(); IEnumerable Offset(int x = 0, int y = 0, int z = 0, int h = 0); } public sealed class Wireframe : IEquatable, IWireframe { public static readonly Wireframe Empty = new Wireframe(0); public Block3D[] Blocks { get; private set; } public int Volume => Blocks.Length; public int Length => Blocks.Length; public Wireframe(params IBlock3D[] blocks) : this(blocks.Ensure().Select(b => new Block3D(b))) { } public Wireframe(IEnumerable blocks) : this(blocks.Ensure().Select(b => new Block3D(b))) { } public Wireframe(Wireframe frame) : this(frame.Blocks) { } public Wireframe(int capacity) { Blocks = new Block3D[capacity]; } public Wireframe(params Block3D[] blocks) { Blocks = blocks.Ensure().ToArray(); } public Wireframe(IEnumerable blocks) { Blocks = blocks.Ensure().ToArray(); } public bool Intersects(IPoint3D p) { return Intersects(p.X, p.Y, p.Z); } public bool Intersects(IPoint3D p, int h) { return Intersects(p.X, p.Y, p.Z, h); } public bool Intersects(IBlock3D b) { return Intersects(b.X, b.Y, b.Z, b.H); } public bool Intersects(int x, int y, int z) { return Intersects(x, y, z, 0); } public bool Intersects(int x, int y, int z, int h) { return Blocks.Any(b => b.Intersects(x, y, z, h)); } public bool Intersects(IWireframe frame) { return frame != null && Blocks.Any(b => frame.Intersects(b)); } public Rectangle3D GetBounds() { Point3D min = Point3D.Zero, max = Point3D.Zero; foreach (var b in Blocks) { min.X = Math.Min(min.X, b.X); min.Y = Math.Min(min.Y, b.Y); min.Z = Math.Min(min.Z, b.Z); max.X = Math.Max(max.X, b.X); max.Y = Math.Max(max.Y, b.Y); max.Z = Math.Max(max.Z, b.Z + b.H); } return new Rectangle3D(min, max); } public IEnumerable Offset(int x = 0, int y = 0, int z = 0, int h = 0) { return Blocks.Select(b => b.Offset(x, y, z, h)); } public IEnumerator GetEnumerator() { return Blocks.AsEnumerable().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public Block3D this[int index] { get { if (index < 0 || index >= Blocks.Length) { return Block3D.Empty; } return Blocks[index]; } set { if (index >= 0 && index < Blocks.Length) { Blocks[index] = value; _Hash = null; } } } private int? _Hash; public int HashCode => _Hash ?? (_Hash = Blocks.GetContentsHashCode(true)).Value; public override int GetHashCode() { return HashCode; } public override bool Equals(object obj) { return obj is Wireframe && Equals((Wireframe)obj); } public bool Equals(Wireframe other) { return !ReferenceEquals(other, null) && (ReferenceEquals(this, other) || GetHashCode() == other.GetHashCode()); } public override string ToString() { return String.Format("Wireframe ({0:#,0} blocks)", Length); } public static bool operator ==(Wireframe l, Wireframe r) { return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r); } public static bool operator !=(Wireframe l, Wireframe r) { return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r); } } public class DynamicWireframe : IEquatable, IWireframe { public bool Rendering { get; protected set; } public virtual List Blocks { get; set; } public virtual int Volume => Blocks.Count; public int Count => Blocks.Count; public DynamicWireframe(params IBlock3D[] blocks) : this(blocks.Ensure().Select(b => new Block3D(b))) { } public DynamicWireframe(IEnumerable blocks) : this(blocks.Ensure().Select(b => new Block3D(b))) { } public DynamicWireframe(Wireframe frame) : this(frame.Blocks) { } public DynamicWireframe() : this(0x100) { } public DynamicWireframe(int capacity) { Blocks = new List(capacity); } public DynamicWireframe(params Block3D[] blocks) { Blocks = blocks.Ensure().ToList(); } public DynamicWireframe(IEnumerable blocks) { Blocks = blocks.Ensure().ToList(); } public DynamicWireframe(GenericReader reader) { Rendering = true; Deserialize(reader); Rendering = false; } public void Flatten() { var list = ListPool.AcquireObject(); list.AddRange(this); Clear(); AddRange(list.Flatten()); ObjectPool.Free(ref list); } public bool Intersects(IPoint3D p) { return Intersects(p.X, p.Y, p.Z); } public bool Intersects(IBlock3D b) { return Intersects(b.X, b.Y, b.Z, b.H); } public bool Intersects(int x, int y, int z) { return Intersects(x, y, z, 0); } public bool Intersects(int x, int y, int z, int h) { return Blocks.Any(b => b.Intersects(x, y, z, h)); } public bool Intersects(IWireframe frame) { return frame != null && Blocks.Any(b => frame.Intersects(b)); } public Rectangle3D GetBounds() { Point3D min = Point3D.Zero, max = Point3D.Zero; foreach (var b in Blocks) { min.X = Math.Min(min.X, b.X); min.Y = Math.Min(min.Y, b.Y); min.Z = Math.Min(min.Z, b.Z); max.X = Math.Max(max.X, b.X); max.Y = Math.Max(max.Y, b.Y); max.Z = Math.Max(max.Z, b.Z + b.H); } return new Rectangle3D(min, max); } public IEnumerable Offset(int x = 0, int y = 0, int z = 0, int h = 0) { return Blocks.Select(b => b.Offset(x, y, z, h)); } public virtual void Clear() { Blocks.Free(true); _Hash = null; } public virtual void Add(Block3D item) { if (item != null) { Blocks.Add(item); _Hash = null; } } public virtual void AddRange(IEnumerable collection) { if (collection != null) { Blocks.AddRange(collection); _Hash = null; } } public virtual bool Remove(Block3D item) { if (item == null) { return false; } var success = Blocks.Remove(item); Blocks.Free(false); _Hash = null; return success; } public virtual int RemoveAll(Predicate match) { if (match == null) { return 0; } var success = Blocks.RemoveAll(match); Blocks.Free(false); _Hash = null; return success; } public virtual void RemoveAt(int index) { if (!Blocks.InBounds(index)) { return; } Blocks.RemoveAt(index); Blocks.Free(false); _Hash = null; } public virtual void RemoveRange(int index, int count) { if (!Blocks.InBounds(index)) { return; } Blocks.RemoveRange(index, count); Blocks.Free(false); _Hash = null; } public virtual void ForEach(Action action) { Blocks.ForEach(action); } public virtual IEnumerator GetEnumerator() { return Blocks.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public virtual Block3D this[int index] { get { if (index < 0 || index >= Blocks.Count) { return Block3D.Empty; } return Blocks[index]; } set { if (index >= 0 && index < Blocks.Count) { Blocks[index] = value; _Hash = null; } } } private int? _Hash; public int HashCode => _Hash ?? (_Hash = Blocks.GetContentsHashCode(true)).Value; public override int GetHashCode() { return HashCode; } public override bool Equals(object obj) { return obj is DynamicWireframe && Equals((DynamicWireframe)obj); } public bool Equals(DynamicWireframe other) { return !ReferenceEquals(other, null) && (ReferenceEquals(this, other) || GetHashCode() == other.GetHashCode()); } public override string ToString() { return String.Format("DynamicWireframe ({0:#,0} blocks)", Count); } public virtual void Serialize(GenericWriter writer) { writer.SetVersion(0); writer.WriteList(Blocks, (w, b) => w.WriteBlock3D(b)); } public virtual void Deserialize(GenericReader reader) { reader.GetVersion(); Blocks = reader.ReadList(r => reader.ReadBlock3D()); } public static bool operator ==(DynamicWireframe l, DynamicWireframe r) { return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r); } public static bool operator !=(DynamicWireframe l, DynamicWireframe r) { return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r); } } }