三角箱で、跳ねるボール

 投稿者:SECOND  投稿日:2009年12月19日(土)16時24分33秒
  !三角箱で、跳ねるボール
!-----------------------
!ボールの方向を、適当な無理数にすると、周期がなくなり、
!ベルヌーイ・シフト写像( 無理数の小数下位を、無限に読み進む構造で、周期を失うカオス )
!に、似たカオスが現れる。

LET si=11   !正三角形(x1,y1)(x2,y2)(x3,y3) の一辺。
LET x1=1.5
LET y1=2.5
!----       !必ずしも、等辺でなくてよいが、外壁表示はズレる。
LET x2=x1+si
LET y2=y1
LET x3=x1+si/2
LET y3=y1+SQR(3)*si/2
!----                    !       3
LET A12=(y2-y1)/(x2-x1)  ! f13 /  \ f23
LET A13=(y3-y1)/(x3-x1)  !   1───2
LET A23=(y3-y2)/(x3-x2)  !      f12
DEF f12(x)=A12*(x-x1)+y1 ! ─
DEF f13(x)=A13*(x-x1)+y1 ! /
DEF f23(x)=A23*(x-x2)+y2 ! \
!
!ボール位置(bx,by)の前歴の線 y=my/mx*(x-bx)+by と壁の
!
!  直線f12 y=A12*(x-x1)+y1 との交点の式 A12*(x-x1)+y1=my/mx*(x-bx)+by
!  x=(A12*x1-y1-bx*my/mx+by)/(A12-my/mx)
!  y=f12(x)
!  直線f13 y=A13*(x-x1)+y1 との交点の式 A13*(x-x1)+y1=my/mx*(x-bx)+by
!  x=(A13*x1-y1-bx*my/mx+by)/(A13-my/mx)
!  y=f13(x)
!  直線f23 y=A23*(x-x2)+y2 との交点の式 A23*(x-x2)+y2=my/mx*(x-bx)+by
!  x=(A23*x2-y2-bx*my/mx+by)/(A23-my/mx)
!  y=f23(x)
!
LET px12= (x2-x1)/SQR((y2-y1)^2+(x2-x1)^2)
LET py12= (y2-y1)/SQR((y2-y1)^2+(x2-x1)^2) !直線f12 に平行な、単位ベクトル
LET px13= (x3-x1)/SQR((y3-y1)^2+(x3-x1)^2)
LET py13= (y3-y1)/SQR((y3-y1)^2+(x3-x1)^2) !直線f13 に平行な、単位ベクトル
LET px23= (x3-x2)/SQR((y3-y2)^2+(x3-x2)^2)
LET py23= (y3-y2)/SQR((y3-y2)^2+(x3-x2)^2) !直線f23 に平行な、単位ベクトル
LET ox12= py12
LET oy12=-px12   !直線f12 に垂直な、単位ベクトル
LET ox13= py13
LET oy13=-px13   !直線f13 に垂直な、単位ベクトル
LET ox23= py23
LET oy23=-px23   !直線f23 に垂直な、単位ベクトル
!
LET bx=X1            !ボールの初期位置
LET by=Y1
LET mx=SQR(5)/8      !ボールのX速度、ステップ⊿X
LET my=SQR(3)/20     !ボールのY速度、ステップ⊿Y
!
SET WINDOW 0,14, 0,14
! DRAW grid(1,1)
SET DRAW MODE NOTXOR  !2度書きで消える NOTXOR モード
LET r=0.7             !ボールの半径
!----
PLOT LINES: x1-r*SQR(3),y1-r; x2+r*SQR(3),y2-r; x3,y3+r*2; x1-r*SQR(3),y1-r !表示壁面
SET LINE COLOR 15     !銀
PLOT LINES: x1,y1; x2,y2; x3,y3; x1,y1 ! 計算壁面
SET LINE COLOR 2      !青
SET AREA COLOR 2      !青
!
PLOT TEXT,AT 10,13: "右クリック:停止"
DO
   DRAW disk WITH SCALE(r)*SHIFT(bx,by) !ボールを書く
   ! SET DRAW mode explicit
   WAIT DELAY 0.02              !省電力効果と、速度
   ! SET DRAW mode hidden
   DRAW disk WITH SCALE(r)*SHIFT(bx,by) !ボールだけを消す
   PLOT LINES : bx,by;                  !履歴線を(書く・消す)
   LET bx=bx+mx
   LET by=by+my
   IF f23(bx)<=by THEN LET bx23=(A23*x2-y2-bx*my/mx+by)/(A23-my/mx)
   IF f13(bx)<=by THEN LET bx13=(A13*x1-y1-bx*my/mx+by)/(A13-my/mx)
   IF f12(bx)>=by THEN LET bx12=(A12*x1-y1-bx*my/mx+by)/(A12-my/mx)
   !----
   IF f23(bx)<=by AND x3<=bx23 AND bx23<=x2 THEN
      LET bx=bx23
      LET by=f23(bx)
      LET wy=(mx*px23+my*py23)*py23-(mx*ox23+my*oy23)*oy23
      LET mx=(mx*px23+my*py23)*px23-(mx*ox23+my*oy23)*ox23 !mx,my の、壁に平行成分-壁に垂直成分
      LET my=wy
   ELSEIF f13(bx)<=by AND x1<=bx13 AND bx13<=x3 THEN
      LET bx=bx13
      LET by=f13(bx)
      LET wy=(mx*px13+my*py13)*py13-(mx*ox13+my*oy13)*oy13
      LET mx=(mx*px13+my*py13)*px13-(mx*ox13+my*oy13)*ox13
      LET my=wy
   ELSEIF f12(bx)>=by AND x1<=bx12 AND bx12<=x2 THEN
      LET bx=bx12
      LET by=f12(bx)
      LET wy=(mx*px12+my*py12)*py12-(mx*ox12+my*oy12)*oy12
      LET mx=(mx*px12+my*py12)*px12-(mx*ox12+my*oy12)*ox12
      LET my=wy
   END IF
   MOUSE POLL mox,moy,mlb,mrb
