# 色クラス

色管理クラス。こういう無駄な機能を作るのは楽しい。

# ソース

色クラス

package game;


private enum ColorElement {
	R; G; B;
}
/**
 * 色データクラス
 * @author Yakoi
 * @since 2016-07-09
 */
class YkiColor
{
	// 赤[0.0, 1.0]
	public var red(default, set)    : Float;
	// 緑[0.0, 1.0]
	public var green(default, set)  : Float;
	// 青[0.0, 1.0]
	public var blue(default, set)   : Float;
	// シアン
	public var cyan(get, set)       : Float;
	// マゼンタ
	public var magenta(get, set)    : Float;
	// イエロー
	public var yellow(get, set)     : Float;
	// 色相[0.0, 1.0]
	public var hue(get, set)        : Float;
	// 彩度[0.0, 1.0]
	public var saturation(get, set) : Float;
	// 輝度[0.0, 1.0]
	public var lightness(get, set)  : Float;
	// 明度[0.0, 1.0]
	public var value(get, never)    : Float;
	// 0x000000~0xFFFFFFまでの色情報
	public var colorCode(get, set)  : UInt;
	
	

	/**
	 * コンストラクタ
	 */
	private function new() 
	{
		
	}
	/**
	 * 赤色要素設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定後パラメタ
	 */
	public function set_red(val : Float) : Float
	{
		// 0以下の値は0,1以上の値は1に補正する。
		this.red = Math.max(0, Math.min(1.0, val));
		return this.red;
	}
	/**
	 * 緑色要素設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定後パラメタ
	 */
	public function set_green(val : Float) : Float
	{
		// 0以下の値は0,1以上の値は1に補正する。
		this.green = Math.max(0, Math.min(1.0, val));
		return this.green;
	}
	/**
	 * 青色要素設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定後パラメタ
	 */
	public function set_blue(val : Float) : Float
	{
		// 0以下の値は0,1以上の値は1に補正する。
		this.blue = Math.max(0, Math.min(1.0, val));
		return this.blue;
	}
	/**
	 * シアン色要素取得プロパティ
	 * @return  シアン色要素[0.0, 1.0]
	 */
	public function get_cyan() : Float
	{
		return 1 - this.red;
	}
	/**
	 * シアン色要素設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定後パラメタ
	 */
	public function set_cyan(val : Float) : Float
	{
		// 0以下の値は0,1以上の値は1に補正する。
		this.red = 1 - Math.max(0, Math.min(1.0, val));
		return this.cyan;
	}
	/**
	 * マゼンタ色要素取得プロパティ
	 * @return  マゼンタ色要素[0.0, 1.0]
	 */
	public function get_magenta() : Float
	{
		return 1 - this.green;
	}
	/**
	 * マゼンタ色要素設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定後パラメタ
	 */
	public function set_magenta(val : Float) : Float
	{
		// 0以下の値は0,1以上の値は1に補正する。
		this.green = 1 - Math.max(0, Math.min(1.0, val));
		return this.magenta;
	}
	/**
	 * イエロー色要素取得プロパティ
	 * @return  イエロー色要素[0.0, 1.0]
	 */
	public function get_yellow() : Float
	{
		return 1 - this.blue;
	}
	/**
	 * イエロー色要素設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定後パラメタ
	 */
	public function set_yellow(val : Float) : Float
	{
		// 0以下の値は0,1以上の値は1に補正する。
		this.blue = 1 - Math.max(0, Math.min(1.0, val));
		return this.yellow;
	}
	
