Example #1
0
    private MelDB LoadIndexFromBytes(byte[] bytes)
    {
        var          stream         = new MemoryStream(bytes);
        BinaryReader br             = new BinaryReader(stream, encoding);
        var          result         = new MelDB();
        int          particlesCount = br.ReadInt32();
        var          particles      = new List <ParticleInfo>(particlesCount);

        result.particles = particles;

        for (int i = particlesCount - 1; i >= 0; i--)
        {
            var p = new ParticleInfo();
            particles.Add(p);

            p.atomsHash                  = br.ReadUInt32();
            p.structureHash              = br.ReadUInt32();
            p.structureHashExact         = br.ReadUInt32();
            p.binaryDataLocationInBucket = br.ReadUInt16();
            p.id   = br.ReadUInt64();
            p.name = br.ReadString();
            var flags = (ParticleInfo.ParticleFlags)br.ReadUInt16();
            p.flags = flags;
            if ((flags & ParticleInfo.ParticleFlags.HasChemicalFormula) > 0)
            {
                p.chemicalFormula = br.ReadString();
            }
            if ((flags & ParticleInfo.ParticleFlags.HasParticleCharge) > 0)
            {
                p.charge = br.ReadSByte();
            }
            int casesCount = br.ReadByte();
            p.CASes = new List <uint>(casesCount);
            for (int cas = 0; cas < casesCount; cas++)
            {
                p.CASes.Add(br.ReadUInt32());
            }
        }

        result.__sortedIds = new ushort[particlesCount];
        for (int i = 0; i < particlesCount; i++)
        {
            result.__sortedIds[i] = br.ReadUInt16();
        }
        //result.__sortedStructureHashes = new ushort[particlesCount];
        //for (int i = 0; i < particlesCount; i++)
        //    result.__sortedStructureHashes[i] = br.ReadUInt16();
        //result.__sortedStructureHashesExact = new ushort[particlesCount];
        //for (int i = 0; i < particlesCount; i++)
        //    result.__sortedStructureHashesExact[i] = br.ReadUInt16();
        result.__sortedAtomsHashes = new ushort[particlesCount];
        for (int i = 0; i < particlesCount; i++)
        {
            result.__sortedAtomsHashes[i] = br.ReadUInt16();
        }

        br.Close();
        stream.Dispose();
        return(result);
    }
Example #2
0
    public override IEnumerator LoadParticleDataAsync(ParticleInfo p)
    {
        string path = GetParticlePath(p);

        if (!File.Exists(path))
        {
            throw new Exception("file was not found: " + path);
        }

        var request = new ParticleDataRequest();

        var thread = new System.Threading.Thread(() => {
            var reader   = new FileStream(path, FileMode.Open);
            request.data = _pDataSerializer.Deserialize(reader) as ParticleInfo.ParticleInfoData;
            reader.Dispose();
            request.isDone = true;
        });

        thread.IsBackground = true;
        thread.Start();

        while (!request.isDone)
        {
            yield return(null);
        }

        p.data = request.data;
    }
 private void Update()
 {
     //IL_009f: Unknown result type (might be due to invalid IL or missing references)
     if (isWorking)
     {
         execSec += Time.get_deltaTime();
         float num = 0f;
         if (execSec >= targetSec)
         {
             execSec   = targetSec;
             num       = 1f;
             isWorking = false;
         }
         else
         {
             num = execSec / targetSec;
         }
         float num2 = 1f - (1f - endScale) * num;
         if (isScale)
         {
             float num3 = firstScale * num2;
             _scale.Set(num3, num3, num3);
             _transform.set_localScale(_scale);
         }
         int i = 0;
         for (int count = this.particleInfo.Count; i < count; i++)
         {
             ParticleInfo particleInfo = this.particleInfo[i];
             particleInfo.psr.set_lengthScale(particleInfo.firstLength * num2);
         }
     }
 }