LOOP UNTIL 0< mrb

END
 

跳ねるボールを、N角形 の壁面へ 拡張

 投稿者:SECOND  投稿日:2009年12月22日(火)04時55分8秒
  > No.899[元記事へ]

! 跳ねるボールを、N角形 の壁面へ 拡張
!--------------------------------------
!ボールの方向を、適当な無理数にすると、周期がなくなり、
!ベルヌーイ・シフト写像( 無理数の小数下位を、無限に読み進む構造で、周期を失うカオス )
!に、似たカオスが現れる。

OPTION BASE 0
SET WINDOW -7,7, -7,7
DRAW axes
!----
LET ma=9                    !多角形の 角数 3,4,5,6,7,8,,,,
DIM x(ma),y(ma),A(ma),px(ma),py(ma)
LET r=0.7                   !ボールの半径
LET r0=5.5                  !計算で使用の 多角形、外接円の半径
LET r1=r0+r/SIN(PI/2-PI/ma) !ボールの当る 多角形、外接円の半径
!
!LET a0=PI*(1.5-1/ma)        !(x1,y1)の角。
LET a0=PI*(1.5-3/ma)        !(x1,y1)の1つ手前の角。
FOR i=0 TO ma
   LET x(i)=r0*COS(a0)
   LET y(i)=r0*SIN(a0)
   IF 0< i THEN
      SET LINE COLOR "silver"
      PLOT LINES: x(i-1),y(i-1); x(i),y(i) !計算壁面
      SET LINE COLOR "black"
      PLOT LINES: r1/r0*x(i-1),r1/r0*y(i-1); r1/r0*x(i),r1/r0*y(i) !ボール壁面
   END IF
   LET a0=a0+2*PI/ma
