アカウント名:
パスワード:
リストやらLinqやらを持ち出すはちょいとやりすぎでは…コーディングサンプルとしてはとても面白いのですが。
ってことで、もうちょい簡潔な処理を書いてみましたが、いかがでしょう?Color GetColorFromHsv(double h, double s, double v){ double hue6 = h / 60.0; // 6.0 * (h / 360.0) double saturation = s / 100.0; double value = v / 100.0;
double amplitude = saturation * value; double background = value - amplitude;
double red = Math.Min(Math.Max(Math.Max(-hue6 + 2.0, hue6 - 4.0), 0.0), 1.0) * amplitude + background; double green = Math.Min(Math.Max(Math.Min(hue6, -hue6 + 4.0), 0.0), 1.0) * amplitude + background; double blue = Math.Min(Math.Max(Math.Min(hue6 - 2.0, -hue6 + 6.0), 0.0), 1.0) * amplitude + background;
return Color.FromRgb((byte)(red * byte.MaxValue), (byte)(green * Byte.MaxValue), (byte)(blue * Byte.MaxValue));}色相→RGB成分のグラフをプロットするようなイメージです。域外となる部分をMinとMaxでクリップすることで分岐を省いています。計算式を単純化するため、色相の係数が1になるよう1周=6.0とする値(hue6)を用いています。彩度と明度からRGB成分の振幅(乗算)とグレー成分のバックグラウンド(加算)を算出しています。
なるほど。確かに行数は少ないですね。ただ、ぱっと見の可読性が低いので元のロジック(根本の導出ロジックはおそらくWikipediaにあるものがベースですよね?)を理解するのに時間がかかるのがネックかなという気はします。
ListやLinqは正直使わないとC#である利点を感じないので、わりとよく使ってます。特にListは配列よりも扱いが楽で良いですよ。大きさを気にしなくてもいいですし。もちろん日記にあるようなif文もないような言語だと、Linqはおろかfor系すら怪しいので、ご提示されたコードのほうがその場合は適切かもしれませんね。
もっとも、今回このコードを提示したのはif文を使わないというよりも、むしろ解説にあるような根本のロジックに着目してほしかったというのが大きいですかね。まあ、得られる結果は別に変わらないんですけれども、なんかWikipedia流のロジックは釈然としなかったものでして。まああれはあれで行列で考えれば数学的にまとまったのかもしれませんが……。
ロジックはこちらのサイト [peko-step.com]の下の方にある「RGB値を求める」を参考に、式を整理したものです。
可読性については、一次方程式(ax+bの式)を見てxy平面上にナナメの直線が想像できるタイプの人で、彩度が100の時の色相に対するR,G,Bの値を知っている(方眼紙にグラフを描ける)なら、理解できるかと思います。R,G,Bの上がり下がりのうち上がりの直線と下がりの直線のどちらを採用するかでMin,Maxを使っているところがトリッキーですが(というかハックです。上がり下がりが2回以上あったらこの書き方はできない)。
なお外側2つのMinとMaxは、.Netに値を0〜1にクリッピングする関数がないためにそう書いているだけなので、clip関数を書いてred = clip(Math.Min(-hue6 + 2.0, hue6 - 4.0)) * amplitude + background;こんな感じに整理してもよいと思います。
Wikipediaのコードは非常に手続き的というか中間状態を持ち過ぎで、好きじゃないですね。
すみませんミスです。red = clip(Math.Max(-hue6 + 2.0, hue6 - 4.0)) * amplitude + background;ですね。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
最初のバージョンは常に打ち捨てられる。
もうちょい簡潔に、 (スコア:1)
リストやらLinqやらを持ち出すはちょいとやりすぎでは…
コーディングサンプルとしてはとても面白いのですが。
ってことで、もうちょい簡潔な処理を書いてみましたが、いかがでしょう?
Color GetColorFromHsv(double h, double s, double v)
{
double hue6 = h / 60.0; // 6.0 * (h / 360.0)
double saturation = s / 100.0;
double value = v / 100.0;
double amplitude = saturation * value;
double background = value - amplitude;
double red = Math.Min(Math.Max(Math.Max(-hue6 + 2.0, hue6 - 4.0), 0.0), 1.0) * amplitude + background;
double green = Math.Min(Math.Max(Math.Min(hue6, -hue6 + 4.0), 0.0), 1.0) * amplitude + background;
double blue = Math.Min(Math.Max(Math.Min(hue6 - 2.0, -hue6 + 6.0), 0.0), 1.0) * amplitude + background;
return Color.FromRgb((byte)(red * byte.MaxValue), (byte)(green * Byte.MaxValue), (byte)(blue * Byte.MaxValue));
}
色相→RGB成分のグラフをプロットするようなイメージです。
域外となる部分をMinとMaxでクリップすることで分岐を省いています。
計算式を単純化するため、色相の係数が1になるよう1周=6.0とする値(hue6)を用いています。
彩度と明度からRGB成分の振幅(乗算)とグレー成分のバックグラウンド(加算)を算出しています。
Re:もうちょい簡潔に、 (スコア:1)
なるほど。確かに行数は少ないですね。
ただ、ぱっと見の可読性が低いので元のロジック
(根本の導出ロジックはおそらくWikipediaにあるものがベースですよね?)
を理解するのに時間がかかるのがネックかなという気はします。
ListやLinqは正直使わないとC#である利点を感じないので、わりとよく使ってます。
特にListは配列よりも扱いが楽で良いですよ。大きさを気にしなくてもいいですし。
もちろん日記にあるようなif文もないような言語だと、Linqはおろかfor系すら怪しいので、ご提示されたコードのほうがその場合は適切かもしれませんね。
もっとも、今回このコードを提示したのはif文を使わないというよりも、むしろ解説にあるような根本のロジックに着目してほしかったというのが大きいですかね。
まあ、得られる結果は別に変わらないんですけれども、なんかWikipedia流のロジックは釈然としなかったものでして。まああれはあれで行列で考えれば数学的にまとまったのかもしれませんが……。
Re:もうちょい簡潔に、 (スコア:1)
ロジックはこちらのサイト [peko-step.com]の下の方にある「RGB値を求める」を参考に、式を整理したものです。
可読性については、
一次方程式(ax+bの式)を見てxy平面上にナナメの直線が想像できるタイプの人で、彩度が100の時の色相に対するR,G,Bの値を知っている(方眼紙にグラフを描ける)なら、理解できるかと思います。
R,G,Bの上がり下がりのうち上がりの直線と下がりの直線のどちらを採用するかでMin,Maxを使っているところがトリッキーですが(というかハックです。上がり下がりが2回以上あったらこの書き方はできない)。
なお外側2つのMinとMaxは、.Netに値を0〜1にクリッピングする関数がないためにそう書いているだけなので、clip関数を書いて
red = clip(Math.Min(-hue6 + 2.0, hue6 - 4.0)) * amplitude + background;
こんな感じに整理してもよいと思います。
Wikipediaのコードは非常に手続き的というか中間状態を持ち過ぎで、好きじゃないですね。
Re:もうちょい簡潔に、 (スコア:1)
すみませんミスです。
red = clip(Math.Max(-hue6 + 2.0, hue6 - 4.0)) * amplitude + background;
ですね。