	/**
	 * 色相取得プロパティ
	 * @return  色相[0.0, 1.0]
	 */
	public function get_hue() : Float
	{
		// 赤色要素、青色要素、緑色要素から最小の値を取得し、最小値に設定する。
		var minVal = Math.min(Math.min(this.red, this.green), this.blue);
		
		// 赤色要素、青色要素、緑色要素から最大の値を取得し、最大値に設定する。
		var maxVal = Math.max(Math.max(this.red, this.green), this.blue);
		
		// 最小属性
		var minElement : ColorElement =
		    // 最小値を判定する。
		    if (minVal == this.red) {
				// 最小値が赤要素と等しい場合、
				// 最小属性にR(赤)を設定する。
				ColorElement.R;	
			}else if (minVal == this.green) {
				// 最小値が緑要素と等しい場合、
				// 最小属性にG(赤)を設定する。
				ColorElement.G;
			} else {
				// いずれでもない場合、最小値が青要素と等しいとみなし、
				// 最小属性にB(青)を設定する。
				ColorElement.B;
			}
		
		// 結果(360段階色相)を設定する。
		// 最小属性により場合分けする。
		var result360 : Float = switch(minElement) {
		case ColorElement.B:
			// 最小属性がB(青)の場合、以下の式で360段階色相を決定する。
			60 * (this.green - this.red)   / (maxVal - minVal) +  60;
		case ColorElement.R:
			// 最小属性がR(赤)の場合、以下の式で360段階色相を決定する。
			60 * (this.blue  - this.green) / (maxVal - minVal) + 180;
		case ColorElement.G:
			// 最小属性がG(緑)の場合、以下の式で360段階色相を決定する。
			60 * (this.red   - this.blue)  / (maxVal - minVal) + 300;
		}
		// 結果(360段階色相)を360で割り、リターンして処理終了する。
		return result360 / 360; 
	}
	/**
	 * 色相設定プロパティ
	 * @param	val 設定値 ※整数桁は除去する。
	 * @return  設定パラメタ
	 */
	public function set_hue(val : Float) : Float
	{
		// 現在の輝度、彩度と、引数1(色相の設定値)より、色クラスを作成し一次色情報に格納する。
		// ※引数1(色相の設定値)は、0.0~1.0で回転することを考慮し、整数部分を取り除く。
		var tmpColor : YkiColor = YkiColor.hls((val - Math.floor(val)), this.lightness, this.saturation);
		// 一次色情報の赤、緑、青のパラメータを、thisの各パラメタに設定する。
		this.red   = tmpColor.red;
		this.green = tmpColor.green;
		this.blue  = tmpColor.blue;
		// 現在の色相情報をリターンし、処理終了する。
		return this.hue;
	}
	/**
	 * 彩度取得プロパティ
	 * @return  彩度[0.0, 1.0]
	 */
	public function get_saturation() : Float
	{
		// 赤、緑、青プロパティの最大値と最小値の差を求め、リターンして処理終了する。
		return Math.max(Math.max(this.red, this.green), this.blue)
		     - Math.min(Math.min(this.red, this.green), this.blue); 
	}
	