NEXT i
!                      A3         A4  4  A3
!       3          4──3      5/  \3
!  A3 /  \ A2   A4│    │A2   A5\    /A2   ・・・
!   1───2      1──2        1─2
!       A1             A1             A1
!
FOR i=1 TO ma
   LET j=MOD(i,ma)+1
   LET A(i)=(y(j)-y(i))/(x(j)-x(i))                         !直線ij の勾配
   LET px(i)=(x(j)-x(i))/SQR((y(j)-y(i))^2+(x(j)-x(i))^2)
   LET py(i)=(y(j)-y(i))/SQR((y(j)-y(i))^2+(x(j)-x(i))^2)   !直線ij に平行な、単位ベクトル
NEXT i
!
LET a0=ANGLE(x(1),y(1))
LET bx=r0*COS(a0)*0.999 ! ボールの初期位置X
LET by=r0*SIN(a0)*0.999 ! ボールの初期位置Y
LET a0=ANGLE(x(2)-x(1),y(2)-y(1))+SQR(2)*PI/ma/1.1313 !ボールの初期角度
LET m0=.23        !ボールの速さ⊿
LET mx=m0*COS(a0) !ボールの初期⊿X
LET my=m0*SIN(a0) !ボールの初期⊿Y

SUB Cross   !各辺への衝突検出と反射
   LET ok=0
   IF ABS(A(n))< 1 THEN
   !---壁の直線(y-y0)=(x-x0)*A ,ボール位置と図中心を結ぶ線 y=x*by/bx の交点(xw,yw)。
      LET xw=(x(n)*A(n)-y(n))/(A(n)-by/bx)                  !xw 優先
      LET yw=(xw-x(n))*A(n)+y(n)
      IF 0< xw*bx+yw*by AND xw^2+yw^2<=bx^2+by^2 THEN       !壁の外
      !---壁の直線(y-y0)=(x-x0)*A, ボール軌跡線(y-by)=(x-bx)*my/mx の交点(xc,yc)。
         LET xc=(x(n)*A(n)-y(n)-bx*my/mx+by)/(A(n)-my/mx)   !xc 優先
         LET yc=(xc-x(n))*A(n)+y(n)
         !---壁の一辺内なら、反射処理
         IF (x(n)<=xc AND xc<=x(MOD(n,ma)+1) OR x(MOD(n,ma)+1)<=xc AND xc<=x(n)) THEN CALL Mirror
      END IF
   ELSE
   !---壁の直線(y-y0)=(x-x0)*A ,ボール位置と図中心を結ぶ線 y=x*by/bx の交点(xw,yw)。
      LET yw=(y(n)/A(n)-x(n))/(1/A(n)-bx/by)                !yw 優先
      LET xw=(yw-y(n))/A(n)+x(n)
      IF 0< xw*bx+yw*by AND xw^2+yw^2<=bx^2+by^2 THEN       !壁の外
      !---壁の直線(y-y0)=(x-x0)*A, ボール軌跡線(y-by)=(x-bx)*my/mx の交点(xc,yc)。
         LET yc=(y(n)/A(n)-x(n)-by*mx/my+bx)/(1/A(n)-mx/my) !yc 優先
         LET xc=(Yc-y(n))/A(n)+x(n)
         !---壁の一辺内なら、反射処理
         IF (y(n)<=yc AND yc<=y(MOD(n,ma)+1) OR y(MOD(n,ma)+1)<=yc AND yc<=y(n)) THEN CALL Mirror
      END IF
   END IF
END SUB

SUB Mirror   !ベクトル(mx,my)の反射を、同じ(mx,my)に上書。
   LET bx=xc !ボールを衝突点に置く
   LET by=yc                                !単位ベクトル:壁に平行( px(n), py(n) )
   !----                                                       垂直(-py(n), px(n) )
   LET wy=(mx*px(n)+my*py(n))*py(n)+(mx*py(n)-my*px(n))*px(n)
   LET mx=(mx*px(n)+my*py(n))*px(n)-(mx*py(n)-my*px(n))*py(n)
   LET my=wy                     !                            内積 *方向        内積 *方向
   LET ok=1  !反射報告           !ball速度ベクトルm= (mx*px+my*py)*p-(mx*ox+my*oy)*o