Example #4
0
        public Form1()
        {
            InitializeComponent();

            EnvMeta = new EnvironmentInfo(MapPanel.Height,
                                          MapPanel.Width,
                                          decimal.ToInt32(MapScaleSpinBttn.Value),
                                          (double)ObstacleWidthSpinBttn.Value);
            SensorMeta = new SensorInfo(decimal.ToInt32(SensorAngleSpinBttn.Value),
                                        (double)SensorDistanceSpinBttn.Value,
                                        (double)SigmaHitSpinBttn.Value,
                                        (double)ZHitSpinBttn.Value,
                                        (double)ZRandSpinBttn.Value,
                                        (double)ZMaxSpinBttn.Value);
            RobotMeta = new RobotInfo((double)a1SpinBttn.Value,
                                      (double)a2SpinBttn.Value,
                                      (double)a3SpinBttn.Value,
                                      (double)a4SpinBttn.Value,
                                      (double)RobotRadiusSpinBttn.Value,
                                      (double)RobotTransStepSpinBttn.Value,
                                      (double)RobotRotStepSpinBttn.Value,
                                      new Point(EnvMeta.Width / 2, EnvMeta.Height / 2));
            ParticleMeta      = new ParticleInfo(0, ResampleMethod.Multinomial);
            ParticleList.View = View.Details;
        }
Example #5
0
        private void AddTimeline(ParticleContainer container, ParticleInfo info, ChemicalVisualization viz)
        {
            Timeline tl = new Timeline(info.Name, ConvertColor(info.Color));

            Functions.Add(new BasicFunctionPair(() => viz.Time, () => container.GetNParticles(info.Name)));
            AddTimeline(tl);
        }
Example #6
0
        public void Launch_AnimatedParticle(ParticleInfo info)
        {
//            isAdditive = false;
            this.SetIsAdditive(false);
            type          = info.type;
            hasGravity    = info.hasGravity;
            isAnimated    = info.isAnimated;
            numAnimFrames = info.numAnimFrames;
            texture       = info.texture[0];
            velocity      = info.velocity;
            mapPosition   = info.startPosition;
            rotation      = info.rotationStart;
            for (int i = 0; i < numAnimFrames; i++)
            {
                Globals.Assert(i < (int)Enum1.kMaxAnimFrames);
                animFrame[i]             = info.texture[i];
                animatedSubtexture[i]    = info.animatedSubtexture[i];
                timeBetweenAnimFrames[i] = info.timeBetweenAnimFrames[i];
            }

            animTimer      = 0;
            currentAnim    = 0;
            scale          = info.scaleStart;
            scaleSpeed     = info.scaleSpeed;
            alpha          = info.alphaStart;
            screenPosition = (Globals.g_world.game).GetScreenPosition(mapPosition);
        }
Example #7
0
    //随机粒子的位置,大小,半径
    void randomLocationAndSize()
    {
        for (int i = 0; i < number; i++)
        {
            //扩展后的随机运动半径
            float MidRadius = (MaxRadius + MinRadius) / 2;
            float outRate   = Random.Range(1f, MidRadius / MinRadius);
            float inRate    = Random.Range(MaxRadius / MidRadius, 1f);
            float _radius   = Random.Range(MinRadius * outRate, MaxRadius * inRate);
            radius[i] = _radius;

            //收缩后的随机运动半径
            float collect_MidRadius = (collect_MaxRadius + collect_MinRadius) / 2;
            float collect_outRate   = Random.Range(1f, collect_MidRadius / collect_MinRadius);
            float collect_inRate    = Random.Range(collect_MaxRadius / collect_MidRadius, 1f);
            float _collect_radius   = Random.Range(collect_MinRadius * collect_outRate, collect_MaxRadius * collect_inRate);
            collect_radius[i] = _collect_radius;

            //下面保持不变
            float size       = Random.Range(MinSize, MaxSize);
            float angleDgree = Random.Range(0, 360f);
            float angle      = (angleDgree * Mathf.PI) / 180;

            float time = Random.Range(0, 360f);

            particles[i]             = new ParticleInfo(_radius, angleDgree, time, size);
            particleArr[i].position  = new Vector3(particles[i].radius * Mathf.Cos(angle), particles[i].radius * Mathf.Sin(angle), 0);
            particleArr[i].startSize = particles[i].size;
        }
        particleSys.SetParticles(particleArr, particleArr.Length);
    }
    // Caches find request.
    private ParticleInfo FindParticleCAS(string cas)
    {
        Debug.Log("FindParticleCAS " + cas);

        if (string.IsNullOrEmpty(cas))
        {
            return(null);
        }

        uint casNumber = MelDB.ParseCASNumber(cas);

        if (casNumber == 0)
        {
            return(null);
        }

        if ((_cachedParticle != null) && (_cachedParticle.CASes.Contains(casNumber)))
        {
            return(_cachedParticle);
        }

        _cachedParticle = MelDB.Particles.Find(p => p.CASes.Contains(casNumber));

        return(_cachedParticle);
    }
