Skip to content

Commit 7685894

Browse files
committed
Added animation for synapses
Changed neuron display to filling glass Added/commented 7-segment display hack
1 parent 3a1b99f commit 7685894

File tree

4 files changed

+240
-12
lines changed

4 files changed

+240
-12
lines changed

BrainSimulator/MainWindow.xaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
66
xmlns:local="clr-namespace:BrainSimulator"
77
mc:Ignorable="d"
8-
Title="Brain Simulator II" Height="520.771" Width="1080"
8+
Title="Brain Simulator II" Height="520.771" Width="1920"
99
KeyUp="Window_KeyUp" KeyDown="Window_KeyDown"
1010
Closing="Window_Closing" ContentRendered="Window_ContentRendered" WindowState="Maximized"
1111
MouseEnter="Window_MouseEnter" MouseLeave="Window_MouseLeave">
@@ -329,6 +329,8 @@
329329
<Label Visibility="Hidden" Width="5"></Label>
330330
<CheckBox x:Name="checkBox" Content="All Synapses" Height="18" VerticalAlignment="Center" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
331331
<Label Visibility="Hidden" Width="30"></Label>
332+
<CheckBox x:Name="checkBoxAnimate" Content="Animate" Height="18" VerticalAlignment="Center" />
333+
<Label Visibility="Hidden" Width="30"></Label>
332334
<Button x:Name="buttonInit" FontSize="20" FontFamily="Segoe MDL2 Assets" Content="&#xEB9E;" Foreground="#FF00539C" VerticalAlignment="Top" Click="ButtonInit_Click" ToolTip="Reset all modules" Grid.Column="2" >
333335
<!--<Image Source="/resources/Rewind.png" Height="20"></Image>-->
334336
</Button>

BrainSimulator/NeuronArrayView.xaml.cs

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55

66
using System;
77
using System.Collections.Generic;
8-
using System.Diagnostics;
98
using System.Windows;
109
using System.Windows.Controls;
11-
using System.Windows.Input;
1210
using System.Windows.Media;
11+
using System.Windows.Media.Animation;
1312
using System.Windows.Shapes;
14-
using System.Windows.Threading;
1513

