From eb74c928b02c81ab8a1458bffe7aa7bbb29f4faa Mon Sep 17 00:00:00 2001 From: bparks13 Date: Wed, 18 Dec 2024 16:26:37 -0500 Subject: [PATCH] Explicitly define orientation of Rhs2116 channel configuration - Added contact annotation labels to the default configuration that aligns with documentation images (i.e., A1 / B1 / etc.) - Added a label to the top of the image that defines the side of the PCB that contains the tether --- Directory.Build.props | 2 +- .../ChannelConfigurationDialog.cs | 23 +++++-- .../OpenEphys.Onix1.Design.csproj | 2 +- .../Rhs2116ChannelConfigurationDialog.cs | 68 ++++++++++++++++++- OpenEphys.Onix1/OpenEphys.Onix1.csproj | 2 +- OpenEphys.Onix1/Rhs2116ProbeGroup.cs | 30 +++++++- 6 files changed, 115 insertions(+), 12 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9db0f63..6e2f429 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,7 @@ LICENSE true icon.png - 0.4.2 + 0.4.3 10.0 strict diff --git a/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs b/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs index 82f6d1f..09fb44a 100644 --- a/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs +++ b/OpenEphys.Onix1.Design/ChannelConfigurationDialog.cs @@ -739,8 +739,6 @@ internal virtual void DrawContactLabels() zedGraphChannels.GraphPane.GraphObjList.RemoveAll(obj => obj is TextObj && obj.Tag is ContactTag); - var fontSize = CalculateFontSize(0.5); - int probeNumber = 0; int indexOffset = 0; @@ -757,7 +755,7 @@ internal virtual void DrawContactLabels() Tag = new ContactTag(probeNumber, i) }; - SetTextObj(textObj, fontSize); + SetTextObj(textObj); textObj.FontSpec.FontColor = indices[i] == -1 ? DisabledContactTextColor : EnabledContactTextColor; @@ -769,13 +767,12 @@ internal virtual void DrawContactLabels() } } - internal void SetTextObj(TextObj textObj, float fontSize) + internal void SetTextObj(TextObj textObj) { textObj.FontSpec.IsBold = true; textObj.FontSpec.Border.IsVisible = false; textObj.FontSpec.Fill.IsVisible = false; textObj.FontSpec.Fill.IsVisible = false; - textObj.FontSpec.Size = fontSize; } const string DisabledContactString = "Off"; @@ -1086,6 +1083,7 @@ private void MenuItemLoadDefaultConfig(object sender, EventArgs e) { LoadDefaultChannelLayout(); DrawProbeGroup(); + UpdateFontSize(); RefreshZedGraph(); } @@ -1339,5 +1337,20 @@ private static PointD TransformPixelsToCoordinates(Point pixels, GraphPane graph return new PointD(x, y); } + + internal static bool HasContactAnnotations(ProbeGroup probeGroup) + { + foreach (var probe in probeGroup.Probes) + { + if (probe.ContactAnnotations != null + && probe.ContactAnnotations.Annotations != null + && probe.ContactAnnotations.Annotations.Length > 0) + { + return true; + } + } + + return false; + } } } diff --git a/OpenEphys.Onix1.Design/OpenEphys.Onix1.Design.csproj b/OpenEphys.Onix1.Design/OpenEphys.Onix1.Design.csproj index 4859e23..94eaa9e 100644 --- a/OpenEphys.Onix1.Design/OpenEphys.Onix1.Design.csproj +++ b/OpenEphys.Onix1.Design/OpenEphys.Onix1.Design.csproj @@ -15,7 +15,7 @@ - + diff --git a/OpenEphys.Onix1.Design/Rhs2116ChannelConfigurationDialog.cs b/OpenEphys.Onix1.Design/Rhs2116ChannelConfigurationDialog.cs index a2ec44c..a3d7239 100644 --- a/OpenEphys.Onix1.Design/Rhs2116ChannelConfigurationDialog.cs +++ b/OpenEphys.Onix1.Design/Rhs2116ChannelConfigurationDialog.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using System.Windows.Forms; +using Newtonsoft.Json; using OpenEphys.ProbeInterface.NET; using ZedGraph; @@ -67,9 +69,71 @@ private void OnZoomHandler() OnZoom?.Invoke(this, EventArgs.Empty); } - internal override float CalculateFontSize(double _) + internal override float CalculateFontSize(double scale) { - return base.CalculateFontSize(1.35); + scale *= HasContactAnnotations(ProbeGroup) ? 0.5 : 1; + return base.CalculateFontSize(1.35 * scale); + } + + internal override string ContactString(int deviceChannelIndex, int index) + { + string s = base.ContactString(deviceChannelIndex, index); + + int indexOffset = 0; + int probeIndex = 0; + + foreach (var probe in ProbeGroup.Probes) + { + if (probe.NumberOfContacts - 1 + indexOffset < index) + { + indexOffset += probe.NumberOfContacts; + probeIndex++; + } + else break; + } + + int currentIndex = index - indexOffset; + + var currentProbe = ProbeGroup.Probes.ElementAt(probeIndex); + + if (currentProbe.ContactAnnotations != null + && currentProbe.ContactAnnotations.Annotations != null + && currentProbe.ContactAnnotations.Annotations.Length > currentIndex) + { + s += "\n" + currentProbe.ContactAnnotations.Annotations[currentIndex]; + } + + return s; + } + + // NB: Currently there is only a text label drawn as the scale for this dialog, used to denote the + // absolute orientation of the default probe group + internal override void DrawScale() + { + const string scaleTag = "scale"; + + zedGraphChannels.GraphPane.GraphObjList.RemoveAll(obj => obj.Tag is string tag && tag == scaleTag); + + bool isDefault = JsonConvert.SerializeObject(ProbeGroup) == JsonConvert.SerializeObject(new Rhs2116ProbeGroup()); + + if (isDefault) + { + var middle = GetProbeContourLeft(zedGraphChannels.GraphPane.GraphObjList) + + (GetProbeContourRight(zedGraphChannels.GraphPane.GraphObjList) - GetProbeContourLeft(zedGraphChannels.GraphPane.GraphObjList)) / 2; + var top = GetProbeContourTop(zedGraphChannels.GraphPane.GraphObjList); + + TextObj textObj = new("Tether Side", middle, top + 0.5, CoordType.AxisXYScale, AlignH.Center, AlignV.Center) + { + ZOrder = ZOrder.A_InFront, + Tag = scaleTag + }; + + SetTextObj(textObj); + + textObj.FontSpec.Size = CalculateFontSize(4.0); + + zedGraphChannels.GraphPane.GraphObjList.Add(textObj); + } } } } diff --git a/OpenEphys.Onix1/OpenEphys.Onix1.csproj b/OpenEphys.Onix1/OpenEphys.Onix1.csproj index a807b8e..9c7fd88 100644 --- a/OpenEphys.Onix1/OpenEphys.Onix1.csproj +++ b/OpenEphys.Onix1/OpenEphys.Onix1.csproj @@ -13,6 +13,6 @@ - + diff --git a/OpenEphys.Onix1/Rhs2116ProbeGroup.cs b/OpenEphys.Onix1/Rhs2116ProbeGroup.cs index 160e7a3..c224d6e 100644 --- a/OpenEphys.Onix1/Rhs2116ProbeGroup.cs +++ b/OpenEphys.Onix1/Rhs2116ProbeGroup.cs @@ -31,7 +31,7 @@ private static Probe[] DefaultProbes() probe[0] = new(ProbeNdim.Two, ProbeSiUnits.mm, new ProbeAnnotations("Rhs2116A", ""), - null, + DefaultContactAnnotations(DefaultNumberOfChannelsPerProbe, 0), DefaultContactPositions(DefaultNumberOfChannelsPerProbe, 0), Probe.DefaultContactPlaneAxes(DefaultNumberOfChannelsPerProbe), Probe.DefaultContactShapes(DefaultNumberOfChannelsPerProbe, ContactShape.Circle), @@ -44,7 +44,7 @@ private static Probe[] DefaultProbes() probe[1] = new(ProbeNdim.Two, ProbeSiUnits.mm, new ProbeAnnotations("Rhs2116B", ""), - null, + DefaultContactAnnotations(DefaultNumberOfChannelsPerProbe, 1), DefaultContactPositions(DefaultNumberOfChannelsPerProbe, 1), Probe.DefaultContactPlaneAxes(DefaultNumberOfChannelsPerProbe), Probe.DefaultContactShapes(DefaultNumberOfChannelsPerProbe, ContactShape.Circle), @@ -82,6 +82,32 @@ public Rhs2116ProbeGroup(Rhs2116ProbeGroup probeGroup) { } + internal static ContactAnnotations DefaultContactAnnotations(int numberOfChannels, int probeIndex) + { + string[] contactAnnotations = new string[numberOfChannels]; + + if (probeIndex == 0) + { + for (int i = 0; i < numberOfChannels; i++) + { + contactAnnotations[i] = "A" + i.ToString(); + } + } + else if (probeIndex == 1) + { + for (int i = 0; i < numberOfChannels; i++) + { + contactAnnotations[i] = "B" + i.ToString(); + } + } + else + { + throw new InvalidOperationException($"Probe {probeIndex} is invalid for getting default contact annotations for {nameof(Rhs2116ProbeGroup)}"); + } + + return new(contactAnnotations); + } + internal static float[][] DefaultContactPositions(int numberOfChannels, int probeIndex) { float[][] contactPositions = new float[numberOfChannels][];