Example #9
0
        public override void OnPauseUpdateLoop()
        {
            UnRegisterEntity(particleInfo);

            c = getMouseHoveredCircle();

            if (c != null)
            {
                particleInfo = new ParticleInfo(c.CenterPoint, c.Velocity, c.Mass);

                h = c;

                if (MouseWheelSpins)
                {
                    if (BiggerSmaller == 1)
                    {
                        if (h.Mass < 30)
                        {
                            h.Mass++;
                        }
                    }
                    if (BiggerSmaller == -1)
                    {
                        if (h.Mass != 1)
                        {
                            h.Mass--;
                        }
                    }
                    MouseWheelSpins = false;
                }
            }

            if (mouseLeftDown)
            {
                if (h != null)
                {
                    UnRegisterEntity(particleInfo);
                    particleInfo = new ParticleInfo(h.CenterPoint, new Vector2((MousePos.x - h.CenterPoint.x) / 20, (MousePos.y - h.CenterPoint.y) / 20), h.Mass);
                }
                if (h == null)
                {
                    new Circle(new Vector2(MousePos.x, MousePos.y), new Vector2(), 20, 1);
                    mouseLeftDown = false;
                }
            }
            if (mouseRightDown)
            {
                if (h != null)
                {
                    h.UnregisterInList(h);
                    h = null;
                }
            }

            if (!mouseLeftDown && h != null)
            {
                h.Velocity = particleInfo.Scale;
                h          = null;
            }
        }
 public void Work(float sec)
 {
     //IL_0084: Unknown result type (might be due to invalid IL or missing references)
     //IL_0089: Unknown result type (might be due to invalid IL or missing references)
     if (!isWorking && sec != 0f)
     {
         this.particleInfo.Clear();
         int i = 0;
         for (int num = particles.Length; i < num; i++)
         {
             ParticleSystemRenderer component = particles[i].GetComponent <ParticleSystemRenderer>();
             if (!object.ReferenceEquals(component, null))
             {
                 ParticleInfo particleInfo = new ParticleInfo();
                 particleInfo.psr         = component;
                 particleInfo.firstLength = component.get_lengthScale();
                 this.particleInfo.Add(particleInfo);
             }
         }
         Vector3 localScale = _transform.get_localScale();
         firstScale = localScale.x;
         execSec    = 0f;
         targetSec  = sec;
         isWorking  = true;
     }
 }
    public static string GetMolecularFormula(ParticleInfo particle, bool formatted = true)
    {
        CountDifferentAtoms(particle.atoms);
        var ordering = GetMolecularFormulaOrderingFor(particle.flags);

        return(GetSimpleMolecularFormulaInner(ordering, formatted));
    }
Example #12
0
 public static void RemoveParticle(ParticleInfo p)
 {
     if (Instance.particles.Remove(p))
     {
         MelDBSerializer.xmlInstance.RemoveParticleFile(p);
     }
 }
