Files
VirtualChemistry.Demo/Scenes/CompoundConstructor.cs
2024-06-27 04:16:35 +08:00

218 lines
5.2 KiB
C#
Executable File

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<Atom> Atoms { get; set; } = new();
public BaseBond ConnectPending { get; set; } = BaseBond.Null;
public Atom PendingAtom { get; set; }
public Dictionary<Atom, HashSet<Bond2D>> BondMap { get; set; } = new();
private Viewer PanelViewer { get; set; }
public override void _Ready()
{
GlobalScene.CompoundConstructor = this;
HeterogeneousMixture = new();
HomogeneousMixture = HeterogeneousMixture.AddLayer();
PanelViewer = GetNode<Viewer>("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<Atom>();
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<PackedScene>("res://Scenes/Atom.tscn").Instantiate<Atom>();
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<Bond2D>();
if (BondMap.TryGetValue(atom, out HashSet<Bond2D> 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<Bond2D>();
BondMap[a].Add(bond);
if (!BondMap.ContainsKey(PendingAtom!))
BondMap[PendingAtom] = new HashSet<Bond2D>();
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<Bond2D> 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();
}