8

私は Mathematica で、充電されたボールベアリングが同様の電荷で充電されたときに広がる方法をシミュレートするプログラムを作成しようとしています(互いに反発します)。これまでのプログラムでは、ボール ベアリングが画面からはみ出さないようにし、ボール ベアリングがボックスの側面に当たった回数をカウントしています。これまでのところ、ボール ベアリングが箱の周りをランダムに動いていますが、互いに反発させる方法を知る必要があります。

これまでの私のコードは次のとおりです。

Manipulate[
 (*If the number of points has been reduced, discard  points*)
 If[ballcount < Length[contents], 
   contents = Take[contents, ballcount]];

 (*If the number of points has been increased, generate some random points*)
 If[ballcount > Length[contents], 
  contents = 
   Join[contents, 
    Table[{RandomReal[{-size, size}, {2}], {Cos[#], Sin[#]} &[
       RandomReal[{0, 2 \[Pi]}]]}, {ballcount - Length[contents]}]]];

 Grid[{{Graphics[{PointSize[0.02],

  (*Draw the container*)
  Line[size {{-1, -1}, {1, -1}, {1, 1}, {-1, 1}, {-1, -1}}], 
  Blend[{Blue, Red}, charge/0.3],
  Point[

   (*Start the main dynamic actions*)
   Dynamic[

    (*Reset the collision counter*)
    collision = 0;

    (*Check for mouse interaction and add points if there has been one*)
    Refresh[
     If[pt =!= lastpt, If[ballcount =!= 50, ballcount++]; 
      AppendTo[
       contents, {pt, {Cos[#], Sin[#]} &[
         RandomReal[{0, 2 \[Pi]}]]}]; lastpt = pt], 
     TrackedSymbols -> {pt}];

    (*Update the position of the points using their velocity values*)
    contents = Map[{#[[1]] + #[[2]] charge, #[[2]]} &, contents];

    (*Check for and fix points that have exceeded the box in Y
      direction, incrementing the collision counter for each one*)
    contents = Map[
      If[Abs[#[[1, 2]]] > size, 
        collision++; {{#[[1, 1]], 
          2 size Sign[#[[1, 2]]] - #[[1, 2]]}, {1, -1} #[[
           2]]}, #] &,
      contents];


    (*Check for and fix points that have exceeded the box in X 
      direction, incrementing the collision counter for each one*)
    contents = Map[
      If[Abs[#[[1, 1]]] > size, 
        collision++; {{2 size Sign[#[[1, 1]]] - #[[1, 1]], #[[1, 
           2]]}, {-1, 1} #[[2]]}, #] &,
      contents];

    hits = Take[PadLeft[Append[hits, collision/size], 200], 200];
    Map[First, contents]]]},
 PlotRange -> {{-1.01, 1.01}, {-1.01, 1.01}}, 
 ImageSize -> {250, 250}],

(*Show the hits*)
Dynamic@Show
  [
   ListPlot
   [
   Take[MovingAverage[hits, smooth], -100
    ]
   ,
   Joined -> True, ImageSize -> {250, 250}, AspectRatio -> 1, 
   PlotLabel -> "number of hits", AxesLabel -> {"time", "hits"}, 
   PlotRange -> {0, Max[Max[hits], 1]}], Graphics[]
  ]
}}
  ]
 ,
 {{pt, {0, 1}}, {-1, -1}, {1, 1}, Locator, Appearance -> None},
 {{ballcount, 5, "number of ball bearings"}, 1, 50, 1},
 {{charge, 0.05, "charge"}, 0.002, 0.3},
 {smooth, 1, ControlType -> None, Appearance -> None},
 {size, 1, ControlType -> None, Appearance -> None},
 {hits, {{}}, ControlType -> None},
 {contents, {{}}, ControlType -> None},
 {lastpt, {{0, 0}}, ControlType -> None}
 ]

Mathematica グラフィックス

4

2 に答える 2

7

シミュレーションに必要なのは「衝突検出アルゴリズム」です。これらのアルゴリズムの分野は、コンピュータゲーム(Pong)と同じくらい古く、ここで完全な答えを出すことは不可能であるため、広く普及しています。

チャージされたボールをタイムステップごとに進めて、位置から位置へと「ジャンプ」させるため、現在のシミュレーションは非常に基本的です。動きが一定の速度とゼロの加速度でのように単純である場合、動きの正確な方程式を知っており、方程式に時間を入れるだけですべての位置を計算できます。ボールが壁に当たって跳ね返ると、新しい方程式が得られます。

これにより、2つのボールがいつ衝突するかを予測できます。同時に同じ位置にあるかどうかに関係なく、2つのボールを解くだけです。これはアプリオリ検出と呼ばれます。現在のようにシミュレーションを行う場合、2つのボールが衝突する可能性があるほど接近しているかどうかを、タイムステップごとに確認する必要があります。

問題は、シミュレーション速度が無限に高くなく、ボールが速いほど、シミュレーションのジャンプが大きくなることです。その場合、2つのボールが互いにオーバージャンプし、衝突を逃す可能性はほとんどありません。

これを念頭に置いて、そのトピックに関するWikipediaの記事を読んで、概要を把握することから始めることができます。次に、それに関するいくつかの科学記事を読んだり、亀裂がどのようにそれを行うかを確認したりすることができます。たとえば、Chipmunk物理エンジンは、驚くべき2D物理エンジンですそのようなものが機能することを確実にするために、私は彼らが彼らの衝突検出に多くの考えを入れなければならなかったと確信しています。

于 2011-12-30T09:13:28.407 に答える
2

それ自体がプロジェクトであるため、検出の部分は実行できません。しかし、今ではインタラクションが速くなったようで、必要のないダイナミクスはほとんどありませんでした。(セルの側が常にビジーである場合、これは常に、本来あるべきではない場所でダイナミックがビジーであることを意味します)。

STOP/STARTボタンも追加しました。あなたがしていることすべてを理解することはできませんでしたが、私が行った変更を行うには十分でした. あなたもAppendToすべてを使用しています。事前にコンテンツを割り当てPart[]て、アクセスするために使用する必要があります。許可されている最大ポイントを知っているように見えるので、はるかに高速でしょうか?

コードをもっと広げるのが好きです。これは、ロジックをより理解するのに役立ちます。

これはスクリーン ショットで、更新されたバージョン コードは以下のとおりです。あなたがそれをより速く見つけることを願っています。

ここに画像の説明を入力

更新 (1) の以下のコードを参照してください。

アップデート (1)

(*updated version 12/30/11 9:40 AM*)
Manipulate[(*If the number of points has been reduced,discard points*)
\


 Module[{tbl, rand, npt, ballsToAdd},

  If[running,
   (
    tick += $MachineEpsilon;
    If[ballcount < Length[contents], 
     contents = Take[contents, ballcount]];

    (*If the number of points has been increased,
    generate some random points*)

    If[ballcount > Length[contents],
     (
      ballsToAdd = ballcount - Length[contents];
      tbl = 
       Table[{RandomReal[{-size, size}, {2}], {Cos[#], Sin[#]} &[
          RandomReal[{0, 2 \[Pi]}]]}, {ballsToAdd}];
      contents = Join[contents, tbl]
      )
     ];

    image = Grid[{
       {LocatorPane[Dynamic[pt], Graphics[{

           PointSize[0.02],(*Draw the container*)
           Line[size {{-1, -1}, {1, -1}, {1, 1}, {-1, 1}, {-1, -1}}],
           Blend[{Blue, Red}, charge/0.3],

           Point[(*Start the main dynamic actions*)

            (*Reset the collision counter*)
            collision = 0;

            (*Check for mouse interaction and add points if there has \
been one*)
            If[EuclideanDistance[pt, lastpt] > 0.001, (*adjust*)
             (
              If[ballcount < MAXPOINTS,
               ballcount++
               ];

              rand = RandomReal[{0, 2 \[Pi]}];
              npt = {Cos[rand], Sin[rand]};
              AppendTo[contents, {pt, npt}  ];
              lastpt = pt
              )
             ];

            (*Update the position of the points using their velocity \
values*)

            contents = 
             Map[{#[[1]] + #[[2]] charge, #[[2]]} &, contents];

            (*Check for and fix points that have exceeded the box in \
Y direction,incrementing the collision counter for each one*)

            contents = Map[
              If[Abs[#[[1, 2]]] > size,
                (
                 collision++;
                 {{#[[1, 1]], 
                   2 size Sign[#[[1, 2]]] - #[[1, 2]]}, {1, -1} #[[2]]}
                 ),
                (
                 #
                 )
                ] &, contents
              ];

            (*Check for and fix points that have exceeded the box in \
X direction,
            incrementing the collision counter for each one*)


            contents = 
             Map[If[Abs[#[[1, 1]]] > size, 
                collision++; {{2 size Sign[#[[1, 1]]] - #[[1, 1]], #[[
                   1, 2]]}, {-1, 1} #[[2]]}, #] &, contents
              ];


            hits = Take[PadLeft[Append[hits, collision/size], 200], 
              200];
            Map[First, contents]
            ]
           },
          PlotRange -> {{-1.01, 1.01}, {-1.01, 1.01}}, 
          ImageSize -> {250, 250}
          ], Appearance -> None
         ],(*Show the hits*)

        Show[ListPlot[Take[MovingAverage[hits, smooth], -100],
          Joined -> True, ImageSize -> {250, 250}, AspectRatio -> 1,
          PlotLabel -> "number of hits", AxesLabel -> {"time", "hits"},
          PlotRange -> {0, Max[Max[hits], 1]}
          ]
         ]
        }
       }
      ]
    )
   ];

  image
  ],

 {{MAXPOINTS, 50}, None},
 {pt, {{0, 1}}, None},
 {{ballcount, 5, "number of ball bearings"}, 1, MAXPOINTS, 1, 
  Appearance -> "Labeled", ImageSize -> Small},
 {{charge, 0.05, "charge"}, 0.002, 0.3, Appearance -> "Labeled", 
  ImageSize -> Small},
 Row[{Button["START", {running = True; tick += $MachineEpsilon}], 
   Button["STOP", running = False]}],
 {{tick, 0}, None},
 {smooth, 1, None},
 {size, 1, None},
 {hits, {{}}, None},
 {{contents, {}}, None},
 {lastpt, {{0, 0}}, None},
 {{collision, 0}, None},
 {image, None},
 {{running, True}, None},
 TrackedSymbols ->     { tick},
 ContinuousAction -> False,
 SynchronousUpdating -> True

 ]
于 2011-12-30T16:16:28.620 に答える