Example #13
0
        private void SaveParticleBttn_Click(object sender, EventArgs e)
        {
            if (SimulationOn)
            {
                return;
            }
            ResampleMethod r;

            if (MultinomialResample.Checked)
            {
                r = ResampleMethod.Multinomial;
            }
            else if (SystematicResample.Checked)
            {
                r = ResampleMethod.Systematic;
            }
            else if (StratifiedResample.Checked)
            {
                r = ResampleMethod.Stratified;
            }
            else
            {
                throw new System.ArgumentOutOfRangeException("Resample method", "Particle resample method not implemented");
            }
            ParticleMeta = new ParticleInfo(decimal.ToInt32(ParticleCountSpinBttn.Value), r);
        }
Example #14
0
    void IniAll()
    {
        float minRadius = 6.0f;  // 最小半径
        float maxRadius = 10.0f; // 最大半径

        for (int i = 0; i < count; ++i)
        {
            // 随机每个粒子半径,集中于平均半径附近
            float midRadius = (maxRadius + minRadius) / 2;
            float minRate   = Random.Range(1.0f, midRadius / minRadius);
            float maxRate   = Random.Range(midRadius / maxRadius, 1.0f);
            float radius    = Random.Range(minRadius * minRate, maxRadius * maxRate);

            // 随机每个粒子的角度
            float angle = Random.Range(0, 360);
            // 转换成弧度制
            float radian = angle / 180 * Mathf.PI;

            // 随机每个粒子的大小
            float size = Random.Range(0.01f, 0.03f);

            info[i] = new ParticleInfo(radius, angle);

            particleArr[i].position = new Vector3(info[i].radius * Mathf.Cos(radian), 0f, info[i].radius * Mathf.Sin(radian));
            particleArr[i].size     = size;
        }
        // 通过初始化好的粒子数组设置粒子系统
        particleSys.SetParticles(particleArr, particleArr.Length);
    }
Example #15
0
    /// <summary>
    /// Compares two particles on topological equality
    /// </summary>
    /// <param name="exact">pass true if you want the bonds to be thoroughly compared</param>
    /// <param name="reordering">if you pass it, the correspondance atom indexes will be written in it: if reordering[11] == 22 then atom 11 from particle 1 is the same as atom 22 in particle 2</param>
    /// <returns></returns>
    public static bool AreEqual(List <Element> atms, List <BondInfo> bonds, ParticleInfo part2, bool exact, List <int> reordering, bool checkMolecularFormula = true)
    {
        _reordering1.selectedReordering = 0;
        _reordering1.reordering         = reordering;
        var result = AreEqual(atms, bonds, part2, exact, _reordering1, checkMolecularFormula);

        _reordering1.reordering = null;
        return(result);
    }
Example #16
0
    /// <summary>
    /// Compares two particles on topological equality
    /// </summary>
    /// <param name="exact">pass true if you want the bonds types to be taken into account</param>
    /// <param name="reordering">if you pass it, the correspondance atom indexes will be written in it: if reordering[11] == 22 then atom 11 from particle 1 is the same as atom 22 in particle 2</param>
    /// <returns>true if the particles are equal</returns>
    public static bool AreEqual(ParticleInfo part1, ParticleInfo part2, bool exact, List <int> reordering)
    {
        _reordering1.selectedReordering = 0;
        _reordering1.reordering         = reordering;
        var result = AreEqual(part1, part2, exact, _reordering1);

        _reordering1.reordering = null;
        return(result);
    }
Example #17
0
    public static uint GetStructureHash(ParticleInfo particle, bool exact, List <int> reordering)
    {
        _reordering2.selectedReordering = 0;
        _reordering2.reordering         = reordering;
        var hash = GetStructureHash(particle, exact, _reordering2);

        _reordering2.reordering = null;
        return(hash);
    }
    public void ShowCAS(string cas)
    {
        Debug.Log("ShowCAS " + cas);

        ParticleInfo particleInfo = FindParticleCAS(cas);

        ShowParticle(particleInfo);

        JSImports.ShowCAS_Callback(cas, particleInfo != null);
    }
Example #19
0
    protected bool IncludeInBuild(ParticleInfo p)
    {
        var flags = p.flags;

        if ((flags & _include) > 0)
        {
            return(true);
        }
        return(false);
    }
