tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルアナログ時計の秒針が真っ直ぐにならない
記事No13070
投稿日: 2008/09/30(Tue) 02:01
投稿者ブロッコリー
アナログ時計を作っているときに気が付いたのですが、なぜか秒針が0秒と30秒の位置にあるときに真っ直ぐにならず斜めになってしまいます。(15秒と45秒の位置にあるときは、真っ直ぐになるのですが。)

下のコードは再現可能なように簡略化したコードです。

タイマーとピクチャーボックスを1つずつ使います。
Private Sub Form_Load()

    Timer1.Interval = 1000
    Picture1.Width = 825 '735 のときは真っ直ぐになる。
    Picture1.Height = Picture1.Width
    Picture1.ScaleTop = -1
    Picture1.ScaleLeft = -1
    Picture1.ScaleWidth = 2
    Picture1.ScaleHeight = 2
    Picture1.BackColor = QBColor(0)
    
End Sub

Private Sub Timer1_Timer()

    Dim a As Double
    
    Picture1.Cls

    a = 2 * 3.141592 * (Second(Now) / 60 - 90 / 360)
    Picture1.Line (0, 0)-(Cos(a), Sin(a)), QBColor(15)

End Sub


Picture1 の Width が 735 のときは真っ直ぐになるのに 825 のときは斜めになってしまいます。
一体、何が原因なのでしょうか? また、どういう条件のときに真っ直ぐになるのでしょうか?
どうかよろしくお願いいたします。

[ツリー表示へ]
タイトルRe: アナログ時計の秒針が真っ直ぐにならない
記事No13071
投稿日: 2008/09/30(Tue) 09:33
投稿者よねKEN
>     Picture1.Line (0, 0)-(Cos(a), Sin(a)), QBColor(15)

(1) 変数aの値はDouble型で計算時の誤差が含まれています。
(2) Cos関数はDouble型の値を返します。計算結果には誤差を含まれています。

>     Picture1.ScaleTop = -1
>     Picture1.ScaleLeft = -1
>     Picture1.ScaleWidth = 2
>     Picture1.ScaleHeight = 2

(3) Picture1.Lineに指定している(Cos(a), Sin(a))が表す座標は上記の独自座標系から
実際の長さPicture1.Width で表される長さ(たぶんtwips単位?)の値を元に
画面に描画するために画面の座標系であるpixelに変換されることになりますが、
ここでも浮動小数点数の演算が発生しますので誤差が含まれています。

> 一体、何が原因なのでしょうか? また、どういう条件のときに真っ直ぐになるのでしょうか?

Picture1.Lineの2番目の座標のXに指定されたCos(a)の計算結果(Double型)の値を
pixel座標系に直すと最終的に整数に変換されることになりますが、
ここで丸めが発生します。そのときに0に丸められればまっすぐに、
1に丸められれば斜めになります。

[ツリー表示へ]
タイトルRe^2: 【解決】有り難うございました。
記事No13077
投稿日: 2008/09/30(Tue) 18:54
投稿者ブロッコリー
よねKENさん有り難うございます。

誤差についていろいろ教えてくださって有り難うございます。
こんなに小さな誤差が、見た目に表れるような大きな結果を生むとは驚きました。

いろいろ勉強になりました。
有り難うございました。

[ツリー表示へ]
タイトルRe: アナログ時計の秒針が真っ直ぐにならない
記事No13072
投稿日: 2008/09/30(Tue) 10:01
投稿者魔界の仮面弁士
> 一体、何が原因なのでしょうか?

計算誤差でしょう。"3.141592" では、有効桁数が不足していますし。

πの計算時に微小な差があったとしても、たとえば画面側では「0.6ドット」のような
座標位置へ描画する事はできないので、1 ドット単位にまでずれる可能性はあるかと。


> また、どういう条件のときに真っ直ぐになるのでしょうか?

誤差を減らすには、
 pi = 4 * Atn(1)
のような値を使うことですが、斜めにずれてしまう事を避けたいのであれば、
pi / 2 単位の座標位置は、計算で出さず、固定化しておいた方が良いでしょう。


ちなみに、高速に描画を必要とするソフトなどでは、いちいち三角関数を
使っていると処理速度が落ちるので、良く使う角度などは、最初から
計算結果を配列に保持しておき、それを利用する事も珍しくありません。

[ツリー表示へ]
タイトルRe^2: 【解決】有り難うございました。
記事No13078
投稿日: 2008/09/30(Tue) 18:56
投稿者ブロッコリー
魔界の仮面弁士さん有り難うございます。

円周率を "3.14159265358979" にすることによって見事に真っ直ぐに表示されるようになりました!!

円周率は "3.14" でも十分だと思い込んでいたので、"3.141592" もあれば十分すぎると思って、全く円周率のことを考えていませんでした。

いろいろ勉強になりました。
有り難うございました。

[ツリー表示へ]