END SUB                          !                     平行単位vect.p   垂直単位vect.o

SET LINE COLOR "blue"
SET AREA COLOR "blue"
SET DRAW MODE NOTXOR !2度書きで消える NOTXOR モード
!
PLOT TEXT,AT 3.7, 6.4: "右クリック:停止"
DO
   DRAW disk WITH SCALE(r)*SHIFT(bx,by) !ボールを書く
   ! SET DRAW mode explicit             !ちらつき防止。| かなりな負荷が、かかります。遅い|
   ! SET DRAW mode hidden               !ちらつき防止。| パソコンや省電力なら使わないが良|
   WAIT DELAY 0.02                      !省電力効果と、速度
   DRAW disk WITH SCALE(r)*SHIFT(bx,by) !ボールだけを消す
   PLOT LINES : bx,by;                  !履歴線を(書く・消す)
   LET bx=bx+mx
   LET by=by+my
   !----
   FOR n=1 TO ma
      CALL Cross  !衝突検出と反射
      IF ok=1 THEN EXIT FOR
   NEXT n
   MOUSE POLL mox,moy,mlb,mrb
LOOP UNTIL 0< mrb

END
 

Re: 跳ねるボールを、N角形 の壁面へ 拡張

 投稿者:山中和義  投稿日:2009年12月22日(火)14時00分24秒
  > No.940[元記事へ]

先のブロック崩しのボールの軌道の解析プログラムです。
ベクトルと図形方程式で記述してみました。
LET cEps=1e-13 !精度

DIM t(2) !作業用

SET bitmap SIZE 600,600
SET WINDOW -5,5,-5,5
DRAW grid

LET iter=200 !繰り返し回数

LET M=3 !m角形 ※3以上の整数

DIM Pw(M,4) !壁面の端
!DATA  3,-4,  3, 4 !正方形 始点(x1,y1)、終点(x2,y2)
!DATA  3, 4, -3, 4
!DATA -3, 4, -3,-4
!DATA -3,-4,  3,-4
!MAT READ Pw
!MAT PRINT Pw;

LET R=4 !外接円の半径
FOR i=1 TO M !X軸上の点(R,0)から反時計まわりに頂点を得る
   LET th=2*PI*(i-1)/M !始点(x1,y1)
   LET Pw(i,1)=R*COS(th)
   LET Pw(i,2)=R*SIN(th)
   LET th=2*PI*i/M !終点(x2,y2)
   LET Pw(i,3)=R*COS(th)
   LET Pw(i,4)=R*SIN(th)
NEXT i
MAT PRINT Pw;

DIM w(M,2) !壁面の法線ベクトル
FOR i=1 TO M !線分の方向ベクトルから算出する
   LET t(1)=-(Pw(i,4)-Pw(i,2)) !X方向
   LET t(2)=  Pw(i,3)-Pw(i,1)  !Y方向
   CALL Vec2Normalize(t,t) !正規化
   MAT PRINT t;
   LET w(i,1)=t(1)
   LET w(i,2)=t(2)
NEXT i

FOR i=1 TO M !壁面を表示する
   PLOT LINES: Pw(i,1),Pw(i,2); Pw(i,3),Pw(i,4)
NEXT i


!ボールの軌道 直線p(t)=Pa+t*a
DIM a(2) !ボールの移動方向ベクトル
DATA 1,2
MAT READ a
CALL Vec2Normalize(a,a) !|a|=1
MAT PRINT a;

DIM Pa(2) !ボールの発射位置
DATA 1,0
MAT READ Pa