Example #20
0
    public GameObject Spawner(int effId, Vector3 v, Transform parent)
    {
        ParticleInfo particleInfo = InfoMgr <ParticleInfo> .Instance.GetInfo(effId);

        if (null != particleInfo)
        {
            return(Spawner(particleInfo.data, v, parent));
        }
        return(null);
    }
Example #21
0
 public void Launch_WaterLine(ParticleInfo info)
 {
     type         = ParticleType.kParticle_WaterLine;
     mapPosition  = info.startPosition;
     animTimer    = 0.0f;
     alphaSpeed   = 1.0f;
     alphaStart   = 1.0f;
     subTextureId = 22;
     scale        = 0.75f;
     rotation     = 0.0f;
 }
Example #22
0
 public void StopParticle(string name, bool clear = false)
 {
     if (!string.IsNullOrEmpty(name))
     {
         ParticleInfo info = _activeParticles.Find(delegate(ParticleInfo p) { return(p._name == name); });
         if (info != null)
         {
             StopParticleInternal(info, clear, clear);
         }
     }
 }
        static internal void Run()
        {
            const double containerSize = 50;
            const double minSpeed      = 0;
            const double maxSpeed      = 4200;
            const double mass          = 1.7e-25;
            Color        color         = Colors.Lavender;
            const int    nParticles    = 1000;
            const double deltaTime     = 0.1;
            const string name          = "Molecule";

            double temperature = 293.15;


            var cont      = new ParticleContainer(containerSize);
            var info      = new ParticleInfo(name, mass, ConvertColor(color));
            var generator = new BoltzmannGenerator(cont, minSpeed, maxSpeed);


            cont.Dictionary.AddParticle(info);
            cont.AddRandomParticles(generator, name, nParticles);

            var visualization = new ThermodynamicsVisualization(cont)
            {
                BoxColor = Colors.IndianRed
            };

            var viz = new MotionVisualizer3DControl(visualization)
            {
                TimeIncrement = deltaTime,
                TimeScale     = 1
            };

            viz.FastDraw = true;

            const int histogramBins = 50;



            viz.Manager.AddSingleGraph("Temperature", ConvertColor(Colors.CornflowerBlue), () => visualization.Time, () => cont.GetTemperature(), "Time (s)", "Temperature (K)");

            viz.Manager.AddHist(histogramBins, ConvertColor(Colors.BlueViolet), () => cont.GetParticlePropertyList((Particle part) => part.Velocity.Magnitude), "Speed (m/s)");

            //viz.Manager.AddText("Temperature (K)", ConvertColor(Colors.CadetBlue), () => GetTemperature(cont)+"");

            viz.Manager.AddSingleGraph("Pressure", ConvertColor(Colors.Red), () => visualization.Time, () => cont.Pressure, "Time (s)", "Pressure (Pa)");

            viz.Manager.AddSingleGraph("# Particles", ConvertColor(Colors.Green), () => visualization.Time, () => cont.Particles.Count, "Time (s)", "# Particles");
            viz.Manager.AddSingleGraph("Volume", ConvertColor(Colors.Orange), () => visualization.Time, () => Math.Pow(cont.Size.X, 3), "Time (s)", "Volume (m^3)");



            viz.Show();
        }
Example #24
0
    public override void LoadParticleData(ParticleInfo p)
    {
        var path      = BucketFilename + GetParticleBuckedIndex(p).ToString("000");
        var dataAsset = Resources.Load <TextAsset>(path);

        if (dataAsset == null)
        {
            throw new Exception("Failed to load from Resources: " + path);
        }
        LoadParticleFromBytes(dataAsset.bytes, p);
    }
