1 module ggplotd.color.hsx; 2 3 import ggplotd.color; 4 5 import std.traits : isFloatingPoint, isIntegral, isSigned, isUnsigned, isSomeChar, Unqual; 6 import std.typetuple : TypeTuple; 7 import std.typecons : tuple; 8 9 @safe pure nothrow @nogc: 10 11 /** 12 Detect whether $(D T) is a member of the HSx color family. 13 */ 14 enum isHSx(T) = isInstanceOf!(HSx, T); 15 16 /// 17 unittest 18 { 19 static assert(isHSx!(HSx!(HSxType.HSV, ushort)) == true); 20 static assert(isHSx!string == false); 21 } 22 23 /** 24 Alias for a HSV (HSB) color. 25 */ 26 alias HSV(CT = float, RGBColorSpace cs = RGBColorSpace.sRGB) = HSx!(HSxType.HSV, CT, cs); 27 28 /** 29 Alias for a HSL color. 30 */ 31 alias HSL(CT = float, RGBColorSpace cs = RGBColorSpace.sRGB) = HSx!(HSxType.HSL, CT, cs); 32 33 /** 34 Alias for a HSI color. 35 */ 36 alias HSI(CT = float, RGBColorSpace cs = RGBColorSpace.sRGB) = HSx!(HSxType.HSI, CT, cs); 37 38 /** 39 Alias for a HCY' color. 40 */ 41 alias HCY(CT = float, RGBColorSpace cs = RGBColorSpace.sRGB) = HSx!(HSxType.HCY, CT, cs); 42 43 /** 44 Define a HSx family colour type. 45 */ 46 enum HSxType 47 { 48 /** Hue-saturation-value (aka HSB: Hue-saturation-brightness) */ 49 HSV, 50 /** Hue-saturation-lightness */ 51 HSL, 52 /** Hue-saturation-intensity */ 53 HSI, 54 /** Hue-chroma-luma */ 55 HCY 56 } 57 58 /** 59 HSx color space is used to describe a suite of angular color spaces including HSL, HSV, HSI, HSY. 60 */ 61 struct HSx(HSxType type_, CT = float, RGBColorSpace colorSpace_ = RGBColorSpace.sRGB) if(isFloatingPoint!CT || isUnsigned!CT) 62 { 63 @safe pure nothrow @nogc: 64 65 /** Type of the color components. */ 66 alias ComponentType = CT; 67 /** The color space specified. */ 68 enum colorSpace = colorSpace_; 69 /** The color type from the HSx family. */ 70 enum type = type_; 71 72 // mixin the color channels according to the type 73 mixin("CT " ~ Components!type[0] ~ " = 0;"); 74 mixin("CT " ~ Components!type[1] ~ " = 0;"); 75 mixin("CT " ~ Components!type[2] ~ " = 0;"); 76 77 // casts 78 Color opCast(Color)() const if(isColor!Color) 79 { 80 return convertColor!Color(this); 81 } 82 83 // operators 84 mixin ColorOperators!(Components!type); 85 86 private: 87 template Components(HSxType type) 88 { 89 static if(type == HSxType.HSV) 90 alias Components = TypeTuple!("h","s","v"); 91 else static if(type == HSxType.HSL) 92 alias Components = TypeTuple!("h","s","l"); 93 else static if(type == HSxType.HSI) 94 alias Components = TypeTuple!("h","s","i"); 95 else static if(type == HSxType.HCY) 96 alias Components = TypeTuple!("h","c","y"); 97 } 98 alias ParentColourSpace = RGB!("rgb", CT, false, colorSpace_); 99 } 100 101 /// 102 unittest 103 { 104 // HSL color with float components 105 alias HSLf = HSx!(HSxType.HSL, float); 106 107 HSLf c = HSLf(3.1415, 1, 0.5); 108 109 // test HSL operators and functions 110 static assert(HSLf(3.1415, 0.2, 0.5) + HSLf(0, 0.5, 0.5) == HSLf(3.1415, 0.7, 1)); 111 static assert(HSLf(2, 0.5, 1) * 100.0 == HSLf(200, 50, 100)); 112 } 113 114 /// 115 unittest 116 { 117 // HSV color with float components 118 alias HSVf = HSx!(HSxType.HSV, float); 119 120 HSVf c = HSVf(3.1415, 1, 0.5); 121 122 // test HSV operators and functions 123 static assert(HSVf(3.1415, 0.2, 0.5) + HSVf(0, 0.5, 0.5) == HSVf(3.1415, 0.7, 1)); 124 static assert(HSVf(2, 0.5, 1) * 100.0 == HSVf(200, 50, 100)); 125 } 126 127 /// 128 unittest 129 { 130 // HSI color with float components 131 alias HSIf = HSx!(HSxType.HSI, float); 132 133 HSIf c = HSIf(3.1415, 1, 0.5); 134 135 // test HSI operators and functions 136 static assert(HSIf(3.1415, 0.2, 0.5) + HSIf(0, 0.5, 0.5) == HSIf(3.1415, 0.7, 1)); 137 static assert(HSIf(2, 0.5, 1) * 100.0 == HSIf(200, 50, 100)); 138 } 139 140 /// 141 unittest 142 { 143 // HCY color with float components 144 alias HCYf = HSx!(HSxType.HCY, float); 145 146 HCYf c = HCYf(3.1415, 1, 0.5); 147 148 // test HCY operators and functions 149 static assert(HCYf(3.1415, 0.2, 0.5) + HCYf(0, 0.5, 0.5) == HCYf(3.1415, 0.7, 1)); 150 static assert(HCYf(2, 0.5, 1) * 100.0 == HCYf(200, 50, 100)); 151 }