aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/SideChains
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2018-01-28 19:40:35 +0200
committerRoy Ben-Shabat <Roy@Twine-s.com>2018-01-28 19:40:35 +0200
commit7e8ff4c3ca798d426eb6f381c5312a747f1bb800 (patch)
treecf9702617f9771412c78294ad742c308007ebce1 /Software/Visual_Studio/SideChains
parent10eec8df1dfce197b31d51cfa49746b0ce07a5e5 (diff)
downloadTango-7e8ff4c3ca798d426eb6f381c5312a747f1bb800.tar.gz
Tango-7e8ff4c3ca798d426eb6f381c5312a747f1bb800.zip
Implemented all color spaces on segment brushes (simple conversion).
Embedded ColorMine library as a SideChain.
Diffstat (limited to 'Software/Visual_Studio/SideChains')
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorMine.csproj29
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorMine.nuspec50
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpace.cs83
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.cs791
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.tt89
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.xml88
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie1976Comparison.cs27
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie94Comparison.cs99
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CieDe2000Comparison.cs127
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CmcComparison.cs84
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/IColorSpaceComparison.cs16
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmyConverter.cs22
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmykConverter.cs47
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsbConverter.cs29
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HslConverter.cs149
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsvConverter.cs91
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HunterLabConverter.cs33
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LabConverter.cs51
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LchConverter.cs39
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LuvConverter.cs57
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/RgbConverter.cs17
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/XyzConverter.cs75
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/YxyConverter.cs32
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/DoubleExtension.cs19
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/MathUtils.cs17
-rw-r--r--Software/Visual_Studio/SideChains/ColorMine/Properties/AssemblyInfo.cs1
26 files changed, 2162 insertions, 0 deletions
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorMine.csproj b/Software/Visual_Studio/SideChains/ColorMine/ColorMine.csproj
new file mode 100644
index 000000000..b47e55306
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorMine.csproj
@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
+ <PropertyGroup>
+ <TargetFrameworks>net45;netstandard1.6</TargetFrameworks>
+ <AssemblyTitle>ColorMine</AssemblyTitle>
+ <RootNamespace>ColorMine</RootNamespace>
+ <Version>1.2.0</Version>
+ <FileVersion>1.2.0</FileVersion>
+ <Description>.NET library that makes converting betwewen color spaces and comparing colors easy</Description>
+ <Company>Continuous Automation LLC</Company>
+ <Copyright>Copyright © 2017 Joe Zack</Copyright>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <!-- The T4 TextTemplatingFileGenerator Service-->
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <None Update="ColorSpaces\ColorSpaces.tt">
+ <Generator>TextTemplatingFileGenerator</Generator>
+ <LastGenOutput>ColorSpaces.cs</LastGenOutput>
+ </None>
+ <Compile Update="ColorSpaces\ColorSpaces.cs">
+ <DesignTime>True</DesignTime>
+ <AutoGen>True</AutoGen>
+ <DependentUpon>ColorSpaces.tt</DependentUpon>
+ </Compile>
+ </ItemGroup>
+</Project>
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorMine.nuspec b/Software/Visual_Studio/SideChains/ColorMine/ColorMine.nuspec
new file mode 100644
index 000000000..a8a40c98d
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorMine.nuspec
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
+ <metadata>
+ <id>ColorMine</id>
+ <version>1.1.3.0</version>
+ <title>ColorMine</title>
+ <authors>Joe Zack</authors>
+ <licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
+ <projectUrl>https://github.com/THEjoezack/ColorMine</projectUrl>
+ <requireLicenseAcceptance>false</requireLicenseAcceptance>
+ <description>Open source library that makes converting and comparing colors easy.
+
+ ## Supported Color Models:
+ * CMY
+ * CMYK
+ * HSL
+ * HSB
+ * HSV
+ * CIE L*AB
+ * Hunter LAB
+ * LCH
+ * LUV
+ * sRGB
+ * XYZ
+ * YXY
+
+ ## Supported Comparisons
+ * CIE76
+ * CMC l:c
+ * CIE94
+ * CIE2000
+
+ Demonstrations at http://colormine.org.</description>
+ <releaseNotes>1.1.3.0 - 04/02/2014
+Bumped .Net version down to 4.0
+Fixed HSB Calcuations
+
+1.1.2.1 - 03/12/2014
+Now strongly signed
+
+1.1.2 - 03/12/2014
+Fixed CIE2000 calculations</releaseNotes>
+ <copyright>2014</copyright>
+ <language />
+ <tags>color delta-e rgb to lab</tags>
+ </metadata>
+ <files>
+ <file src="bin\Release\ColorMine.dll" target="lib\ColorMine.dll" />
+ </files>
+</package> \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpace.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpace.cs
new file mode 100644
index 000000000..d67309e63
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpace.cs
@@ -0,0 +1,83 @@
+using ColorMine.ColorSpaces.Comparisons;
+
+namespace ColorMine.ColorSpaces
+{
+ public delegate double ComparisonAlgorithm(IColorSpace a, IColorSpace b);
+
+ /// <summary>
+ /// Defines the public methods for all color spaces
+ /// </summary>
+ public interface IColorSpace
+ {
+ /// <summary>
+ /// Initialize settings from an Rgb object
+ /// </summary>
+ /// <param name="color"></param>
+ void Initialize(IRgb color);
+
+ /// <summary>
+ /// Convert the color space to Rgb, you should probably using the "To" method instead. Need to figure out a way to "hide" or otherwise remove this method from the public interface.
+ /// </summary>
+ /// <returns></returns>
+ IRgb ToRgb();
+
+ /// <summary>
+ /// Convert any IColorSpace to any other IColorSpace.
+ /// </summary>
+ /// <typeparam name="T">IColorSpace type to convert to</typeparam>
+ /// <returns></returns>
+ T To<T>() where T : IColorSpace, new();
+
+ /// <summary>
+ /// Determine how close two IColorSpaces are to each other using a passed in algorithm
+ /// </summary>
+ /// <param name="compareToValue">Other IColorSpace to compare to</param>
+ /// <param name="comparer">Algorithm to use for comparison</param>
+ /// <returns>Distance in 3d space as double</returns>
+ double Compare(IColorSpace compareToValue, IColorSpaceComparison comparer);
+
+ /// <summary>
+ /// Array of signifigant values in a consistent order. Useful for generic n-dimensional math.
+ /// </summary>
+ double[] Ordinals { get; set; }
+ }
+
+ /// <summary>
+ /// Abstract ColorSpace class, defines the To method that converts between any IColorSpace.
+ /// </summary>
+ public abstract class ColorSpace : IColorSpace
+ {
+ public abstract void Initialize(IRgb color);
+ public abstract IRgb ToRgb();
+ public abstract double[] Ordinals { get; set; }
+
+ /// <summary>
+ /// Convienience method for comparing any IColorSpace
+ /// </summary>
+ /// <param name="compareToValue"></param>
+ /// <param name="comparer"></param>
+ /// <returns>Single number representing the difference between two colors</returns>
+ public double Compare(IColorSpace compareToValue, IColorSpaceComparison comparer)
+ {
+ return comparer.Compare(this, compareToValue);
+ }
+
+ /// <summary>
+ /// Convert any IColorSpace to any other IColorSpace
+ /// </summary>
+ /// <typeparam name="T">Must implement IColorSpace, new()</typeparam>
+ /// <returns></returns>
+ public T To<T>() where T : IColorSpace, new()
+ {
+ if (typeof(T) == GetType())
+ {
+ return (T)MemberwiseClone();
+ }
+
+ var newColorSpace = new T();
+ newColorSpace.Initialize(ToRgb());
+
+ return newColorSpace;
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.cs
new file mode 100644
index 000000000..4344113de
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.cs
@@ -0,0 +1,791 @@
+// Note: This is a generated file.
+using ColorMine.ColorSpaces.Conversions;
+
+namespace ColorMine.ColorSpaces
+{
+ public interface IRgb : IColorSpace
+ {
+ double R { get; set; }
+ double G { get; set; }
+ double B { get; set; }
+ }
+
+ public class Rgb : ColorSpace, IRgb
+ {
+ public double R { get; set; }
+ public double G { get; set; }
+ public double B { get; set; }
+
+ public Rgb() { }
+
+ public Rgb(double r, double g, double b)
+ {
+ R = r;
+ G = g;
+ B = b;
+ }
+
+ public Rgb(IColorSpace color)
+ {
+ Ordinals = color.To<Rgb>().Ordinals;
+ }
+
+ public Rgb(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ RgbConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "R: " + R,
+ "G: " + G,
+ "B: " + B,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return RgbConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { R, G, B, };
+ }
+ set
+ {
+ R = value[0];
+ G = value[1];
+ B = value[2];
+ }
+ }
+ }
+ public interface IXyz : IColorSpace
+ {
+ double X { get; set; }
+ double Y { get; set; }
+ double Z { get; set; }
+ }
+
+ public class Xyz : ColorSpace, IXyz
+ {
+ public double X { get; set; }
+ public double Y { get; set; }
+ public double Z { get; set; }
+
+ public Xyz() { }
+
+ public Xyz(double x, double y, double z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ public Xyz(IColorSpace color)
+ {
+ Ordinals = color.To<Xyz>().Ordinals;
+ }
+
+ public Xyz(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ XyzConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "X: " + X,
+ "Y: " + Y,
+ "Z: " + Z,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return XyzConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { X, Y, Z, };
+ }
+ set
+ {
+ X = value[0];
+ Y = value[1];
+ Z = value[2];
+ }
+ }
+ }
+ public interface IHsl : IColorSpace
+ {
+ double H { get; set; }
+ double S { get; set; }
+ double L { get; set; }
+ }
+
+ public class Hsl : ColorSpace, IHsl
+ {
+ public double H { get; set; }
+ public double S { get; set; }
+ public double L { get; set; }
+
+ public Hsl() { }
+
+ public Hsl(double h, double s, double l)
+ {
+ H = h;
+ S = s;
+ L = l;
+ }
+
+ public Hsl(IColorSpace color)
+ {
+ Ordinals = color.To<Hsl>().Ordinals;
+ }
+
+ public Hsl(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ HslConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "H: " + H,
+ "S: " + S,
+ "L: " + L,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return HslConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { H, S, L, };
+ }
+ set
+ {
+ H = value[0];
+ S = value[1];
+ L = value[2];
+ }
+ }
+ }
+ public interface ILab : IColorSpace
+ {
+ double L { get; set; }
+ double A { get; set; }
+ double B { get; set; }
+ }
+
+ public class Lab : ColorSpace, ILab
+ {
+ public double L { get; set; }
+ public double A { get; set; }
+ public double B { get; set; }
+
+ public Lab() { }
+
+ public Lab(double l, double a, double b)
+ {
+ L = l;
+ A = a;
+ B = b;
+ }
+
+ public Lab(IColorSpace color)
+ {
+ Ordinals = color.To<Lab>().Ordinals;
+ }
+
+ public Lab(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ LabConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "L: " + L,
+ "A: " + A,
+ "B: " + B,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return LabConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { L, A, B, };
+ }
+ set
+ {
+ L = value[0];
+ A = value[1];
+ B = value[2];
+ }
+ }
+ }
+ public interface ILch : IColorSpace
+ {
+ double L { get; set; }
+ double C { get; set; }
+ double H { get; set; }
+ }
+
+ public class Lch : ColorSpace, ILch
+ {
+ public double L { get; set; }
+ public double C { get; set; }
+ public double H { get; set; }
+
+ public Lch() { }
+
+ public Lch(double l, double c, double h)
+ {
+ L = l;
+ C = c;
+ H = h;
+ }
+
+ public Lch(IColorSpace color)
+ {
+ Ordinals = color.To<Lch>().Ordinals;
+ }
+
+ public Lch(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ LchConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "L: " + L,
+ "C: " + C,
+ "H: " + H,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return LchConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { L, C, H, };
+ }
+ set
+ {
+ L = value[0];
+ C = value[1];
+ H = value[2];
+ }
+ }
+ }
+ public interface ILuv : IColorSpace
+ {
+ double L { get; set; }
+ double U { get; set; }
+ double V { get; set; }
+ }
+
+ public class Luv : ColorSpace, ILuv
+ {
+ public double L { get; set; }
+ public double U { get; set; }
+ public double V { get; set; }
+
+ public Luv() { }
+
+ public Luv(double l, double u, double v)
+ {
+ L = l;
+ U = u;
+ V = v;
+ }
+
+ public Luv(IColorSpace color)
+ {
+ Ordinals = color.To<Luv>().Ordinals;
+ }
+
+ public Luv(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ LuvConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "L: " + L,
+ "U: " + U,
+ "V: " + V,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return LuvConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { L, U, V, };
+ }
+ set
+ {
+ L = value[0];
+ U = value[1];
+ V = value[2];
+ }
+ }
+ }
+ public interface IYxy : IColorSpace
+ {
+ double Y1 { get; set; }
+ double X { get; set; }
+ double Y2 { get; set; }
+ }
+
+ public class Yxy : ColorSpace, IYxy
+ {
+ public double Y1 { get; set; }
+ public double X { get; set; }
+ public double Y2 { get; set; }
+
+ public Yxy() { }
+
+ public Yxy(double y1, double x, double y2)
+ {
+ Y1 = y1;
+ X = x;
+ Y2 = y2;
+ }
+
+ public Yxy(IColorSpace color)
+ {
+ Ordinals = color.To<Yxy>().Ordinals;
+ }
+
+ public Yxy(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ YxyConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "Y1: " + Y1,
+ "X: " + X,
+ "Y2: " + Y2,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return YxyConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { Y1, X, Y2, };
+ }
+ set
+ {
+ Y1 = value[0];
+ X = value[1];
+ Y2 = value[2];
+ }
+ }
+ }
+ public interface ICmy : IColorSpace
+ {
+ double C { get; set; }
+ double M { get; set; }
+ double Y { get; set; }
+ }
+
+ public class Cmy : ColorSpace, ICmy
+ {
+ public double C { get; set; }
+ public double M { get; set; }
+ public double Y { get; set; }
+
+ public Cmy() { }
+
+ public Cmy(double c, double m, double y)
+ {
+ C = c;
+ M = m;
+ Y = y;
+ }
+
+ public Cmy(IColorSpace color)
+ {
+ Ordinals = color.To<Cmy>().Ordinals;
+ }
+
+ public Cmy(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ CmyConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "C: " + C,
+ "M: " + M,
+ "Y: " + Y,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return CmyConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { C, M, Y, };
+ }
+ set
+ {
+ C = value[0];
+ M = value[1];
+ Y = value[2];
+ }
+ }
+ }
+ public interface ICmyk : IColorSpace
+ {
+ double C { get; set; }
+ double M { get; set; }
+ double Y { get; set; }
+ double K { get; set; }
+ }
+
+ public class Cmyk : ColorSpace, ICmyk
+ {
+ public double C { get; set; }
+ public double M { get; set; }
+ public double Y { get; set; }
+ public double K { get; set; }
+
+ public Cmyk() { }
+
+ public Cmyk(double c, double m, double y, double k)
+ {
+ C = c;
+ M = m;
+ Y = y;
+ K = k;
+ }
+
+ public Cmyk(IColorSpace color)
+ {
+ Ordinals = color.To<Cmyk>().Ordinals;
+ }
+
+ public Cmyk(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ CmykConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "C: " + C,
+ "M: " + M,
+ "Y: " + Y,
+ "K: " + K,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return CmykConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { C, M, Y, K, };
+ }
+ set
+ {
+ C = value[0];
+ M = value[1];
+ Y = value[2];
+ K = value[3];
+ }
+ }
+ }
+ public interface IHsv : IColorSpace
+ {
+ double H { get; set; }
+ double S { get; set; }
+ double V { get; set; }
+ }
+
+ public class Hsv : ColorSpace, IHsv
+ {
+ public double H { get; set; }
+ public double S { get; set; }
+ public double V { get; set; }
+
+ public Hsv() { }
+
+ public Hsv(double h, double s, double v)
+ {
+ H = h;
+ S = s;
+ V = v;
+ }
+
+ public Hsv(IColorSpace color)
+ {
+ Ordinals = color.To<Hsv>().Ordinals;
+ }
+
+ public Hsv(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ HsvConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "H: " + H,
+ "S: " + S,
+ "V: " + V,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return HsvConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { H, S, V, };
+ }
+ set
+ {
+ H = value[0];
+ S = value[1];
+ V = value[2];
+ }
+ }
+ }
+ public interface IHsb : IColorSpace
+ {
+ double H { get; set; }
+ double S { get; set; }
+ double B { get; set; }
+ }
+
+ public class Hsb : ColorSpace, IHsb
+ {
+ public double H { get; set; }
+ public double S { get; set; }
+ public double B { get; set; }
+
+ public Hsb() { }
+
+ public Hsb(double h, double s, double b)
+ {
+ H = h;
+ S = s;
+ B = b;
+ }
+
+ public Hsb(IColorSpace color)
+ {
+ Ordinals = color.To<Hsb>().Ordinals;
+ }
+
+ public Hsb(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ HsbConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "H: " + H,
+ "S: " + S,
+ "B: " + B,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return HsbConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { H, S, B, };
+ }
+ set
+ {
+ H = value[0];
+ S = value[1];
+ B = value[2];
+ }
+ }
+ }
+ public interface IHunterLab : IColorSpace
+ {
+ double L { get; set; }
+ double A { get; set; }
+ double B { get; set; }
+ }
+
+ public class HunterLab : ColorSpace, IHunterLab
+ {
+ public double L { get; set; }
+ public double A { get; set; }
+ public double B { get; set; }
+
+ public HunterLab() { }
+
+ public HunterLab(double l, double a, double b)
+ {
+ L = l;
+ A = a;
+ B = b;
+ }
+
+ public HunterLab(IColorSpace color)
+ {
+ Ordinals = color.To<HunterLab>().Ordinals;
+ }
+
+ public HunterLab(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ HunterLabConverter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+ "L: " + L,
+ "A: " + A,
+ "B: " + B,
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return HunterLabConverter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] { L, A, B, };
+ }
+ set
+ {
+ L = value[0];
+ A = value[1];
+ B = value[2];
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.tt b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.tt
new file mode 100644
index 000000000..42581f739
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.tt
@@ -0,0 +1,89 @@
+<#@ template debug="true" hostspecific="true" language="C#" #>
+<#@ assembly name="System.Core" #>
+<#@ assembly name="System.Xml.dll" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import Namespace="System.Xml" #>
+<#@ import Namespace="System.IO" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#
+ var document = new XmlDocument();
+ var file = Host.ResolvePath("ColorSpaces.xml");
+ document.Load(file);
+ var colorSpaces = document.SelectNodes("colorSpaces/colorSpace");
+#>
+<#@ output extension=".cs" #>// Note: This is a generated file.
+using ColorMine.ColorSpaces.Conversions;
+
+namespace ColorMine.ColorSpaces
+{
+<# foreach (XmlNode space in colorSpaces) {
+var spaceName = space.Attributes["name"].Value;
+var points = space.SelectNodes("dataPoints/dataPoint");#>
+ public interface I<#=spaceName#> : IColorSpace
+ {
+<# foreach(XmlNode point in points) { #>
+ double <#=point.Attributes["label"].Value#> { get; set; }
+<# } #>
+ }
+
+ public class <#=spaceName#> : ColorSpace, I<#=spaceName#>
+ {
+<# foreach(XmlNode point in points) { #>
+ public double <#=point.Attributes["label"].Value#> { get; set; }
+<# } #>
+
+ public <#=spaceName#>() { }
+
+ public <#=spaceName#>(<# foreach(XmlNode point in points) { #>double <#=point.Attributes["label"].Value.ToLower()#><# if(point.Attributes != points[points.Count - 1].Attributes) { #>, <# } #><# } #>)
+ {
+<# foreach(XmlNode point in points) { #>
+ <#=point.Attributes["label"].Value#> = <#=point.Attributes["label"].Value.ToLower()#>;
+<# } #>
+ }
+
+ public <#=spaceName#>(IColorSpace color)
+ {
+ Ordinals = color.To<<#=spaceName#>>().Ordinals;
+ }
+
+ public <#=spaceName#>(double[] ordinals)
+ {
+ Ordinals = ordinals;
+ }
+
+ public override void Initialize(IRgb color)
+ {
+ <#=spaceName#>Converter.ToColorSpace(color,this);
+ }
+
+ public override string ToString()
+ {
+ return string.Join(", ", new []{
+<# foreach(XmlNode point in points) { #>
+ "<#=point.Attributes["label"].Value#>: " + <#=point.Attributes["label"].Value#>,
+<# } #>
+ });
+ }
+
+ public override IRgb ToRgb()
+ {
+ return <#=spaceName#>Converter.ToColor(this);
+ }
+
+ public override sealed double[] Ordinals
+ {
+ get
+ {
+ return new[] {<# foreach(XmlNode point in points) { #> <#=point.Attributes["label"].Value#>,<# } #> };
+ }
+ set
+ {
+<# var counter = 0;
+ foreach(XmlNode point in points) { #>
+ <#=point.Attributes["label"].Value#> = value[<#=counter++#>];
+<# } #>
+ }
+ }
+ }
+<# } #>} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.xml b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.xml
new file mode 100644
index 000000000..20e675bf3
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/ColorSpaces.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<colorSpaces>
+ <colorSpace name="Rgb">
+ <dataPoints>
+ <dataPoint label="R" description="Red" min="0" max="255" />
+ <dataPoint label="G" description="Green" min="0" max="255" />
+ <dataPoint label="B" description="Blue" min="0" max="255" />
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Xyz">
+ <dataPoints>
+ <dataPoint label="X" min="0" max="100"/>
+ <dataPoint label="Y" min="0" max="100"/>
+ <dataPoint label="Z" min="0" max="100"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Hsl">
+ <dataPoints>
+ <dataPoint label="H" min="0" max="360"/>
+ <dataPoint label="S" min="0" max="100"/>
+ <dataPoint label="L" min="0" max="100"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Lab" description="CIE-L*ab">
+ <dataPoints>
+ <dataPoint label="L" min="0" max="100"/>
+ <dataPoint label="A" min="-128" max="128"/>
+ <dataPoint label="B" min="-128" max="128"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Lch" description="CIE-Lch">
+ <dataPoints>
+ <dataPoint label="L" min="0" max="100"/>
+ <dataPoint label="C" min="0" max="100"/>
+ <dataPoint label="H" min="0" max="360"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Luv" description="CIE-Luv">
+ <dataPoints>
+ <dataPoint label="L" min="0" max="100"/>
+ <dataPoint label="U" min="-134" max="224"/>
+ <dataPoint label="V" min="-140" max ="122"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Yxy">
+ <dataPoints>
+ <dataPoint label="Y1" min="0" max="100"/>
+ <dataPoint label="X" min="0" max="1"/>
+ <dataPoint label="Y2" min="0" max="1"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Cmy">
+ <dataPoints>
+ <dataPoint label="C" min="0" max="1"/>
+ <dataPoint label="M" min="0" max="1"/>
+ <dataPoint label="Y" min="0" max="1"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Cmyk">
+ <dataPoints>
+ <dataPoint label="C" min="0" max="1"/>
+ <dataPoint label="M" min="0" max="1"/>
+ <dataPoint label="Y" min="0" max="1"/>
+ <dataPoint label="K" min="0" max="1"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Hsv">
+ <dataPoints>
+ <dataPoint label="H" min="0" max="360"/>
+ <dataPoint label="S" min="0" max="1"/>
+ <dataPoint label="V" min="0" max="1"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="Hsb">
+ <dataPoints>
+ <dataPoint label="H" min="0" max="360"/>
+ <dataPoint label="S" min="0" max="1"/>
+ <dataPoint label="B" min="0" max="1"/>
+ </dataPoints>
+ </colorSpace>
+ <colorSpace name="HunterLab">
+ <dataPoints>
+ <dataPoint label="L" min="0" max="100"/>
+ <dataPoint label="A" min="-128" max="128"/>
+ <dataPoint label="B" min="-128" max="128"/>
+ </dataPoints>
+ </colorSpace>
+</colorSpaces> \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie1976Comparison.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie1976Comparison.cs
new file mode 100644
index 000000000..276605fca
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie1976Comparison.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Comparisons
+{
+ /// <summary>
+ /// Implements the CIE76 method of delta-e: http://en.wikipedia.org/wiki/Color_difference#CIE76
+ /// </summary>
+ public class Cie1976Comparison : IColorSpaceComparison
+ {
+ /// <summary>
+ /// Calculates the CIE76 delta-e value: http://en.wikipedia.org/wiki/Color_difference#CIE76
+ /// </summary>
+ public double Compare(IColorSpace colorA, IColorSpace colorB)
+ {
+ var a = colorA.To<Lab>();
+ var b = colorB.To<Lab>();
+
+ var differences = Distance(a.L, b.L) + Distance(a.A, b.A) + Distance(a.B, b.B);
+ return Math.Sqrt(differences);
+ }
+
+ private static double Distance(double a, double b)
+ {
+ return (a - b) * (a - b);
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie94Comparison.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie94Comparison.cs
new file mode 100644
index 000000000..a2585b688
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/Cie94Comparison.cs
@@ -0,0 +1,99 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Comparisons
+{
+ /// <summary>
+ /// Implements the Cie94 method of delta-e: http://en.wikipedia.org/wiki/Color_difference#CIE94
+ /// </summary>
+ public class Cie94Comparison : IColorSpaceComparison
+ {
+ /// <summary>
+ /// Application type defines constants used in the Cie94 comparison
+ /// </summary>
+ public enum Application
+ {
+ GraphicArts,
+ Textiles
+ }
+
+
+ internal ApplicationConstants Constants { get; private set; }
+
+ /// <summary>
+ /// Create new Cie94Comparison. Defaults to GraphicArts application type.
+ /// </summary>
+ public Cie94Comparison()
+ {
+ Constants = new ApplicationConstants(Application.GraphicArts);
+ }
+
+ /// <summary>
+ /// Create new Cie94Comparison for specific application type.
+ /// </summary>
+ /// <param name="application"></param>
+ public Cie94Comparison(Application application)
+ {
+ Constants = new ApplicationConstants(application);
+ }
+
+ /// <summary>
+ /// Compare colors using the Cie94 algorithm. The first color (a) will be used as the reference color.
+ /// </summary>
+ /// <param name="a">Reference color</param>
+ /// <param name="b">Comparison color</param>
+ /// <returns></returns>
+ public double Compare(IColorSpace a, IColorSpace b)
+ {
+ var labA = a.To<Lab>();
+ var labB = b.To<Lab>();
+
+ var deltaL = labA.L - labB.L;
+ var deltaA = labA.A - labB.A;
+ var deltaB = labA.B - labB.B;
+
+ var c1 = Math.Sqrt(labA.A * labA.A + labA.B * labA.B);
+ var c2 = Math.Sqrt(labB.A * labB.A + labB.B * labB.B);
+ var deltaC = c1 - c2;
+
+ var deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
+ deltaH = deltaH < 0 ? 0 : Math.Sqrt(deltaH);
+
+ const double sl = 1.0;
+ const double kc = 1.0;
+ const double kh = 1.0;
+
+ var sc = 1.0 + Constants.K1 * c1;
+ var sh = 1.0 + Constants.K2 * c1;
+
+ var deltaLKlsl = deltaL / (Constants.Kl * sl);
+ var deltaCkcsc = deltaC / (kc * sc);
+ var deltaHkhsh = deltaH / (kh * sh);
+ var i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
+ return i < 0 ? 0 : Math.Sqrt(i);
+ }
+
+ internal class ApplicationConstants
+ {
+ internal double Kl { get; private set; }
+ internal double K1 { get; private set; }
+ internal double K2 { get; private set; }
+
+ public ApplicationConstants(Application application)
+ {
+ switch (application)
+ {
+ case Application.GraphicArts:
+ Kl = 1.0;
+ K1 = .045;
+ K2 = .015;
+ break;
+ case Application.Textiles:
+ Kl = 2.0;
+ K1 = .048;
+ K2 = .014;
+ break;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CieDe2000Comparison.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CieDe2000Comparison.cs
new file mode 100644
index 000000000..f47ad6917
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CieDe2000Comparison.cs
@@ -0,0 +1,127 @@
+using ColorMine.ColorSpaces.Utility;
+using System;
+
+namespace ColorMine.ColorSpaces.Comparisons
+{
+ /// <summary>
+ /// Implements the DE2000 method of delta-e: http://en.wikipedia.org/wiki/Color_difference#CIEDE2000
+ /// Correct implementation provided courtesy of Jonathan Hofinger, jaytar42
+ /// </summary>
+ public class CieDe2000Comparison : IColorSpaceComparison
+ {
+ /// <summary>
+ /// Calculates the DE2000 delta-e value: http://en.wikipedia.org/wiki/Color_difference#CIEDE2000
+ /// Correct implementation provided courtesy of Jonathan Hofinger, jaytar42
+ /// </summary>
+ public double Compare(IColorSpace c1, IColorSpace c2)
+ {
+ //Set weighting factors to 1
+ double k_L = 1.0d;
+ double k_C = 1.0d;
+ double k_H = 1.0d;
+
+
+ //Change Color Space to L*a*b:
+ Lab lab1 = c1.To<Lab>();
+ Lab lab2 = c2.To<Lab>();
+
+ //Calculate Cprime1, Cprime2, Cabbar
+ double c_star_1_ab = Math.Sqrt(lab1.A * lab1.A + lab1.B * lab1.B);
+ double c_star_2_ab = Math.Sqrt(lab2.A * lab2.A + lab2.B * lab2.B);
+ double c_star_average_ab = (c_star_1_ab + c_star_2_ab) / 2;
+
+ double c_star_average_ab_pot7 = c_star_average_ab * c_star_average_ab * c_star_average_ab;
+ c_star_average_ab_pot7 *= c_star_average_ab_pot7 * c_star_average_ab;
+
+ double G = 0.5d * (1 - Math.Sqrt(c_star_average_ab_pot7 / (c_star_average_ab_pot7 + 6103515625))); //25^7
+ double a1_prime = (1 + G) * lab1.A;
+ double a2_prime = (1 + G) * lab2.A;
+
+ double C_prime_1 = Math.Sqrt(a1_prime * a1_prime + lab1.B * lab1.B);
+ double C_prime_2 = Math.Sqrt(a2_prime * a2_prime + lab2.B * lab2.B);
+ //Angles in Degree.
+ double h_prime_1 = (MathUtils.RadToDeg(Math.Atan2(lab1.B, a1_prime)) + 360) % 360d;
+ double h_prime_2 = (MathUtils.RadToDeg(Math.Atan2(lab2.B, a2_prime)) + 360) % 360d;
+
+ double delta_L_prime = lab2.L - lab1.L;
+ double delta_C_prime = C_prime_2 - C_prime_1;
+
+ double h_bar = Math.Abs(h_prime_1 - h_prime_2);
+ double delta_h_prime;
+ if (C_prime_1 * C_prime_2 == 0) delta_h_prime = 0;
+ else
+ {
+ if (h_bar <= 180d)
+ {
+ delta_h_prime = h_prime_2 - h_prime_1;
+ }
+ else if (h_bar > 180d && h_prime_2 <= h_prime_1)
+ {
+ delta_h_prime = h_prime_2 - h_prime_1 + 360.0;
+ }
+ else
+ {
+ delta_h_prime = h_prime_2 - h_prime_1 - 360.0;
+ }
+ }
+ double delta_H_prime = 2 * Math.Sqrt(C_prime_1 * C_prime_2) * Math.Sin(MathUtils.DegToRad(delta_h_prime / 2));
+
+ // Calculate CIEDE2000
+ double L_prime_average = (lab1.L + lab2.L) / 2d;
+ double C_prime_average = (C_prime_1 + C_prime_2) / 2d;
+
+ //Calculate h_prime_average
+
+ double h_prime_average;
+ if (C_prime_1 * C_prime_2 == 0) h_prime_average = 0;
+ else
+ {
+ if (h_bar <= 180d)
+ {
+ h_prime_average = (h_prime_1 + h_prime_2) / 2;
+ }
+ else if (h_bar > 180d && (h_prime_1 + h_prime_2) < 360d)
+ {
+ h_prime_average = (h_prime_1 + h_prime_2 + 360d) / 2;
+ }
+ else
+ {
+ h_prime_average = (h_prime_1 + h_prime_2 - 360d) / 2;
+ }
+ }
+ double L_prime_average_minus_50_square = (L_prime_average - 50);
+ L_prime_average_minus_50_square *= L_prime_average_minus_50_square;
+
+ double S_L = 1 + ((.015d * L_prime_average_minus_50_square) / Math.Sqrt(20 + L_prime_average_minus_50_square));
+ double S_C = 1 + .045d * C_prime_average;
+ double T = 1
+ - .17 * Math.Cos(MathUtils.DegToRad(h_prime_average - 30))
+ + .24 * Math.Cos(MathUtils.DegToRad(h_prime_average * 2))
+ + .32 * Math.Cos(MathUtils.DegToRad(h_prime_average * 3 + 6))
+ - .2 * Math.Cos(MathUtils.DegToRad(h_prime_average * 4 - 63));
+ double S_H = 1 + .015 * T * C_prime_average;
+ double h_prime_average_minus_275_div_25_square = (h_prime_average - 275) / (25);
+ h_prime_average_minus_275_div_25_square *= h_prime_average_minus_275_div_25_square;
+ double delta_theta = 30 * Math.Exp(-h_prime_average_minus_275_div_25_square);
+
+ double C_prime_average_pot_7 = C_prime_average * C_prime_average * C_prime_average;
+ C_prime_average_pot_7 *= C_prime_average_pot_7 * C_prime_average;
+ double R_C = 2 * Math.Sqrt(C_prime_average_pot_7 / (C_prime_average_pot_7 + 6103515625));
+
+ double R_T = -Math.Sin(MathUtils.DegToRad(2 * delta_theta)) * R_C;
+
+ double delta_L_prime_div_k_L_S_L = delta_L_prime / (S_L * k_L);
+ double delta_C_prime_div_k_C_S_C = delta_C_prime / (S_C * k_C);
+ double delta_H_prime_div_k_H_S_H = delta_H_prime / (S_H * k_H);
+
+ double CIEDE2000 = Math.Sqrt(
+ delta_L_prime_div_k_L_S_L * delta_L_prime_div_k_L_S_L
+ + delta_C_prime_div_k_C_S_C * delta_C_prime_div_k_C_S_C
+ + delta_H_prime_div_k_H_S_H * delta_H_prime_div_k_H_S_H
+ + R_T * delta_C_prime_div_k_C_S_C * delta_H_prime_div_k_H_S_H
+ );
+
+ return CIEDE2000;
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CmcComparison.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CmcComparison.cs
new file mode 100644
index 000000000..34a06da24
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/CmcComparison.cs
@@ -0,0 +1,84 @@
+using ColorMine.ColorSpaces.Utility;
+using System;
+
+namespace ColorMine.ColorSpaces.Comparisons
+{
+ /// <summary>
+ /// Implements the CMC l:c (1984) method of delta-e: http://en.wikipedia.org/wiki/Color_difference#CMC_l:c_.281984.29
+ /// </summary>
+ public class CmcComparison : IColorSpaceComparison
+ {
+ public const double DefaultLightness = 2.0;
+ public const double DefaultChroma = 1.0;
+
+ private readonly double _lightness;
+ private readonly double _chroma;
+
+ /// <summary>
+ /// Create CMC l:c comparison with DefaultLightness and DefaultChroma values.
+ /// </summary>
+ public CmcComparison()
+ {
+ _lightness = DefaultLightness;
+ _chroma = DefaultChroma;
+ }
+
+ /// <summary>
+ /// Create CMC l:c comparison with specific lightness (l) and chroma (c) values.
+ /// </summary>
+ /// <param name="lightness"></param>
+ /// <param name="chroma"></param>
+ public CmcComparison(double lightness = DefaultLightness, double chroma = DefaultChroma)
+ {
+ _lightness = lightness;
+ _chroma = chroma;
+ }
+
+ /// <summary>
+ /// Calculates the CMC l:c (1984) delta-e value: http://en.wikipedia.org/wiki/Color_difference#CMC_l:c_.281984.29
+ /// </summary>
+ /// <param name="colorA"></param>
+ /// <param name="colorB"></param>
+ /// <returns></returns>
+ public double Compare(IColorSpace colorA, IColorSpace colorB)
+ {
+ var aLab = colorA.To<Lab>();
+ var bLab = colorB.To<Lab>();
+
+ var deltaL = aLab.L - bLab.L;
+ var h = MathUtils.RadToDeg(Math.Atan2(aLab.B, aLab.A));
+
+ var c1 = Math.Sqrt(aLab.A * aLab.A + aLab.B * aLab.B);
+ var c2 = Math.Sqrt(bLab.A * bLab.A + bLab.B * bLab.B);
+ var deltaC = c1 - c2;
+
+ var deltaH_2 =
+ (aLab.A - bLab.A) * (aLab.A - bLab.A) +
+ (aLab.B - bLab.B) * (aLab.B - bLab.B) -
+ deltaC * deltaC;
+
+ var c1_4 = c1 * c1;
+ c1_4 *= c1_4;
+ var t = 164 <= h && h <= 345
+ ? .56 + Math.Abs(.2 * Math.Cos(MathUtils.DegToRad(h + 168.0)))
+ : .36 + Math.Abs(.4 * Math.Cos(MathUtils.DegToRad(h + 35.0)));
+ var f = Math.Sqrt(c1_4 / (c1_4 + 1900.0));
+
+ var sL = aLab.L < 16 ? .511 : (.040975 * aLab.L) / (1.0 + .01765 * aLab.L);
+ var sC = (.0638 * c1) / (1 + .0131 * c1) + .638;
+ var sH = sC * (f * t + 1 - f);
+
+ var differences = DistanceDivided(deltaL, _lightness * sL) +
+ DistanceDivided(deltaC, _chroma * sC) +
+ deltaH_2 / (sH * sH);
+
+ return Math.Sqrt(differences);
+ }
+
+ private static double DistanceDivided(double a, double dividend)
+ {
+ var adiv = a / dividend;
+ return adiv * adiv;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/IColorSpaceComparison.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/IColorSpaceComparison.cs
new file mode 100644
index 000000000..c6a789e62
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Comparisons/IColorSpaceComparison.cs
@@ -0,0 +1,16 @@
+namespace ColorMine.ColorSpaces.Comparisons
+{
+ /// <summary>
+ /// Defines how comparison methods may be called
+ /// </summary>
+ public interface IColorSpaceComparison
+ {
+ /// <summary>
+ /// Returns the difference between two colors given based on the specified defined in the called class.
+ /// </summary>
+ /// <param name="a"></param>
+ /// <param name="b"></param>
+ /// <returns>Score based on similarity, the lower the score the closer the colors</returns>
+ double Compare(IColorSpace a, IColorSpace b);
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmyConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmyConverter.cs
new file mode 100644
index 000000000..9851d809a
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmyConverter.cs
@@ -0,0 +1,22 @@
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class CmyConverter
+ {
+ internal static void ToColorSpace(IRgb color, ICmy item)
+ {
+ item.C = 1 - color.R / 255.0;
+ item.M = 1 - color.G / 255.0;
+ item.Y = 1 - color.B / 255.0;
+ }
+
+ internal static IRgb ToColor(ICmy item)
+ {
+ return new Rgb
+ {
+ R = (1 - item.C) * 255.0,
+ G = (1 - item.M) * 255.0,
+ B = (1 - item.Y) * 255.0
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmykConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmykConverter.cs
new file mode 100644
index 000000000..cd5a33eb5
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/CmykConverter.cs
@@ -0,0 +1,47 @@
+using ColorMine.ColorSpaces.Utility;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ public static class CmykConverter
+ {
+ public static void ToColorSpace(IRgb color, ICmyk item)
+ {
+ var cmy = new Cmy();
+ cmy.Initialize(color);
+
+ var k = 1.0;
+ if (cmy.C < k)
+ k = cmy.C;
+ if (cmy.M < k)
+ k = cmy.M;
+ if (cmy.Y < k)
+ k = cmy.Y;
+ item.K = k;
+
+ if (k.BasicallyEqualTo(1))
+ {
+ item.C = 0;
+ item.M = 0;
+ item.Y = 0;
+ }
+ else
+ {
+ item.C = (cmy.C - k) / (1 - k);
+ item.M = (cmy.M - k) / (1 - k);
+ item.Y = (cmy.Y - k) / (1 - k);
+ }
+ }
+
+ public static IRgb ToColor(ICmyk item)
+ {
+ var cmy = new Cmy
+ {
+ C = (item.C * (1 - item.K) + item.K),
+ M = (item.M * (1 - item.K) + item.K),
+ Y = (item.Y * (1 - item.K) + item.K)
+ };
+
+ return cmy.ToRgb();
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsbConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsbConverter.cs
new file mode 100644
index 000000000..f3705fdd5
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsbConverter.cs
@@ -0,0 +1,29 @@
+namespace ColorMine.ColorSpaces.Conversions
+{
+ /// <summary>
+ /// HSB is another name for HSV
+ /// </summary>
+ internal static class HsbConverter
+ {
+ internal static void ToColorSpace(IRgb color, IHsb item)
+ {
+ var hsv = new Hsv();
+ HsvConverter.ToColorSpace(color, hsv);
+
+ item.H = hsv.H;
+ item.S = hsv.S;
+ item.B = hsv.V;
+ }
+
+ internal static IRgb ToColor(IHsb item)
+ {
+ var hsv = new Hsv
+ {
+ H = item.H,
+ S = item.S,
+ V = item.B
+ };
+ return HsvConverter.ToColor(hsv);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HslConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HslConverter.cs
new file mode 100644
index 000000000..4be751723
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HslConverter.cs
@@ -0,0 +1,149 @@
+using static System.Math;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class HslConverter
+ {
+ public static IHsl ToColorSpace(double R, double G, double B)
+ {
+ var min = Min(R, Min(G, B)); //Min. value of RGB
+ var max = Max(R, Max(G, B)); //Max. value of RGB
+ var chroma = max - min;
+
+ double H = 0, S = 0, L = 0;
+ L = (max + min) / 2;
+
+ if (chroma == 0) // This is a gray, no chroma...
+ {
+ H = 0;
+ S = 0;
+ }
+ else
+ {
+ if (L <= 0.5)
+ {
+ S = chroma / (2 * L); //max / (max + min);
+ }
+ else
+ {
+ S = chroma / (2 - 2 * L); // max / (2 - max - min);
+ }
+
+ if (R == max)
+ {
+ H = (G - B) / chroma;
+ if (G < B)
+ {
+ H += 6;
+ }
+ }
+ else if (B == max)
+ {
+ H = 4 + ((R - G) / chroma);
+ }
+ else if (G == max)
+ {
+ H = 2 + ((B - R) / chroma);
+ }
+
+
+ H *= 60;
+ }
+ return new Hsl(H, S, L);
+ }
+
+ internal static void ToColorSpace(IRgb color, IHsl item)
+ {
+ var result = ToColorSpace(color.R / 255d, color.G / 255d, color.B / 255d);
+ item.H = result.H;
+ item.S = result.S;
+ item.L = result.L;
+
+ // Range expected by HSL is integer
+ item.S = Round(item.S * 100, 3);
+ item.L = Round(item.L * 100, 3);
+ }
+
+ private static IRgb Rotate(double h, double s, ref double l)
+ {
+ // Avoid exactly zero hue, it does weird things
+ if(h==0) { h = 0.00001; }
+ var chroma = (1 - Abs(2 * l - 1)) * s;
+ var x = chroma * (1 - Abs((h % 2d) - 1));
+ l -= 0.5 * chroma;
+
+ switch (Ceiling(h))
+ {
+ case 1d:
+ return new Rgb(chroma, x, 0);
+ case 2d:
+ return new Rgb(x, chroma, 0);
+ case 3d:
+ return new Rgb(0, chroma, x);
+ case 4d:
+ return new Rgb(0, x, chroma);
+ case 5d:
+ return new Rgb(x, 0, chroma);
+ case 6d:
+ return new Rgb(chroma, 0, x);
+ default:
+ return new Rgb(0, 0, 0);
+ }
+ }
+
+ internal static IRgb ToColor(IHsl item)
+ {
+ var h = item.H / 60.0;
+ var s = item.S / 100.0;
+ var l = item.L / 100.0;
+ if (s > 0)
+ {
+ var result = Rotate(h, s, ref l);
+
+ return new Rgb
+ {
+ R = (result.R + l) * 255,
+ G = (result.G + l) * 255,
+ B = (result.B + l) * 255
+ };
+ }
+ else
+ {
+ return new Rgb
+ {
+ R = l * 255,
+ G = l * 255,
+ B = l * 255
+ };
+ }
+ }
+
+ private static double GetColorComponent(double temp1, double temp2, double temp3)
+ {
+ temp3 = MoveIntoRange(temp3);
+ if (temp3 < 1.0 / 6.0)
+ {
+ return temp1 + (temp2 - temp1) * 6.0 * temp3;
+ }
+
+ if (temp3 < 0.5)
+ {
+ return temp2;
+ }
+
+ if (temp3 < 2.0 / 3.0)
+ {
+ return temp1 + ((temp2 - temp1) * ((2.0 / 3.0) - temp3) * 6.0);
+ }
+
+ return temp1;
+ }
+
+ private static double MoveIntoRange(double temp3)
+ {
+ if (temp3 < 0.0) return temp3 + 1.0;
+ if (temp3 > 1.0) return temp3 - 1.0;
+ return temp3;
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsvConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsvConverter.cs
new file mode 100644
index 000000000..c980a7739
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HsvConverter.cs
@@ -0,0 +1,91 @@
+using System;
+using static System.Math;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class HsvConverter
+ {
+ public static IHsv ToColorSpace(double R, double G, double B)
+ {
+ var min = Min(R, Min(G, B)); //Min. value of RGB
+ var max = Max(R, Max(G, B)); //Max. value of RGB
+ var chroma = max - min;
+
+ double H = 0, S = 0, V = 0;
+ V = max;
+
+ if (chroma == 0) // This is a gray, no chroma...
+ {
+ H = 0;
+ S = 0;
+ }
+ else
+ {
+ S = chroma / max;
+
+ if (R == max)
+ {
+ H = (G - B) / chroma;
+ if (G < B)
+ {
+ H += 6;
+ }
+ }
+ else if (G == max)
+ {
+ H = 2 + ((B - R) / chroma);
+ }
+ else if (B == max)
+ {
+ H = 4 + ((R - G) / chroma);
+ }
+
+ H *= 60;
+ }
+ return new Hsv(H, S, V);
+ }
+
+ internal static void ToColorSpace(IRgb color, IHsv item)
+ {
+ var result = ToColorSpace(color.R / 255d, color.G / 255d, color.B / 255d);
+ item.H = result.H;
+ item.S = result.S;
+ item.V = result.V;
+
+ //item.H = Color.FromArgb(255, (int)color.R, (int)color.G, (int)color.B).GetHue();
+ //item.S = (max <= 0) ? 0 : 1d - (1d * min / max);
+ //item.V = max / 255d;
+ }
+
+ internal static IRgb ToColor(IHsv item)
+ {
+ var range = Convert.ToInt32(Math.Floor(item.H / 60.0)) % 6;
+ var f = item.H / 60.0 - Math.Floor(item.H / 60.0);
+
+ var v = item.V * 255.0;
+ var p = v * (1 - item.S);
+ var q = v * (1 - f * item.S);
+ var t = v * (1 - (1 - f) * item.S);
+
+ switch (range)
+ {
+ case 0:
+ return NewRgb(v, t, p);
+ case 1:
+ return NewRgb(q, v, p);
+ case 2:
+ return NewRgb(p, v, t);
+ case 3:
+ return NewRgb(p, q, v);
+ case 4:
+ return NewRgb(t, p, v);
+ }
+ return NewRgb(v, p, q);
+ }
+
+ private static IRgb NewRgb(double r, double g, double b)
+ {
+ return new Rgb { R = r, G = g, B = b };
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HunterLabConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HunterLabConverter.cs
new file mode 100644
index 000000000..0e0b4f3bb
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/HunterLabConverter.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class HunterLabConverter
+ {
+
+ internal static void ToColorSpace(IRgb color, IHunterLab item)
+ {
+ var xyz = color.To<Xyz>();
+
+ item.L = 10.0 * Math.Sqrt(xyz.Y);
+ item.A = xyz.Y != 0 ? 17.5 * (((1.02 * xyz.X) - xyz.Y) / Math.Sqrt(xyz.Y)) : 0;
+ item.B = xyz.Y != 0 ? 7.0 * ((xyz.Y - (.847 * xyz.Z)) / Math.Sqrt(xyz.Y)) : 0;
+ }
+
+ internal static IRgb ToColor(IHunterLab item)
+ {
+ var x = (item.A / 17.5) * (item.L / 10.0);
+ var itemL_10 = item.L / 10.0;
+ var y = itemL_10 * itemL_10;
+ var z = item.B / 7.0 * item.L / 10.0;
+
+ var xyz = new Xyz
+ {
+ X = (x + y) / 1.02,
+ Y = y,
+ Z = -(z - y) / .847
+ };
+ return xyz.To<Rgb>();
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LabConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LabConverter.cs
new file mode 100644
index 000000000..57535b40c
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LabConverter.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class LabConverter
+ {
+ internal static void ToColorSpace(IRgb color, ILab item)
+ {
+ var xyz = new Xyz();
+ xyz.Initialize(color);
+
+ var white = XyzConverter.WhiteReference;
+ var x = PivotXyz(xyz.X / white.X);
+ var y = PivotXyz(xyz.Y / white.Y);
+ var z = PivotXyz(xyz.Z / white.Z);
+
+ item.L = Math.Max(0, 116 * y - 16);
+ item.A = 500 * (x - y);
+ item.B = 200 * (y - z);
+ }
+
+ internal static IRgb ToColor(ILab item)
+ {
+ var y = (item.L + 16.0) / 116.0;
+ var x = item.A / 500.0 + y;
+ var z = y - item.B / 200.0;
+
+ var white = XyzConverter.WhiteReference;
+ var x3 = x * x * x;
+ var z3 = z * z * z;
+ var xyz = new Xyz
+ {
+ X = white.X * (x3 > XyzConverter.Epsilon ? x3 : (x - 16.0 / 116.0) / 7.787),
+ Y = white.Y * (item.L > (XyzConverter.Kappa * XyzConverter.Epsilon) ? Math.Pow(((item.L + 16.0) / 116.0), 3) : item.L / XyzConverter.Kappa),
+ Z = white.Z * (z3 > XyzConverter.Epsilon ? z3 : (z - 16.0 / 116.0) / 7.787)
+ };
+
+ return xyz.ToRgb();
+ }
+
+ private static double PivotXyz(double n)
+ {
+ return n > XyzConverter.Epsilon ? CubicRoot(n) : (XyzConverter.Kappa * n + 16) / 116;
+ }
+
+ private static double CubicRoot(double n)
+ {
+ return Math.Pow(n, 1.0 / 3.0);
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LchConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LchConverter.cs
new file mode 100644
index 000000000..871777851
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LchConverter.cs
@@ -0,0 +1,39 @@
+using ColorMine.ColorSpaces.Utility;
+using System;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class LchConverter
+ {
+ internal static void ToColorSpace(IRgb color, ILch item)
+ {
+ var lab = color.To<Lab>();
+ var h = MathUtils.RadToDeg(Math.Atan2(lab.B, lab.A));
+
+ if (h < 0)
+ {
+ h += 360.0;
+ }
+ else if (h >= 360)
+ {
+ h -= 360.0;
+ }
+
+ item.L = lab.L;
+ item.C = Math.Sqrt(lab.A * lab.A + lab.B * lab.B);
+ item.H = h;
+ }
+
+ internal static IRgb ToColor(ILch item)
+ {
+ var hRadians = MathUtils.DegToRad(item.H);
+ var lab = new Lab
+ {
+ L = item.L,
+ A = Math.Cos(hRadians) * item.C,
+ B = Math.Sin(hRadians) * item.C
+ };
+ return lab.To<Rgb>();
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LuvConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LuvConverter.cs
new file mode 100644
index 000000000..6b6d1f353
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/LuvConverter.cs
@@ -0,0 +1,57 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class LuvConverter
+ {
+ internal static void ToColorSpace(IRgb color, ILuv item)
+ {
+ var xyz = new Xyz();
+ var white = XyzConverter.WhiteReference;
+ xyz.Initialize(color);
+
+ var y = xyz.Y / XyzConverter.WhiteReference.Y;
+ item.L = y > XyzConverter.Epsilon ? 116.0 * XyzConverter.CubicRoot(y) - 16.0 : XyzConverter.Kappa * y;
+
+ var targetDenominator = GetDenominator(xyz);
+ var referenceDenominator = GetDenominator(white);
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ var xTarget = targetDenominator == 0 ? 0 : ((4.0 * xyz.X / targetDenominator) - (4.0 * white.X / referenceDenominator));
+ var yTarget = targetDenominator == 0 ? 0 : ((9.0 * xyz.Y / targetDenominator) - (9.0 * white.Y / referenceDenominator));
+ // ReSharper restore CompareOfFloatsByEqualityOperator
+
+ item.U = 13.0 * item.L * xTarget;
+ item.V = 13.0 * item.L * yTarget;
+ }
+
+ internal static IRgb ToColor(ILuv item)
+ {
+ var white = XyzConverter.WhiteReference;
+ const double c = -1.0 / 3.0;
+ var uPrime = (4.0 * white.X) / GetDenominator(white);
+ var vPrime = (9.0 * white.Y) / GetDenominator(white);
+ var a = (1.0 / 3.0) * ((52.0 * item.L) / (item.U + 13 * item.L * uPrime) - 1.0);
+ var imteL_16_116 = (item.L + 16.0) / 116.0;
+ var y = item.L > XyzConverter.Kappa * XyzConverter.Epsilon
+ ? imteL_16_116 * imteL_16_116 * imteL_16_116
+ : item.L / XyzConverter.Kappa;
+ var b = -5.0 * y;
+ var d = y * ((39.0 * item.L) / (item.V + 13.0 * item.L * vPrime) - 5.0);
+ var x = (d - b) / (a - c);
+ var z = x * a + b;
+ var xyz = new Xyz
+ {
+ X = 100 * x,
+ Y = 100 * y,
+ Z = 100 * z
+ };
+ return xyz.ToRgb();
+
+ }
+
+ private static double GetDenominator(IXyz xyz)
+ {
+ return xyz.X + 15.0 * xyz.Y + 3.0 * xyz.Z;
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/RgbConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/RgbConverter.cs
new file mode 100644
index 000000000..7774b977f
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/RgbConverter.cs
@@ -0,0 +1,17 @@
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class RgbConverter
+ {
+ internal static void ToColorSpace(IRgb color, IRgb item)
+ {
+ item.R = color.R;
+ item.G = color.G;
+ item.B = color.B;
+ }
+
+ internal static IRgb ToColor(IRgb item)
+ {
+ return item;
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/XyzConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/XyzConverter.cs
new file mode 100644
index 000000000..bf4e187bb
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/XyzConverter.cs
@@ -0,0 +1,75 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class XyzConverter
+ {
+ #region Constants/Helper methods for Xyz related spaces
+ internal static IXyz WhiteReference { get; private set; } // TODO: Hard-coded!
+ internal const double Epsilon = 0.008856; // Intent is 216/24389
+ internal const double Kappa = 903.3; // Intent is 24389/27
+ static XyzConverter()
+ {
+ WhiteReference = new Xyz
+ {
+ X = 95.047,
+ Y = 100.000,
+ Z = 108.883
+ };
+ }
+
+ internal static double CubicRoot(double n)
+ {
+ return Math.Pow(n, 1.0 / 3.0);
+ }
+ #endregion
+
+ internal static void ToColorSpace(IRgb color, IXyz item)
+ {
+ var r = PivotRgb(color.R / 255.0);
+ var g = PivotRgb(color.G / 255.0);
+ var b = PivotRgb(color.B / 255.0);
+
+ // Observer. = 2°, Illuminant = D65
+ item.X = r * 0.4124 + g * 0.3576 + b * 0.1805;
+ item.Y = r * 0.2126 + g * 0.7152 + b * 0.0722;
+ item.Z = r * 0.0193 + g * 0.1192 + b * 0.9505;
+ }
+
+ internal static IRgb ToColor(IXyz item)
+ {
+ // (Observer = 2°, Illuminant = D65)
+ var x = item.X / 100.0;
+ var y = item.Y / 100.0;
+ var z = item.Z / 100.0;
+
+ var r = x * 3.2406 + y * -1.5372 + z * -0.4986;
+ var g = x * -0.9689 + y * 1.8758 + z * 0.0415;
+ var b = x * 0.0557 + y * -0.2040 + z * 1.0570;
+
+ r = r > 0.0031308 ? 1.055 * Math.Pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
+ g = g > 0.0031308 ? 1.055 * Math.Pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
+ b = b > 0.0031308 ? 1.055 * Math.Pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
+
+ return new Rgb
+ {
+ R = ToRgb(r),
+ G = ToRgb(g),
+ B = ToRgb(b)
+ };
+ }
+
+ private static double ToRgb(double n)
+ {
+ var result = 255.0 * n;
+ if (result < 0) return 0;
+ if (result > 255) return 255;
+ return result;
+ }
+
+ private static double PivotRgb(double n)
+ {
+ return (n > 0.04045 ? Math.Pow((n + 0.055) / 1.055, 2.4) : n / 12.92) * 100.0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/YxyConverter.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/YxyConverter.cs
new file mode 100644
index 000000000..51344e897
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Conversions/YxyConverter.cs
@@ -0,0 +1,32 @@
+using ColorMine.ColorSpaces.Utility;
+
+namespace ColorMine.ColorSpaces.Conversions
+{
+ internal static class YxyConverter
+ {
+ internal static void ToColorSpace(IRgb color, IYxy item)
+ {
+ var xyz = new Xyz();
+ xyz.Initialize(color);
+
+ item.Y1 = xyz.Y;
+
+ var xDividend = xyz.X + xyz.Y + xyz.Z;
+ item.X = xDividend.BasicallyEqualTo(0) ? 0.0 : xyz.X / xDividend;
+
+ var y2Dividend = xyz.X + xyz.Y + xyz.Z;
+ item.Y2 = y2Dividend.BasicallyEqualTo(0) ? 0.0 : xyz.Y / (xyz.X + xyz.Y + xyz.Z);
+ }
+
+ internal static IRgb ToColor(IYxy item)
+ {
+ var xyz = new Xyz
+ {
+ X = item.X * (item.Y1 / item.Y2),
+ Y = item.Y1,
+ Z = (1.0 - item.X - item.Y2) * (item.Y1 / item.Y2)
+ };
+ return xyz.ToRgb();
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/DoubleExtension.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/DoubleExtension.cs
new file mode 100644
index 000000000..cc9733ff7
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/DoubleExtension.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Utility
+{
+ internal static class DoubleExtension
+ {
+ private const double DefaultPrecision = .0001;
+
+ internal static bool BasicallyEqualTo(this double a, double b)
+ {
+ return a.BasicallyEqualTo(b, DefaultPrecision);
+ }
+
+ internal static bool BasicallyEqualTo(this double a, double b, double precision)
+ {
+ return Math.Abs(a - b) <= precision;
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/MathUtils.cs b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/MathUtils.cs
new file mode 100644
index 000000000..1aa9334d6
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/ColorSpaces/Utility/MathUtils.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace ColorMine.ColorSpaces.Utility
+{
+ internal static class MathUtils
+ {
+ internal static double DegToRad(double degrees)
+ {
+ return degrees * Math.PI / 180;
+ }
+
+ internal static double RadToDeg(double radians)
+ {
+ return radians / Math.PI * 180;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/SideChains/ColorMine/Properties/AssemblyInfo.cs b/Software/Visual_Studio/SideChains/ColorMine/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..9f0124f76
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/ColorMine/Properties/AssemblyInfo.cs
@@ -0,0 +1 @@
+[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ColorMine.Test")] \ No newline at end of file