Example #25
0
 public void Launch_PondBlob(ParticleInfo info)
 {
     type         = ParticleType.kParticle_PondBlob;
     mapPosition  = info.startPosition;
     animTimer    = 0.0f;
     alphaSpeed   = 2.6f;
     alphaStart   = 1.0f;
     subTextureId = 23;
     scale        = 0.75f;
     rotation     = 0.0f;
 }
        static internal void Run()
        {
            const double containerSize = 50;
            const double minSpeed      = 1;
            const double maxSpeed      = 100;
            const double mass          = 4.65e-23;
            Color        color         = Colors.Lavender;
            const int    nParticles    = 1000;
            const double deltaTime     = .01;
            const string name          = "Molecule";
            double       temperature   = 293.15;

            var cont = new ParticleContainer(containerSize, containerSize, containerSize);
            var info = new ParticleInfo(name, mass, ConvertColor(color));
            //var generator = new FlatGenerator(cont, minSpeed, maxSpeed);
            var generator = new BoltzmannDistribution(cont, minSpeed, maxSpeed, temperature);

            cont.Dictionary.AddParticle(info);
            cont.AddRandomParticles(generator, name, nParticles);

            cont.Pressure = cont.Particles.Count * DongUtility.Constants.BoltzmannConstant * cont.GetTemperature() / (50 * 50 * 50);


            var visualization = new ThermodynamicsVisualization(cont)
            {
                BoxColor = Colors.IndianRed
            };

            var viz = new MotionVisualizer(visualization)
            {
                TimeIncrement = deltaTime,
                TimeScale     = 1
            };

            const int histogramBins = 50;

            viz.AddSingleGraph("Pressure", Colors.CornflowerBlue, () => visualization.Time, () => cont.Pressure, "Time (s)", "Pressure (N/m^2)");
            //viz.AddText("Pressure", Colors.CadetBlue, () => cont.GetTemperature() * nParticles * DongUtility.Constants.BoltzmannConstant / (Math.Pow(containerSize,3)) );

            //viz.AddSingleGraph("Pressure vs. Temperature", Colors.CornflowerBlue, () => cont.GetTemperature(), () => cont.Pressure, "Temperature (K)", "Pressure (N/m^2)");
            viz.AddSingleGraph("Temperature vs. Time", Colors.CornflowerBlue, () => visualization.Time, () => cont.GetTemperature(), "Time (s)", "Temperature (K)");

            //viz.AddHist(histogramBins, Colors.BlueViolet, () => cont.GetParticlePropertyList((Particle part) => part.Velocity.Magnitude), "Speed (m/s)");

            //Volume vs. Temperature when n and P are constant
            viz.AddSingleGraph("Volume vs. Temperature", Colors.CornflowerBlue, () => cont.GetTemperature(), () => nParticles * DongUtility.Constants.BoltzmannConstant * cont.GetTemperature() / cont.Pressure, "Temperature (K)", "Volume (m^3)");
            //viz.AddText("Volume", Colors.CadetBlue, () => cont.GetTemperature() * nParticles * DongUtility.Constants.BoltzmannConstant / (cont.Pressure) );


            viz.AutoCamera = true;
            viz.AutoCamera = false;
            viz.Show();
        }
Example #27
0
        public ParticleGraphProto(ParticleInfo particle, bool exact, uint[] hashes)
        {
            atoms   = new List <AtomNodeProto>();
            _hashes = hashes;
            var atms = particle.atoms;

            for (int i = 0; i < atms.Count; i++)
            {
                atoms.Add(new AtomNodeProto(atms[i].element, i, hashes));
            }
            InitBonds(particle.bonds, exact);
        }
    public bool NamesEqual(ParticleInfo other)
    {
        if (!string.IsNullOrEmpty(name) & !string.IsNullOrEmpty(other.name))
        {
            if (name.Equals(other.name, StringComparison.Ordinal))
            {
                return(true);
            }
        }

        if (!string.IsNullOrEmpty(primaryName) & !string.IsNullOrEmpty(other.primaryName))
        {
            if (primaryName.Equals(other.primaryName, StringComparison.Ordinal))
            {
                return(true);
            }
        }

        if (!string.IsNullOrEmpty(primaryName))
        {
            for (int i = 0; i < other.iupacs.Count; i++)
            {
                if (primaryName.Equals(other.iupacs[i], StringComparison.Ordinal))
                {
                    return(true);
                }
            }
        }
        if (!string.IsNullOrEmpty(other.primaryName))
        {
            for (int i = 0; i < iupacs.Count; i++)
            {
                if (other.primaryName.Equals(iupacs[i], StringComparison.Ordinal))
                {
                    return(true);
                }
            }
        }

        for (int i = 0; i < other.iupacs.Count; i++)
        {
            var otherName = other.iupacs[i];
            for (int j = 0; j < iupacs.Count; j++)
            {
                if (otherName.Equals(iupacs[j], StringComparison.Ordinal))
                {
                    return(true);
                }
            }
        }
        return(false);
    }