	/**
	 * 彩度設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定パラメタ
	 */
	public function set_saturation(val : Float) : Float
	{
		// 現在の輝度、色相と、引数1(彩度の設定値)より、色クラスを作成し一次色情報に格納する。
		// ※hlsメソッド内で、引数1(彩度の設定値)は0以下の値は0,1以上の値は1に補正される。
		var tmpColor = YkiColor.hls(this.hue, this.lightness, val);
		// 一次色情報の赤、緑、青のパラメータを、thisの各パラメタに設定する。
		this.red   = tmpColor.red;
		this.green = tmpColor.green;
		this.blue  = tmpColor.blue;
		// 現在の彩度情報をリターンし、処理終了する。
		return this.saturation;
	}
	/**
	 * 輝度取得プロパティ
	 * @return  輝度[0.0, 1.0]
	 */
	public function get_lightness() : Float
	{
		// 赤、緑、青プロパティの最大値と最小値の平均を求め、リターンして処理終了する。
		return (Math.max(Math.max(this.red, this.green), this.blue)
		      + Math.min(Math.min(this.red, this.green), this.blue)) / 2; 
	}
	/**
	 * 輝度設定プロパティ
	 * @param	val 設定値 ※0以下の値は0,1以上の値は1に補正される。
	 * @return  設定パラメタ
	 */
	public function set_lightness(val : Float) : Float
	{
		// 現在の彩度、色相と、引数1(輝度の設定値)より、色クラスを作成し一次色情報に格納する。
		// ※hlsメソッド内で、引数1(輝度の設定値)は0以下の値は0,1以上の値は1に補正される。
		var tmpColor = YkiColor.hls(this.hue, val, this.saturation);
		// 一次色情報の赤、緑、青のパラメータを、thisの各パラメタに設定する。
		this.red   = tmpColor.red;
		this.green = tmpColor.green;
		this.blue  = tmpColor.blue;
		// 現在の輝度情報をリターンし、処理終了する。
		return this.lightness;
	}
	/**
	 * 明度取得プロパティ
	 * @return  明度[0.0, 1.0]
	 */
	public function get_value() : Float
	{
		// 赤、緑、青プロパティの最大値をリターンして処理終了する。
		return Math.max(Math.max(this.red, this.green), this.blue);
	}
	/**
	 * カラーコード取得プロパティ
	 * @return  カラーコード(0x000000形式)
	 */
	public function get_colorCode() : UInt
	{
		// 赤、緑、青プロパティを取得し、下記計算を行いリターンして処理終了する。
		// (赤*255 * 2^16) + (緑*255 * 2^8) + (青*255)
		return (Std.int(this.red   * 255) << 16)
		     + (Std.int(this.green * 255) <<  8)
			 +  Std.int(this.blue  * 255);
	}
	/**
	 * カラーコード設定プロパティ
	 * @param	val 設定値
	 * @return  設定パラメタ
	 */
	public function set_colorCode(val : UInt) : UInt
	{
		// 引数1(設定値)を16ビット右にシフトし、その後右側16ビットを取り出して赤プロパティに設定する。
		this.red = (val >> 16) % 256;
		// 引数1(設定値)を8ビット右にシフトし、その後右側16ビットを取り出して緑プロパティに設定する。
		this.green = (val >> 8) % 256;
		// 引数1(設定値)の右側16ビットを取り出して青プロパティに設定する。
		this.blue = val % 256;
		// カラーコードをリターンして処理終了する。
		return this.colorCode;
	}
	
	
	/**
	 * RGB指定色オブジェクト生成
	 * @param	r 赤要素[0.0, 1.0]
	 * @param	g 緑要素[0.0, 1.0]
	 * @param	b 青要素[0.0, 1.0]
	 * @return  生成した色オブジェクト
	 */
	public static function rgb(r : Float, g : Float, b : Float) : YkiColor
	{
		// 色オブジェクトを生成し、結果用変数に設定する。
		var result : YkiColor = new YkiColor();
		// 引数1,2,3を、結果用変数の赤、緑、青に設定する。
		result.red = r;
		result.green = g;
		result.blue = b;
		// 結果用変数をリターンして処理終了する。
		return result;
	}
	/**
	 * HLS指定色オブジェクト生成
	 * @param	h 色相要素[0.0, 1.0]
	 * @param	l 輝度要素[0.0, 1.0]
	 * @param	s 彩度要素[0.0, 1.0]
	 * @return  生成した色オブジェクト
	 */
	public static function hls(h : Float, l : Float, s : Float) : YkiColor
	{
		// 引数2(輝度)が0以下の場合は0,1以上の場合は1に補正する。
		l = Math.max(0, Math.min(1.0, l));
		// 引数3(彩度)が0以下の場合は0,1以上の場合は1に補正する。
		s = Math.max(0, Math.min(1.0, s));
		// 最大値に1 + 引数3(彩度)/2を設定する。
		var maxVal : Float = l + s / 2;
		// 最小値に1 - 引数3(彩度)/2を設定する。
		var minVal : Float = l - s / 2;
		// 引数1(色相)の整数部分を除去し、その後360倍して色相360に設定する。
		var h_     : Float = ((h - Math.floor(h)) * 360);
		// 赤要素
		var r      : Float;
		// 緑要素
		var g      : Float;
		// 青要素
		var b      : Float;
		// 色相により場合分けをし、下記計算式により赤要素、緑要素、青要素を決定する。
		if (0 <= h_ && h_ < 60) {
		    r = maxVal;
			g = minVal + (maxVal - minVal) * h_ / 60;
			b = minVal;
		} else if (60 <= h_ && h_ < 120) {
		    r = minVal + (maxVal - minVal) * (120 - h_) / 60;
			g = maxVal;
			b = minVal;
		} else if (120 <= h_ && h_ < 180) {
		    r = minVal;
			g = maxVal;
			b = minVal + (maxVal - minVal) * (h_ - 120) / 60;
		} else if (180 <= h_ && h_ < 240) {
		    r = minVal;
			g = minVal + (maxVal - minVal) * (240 - h_) / 60;
			b = maxVal;
		} else if (240 <= h_ && h_ < 300) {
		    r = minVal + (maxVal - minVal) * (h_ - 240) / 60;
			g = minVal;
			b = maxVal;
		} else {
		    r = maxVal;
			g = minVal;
			b = minVal + (maxVal - minVal) * (360 - h_) / 60;
		}
		// RGB指定色オブジェクト生成メソッドを使用し、
		// 赤要素、緑要素、青要素を引数に設定し色オブジェクトを生成する。
		// 生成した色オブジェクトをリターンして処理終了する。
		return YkiColor.rgb(r, g, b);
	}
	/**
	 * カラーコード指定色オブジェクト生成
	 * @param	code カラーコード(0x000000形式)
	 * @return  生成した色オブジェクト
	 */
	public static function code(code : UInt) : YkiColor
	{
		// 色オブジェクトを生成し、結果用変数に設定する。
		var result : YkiColor = new YkiColor();
		// 引数1(カラーコード)を、結果用変数のカラーコードに設定する。
		result.colorCode = code;
		// 結果用変数をリターンして処理終了する。
		return result;
	}
	
	/**
	 * 反転色色情報取得
	 * @param	色オブジェクト
	 * @return  反転色の色オブジェクト
	 */
	public static function nega(color : YkiColor) : YkiColor
	{
		// RGB指定色オブジェクト生成メソッドを使用し、
		// 引数1(色オブジェクト)の赤、緑、青要素をそれぞれ1から引いた数を指定し、色オブジェクトを生成する。
		// 生成した色オブジェクトをリターンして処理終了する。
		return YkiColor.rgb(1 - color.red, 1 - color.green, 1 - color.blue);
	}
	
	
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

# 解説

気が向いたら記載します。

# メモ

なし