DIM Pc(2) !衝突位置
DIM aa(2) !反射方向ベクトル
FOR k=1 TO iter !バウンドさせる
   CALL CalcCollision(Pc,aa)
   MAT PRINT Pc; !debug
   PLOT LINES: Pa(1),Pa(2); Pc(1),Pc(2) !軌跡を描く

   MAT Pa=Pc !次へ
   MAT a=aa
NEXT k


!衝突する平面の法線ベクトルをn、入射方向ベクトルをaとする。
!反射方向ベクトルbは、b=a-2*(a・n)*n
!
!また、平面上の任意の点をPs、入射方向ベクトルaの始点をPaとすると、
!衝突位置Pcは、Pc=Pa+{n・(Ps-Pa)/(a・n)}*a

SUB CalcReflection(a(),n(), b()) !反射ベクトルを計算する
   MAT t=(2*DOT(a,n))*n !ベクトルaをベクトルnに射影して、その2倍のベクトル
   MAT b=a-t
   MAT PRINT b; !debug
END SUB

SUB CalcCollision(Pc(),b()) !壁面との衝突位置と反射方向ベクトルを計算する
   DIM n(2),Ps(2),Pe(2)
   FOR i=1 TO M
      CALL Vec2Set(w(i,1),w(i,2), n) !法線ベクトル
      CALL Vec2set(Pw(i,1),Pw(i,2), Ps) !平面上の任意の点
      PRINT "壁面=";i !debug

      LET an=DOT(a,n) !ベクトルaとベクトルnとのなす角を得る |a||n|cosθ<0
      IF an<0 THEN !衝突する壁面の表裏判定
         MAT t=Ps-Pa
         LET nT=DOT(n,t)
         IF nT<0 THEN !壁面との位置関係から
            MAT t=(nT/an)*a
            MAT Pc=Pa+t !交点

            CALL Vec2Set(Pw(i,3),Pw(i,4), Pe) !直線の終点
            LET v=InRange(Pc, Ps,Pe)
            IF v>=0 AND v<=1 THEN !線分上なら
               MAT PRINT Pc; !debug

               CALL CalcReflection(a,n, b) !反射方向ベクトル

               EXIT SUB !1つ見つかれば
            ELSE
               PRINT "壁面の延長上で衝突する"
               MAT PRINT Pc; !debug
            END IF
         ELSEIF nT=0 THEN
            PRINT "衝突中"
            MAT PRINT Pa; !debug

            MAT Pc=Pa
            CALL CalcReflection(a,n, b) !反射方向ベクトル

            EXIT SUB !1つ見つかれば
         ELSE
            PRINT "衝突しない"
         END IF

      ELSE
         PRINT "衝突しない..."
         IF i=M THEN
            PRINT "すべての壁面と衝突しません。"
            STOP
         END IF
      END IF
   NEXT i
END SUB

!PsとPeを結ぶ線分を延長した直線上の点Pcと線分との位置関係
!0≦t≦1なら、線分上
FUNCTION InRange(Pc(), Ps(),Pe())
   DIM t1(2),t2(2)
   MAT t1=Pe-Ps
   MAT t2=Pc-Ps
   IF ABS(t1(1))>=cEps THEN !t1(1)<>0
      LET v=t2(1)/t1(1) !X方向の比
   ELSE !垂直線
      IF ABS(t1(2))>=cEps THEN !t1(2)<>0
         LET v=t2(2)/t1(2) !Y方向の比
      ELSE !1点
         LET v=0
      END IF
   END IF
   LET InRange=v
END FUNCTION


END


!ベクトル
EXTERNAL FUNCTION Vec2Length(a()) !長さ |a|
LET Vec2Length=SQR(a(1)*a(1)+a(2)*a(2))
END FUNCTION

EXTERNAL SUB Vec2Normalize(a(),n()) !正規化 n=a/|a|
LET L=Vec2Length(a)
IF L>0 THEN MAT n=(1/L)*a
END SUB

!その他
EXTERNAL SUB Vec2Set(x,y, v())
LET v(1)=x
LET v(2)=y
END SUB
 

戻る