using System; using System.Collections.Generic; using System.Linq; using Godot; using VirtualChemDemo.Concepts; using VirtualChemistry.Chemistry.Atoms.Implements; using VirtualChemistry.Chemistry.Atoms.Resolver; using VirtualChemistry.Chemistry.Bonds.Implements; using VirtualChemistry.Chemistry.Compounds.Implements; using VirtualChemistry.Chemistry.Mixtures.Implements; public partial class CompoundConstructor : Panel { private HeterogeneousMixture HeterogeneousMixture { get; set; } public HomogeneousMixture HomogeneousMixture { get; set; } public HashSet Atoms { get; set; } = new(); public BaseBond ConnectPending { get; set; } = BaseBond.Null; public Atom PendingAtom { get; set; } public Dictionary> BondMap { get; set; } = new(); private Viewer PanelViewer { get; set; } public override void _Ready() { GlobalScene.CompoundConstructor = this; HeterogeneousMixture = new(); HomogeneousMixture = HeterogeneousMixture.AddLayer(); PanelViewer = GetNode("Viewer"); } private static class AtomPositionFixMemory { public static Atom[] SavedAtoms { get; set; } = null; private static int I { get; set; } private static int J { get; set; } public static int Max => SavedAtoms.Length; public static void Reset() { SavedAtoms = null; I = 0; J = 0; } public static void OneStep() { if (J >= Max) { J = 0; I++; } if (I >= Max) { Reset(); return; } if (I == J) { J++; return; } Atom a1 = SavedAtoms[I]; Atom a2 = SavedAtoms[J]; if ((a1.Position - a2.Position).Length() < 64) { Vector2 pd = a1.Position - a2.Position; if (pd == Vector2.Zero) pd = new Vector2(J % 3 - 2, I % 3 - 1); a1.Position += pd; a2.Position -= pd; if (GlobalScene.CompoundConstructor.BondMap.TryGetValue(a1, out var bonds1)) foreach (Bond2D b1 in bonds1) b1.BondUpdate(); if(GlobalScene.CompoundConstructor.BondMap.TryGetValue(a2, out var bonds2)) foreach (Bond2D b2 in bonds2) b2.BondUpdate(); } J++; } } public override void _Process(double delta) { if (AtomPositionFixMemory.SavedAtoms == null) AtomPositionFixMemory.SavedAtoms = Atoms.ToArray(); AtomPositionFixMemory.OneStep(); } public override bool _CanDropData(Vector2 atPosition, Variant data) { return true; } public override void _DropData(Vector2 atPosition, Variant data) { Atom a = data.As(); a.Position = atPosition; if(BondMap.ContainsKey(a)) foreach (Bond2D b in BondMap[a]) b.BondUpdate(); } public void AddAtomOf(int idx) { BaseAtom a = AtomResolver.Resolve(idx); Compound c = a.GrabCompound; c.Amount = 1; a.Compound = c; Atom at = ResourceLoader.Load("res://Scenes/Atom.tscn").Instantiate(); at.BaseAtom = a; AddChild(at); at.Position = new(500, 500); HomogeneousMixture.AddCompound(c, true, true); Atoms.Add(at); AtomPositionFixMemory.Reset(); } public void RemoveAtomOf(Atom atom) { foreach (BaseBond b in atom.BaseAtom.ConnectedBonds) b.Disconnect(); Bond2D[] toRemove = Array.Empty(); if (BondMap.TryGetValue(atom, out HashSet value)) toRemove = value.ToArray(); foreach (Bond2D b in toRemove) { BondMap[b.AtomFrom].Remove(b); BondMap[b.AtomTo].Remove(b); RemoveChild(b); } atom.BaseAtom.Compound.HomogeneousMixture.Compounds.Remove(atom.BaseAtom.Compound); atom.BaseAtom.Compound.HomogeneousMixture = HomogeneousMixture.Null; atom.BaseAtom.Compound = Compound.Null; RemoveChild(atom); Atoms.Remove(atom); AtomPositionFixMemory.Reset(); } public void ConnectAtoms(Atom a, BaseBond b) { b.Connect(ConnectPending); Bond2D bond = Bond2D.Resolve(b, ConnectPending); bond.AtomFrom = PendingAtom; bond.AtomTo = a; bond.BondFrom = ConnectPending; bond.BondTo = b; if (!BondMap.ContainsKey(a)) BondMap[a] = new HashSet(); BondMap[a].Add(bond); if (!BondMap.ContainsKey(PendingAtom!)) BondMap[PendingAtom] = new HashSet(); BondMap[PendingAtom].Add(bond); ConnectPending = BaseBond.Null; a.AtomActions.BuildMenu(); PendingAtom.AtomActions.BuildMenu(); PendingAtom = null; AddChild(bond); foreach (Bond2D bd in BondMap[a]) bd.BondUpdate(); } private void Back() { GlobalScene.MainScene.SwitchToDemo(); } private void Build() { if(HomogeneousMixture.Compounds.Count==0) return; HeterogeneousMixture.Container = GlobalScene.Demo.SelectedBottle; GlobalScene.Demo.SelectedBottle.Content = HeterogeneousMixture; GlobalScene.Demo.SelectedBottle.BuildMenu(); Clear(); Back(); } private void Clear(bool save = true) { if (!save) { foreach (Atom atom in Atoms) RemoveAtomOf(atom); return; } HashSet removedBonds = new(); foreach (Atom atom in Atoms) { RemoveChild(atom); if (!BondMap.ContainsKey(atom)) continue; foreach (Bond2D bond in BondMap[atom]) { if (!removedBonds.Contains(bond)) RemoveChild(bond); removedBonds.Add(bond); } } Atoms = new(); BondMap = new(); HeterogeneousMixture = new HeterogeneousMixture(); HomogeneousMixture = HeterogeneousMixture.AddLayer(); } private void ForceClear() => Clear(false); private void BackToCenter() => PanelViewer.BackToCenter(); }