/* =============================================================================== HypoCycloid.mc : 大円の内周に沿って小円が回転した時の軌跡を描画 =============================================================================== Copyright (C) 2010-2013 Masahiko Watanabe Edition History: 2010.11.15 初版( GK Library: Rev.2009.02.03 使用 ) 2013.02.15 MikoScript3(ユニコード版)用に変更 -----------------------------------------------------------------------------*/ /*****/ // GK Library のモジュールをロードする場合 #include #include #include if( ::Module.Include( "GkLibrary" ) > 0 ) Main( argc, argv ); return; /*****/ /****** // GK Library のソースをインクルードする場合 #include Main( argc, argv ); return; /*****/ //----------------------------------------------------------------------------- // デバッグプリント無効化(リリース時) #set pc #comment #set pv // デバッグプリント有効化(デバッグ時) //#set pc print //#set pv print #set p print //----------------------------------------------------------------------------- /// マクロ定義 /// #set MAIN_TITLE "円の内周回転軌跡" // ウィンドウのキャプション #set Wnd_Xo // ウィンドウの左端位置(空白はデフォールト) #set Wnd_Yo // ウィンドウの上端位置(空白はデフォールト) #set DlgYd 40 // ダイアログ領域の高さ #set FigXd 500 // 図形描画領域の幅 #set FigYd 500 // 図形描画領域の高さ #set TimerId 101 // タイマーの特定値 #set VFR 30 // 画面更新回数/秒 #set MIN_SPEED 15 // 円Aの周回角速度の最小値 [度/秒] #set MAX_SPEED (360*7) //     〃    最大値  〃  #set MIN_SI 1 // 円Aの周回角速度の最小指標 #set MAX_SI 100 //     〃    最大指標 #set INI_SI 50 //     〃    初期指標 #set DIV_SI ( #MAX_SI - #MIN_SI + 1 ) // この指標の分割数 #set INI_KR 3.125 // 2円の半径比の初期値 #set MAX_KR 20.0 //    〃   最大値 #set MIN_KR 0.5 //    〃   最小値 #set INI_KD 0.5 // 軌跡点の遠心率の初期値 #set MAX_KD 5.0 //    〃    最大値 #set MIN_KD 0.0 //    〃    最小値 #set PI 3.14159265358979 #set RAD ( #PI / 180 ) //============================================================================= function Main( argc, argv ) { #pc "開始"; ^DefValue = null; SetupDrawingConds(); class ^MainWindow : ::GK.Window {} R = ::GK.Rect( 0, 0, #FigXd, #DlgYd + #FigYd ); ::GK.Window.GetAdjRect( R ); ^MainWindow.Construct( #MAIN_TITLE, #Wnd_Xo, #Wnd_Yo, R.Xd, R.Yd ); ^MainWindow.Open(); ^MainWindow.StartTimer( #TimerId, 1000 / #VFR ); ::GK.WindowMsgLoop(); delete ^MainWindow; DeleteDrawingConds(); #pc "終了"; } //============================================================================= function SetupDrawingConds() { ^WhitePen = ::GK.Pen( #RGB(255,255,255), #PS_SOLID, 1 ); ^GreyPen = ::GK.Pen( #RGB(160,160,160), #PS_SOLID, 1 ); ^GreenPen = ::GK.Pen( #RGB(0,128,0), #PS_SOLID, 1 ); ^BluePen = ::GK.Pen( #RGB(0,64,255), #PS_SOLID, 1 ); ^BlackBrush = ::GK.Brush( #RGB(0,0,0) ); ^RedBrush = ::GK.Brush( #RGB(255,0,0) ); ^DlgFont = ::GK.Font( "MS ゴシック", 14, #SHIFTJIS_CHARSET, #FIXED_PITCH ); } function DeleteDrawingConds() { delete ^WhitePen,^GreyPen,^GreenPen,^BluePen; delete ^BlackBrush, ^RedBrush; delete ^DlgFont; } //============================================================================= function ^MainWindow.OnCreate() { #pc "OnCreate"; .MakeDlgItems(); .InizFigData(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnClose() { #pc "OnClose"; .StopTimer( #TimerId ); .TermFigData(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnSize() { #pc "OnSize", .gc.Xd, .gc.Yd, .Min?(); if( .gc.Xd <= 0 || .gc.Yd <= 0 ) return; .SetDlgAreaLayout(); .SetFigAreaLayout(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnMinMaxInfo( pMinMax ) { // ウィンドウサイズが変更できないようにする .GetWindowRect( R'STRUCT ); //#pc "OnMinMaxInfo", R.Xd, R.Yd; P'LONG(4) = { R.Xd, R.Yd, R.Xd, R.Yd }; ( pMinMax + 3*4*2 )'memcpy( P'addr, 4*4 ); return #TRUE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnPaint() { #pc "OnPaint"; .GetHotRect( R'STRUCT ); if( ! .DlgRect.Out?( R ) ) .DrawDlgArea(); if( ! .FigRect.Out?( R ) ) .DrawFigArea( 0 ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnTimer( id ) { //#pc "OnTimer: ", id; .DrawFigArea( .Ts ); } //----------------------------------------------------------------------------- function ^MainWindow.MakeDlgItems() { .DefWidgetFont := ^DlgFont; R = ::GK.Rect( 0,0,0,0 ); .KrTitle = .AddLabel( "半径比", R, #SS_RIGHT ); #pv .KrInput = .AddEditBox( #ES_CENTER, R ); .KrInput.SetText( #INI_KR'g ); .KdTitle = .AddLabel( "遠心率", R, #SS_RIGHT ); #pv .KdInput = .AddEditBox( #ES_CENTER, R ); .KdInput.SetText( #INI_KD'g ); .SiTitle = .AddLabel( "速度", R, #SS_RIGHT ); #pv .SiSlide = .AddScrollBar( "H", R ); .SiSlide.OnScroll = function( act, pos ) { .owner.OnSiSlide( act, pos ); }; .SiSlide.SetRange( #MIN_SI, #MAX_SI ); .SiSlide.SetPos( #INI_SI ); #pv .StartBtn = .AddButton( "push", "開始", R ); .StartBtn.OnCommand = function() { .owner.SetFocus(); .owner.OnStartButton(); }; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.SetDlgAreaLayout() { .DlgRect = ::GK.Rect( 0, 0, .gc.Xd, #DlgYd ); R1 = ::GK.Rect( 4, 12, 50, 20 ); R2 = ::GK.Rect( R1.Xo + R1.Xd + 6, 10, 54, 20 ); .KrTitle.Move( R1 ); .KrInput.Move( R2 ); R1.Xo += 114; R2.Xo += 114; .KdTitle.Move( R1 ); .KdInput.Move( R2 ); R1.Xo += 118; R1.Xd = 36; R2 = ::GK.Rect( R1.Xo + R1.Xd + 6, 10, 128, 16 ); .SiTitle.Move( R1 ); .SiSlide.Move( R2 ); .StartBtn.Move( ::GK.Rect( R2.Xo + R2.Xd + 20, 8, 64, 22 ) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.DrawDlgArea() { .gc.DrawEdge( .DlgRect, #EDGE_BUMP, #BF_BOTTOM|#BF_MIDDLE ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnSiSlide( act, pos ) { switch( act ) { case #SB_TOP: v = #MIN_SI; break; case #SB_LINEUP: v = .Ts - 1; break; case #SB_PAGEUP: v = .Ts - #DIV_SI / 10; break; case #SB_BOTTOM: v = #MAX_SI; break; case #SB_LINEDOWN: v = .Ts + 1; break; case #SB_PAGEDOWN: v = .Ts + #DIV_SI / 10; break; case #SB_ENDSLIDE:// v = pos; break; case #SB_SLIDING: v = pos; break; default: case #SB_ENDSCROLL: goto END; } v = v'cut( #MIN_SI, #MAX_SI ); .SiSlide.SetPos( v ); .Ts = v; //#pc "OnSiSlide", act, v; END: ; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnStartButton() { #pc "OnStartButton"; .Tc = 0.0; // 円Aの現周回角度 [rad/秒] // 円B(基底円)と円Aの半径比 .Kr = .KrInput.GetText()'float'cut( #MIN_KR, #MAX_KR ); .KrInput.SetText( .Kr'g ); // 軌跡点の遠心率(円Aの中心から軌跡点までの距離/円Aの半径) .Kd = .KdInput.GetText()'float'cut( #MIN_KD, #MAX_KD ); .KdInput.SetText( .Kd'g ); .Ra = .Rb / .Kr; // 円Aの半径 .Rc = .Rb - .Ra; // 円Bの中心から円Aの中心までの距離 .Rd = .Ra * .Kd; // 円Aの中心から軌跡点までの距離 .CircleA = ::GK.Rect( 0, 0, .Ra'int * 2, .Ra'int * 2 ); .SGC.ClearRect( .MgcFullRect ); .SGC.MoveTo( ( .Rc + .Rd )'int, 0 ); } //----------------------------------------------------------------------------- function ^MainWindow.InizFigData() { .MgcFullRect = ::GK.Rect( - #FigXd / 2, - #FigYd / 2, #FigXd, #FigYd ); .Ts = #INI_SI; // 円Aの周回角速度 [度/秒] .Tc = 0.0; // 円Aの現周回角度 [rad/秒] .Kr = #INI_KR; // 円B(基底円)と円Aの半径比 .Kd = #INI_KD; // 軌跡点の遠心率(円Aの中心から軌跡点までの距離/円Aの半径) .Rb = 200; // 円Bの半径 .Ra = .Rb / .Kr; // 円Aの半径 .Rc = .Rb - .Ra; // 円Bの中心から円Aの中心までの距離 .Rd = .Ra * .Kd; // 円Aの中心から軌跡点までの距離 .CircleB = ::GK.Rect( -.Rb, -.Rb, .Rb * 2, .Rb * 2 ); .CircleA = ::GK.Rect( 0, 0, .Ra'int * 2, .Ra'int * 2 ); // 軌跡描画用の画面バッファ(モノクロ:黒背景、白線) #pv .SGC = ::GK.Image( , #FigXd, #FigYd, 1 ); .SGC.SetMapMode( #MM_ISOTROPIC ); .SGC.SetWindowExt( #FigXd, #FigYd ); .SGC.SetViewportExt( #FigXd, -#FigYd ); .SGC.SetViewportOrg( #FigXd / 2, #FigYd / 2 ); .SGC.SetPen( ^WhitePen ); .SGC.SetBrush( ^BlackBrush ); //.SGC.ClearRect( .MgcFullRect ); .SGC.MoveTo( ( .Rc + .Rd )'int, 0 ); // 画面バッファ(次回の画面更新時に表示する図形を描画) #pv .MGC = ::GK.Image( , #FigXd, #FigYd ); .MGC.SetMapMode( #MM_ISOTROPIC ); .MGC.SetWindowExt( #FigXd, #FigYd ); .MGC.SetViewportExt( #FigXd, -#FigYd ); .MGC.SetViewportOrg( #FigXd / 2, #FigYd / 2 ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.TermFigData() { delete .SGC; delete .MGC; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.SetFigAreaLayout() { .FigRect = ::GK.Rect( 0, #DlgYd, .gc.Xd, .gc.Yd - #DlgYd ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.DrawFigArea( ts ) { if( ts <= 0 ) goto SET_VFRAME; cos := ::Math.cos; sin := ::Math.sin; td = #MIN_SPEED * ::Math.pow( ( #MAX_SPEED'float / #MIN_SPEED ), ( ts - #MIN_SI )'float / ( #MAX_SI - #MIN_SI ) ); // 等比数列の場合 //td = #MIN_SPEED + ( #MAX_SPEED - #MIN_SPEED ) * // ( ts - #MIN_SI )'float / ( #MAX_SI - #MIN_SI ); // 等差数列の場合 Td = td * #RAD / #VFR; // 各画面更新毎の円Aの周回角度 [rad] To = .Tc; M = ( td / #VFR )'int'cut( 1, ); // Td の分割数 for( N = 1 ; N <= M ; N++ ) { Tb = To + Td * N / M; Ta = Tb - .Kr * Tb; Cx = .Rc * cos( Tb ); Cy = .Rc * sin( Tb ); Px = ( Cx + .Rd * cos( Ta ))'int; Py = ( Cy + .Rd * sin( Ta ))'int; .SGC.LineTo( Px, Py ); // 線を引く場合 //.SGC.SetPixel( Px, Py, #RGB(255,255,255) ); // 点を打つ場合 } .Tc = Tb; .MGC.ClearRect( .MgcFullRect, #RGB(255,255,255) ); .MGC.SetPen( ^GreyPen ); .MGC.FrameOval( .CircleB ); .CircleA.Xo = ( Cx - .Ra )'int; .CircleA.Yo = ( Cy - .Ra )'int; .MGC.SetPen( ^GreenPen ); .MGC.FrameOval( .CircleA ); .MGC.SetPen( ^BluePen ); .MGC.MoveTo( Cx'int, Cy'int ); .MGC.LineTo( Px, Py ); .MGC.SetBrush( ^RedBrush ); .MGC.CopyImage( .SGC, .MgcFullRect, .MgcFullRect, 0x00E20746 ); SET_VFRAME: .MGC.SaveDC(); .MGC.SetMapMode( #MM_TEXT ); .gc.CopyImage( .MGC, .FigRect, .MgcFullRect, #SRCCOPY ); //(注意)MM_TEXT にしないと、Y 軸の方向が逆(下向が正)になってしまう! .MGC.RestoreDC(); } //-----------------------------------------------------------------------------