Archive Browser
Download ChemotaxisSimulation.zip, last updated 02/11/2020 (529.88 KB)
Download- md5: d0f0a74f8f3c043fabf60aeb07356f69
- sha1: 645a77d0f7184873fe70c2bb375833e564b348be
- sha256: da9ab3cfc5e17e120b6660a137012b6eca68a7a3218cb213b3e0e3eb9445b104
using Cyotek.ChemotaxisSimulation;
using Cyotek.ChemotaxisSimulation.Renderer;
using Cyotek.ChemotaxisSimulation.Serialization;
using Cyotek.Demo.ChemotaxisSimulation;
using Cyotek.Demo.Windows.Forms;
using Cyotek.Windows.Forms;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Media;
using System.Windows.Forms;
// Simulating Bacterial Chemotaxis
// https://www.cyotek.com/blog/simulating-bacterial-chemotaxis
// Copyright © 2020 Cyotek Ltd. All Rights Reserved.
// This work is licensed under the MIT License.
// See LICENSE.TXT for the full text
// Found this example useful?
// https://www.paypal.me/cyotek
namespace Cyotek.Demo
{
internal partial class MainForm : BaseForm
{
#region Private Fields
private bool _antiAlias;
private string _fileName;
private Random _random;
private string _scriptFileName;
private Simulation _simulation;
private GdiSimulationRenderer _simulationRenderer;
private int _updateIterations;
#endregion Private Fields
#region Public Constructors
public MainForm()
{
this.InitializeComponent();
}
#endregion Public Constructors
#region Protected Methods
protected override void OnShown(EventArgs e)
{
string[] args;
_autoSaveOptions = new AutoSaveOptions
{
SaveFolder = Application.StartupPath
};
_random = new Random();
_antiAlias = true;
_simulation = new Simulation
{
Size = new Size(256, 256)
};
_simulationRenderer = new GdiSimulationRenderer
{
Scale = 2
};
attractorCollisionModeComboBox.SelectedIndex = (int)(CollisionAction.ReduceSelf - 1);
repellentCollisionModeComboBox.SelectedIndex = (int)(CollisionAction.DestroyOther - 1);
this.SetUpdateSpeed(2);
this.NewFile();
base.OnShown(e);
args = Environment.GetCommandLineArgs();
if (args.Length == 2)
{
this.OpenFile(args[1]);
}
// scriptTextBox.Text = File.ReadAllText(@"D:\Checkout\trunk\cyotek\source\demo\ChemotaxisSimulation\samples\allgoodthings.js");
}
#endregion Protected Methods
#region Private Methods
private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
{
AboutDialog.ShowAboutDialog();
}
private void ActualSizeToolStripMenuItem_Click(object sender, EventArgs e)
{
scaleToolStripTrackBar.Value = 10;
}
private void AdvanceToolStripMenuItem_Click(object sender, EventArgs e)
{
decimal count;
count = NumericInputDialog.ShowInputDialog(this, "Enter &iterations to advance:", "Advance", 1, 1, int.MaxValue, _ => true);
if (count > 0)
{
_simulation.Run((int)count);
this.UpdateStatusBar();
renderPanel.Invalidate();
}
}
private void AllowBinaryFissionCheckBox_CheckedChanged(object sender, EventArgs e)
{
_simulation.BinaryFission = allowBinaryFissionCheckBox.Checked;
}
private void AntiAliasToolStripMenuItem_Click(object sender, EventArgs e)
{
_antiAlias = !_antiAlias;
antiAliasToolStripMenuItem.Checked = _antiAlias;
renderPanel.Invalidate();
}
private void AttritionCheckBox_CheckedChanged(object sender, EventArgs e)
{
_simulation.Attrition = attritionCheckBox.Checked;
}
private void BacteriaStrandsToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.ShowStrands = !_simulationRenderer.ShowStrands;
bacteriaStrandsToolStripMenuItem.Checked = _simulationRenderer.ShowStrands;
renderPanel.Invalidate();
}
private void BacteriaStrandTailsToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.ShowTails = !_simulationRenderer.ShowTails;
bacteriaStrandTailsToolStripMenuItem.Checked = _simulationRenderer.ShowTails;
renderPanel.Invalidate();
}
private void CopyImageToolStripMenuItem_Click(object sender, EventArgs e)
{
using (Bitmap bitmap = this.CreatePreviewImage())
{
ClipboardHelper.CopyImage(bitmap);
}
}
private void CopyToolStripMenuItem_Click(object sender, EventArgs e)
{
this.PerformClipboardAction(tb => tb.Copy());
}
private Bitmap CreatePreviewImage()
{
Bitmap bitmap;
bitmap = new Bitmap((int)(_simulation.Size.Width * _simulationRenderer.Scale), (int)(_simulation.Size.Height * _simulationRenderer.Scale), PixelFormat.Format32bppRgb);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
_simulationRenderer.Draw(_simulation, g, new Rectangle(Point.Empty, bitmap.Size));
}
return bitmap;
}
private void CutToolStripMenuItem_Click(object sender, EventArgs e)
{
this.PerformClipboardAction(tb => tb.Cut());
}
private void ExitToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void FillShapesToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.OutlinesOnly = !_simulationRenderer.OutlinesOnly;
fillShapesToolStripMenuItem.Checked = !_simulationRenderer.OutlinesOnly;
renderPanel.Invalidate();
}
private void FoodSourceDetectionZonesToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.ShowFoodDetectionZone = !_simulationRenderer.ShowFoodDetectionZone;
foodSourceDetectionZonesToolStripMenuItem.Checked = _simulationRenderer.ShowFoodDetectionZone;
renderPanel.Invalidate();
}
private void FoodSourcesToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.ShowFoodSources = !_simulationRenderer.ShowFoodSources;
foodSourcesToolStripMenuItem.Checked = _simulationRenderer.ShowFoodSources;
renderPanel.Invalidate();
}
private Control GetActiveControl(Control control)
{
Control activeControl;
ContainerControl containerControl;
TabControl tabControl;
containerControl = control as ContainerControl;
tabControl = control as TabControl;
if (containerControl != null)
{
activeControl = this.GetActiveControl(containerControl.ActiveControl);
}
else if (tabControl?.SelectedTab?.Controls.Count == 1)
{
activeControl = tabControl.SelectedTab.Controls[0];
}
else
{
activeControl = control;
}
return activeControl;
}
private void GoToToolStripMenuItem_Click(object sender, EventArgs e)
{
decimal count;
count = NumericInputDialog.ShowInputDialog(this, "Enter &iteration:", "Go To", 1, 1, int.MaxValue, v => v > _simulation.Iteration);
if (count > 0)
{
long iterations;
iterations = (long)count - _simulation.Iteration;
_simulation.Run(iterations);
this.UpdateStatusBar();
renderPanel.Invalidate();
}
}
private void HighToolStripMenuItem_Click(object sender, EventArgs e)
{
if (sender is ToolStripMenuItem menuItem && menuItem.Tag is string value && int.TryParse(value, out int count))
{
this.SetUpdateSpeed(count);
}
}
private void InitializeButton_Click(object sender, EventArgs e)
{
this.InitializeScenario();
}
private void InitializeScenario()
{
pauseToolStripButton.PerformClick();
_simulation.EnvironmentSeed = (int)environmentSeedNumericUpDown.Value;
_simulation.MovementSeed = (int)movementSeedNumericUpDown.Value;
_simulation.MinimumAttractorStrength = (int)minimumAttractorSizeNumericUpDown.Value;
_simulation.MaximumAttractorStrength = (int)maximumAttractorSizeNumericUpDown.Value;
_simulation.MinimumRepellentStrength = (int)minimumRepellentSizeNumericUpDown.Value;
_simulation.MaximumRepellentStrength = (int)maximumRepellentSizeNumericUpDown.Value;
_simulation.AttractorCollisionAction = (CollisionAction)(attractorCollisionModeComboBox.SelectedIndex + 1);
_simulation.RepellentCollisionAction = (CollisionAction)(repellentCollisionModeComboBox.SelectedIndex + 1);
_simulation.RespawnAttractor = respawnAttractorsCheckBox.Checked;
_simulation.BinaryFission = allowBinaryFissionCheckBox.Checked;
_simulation.Size = new Size((int)widthNumericUpDown.Value, (int)heightNumericUpDown.Value);
_simulation.Wrap = wrapCheckBox.Checked;
_simulation.SolidStrands = solidStrandsCheckBox.Checked;
_simulation.Attrition = attritionCheckBox.Checked;
_simulation.MobileRepellents = mobileRepellentsCheckBox.Checked;
_simulation.Reset();
for (int i = 0; i < (int)strandsNumericUpDown.Value; i++)
{
_simulation.AddStrand();
}
for (int i = 0; i < (int)attractorsNumericUpDown.Value; i++)
{
_simulation.AddAttractor();
}
for (int i = 0; i < (int)repellentsNumericUpDown.Value; i++)
{
_simulation.AddRepellent();
}
this.UpdateSimulationControls();
this.UpdateStatusBar();
renderPanel.Invalidate();
}
private void LoadFields()
{
environmentSeedNumericUpDown.Value = _simulation.EnvironmentSeed;
movementSeedNumericUpDown.Value = _simulation.MovementSeed;
minimumAttractorSizeNumericUpDown.Value = _simulation.MinimumAttractorStrength;
maximumAttractorSizeNumericUpDown.Value = _simulation.MaximumAttractorStrength;
minimumRepellentSizeNumericUpDown.Value = _simulation.MinimumRepellentStrength;
maximumRepellentSizeNumericUpDown.Value = _simulation.MaximumRepellentStrength;
attractorCollisionModeComboBox.SelectedIndex = (int)_simulation.AttractorCollisionAction - 1;
repellentCollisionModeComboBox.SelectedIndex = (int)_simulation.RepellentCollisionAction - 1;
respawnAttractorsCheckBox.Checked = _simulation.RespawnAttractor;
allowBinaryFissionCheckBox.Checked = _simulation.BinaryFission;
widthNumericUpDown.Value = _simulation.Size.Width;
heightNumericUpDown.Value = _simulation.Size.Height;
wrapCheckBox.Checked = _simulation.Wrap;
solidStrandsCheckBox.Checked = _simulation.SolidStrands;
attritionCheckBox.Checked = _simulation.Attrition;
mobileRepellentsCheckBox.Checked = _simulation.MobileRepellents;
}
private void MobileRepellentsCheckBox_CheckedChanged(object sender, EventArgs e)
{
_simulation.MobileRepellents = mobileRepellentsCheckBox.Checked;
}
private void NewFile()
{
_simulation = new Simulation();
_fileName = null;
this.UpdateUi();
this.InitializeScenario();
}
private void NewToolStripMenuItem_Click(object sender, EventArgs e)
{
this.NewFile();
}
private void NextMove(bool single)
{
int sum;
sum = _simulation.Attractors.Count + _simulation.Repellents.Count + _simulation.Strands.Count;
if (single)
{
_simulation.NextMove();
}
else
{
_simulation.Run(_updateIterations);
}
if (_autoSaveOptions.Enabled)
{
this.AutoSaveImage();
}
if ((_simulation.Attractors.Count + _simulation.Repellents.Count + _simulation.Strands.Count) != sum)
{
this.UpdateStatusBar();
}
else
{
this.UpdateIteration();
}
renderPanel.Invalidate();
}
private void AutoSaveImage()
{
string fileName;
fileName = Path.Combine(_autoSaveOptions.SaveFolder, _simulation.Iteration + ".png");
this.SaveImage(fileName);
}
private void NextMoveToolStripButton_Click(object sender, EventArgs e)
{
this.NextMove(true);
}
private void NoxiousSourceDetectionZonesToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.ShowNoxiousDetectionZone = !_simulationRenderer.ShowNoxiousDetectionZone;
noxiousSourceDetectionZonesToolStripMenuItem.Checked = _simulationRenderer.ShowNoxiousDetectionZone;
renderPanel.Invalidate();
}
private void NoxiousSourcesToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.ShowNoxiousSources = !_simulationRenderer.ShowNoxiousSources;
noxiousSourcesToolStripMenuItem.Checked = _simulationRenderer.ShowNoxiousSources;
renderPanel.Invalidate();
}
private void OpenFile()
{
string fileName;
fileName = FileDialogHelper.GetOpenFileName("Open File", Filters.General, "sim");
if (!string.IsNullOrEmpty(fileName))
{
this.OpenFile(fileName);
}
}
private void OpenFile(string fileName)
{
try
{
if (string.Equals(Path.GetExtension(fileName), ".js"))
{
scriptTextBox.Text = File.ReadAllText(fileName);
tabControl.SelectedTab = scriptTabPage;
_scriptFileName = fileName;
}
else
{
_simulation = SimulationSerializer.LoadFrom(fileName);
_fileName = fileName;
}
this.UpdateUi();
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to open file. {0}", ex.GetBaseException().Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void OpenToolStripMenuItem_Click(object sender, EventArgs e)
{
this.OpenFile();
}
private void PasteToolStripMenuItem_Click(object sender, EventArgs e)
{
this.PerformClipboardAction(tb => tb.Paste());
}
private void PauseToolStripButton_Click(object sender, EventArgs e)
{
timer.Stop();
this.UpdateSimulationControls();
}
private void PerformClipboardAction(Action<TextBoxBase> action)
{
Control control;
control = this.GetActiveControl(this);
if (control is TextBoxBase textBox)
{
action(textBox);
}
else
{
SystemSounds.Beep.Play();
}
}
private void PlayToolStripButton_Click(object sender, EventArgs e)
{
timer.Start();
this.UpdateSimulationControls();
}
private void RandomButton_Click(object sender, EventArgs e)
{
string name;
NumericUpDown control;
name = (string)((Control)sender).Tag;
control = (NumericUpDown)setupTabPage.Controls[name];
control.Value = _random.Next((int)control.Minimum, (int)control.Maximum + 1);
this.InitializeScenario();
}
private void RenderPanel_Paint(object sender, PaintEventArgs e)
{
if (_antiAlias)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
}
_simulationRenderer.Draw(_simulation, e.Graphics, e.ClipRectangle);
}
private void RespawnAttractorsCheckBox_CheckedChanged(object sender, EventArgs e)
{
_simulation.RespawnAttractor = respawnAttractorsCheckBox.Checked;
}
private void RunButton_Click(object sender, EventArgs e)
{
string script;
script = scriptTextBox.Text;
if (!string.IsNullOrWhiteSpace(script))
{
ScriptEnvironment engine;
engine = new ScriptEnvironment();
engine.AddVariable("simulation", _simulation);
engine.WrappedExecute(script);
logTextBox.Text = engine.GetOutput();
this.LoadFields();
renderPanel.Invalidate();
}
else
{
SystemSounds.Beep.Play();
}
}
private void SaveAsToolStripMenuItem_Click(object sender, EventArgs e)
{
this.SaveFileAs();
}
private void SaveButton_Click(object sender, EventArgs e)
{
this.SaveScriptAs();
}
private void SaveFile()
{
if (string.IsNullOrEmpty(_fileName))
{
this.SaveFileAs();
}
else
{
this.SaveFile(_fileName);
}
}
private void SaveFile(string fileName)
{
try
{
_simulation.Save(fileName);
this.SaveImage(Path.ChangeExtension(fileName, ".png"));
_fileName = fileName;
this.UpdateUi();
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to save file. {0}", ex.GetBaseException().Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void SaveFileAs()
{
string fileName;
fileName = FileDialogHelper.GetSaveFileName("Save Simulation As", Filters.Simulation, "sim", _fileName);
if (!string.IsNullOrEmpty(fileName))
{
this.SaveFile(fileName);
}
}
private void SaveImage(string fileName)
{
using (Bitmap bitmap = this.CreatePreviewImage())
{
bitmap.Save(fileName, ImageFormat.Png);
}
}
private void SaveScriptAs()
{
string fileName;
fileName = FileDialogHelper.GetSaveFileName("Save Script As", Filters.ScriptFiles, "js", _scriptFileName);
if (!string.IsNullOrEmpty(fileName))
{
this.SaveScriptAs(fileName);
}
}
private void SaveScriptAs(string fileName)
{
try
{
File.WriteAllText(fileName, scriptTextBox.Text);
_scriptFileName = fileName;
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to save file. {0}", ex.GetBaseException().Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void SaveToolStripMenuItem_Click(object sender, EventArgs e)
{
this.SaveFile();
}
private void ScaleToolStripTrackBar_ValueChanged(object sender, EventArgs e)
{
_simulationRenderer.Scale = scaleToolStripTrackBar.Value / 10F;
renderPanel.Invalidate();
}
private void SelectAllToolStripMenuItem_Click(object sender, EventArgs e)
{
this.PerformClipboardAction(tb => tb.SelectAll());
}
private void SetUpdateSpeed(int iterations)
{
_updateIterations = iterations;
foreach (ToolStripItem item in refreshIntervalToolStripMenuItem.DropDownItems)
{
if (item is ToolStripMenuItem menuItem && item.Tag is string value && int.TryParse(value, out int count))
{
menuItem.Checked = iterations == count;
}
}
}
private void ShapesToolStripMenuItem_Click(object sender, EventArgs e)
{
_simulationRenderer.DrawShapes = !_simulationRenderer.DrawShapes;
shapesToolStripMenuItem.Checked = _simulationRenderer.DrawShapes;
renderPanel.Invalidate();
}
private void SolidStrandsCheckBox_CheckedChanged(object sender, EventArgs e)
{
_simulation.SolidStrands = solidStrandsCheckBox.Checked;
}
private void SpeedToolStripTrackBar_ValueChanged(object sender, EventArgs e)
{
timer.Interval = speedToolStripTrackBar.Value;
}
private void Timer_Tick(object sender, EventArgs e)
{
this.NextMove(false);
}
private void UpdateIteration()
{
iterationToolStripStatusLabel.Text = _simulation.Iteration.ToString();
}
private void UpdateSimulationControls()
{
bool isRunning;
isRunning = timer.Enabled;
playToolStripButton.Enabled = !isRunning;
runToolStripMenuItem.Enabled = !isRunning;
pauseToolStripButton.Enabled = isRunning;
pauseToolStripMenuItem.Enabled = isRunning;
nextMoveToolStripButton.Enabled = !isRunning;
nextMoveToolStripMenuItem.Enabled = !isRunning;
}
private void UpdateStatusBar()
{
if (this.InvokeRequired)
{
this.Invoke(new Action(this.UpdateStatusBar));
}
else
{
this.UpdateIteration();
standsToolStripStatusLabel.Text = _simulation.Strands.Count.ToString();
attractorsToolStripStatusLabel.Text = _simulation.Attractors.Count.ToString();
repellentsToolStripStatusLabel.Text = _simulation.Repellents.Count.ToString();
}
}
private void UpdateUi()
{
this.LoadFields();
this.UpdateSimulationControls();
this.UpdateStatusBar();
this.UpdateWindowTitle();
renderPanel.Invalidate();
}
private void UpdateWindowTitle()
{
this.Text = string.Format("{1} - {0}", Application.ProductName, string.IsNullOrEmpty(_fileName) ? "Untitled" : Path.GetFileName(_fileName));
}
private void WrapCheckBox_CheckedChanged(object sender, EventArgs e)
{
_simulation.Wrap = wrapCheckBox.Checked;
}
private void ZoomInToolStripMenuItem_Click(object sender, EventArgs e)
{
scaleToolStripTrackBar.Value = Math.Min(scaleToolStripTrackBar.Maximum, scaleToolStripTrackBar.Value + 1);
}
private void ZoomOutToolStripMenuItem_Click(object sender, EventArgs e)
{
scaleToolStripTrackBar.Value = Math.Max(scaleToolStripTrackBar.Minimum, scaleToolStripTrackBar.Value - 1);
}
#endregion Private Methods
private void AutoSaveImagesEnabledToolStripMenuItem_Click(object sender, EventArgs e)
{
_autoSaveOptions.Enabled = !_autoSaveOptions.Enabled;
autoSaveImagesEnabledToolStripMenuItem.Checked = _autoSaveOptions.Enabled;
if (_autoSaveOptions.Enabled)
{
this.AutoSaveImage();
}
}
private void AutoSaveImagesConfigureToolStripMenuItem_Click(object sender, EventArgs e)
{
string folderName;
folderName = FileDialogHelper.GetFolderName("Select Auto Image Folder", _autoSaveOptions.SaveFolder);
if (!string.IsNullOrEmpty(folderName))
{
_autoSaveOptions.SaveFolder = folderName;
}
}
private AutoSaveOptions _autoSaveOptions;
}
}
Donate
This software may be used free of charge, but as with all free software there are costs involved to develop and maintain.
If this site or its services have saved you time, please consider a donation to help with running costs and timely updates.
Donate