1614
namespace BrainSimulator
1715
{
@@ -84,13 +82,19 @@ public NeuronArrayView()
8482
public DisplayParams Dp { get => dp; set => dp = value; }
8583

8684
private Canvas targetNeuronCanvas = null;
85+
Canvas animationCanvas = null; //used to animate synapses
8786

8887
//refresh the display of the neuron network
8988
public void Update()
9089
{
9190
var watch = System.Diagnostics.Stopwatch.StartNew();
9291
NeuronArray theNeuronArray = MainWindow.theNeuronArray;
9392

93+
if (animationCanvas != null)
94+
{
95+
theCanvas.Children.Remove(animationCanvas);
96+
animationCanvas = null;
97+
}
9498
Canvas labelCanvas = new Canvas();
9599
Canvas.SetLeft(labelCanvas, 0);
96100
Canvas.SetTop(labelCanvas, 0);
@@ -201,7 +205,7 @@ public void Update()
201205
moduleLabel.Background = new SolidColorBrush(Colors.LightGray);
202206
moduleLabel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
203207
Canvas.SetLeft(moduleLabel, Canvas.GetLeft(r));
204-
Canvas.SetTop(moduleLabel, Canvas.GetTop(r)-moduleLabel.DesiredSize.Height);
208+
Canvas.SetTop(moduleLabel, Canvas.GetTop(r) - moduleLabel.DesiredSize.Height);
205209
moduleLabel.SetValue(ShapeType, shapeType.Module);
206210
moduleLabel.SetValue(ModuleView.AreaNumberProperty, i);
207211
labelCanvas.Children.Add(moduleLabel);
@@ -311,12 +315,15 @@ public void Update()
311315
{
312316
if (l is Shape s && s.Fill is SolidColorBrush b && b.Color == Colors.White)
313317
lbl.Foreground = new SolidColorBrush(Colors.Black);
318+
if (l is NeuronView.FillableDisc && n.currentCharge == 1)
319+
lbl.Foreground = new SolidColorBrush(Colors.Black);
314320
lbl.SetValue(ShapeType, shapeType.Neuron);
315321
labelCanvas.Children.Add(lbl);
316322
}
317323

318324
NeuronOnScreen neuronScreenCache = null;
319-
if ((n.inUse || n.Label != "" || n.currentCharge != 0 || n.lastCharge != 0) && (l is Ellipse || l is Rectangle))
325+
if ((n.inUse || n.Label != "" || n.currentCharge != 0 || n.lastCharge != 0) &&
326+
(l is Ellipse || l is Rectangle || l is NeuronView.FillableDisc))
320327
{
321328
neuronScreenCache = new NeuronOnScreen(neuronID, l, -10, lbl);
322329
}
@@ -392,13 +399,13 @@ public void Update()
392399
watch.Stop();
393400
var elapsedMs = watch.ElapsedMilliseconds;
394401
if (synapseCount >= dp.maxSynapsesToDisplay)
395-
MainWindow.thisWindow.SetStatus(0,"Too many synapses to display",1);
402+
MainWindow.thisWindow.SetStatus(0, "Too many synapses to display", 1);
396403
else
397404
{
398405
if (!dp.ShowNeurons())
399-
MainWindow.thisWindow.SetStatus(0,"Grid Size: " + (boxSize * boxSize).ToString("#,##"),1);
406+
MainWindow.thisWindow.SetStatus(0, "Grid Size: " + (boxSize * boxSize).ToString("#,##"), 1);
400407
else
401-
MainWindow.thisWindow.SetStatus(0,"OK",0);
408+
MainWindow.thisWindow.SetStatus(0, "OK", 0);
402409
}
403410
MainWindow.thisWindow.UpdateFreeMem();
404411
//Debug.WriteLine("Update Done " + elapsedMs + "ms");
@@ -412,7 +419,7 @@ public void AddNeuronToUpdateList(int neuronID)
412419
Neuron n = MainWindow.theNeuronArray.GetCompleteNeuron(neuronID);
413420
UIElement l = NeuronView.GetNeuronView(n, this, out TextBlock lbl);
414421
theCanvas.Children.Add(l);
415-
if (lbl != null)
422+
if (lbl != null)
416423
theCanvas.Children.Add(lbl);
417424
NeuronOnScreen neuronScreenCache = new NeuronOnScreen(neuronID, l, -10, lbl);
418425
neuronsOnScreen.Add(neuronScreenCache);
@@ -464,11 +471,71 @@ public void UpdateNeuronColors()
464471
//}
465472

466473
SetTargetNeuronSymbol();
474+
if (animationCanvas == null)
475+
{
476+
animationCanvas = new Canvas();
477+
Canvas.SetLeft(animationCanvas, 0);
478+
Canvas.SetTop(animationCanvas, 0);
479+
theCanvas.Children.Add(animationCanvas);
480+
}
481+
animationCanvas.Children.Clear();
467482

468483
for (int i = 0; i < neuronsOnScreen.Count; i++)
469484
{
470485
NeuronOnScreen a = neuronsOnScreen[i];
471486
Neuron n = MainWindow.theNeuronArray.GetNeuronForDrawing(a.neuronIndex);
487+
488+
if (MainWindow.thisWindow.checkBoxAnimate.IsChecked == true && n.lastCharge >= 1)
489+
{
490+
//synapse animation trial
491+
float electronSize = dp.NeuronDisplaySize * .2f;
492+
n.synapses = MainWindow.theNeuronArray.GetSynapsesList(n.id);
493+
Point pStart = dp.pointFromNeuron(n.id);
494+
pStart.X += -electronSize / 2 + dp.NeuronDisplaySize / 2;
495+
pStart.Y += -electronSize / 2 + dp.NeuronDisplaySize / 2;
496+
foreach (Synapse synapse in n.synapses)
497+
{
498+
Point pTarget = dp.pointFromNeuron(synapse.targetNeuron);
499+
pTarget.X += -electronSize / 2 + dp.NeuronDisplaySize / 2;
500+
pTarget.Y += -electronSize / 2 + dp.NeuronDisplaySize / 2;
501+
var fill = Brushes.Yellow;
502+
if (synapse.weight < 0)
503+
fill = Brushes.DeepPink;
504+
// Create the disk (Ellipse)
505+
Ellipse disk = new Ellipse
506+
{
507+
Width = electronSize,
508+
Height = electronSize,
509+
Fill = fill
510+
};
511+
// Initial position
512+
Canvas.SetLeft(disk, pStart.X);
513+
Canvas.SetTop(disk, pStart.Y);
514+
animationCanvas.Children.Add(disk);
515+
var animX = new DoubleAnimation
516+
{
517+
From = pStart.X,
518+
To = pTarget.X,
519+
Duration = TimeSpan.FromMilliseconds(500)
520+
521+
};
522+
Storyboard.SetTarget(animX, disk);
523+
Storyboard.SetTargetProperty(animX, new PropertyPath("(Canvas.Left)"));
524+
var animY = new DoubleAnimation
525+
{
526+
From = pStart.Y,
527+
To = pTarget.Y,
528+
Duration = TimeSpan.FromMilliseconds(500)
529+
};
530+
Storyboard.SetTarget(animY, disk);
531+
Storyboard.SetTargetProperty(animY, new PropertyPath("(Canvas.Top)"));
532+
Storyboard storyboard = new();
533+
storyboard.Children.Add(animX);
534+
storyboard.Children.Add(animY);
535+
storyboard.Begin();
536+
}
537+
}
538+
472539
if (neuronsOnScreen[i].synapsesOnScreen != null)
473540
{
474541
n.synapses = MainWindow.theNeuronArray.GetSynapsesList(n.id);
@@ -489,6 +556,15 @@ public void UpdateNeuronColors()
489556
}
490557
}
491558
}
559+
if (a.graphic is NeuronView.FillableDisc f)
560+
{
561+
float x = n.lastCharge;
562+
if (a.label != null && x >= 1)
563+
a.label.Foreground = new SolidColorBrush(Colors.Black);
564+
else if (a.label != null)
565+
a.label.Foreground = new SolidColorBrush(Colors.White);
566+
f.SetValue(x);
567+
}
492568
if (a.graphic is Shape e)
493569
{
494570
float x = n.lastCharge;

BrainSimulator/NeuronView.cs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Windows.Shapes;
1313
using System.Collections.Generic;
1414
using System.Diagnostics;
15+
using System.Windows.Media.Effects;
1516

1617

1718
namespace BrainSimulator
@@ -31,13 +32,130 @@ public int NeuronID
3132
}
3233
private static float ellipseSize = 0.7f;
3334

35+
/*****************************************************
36+
* Testing of filling disk neuron
37+
* ***********************************************/
38+
public class FillableDisc : Canvas
39+
{
40+
private Ellipse borderCircle;
41+
private Rectangle fillRect;
42+
private Grid fillContainer;
43+
private double size;
44+
45+
public FillableDisc(double diameter, int neuronID)
46+
{
47+
size = diameter;
48+
Width = Height = diameter;
49+
InitializeDisc(neuronID);
50+
}
51+
52+
private void InitializeDisc(int neuronID)
53+
{
54+
// Border circle
55+
borderCircle = new Ellipse
56+
{
57+
Width = size,
58+
Height = size,
59+
Stroke = Brushes.White,
60+
StrokeThickness = 1,
61+
Fill = Brushes.Gray,
62+
};
63+
borderCircle.SetValue(NeuronIDProperty, neuronID);
64+
borderCircle.SetValue(NeuronArrayView.ShapeType, NeuronArrayView.shapeType.Neuron);
65+
Children.Add(borderCircle);
66+
67+
// Fill container with clipping
68+
fillRect = new Rectangle
69+
{
70+
Width = size,
71+
Fill = Brushes.DodgerBlue,
72+
VerticalAlignment = VerticalAlignment.Bottom,
73+
Height = 0 // Start empty
74+
};
75+
fillRect.SetValue(NeuronIDProperty, neuronID);
76+
fillRect.SetValue(NeuronArrayView.ShapeType, NeuronArrayView.shapeType.Neuron);
77+
78+
fillContainer = new Grid
79+
{
80+
Width = size,
81+
Height = size,
82+
Clip = new EllipseGeometry(new Point(size / 2, size / 2), size / 2, size / 2)
83+
};
84+
85+
fillContainer.Children.Add(fillRect);
86+
Children.Add(fillContainer);
87+
}
88+
89+
/// <summary>
90+
/// Sets the fill level from 0.0 (empty) to 1.0 (full).
91+
/// </summary>
92+
public void SetValue(double value)
93+
{
94+
value = Math.Clamp(value, 0, 1);
95+
fillRect.Height = value * size;
96+
if (value == 1)
97+
fillRect.Fill = Brushes.White;
98+
else
99+
fillRect.Fill = Brushes.DodgerBlue;
100+
101+
// Force alignment from bottom (WPF default is top)
102+
fillRect.VerticalAlignment = VerticalAlignment.Bottom;
103+
}
104+
}
105+
/*****************************************************
106+
* Testing of filling disk neuron
107+
* ***********************************************/
108+
34109
public static UIElement GetNeuronView(Neuron n, NeuronArrayView theNeuronArrayViewI, out TextBlock tb)
35110
{
36111
tb = null;
37112
theNeuronArrayView = theNeuronArrayViewI;
38113

39114
Point p = dp.pointFromNeuron(n.id);
40115

116+
if (dp.ShowNeuronCircles())
117+
{
118+
var fillableCircle = new FillableDisc(dp.NeuronDisplaySize * ellipseSize, n.id);
119+
fillableCircle.SetValue(n.currentCharge);
120+
float offset1 = (1 - ellipseSize) / 2f;
121+
Canvas.SetLeft(fillableCircle, p.X + dp.NeuronDisplaySize * offset1);
122+
Canvas.SetTop(fillableCircle, p.Y + dp.NeuronDisplaySize * offset1);
123+
fillableCircle.Effect = new DropShadowEffect
124+
{
125+
Color = Colors.Black,
126+
Direction = 315, // angle of the shadow in degrees
127+
ShadowDepth = dp.NeuronDisplaySize * ellipseSize * 0.1, // distance of the shadow
128+
Opacity = 0.5, // transparency of the shadow
129+
BlurRadius = 10 // softness of the shadow edge
130+
};
131+
if (n.Label != "" || n.model != Neuron.modelType.IF)
132+
{
133+
tb = new TextBlock();
134+
//l.Content = n.Label;
135+
tb.FontSize = dp.NeuronDisplaySize * .25;
136+
tb.FontWeight = FontWeights.Bold;
137+
tb.Foreground = Brushes.White;
138+
139+
string theLabel = GetNeuronLabel(n);
140+
string theToolTip = n.ToolTip;
141+
if (theToolTip != "")
142+
{
143+
fillableCircle.ToolTip = new ToolTip { Content = theToolTip };
144+
tb.ToolTip = new ToolTip { Content = theToolTip };
145+
}
146+
tb.Text = theLabel;
147+
tb.HorizontalAlignment = HorizontalAlignment.Center;
148+
tb.SetValue(NeuronIDProperty, n.id);
149+
tb.SetValue(NeuronArrayView.ShapeType, NeuronArrayView.shapeType.Neuron);
150+
tb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
151+
Size textSize = tb.DesiredSize;
152+
153+
Canvas.SetLeft(tb, p.X + (dp.NeuronDisplaySize - textSize.Width) / 2);
154+
Canvas.SetTop(tb, p.Y + dp.NeuronDisplaySize * offset1);
155+
Canvas.SetZIndex(tb, 100);
156+
}
157+
return fillableCircle;
158+
}
41159
SolidColorBrush s1 = GetNeuronColor(n);
42160

43161
Shape r = null;

0 commit comments

Comments
 (0)