Example #29
0
    public ParticleInfo CreateNewParticle()
    {
        ParticleInfo particleInfo = new ParticleInfo
        {
            ConfigValues = m_configValues,
            VertInfo     = new VertInfo(),
        };

        particleInfo.VertInfo.VertID = m_vertIDIndex++;
        AddVert(particleInfo.VertInfo);

        return(particleInfo);
    }
Example #30
0
    public static bool AreEqual(ParticleInfo part1, ParticleInfo part2, bool exact, AtomsReordering reordering = null)
    {
        // compare by hashes
        if (exact)
        {
            if (part1.structureHashExact != 0 & part2.structureHashExact != 0) // only if hashes are already calculated
            {
                if (part1.structureHashExact != part2.structureHashExact)
                {
                    return(false);
                }
            }
        }
        else
        {
            if (part1.structureHash != 0 & part2.structureHash != 0) // only if hashes are already calculated
            {
                if (part1.structureHash != part2.structureHash)
                {
                    return(false);
                }
            }
        }
        // init particles and compare the rest
        var atoms1 = part1.atoms;
        var atoms2 = part2.atoms;

        if (atoms1.Count != atoms2.Count)
        {
            return(false);
        }
        if (part1.bonds.Count != part2.bonds.Count)
        {
            return(false);
        }
        // compare by molecular formula
        var a1hash = ParticleInfo.GetAtomsHash(atoms1);
        var a2hash = ParticleInfo.GetAtomsHash(atoms2);

        if (a1hash != a2hash)
        {
            return(false);
        }
        // compare by topology
        _atomsList.Clear();
        for (int i = 0; i < part1.atoms.Count; i++)
        {
            _atomsList.Add(part1.atoms[i].element);
        }
        return(AreEqual(_atomsList, part1.bonds, part2, exact, reordering, false));
    }
    void Setup(int particleCount)
    {
        _particles = new ParticleInfo[particleCount];

            for (int i = 0; i < particleCount; ++i)
            {
                _particles[i] = new ParticleInfo(particleRadius, fallSpeed);
            }

            int vertexCount = particleCount * 4;

            _mesh = new Mesh();// GetComponent<MeshFilter>().sharedMesh;

            _vertices = new Vector3[vertexCount];
            _indices = new int[particleCount*6];
            _colors = new Color[vertexCount];
            _normals = new Vector3[vertexCount];

            // vertices : ??
            // normals : ??
            // indices
            for (int i = 0; i < particleCount; ++i)
            {
                int vtxBase = i * 4;
                int idxBase = i * 6;

                _indices[idxBase + 0] = vtxBase + 0;
                _indices[idxBase + 1] = vtxBase + 1;
                _indices[idxBase + 2] = vtxBase + 2;
                _indices[idxBase + 3] = vtxBase + 3;
                _indices[idxBase + 4] = vtxBase + 2;
                _indices[idxBase + 5] = vtxBase + 1;
            }

            // colors
            for (int i = 0; i < particleCount; ++i)
            {
                for (int j = 0; j < 4; ++j)
                {
                    _colors[i * 4 + j] = _particles[i].color;
                }
            }

            _mesh.vertices = _vertices;
            _mesh.SetIndices(_indices, MeshTopology.Triangles, 0);
            _mesh.normals = _normals;
            _mesh.colors = _colors;

            GetComponent<MeshFilter>().sharedMesh = _mesh;
    }