КП: Движение спутника в двойной системе — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
(Решение)
(Решение)
Строка 149: Строка 149:
 
{{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/MuschakND/K3/K3.html |width=1024 |height=800 |border=0 }}
 
{{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/MuschakND/K3/K3.html |width=1024 |height=800 |border=0 }}
  
 +
 +
Программа: [[Медиа:K3.zip|скачать]]
 +
 +
'''Текст программы на языке JavaScript:''' <div class="mw-collapsible-content">
 +
Файл '''"K3.html"'''
 +
<syntaxhighlight lang="javascript" line start="1" enclose="div">
 +
<!DOCTYPE html>
 +
 +
<html>
 +
<head>
 +
  <meta charset="utf-8" />
 +
  <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <!-- For IE on an intranet. -->
 +
  <title>Moon in Binary System</title>
 +
  <style>
 +
    html, body {
 +
      margin: 0;
 +
      padding: 0;
 +
    }
 +
 +
    html {
 +
      overflow-y: scroll; /* There's an issue with the scrollbar "randomly" appearing - this just keeps it always visible in case the user is using a very wide and narrow monitor. */
 +
    }
 +
 +
    body {
 +
      width: 1024px; /* Currently, most screens can handle this. */
 +
      margin: auto; /* Center the page content. */
 +
      background-color: #777;
 +
      font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; /* Start screen font. */
 +
    }
 +
 +
    header {
 +
      color: #FFF;
 +
      text-shadow: 5px 5px 10px #333;
 +
    }
 +
 +
    section {
 +
      position: relative; /* Float children relative to this element. */
 +
    }
 +
 +
      section form {
 +
        width: 210px; /* This is a bit less than the "section #WebGLCanvasElementContainer margin-left" value to provide a nice space between the form and the viewport. */
 +
        float: left;
 +
        text-align: center; /* Center the button elements. */
 +
      }
 +
 +
        section form fieldset {
 +
          text-align: left; /* Undo the button center aligning trick for the text in the form. */
 +
          margin-bottom: 1.25em; /* Adjust this so that the height of the form is about the same height as the WebGL Three.js viewport element. */
 +
        }
 +
 +
          section form fieldset input {
 +
            width: 100%;
 +
          }
 +
 +
        section form td {
 +
          white-space: nowrap; /* Don't let words like "x-position" break at the hyphen (which occurs in Chrome). */
 +
        }
 +
 +
      section #WebGLCanvasElementContainer {
 +
        border: 1px solid #DDD; /* Match the native color of the fieldset border. */
 +
        width: 800px; /* The assumed fixed width of the WebGL Three.js viewport element. */
 +
        height: 600px; /* The assumed fixed height of the WebGL Three.js viewport element. */
 +
        margin-left: 224px; /* This is "body width" minus "section #WebGLCanvasElementContainer width" or 1024px - 800px = 224px. */
 +
        background-image: url('starField.jpg'); /* 0.15 opacity value. */
 +
      }
 +
 +
      section article {
 +
        padding: 0 1em;
 +
        color: white;
 +
      }
 +
 +
      section button {
 +
        width: 4.5em;
 +
      }
 +
  </style>
 +
  <script>
 +
    /*// Preload all images/bitmaps.
 +
    var preloadImages = [];
 +
    var preloadImagePaths = ["jupiter.png", "saturn.png", "moon.png", "starField.jpg", "starField.jpg"];
 +
   
 +
    for (var i = 0; i < preloadImagePaths.length; i++) {
 +
      preloadImages[i] = new Image();
 +
     
 +
      preloadImages[i].onerror = function() {
 +
        if (console) {
 +
          console.error(this.src + " error.");
 +
        } // if
 +
      }; // onerror
 +
     
 +
      preloadImages[i].src = preloadImagePaths[i]; // Preload images to improve perceived app speed.
 +
    } // for 
 +
  */</script>
 +
</head>
 +
 +
<body>
 +
  <header>
 +
    <h1>Moon in Binary System </h1>
 +
  </header>
 +
  <section>
 +
    <form id="initialConditions">
 +
      <fieldset>
 +
        <legend>Moon</legend>
 +
        <table id="mass1">
 +
          <tr>
 +
            <td>mass:</td>
 +
            <td><input id="m1_mass" type="number" value="1E18" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>x-position:</td>
 +
            <td><input id="m1_position_x" type="number" value="-141" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>y-position:</td>
 +
            <td><input id="m1_position_y" type="number" value="0" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>x-velocity:</td>
 +
            <td><input id="m1_velocity_x" type="number" value="0" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>y-velocity:</td>
 +
            <td><input id="m1_velocity_y" type="number" value="2" required="required" /></td>
 +
          </tr>
 +
          <tr style="display: none;">
 +
            <td>bitmap:</td>
 +
            <td><input type="text" value="moon.png" required="required" /></td>
 +
          </tr>
 +
        </table>
 +
      </fieldset>
 +
      <fieldset>
 +
        <legend>1st star</legend>
 +
        <table id="mass2">
 +
          <tr>
 +
            <td>mass:</td>
 +
            <td><input type="number" value="1E19" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>x-position:</td>
 +
            <td><input type="number" value="-100" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>y-position:</td>
 +
            <td><input type="number" value="0" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>x-velocity:</td>
 +
            <td><input type="number" value="0" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>y-velocity:</td>
 +
            <td><input type="number" value="0" required="required" /></td>
 +
          </tr>
 +
          <tr style="display: none;">
 +
            <td>bitmap:</td>
 +
            <td><input type="text" value="jupiter.png" required="required" /></td>
 +
          </tr>
 +
        </table>
 +
      </fieldset>
 +
      <fieldset>
 +
        <legend>2nd star</legend>
 +
        <table id="mass3">
 +
          <tr>
 +
            <td>mass:</td>
 +
            <td><input type="number" value="1E19" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>x-position:</td>
 +
            <td><input type="number" value="100" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>y-position:</td>
 +
            <td><input type="number" value="0" required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>x-velocity:</td>
 +
            <td><input type="number" value="0"  required="required" /></td>
 +
          </tr>
 +
          <tr>
 +
            <td>y-velocity:</td>
 +
            <td><input type="number" value="0" required="required" /></td>
 +
          </tr>
 +
          <tr style="display: none;">
 +
            <td>bitmap:</td>
 +
            <td><input type="text" value="saturn.png" required="required" /></td>
 +
          </tr>
 +
        </table>
 +
      </fieldset>
 +
      <button id="submitButton">Submit</button>
 +
      <button id="reloadButton">Reload</button>
 +
     
 +
    </form>
 +
    <div id="WebGLCanvasElementContainer">
 +
      <!-- Three.js will add a canvas element to the DOM here. -->
 +
      <!-- The following <article> element (along with its content) will be removed via JavaScript just before the simulation starts: -->
 +
      <article>
 +
        <h2></h2>
 +
        <p>
 +
         
 +
        </p>
 +
        <h2>Running the simulation</h2>
 +
        <ul>
 +
          <li>To start the simulation with the current set of initial conditions, click the <strong>Submit</strong> button.</li>
 +
          <li>To orbit, left-click and drag the mouse.</li>
 +
          <li>To pan, right-click and drag the mouse.</li>
 +
          <li>To zoom, roll the mouse wheel.</li>
 +
          <li>To enter your own initial conditions, enter numeric values of your choice (in the form to the left) and click <strong>Submit</strong>.
 +
          Note that large values such as 10<sup>18</sup> can be entered as 1E18.</li>
 +
          <li>To restart the simulation from scratch, click the <strong>Reload</strong> button (equivalent to refreshing the page).</li>
 +
          <li>For additional information and resources, click the <strong>Info</strong> button.</li>
 +
        </ul>
 +
      </article>
 +
    </div>
 +
  </section>
 +
  <script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script> <!-- The "CDN" for Three.js  -->
 +
  <script src="https://rawgithub.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script> <!-- Allows for orbiting, panning, and zooming. -->
 +
  <script>
 +
    var  DENSITY= 1.38E14; // This value determined qualitatively by observing how large the spheres look onscreen (i.e., their radii).
 +
 +
    document.getElementById('submitButton').addEventListener('click', handleSubmitButton, false);
 +
    document.getElementById('reloadButton').addEventListener('click', handleReloadButton, false);
 +
   
 +
 +
    var simulation = Simulation(); // Call the Simulation constructor to create a new simulation object.
 +
 +
    function Simulation() { // A constructor.
 +
      var that = {}; // The object returned by this constructor.
 +
      var worker; // Will contain a reference to a fast number-chrunching worker thread that runs outside of this UR/animation thread.
 +
      var requestAnimationFrameID = null; // Used to cancel a prior requestAnimationFrame request.
 +
      var gl = {}; // Will contain WebGL related items.
 +
 +
      gl.viewportWidth = 800; // The width of the Three.js viewport.
 +
      gl.viewportHeight = 600; // The height of the Three.js viewport.
 +
 +
      gl.cameraSpecs = {
 +
        aspectRatio: gl.viewportWidth / gl.viewportHeight, // Camera frustum aspect ratio.
 +
        viewAngle: 50 // Camera frustum vertical field of view, in degrees.
 +
      };
 +
 +
      gl.clippingPlane = {
 +
        near: 0.1, // The distance of the near clipping plane (which always coincides with the monitor).
 +
        far: 1000 // The distance of the far clipping plane (note that you get a negative far clipping plane for free, which occurs at the negative of this value).
 +
      };
 +
 +
      gl.quads = 32; // Represents both the number of vertical segments and the number of horizontal rings for each mass's sphere wireframe.
 +
 +
      gl.renderer = window.WebGLRenderingContext ? new THREE.WebGLRenderer({ alpha: true }) : new THREE.CanvasRenderer({ alpha: true }); // If WebGL isn't supported, fallback to using the canvas-based renderer (which most browsers support). Note that passing in "{ antialias: true }" is unnecessary in that this is the default behavior. However, we pass in "{ alpha: true }" in order to let the background PNG image shine through.
 +
      gl.renderer.setClearColor(0x000000, 0); // Make the background completely transparent (the actual color, black in this case, does not matter) so that the PNG background image can shine through.
 +
      gl.renderer.setSize(gl.viewportWidth, gl.viewportHeight); // Set the size of the renderer.
 +
 +
      gl.scene = new THREE.Scene(); // Create a Three.js scene.
 +
 +
      gl.camera = new THREE.PerspectiveCamera(gl.cameraSpecs.viewAngle, gl.cameraSpecs.aspectRatio, gl.clippingPlane.near, gl.clippingPlane.far); // Set up the viewer's eye position.
 +
      gl.camera.position.set(0, 450, 0); // The camera starts at the origin, so move it to a good position.
 +
      gl.camera.lookAt(gl.scene.position); // Make the camera look at the origin of the xyz-coordinate system.
 +
 +
      gl.controls = new THREE.OrbitControls(gl.camera, gl.renderer.domElement); // Allows for orbiting, panning, and zooming via OrbitsControls.js by http://threejs.org. For an example, see http://threejs.org/examples/misc_controls_orbit.html.
 +
 +
      gl.pointLight = new THREE.PointLight(0xFFFFFF); // Set the color of the light source (white).
 +
      gl.pointLight.position.set(0, 250, 250); // Position the light source at (x, y, z).
 +
      gl.scene.add(gl.pointLight); // Add the light source to the scene.
 +
 +
      gl.spheres = []; // Will contain WebGL sphere mesh objects representing the point masses.
 +
 +
      var init = function (initialConditions) { // Public method, resets everything when called.
 +
        if (requestAnimationFrameID) {
 +
          cancelAnimationFrame(requestAnimationFrameID); // Cancel the previous requestAnimationFrame request.
 +
        }
 +
 +
        if (worker) {
 +
          worker.terminate(); // Terminate the previously running worker thread to ensure a responsive UI.
 +
        }
 +
        worker = new Worker('K3.js'); // Spawn a fast number-chrunching thread that runs outside of this UR/animation thread.
 +
 +
        document.getElementById('WebGLCanvasElementContainer').style.backgroundImage = "url('starField.jpg')"; // Switch back to the non-opaque PNG background image.
 +
        document.getElementsByTagName('article')[0].style.display = "none"; // Remove from page-flow the one (and only) article element (along with all of its content).
 +
        document.getElementById('WebGLCanvasElementContainer').appendChild(gl.renderer.domElement); // Append renderer element to DOM.
 +
 +
        while (gl.spheres.length) { // Remove any prior spheres from the scene and empty the gl.spheres array:
 +
          gl.scene.remove(gl.spheres.pop());
 +
        } // while
 +
 +
        for (var i = 0; i < initialConditions.length; i++) { // Set the sphere objects in gl.spheres to initial conditions.
 +
          initializeMesh(initialConditions[i]); // This call sets the gl.spheres array.
 +
        } // for
 +
 +
        worker.postMessage({
 +
          cmd: 'init', // Pass the initialization command to the web worker.
 +
          initialConditions: initialConditions // Send a copy of the initial conditions to the web worker, so it can initialize its persistent global variables.
 +
        }); // worker.postMessage
 +
 +
        worker.onmessage = function (evt) { // Process the results of the "crunch" command sent to the web worker (via this UI thread).
 +
          for (var i = 0; i < evt.data.length; i++) {
 +
            gl.spheres[i].position.x = evt.data[i].p.x;
 +
            gl.spheres[i].position.z = evt.data[i].p.y;
 +
            gl.spheres[i].position.y = 0; // 3BodyWorker.js is 2D (i.e., the physics are constrained to a plane).
 +
            gl.spheres[i].rotation.y += initialConditions[i].rotation; // Place worker.onmessage in the init method in order to access its initialConditions array.
 +
          }
 +
          gl.renderer.render(gl.scene, gl.camera); // Update the positions of the masses (sphere meshes) onscreen based on the data returned by 3BodyWorker.js.
 +
        }; // worker.onmessage
 +
 +
        function initializeMesh(initialCondition) {
 +
          var texture = THREE.ImageUtils.loadTexture(initialCondition.bitmap); // Create texture object based on the given bitmap path.
 +
          var material = new THREE.MeshPhongMaterial({ map: texture }); // Create a material (for the spherical mesh) that reflects light, potentially causing sphere surface shadows.
 +
          var geometry = new THREE.SphereGeometry(initialCondition.radius, gl.quads, gl.quads); // Radius size, number of vertical segments, number of horizontal rings.
 +
          var mesh = new THREE.Mesh(geometry, material); // A mesh represents the object (typically composed of many tiny triangles) to be displayed - in this case a hollow sphere with a bitmap on its surface.
 +
 +
          mesh.position.x = initialCondition.position.x;
 +
          mesh.position.z = initialCondition.position.y; // Convert from 2D to "3D".
 +
          mesh.position.y = 0; // The physics are constrained to the xz-plane (i.e., the xy-plane in 3BodyWorker.js).
 +
 +
          gl.scene.add(mesh); // Add the sphere to the Three.js scene.
 +
          gl.spheres.push(mesh); // Make the Three.js mesh sphere objects accessible outside of this helper function.
 +
        } // initializeMesh
 +
      } // init
 +
      that.init = init; // This is what makes the method public.
 +
 +
      var run = function () { // Public method.
 +
        worker.postMessage({
 +
          cmd: 'crunch' // This processing occurs between animation frames and, therefore, is assumed to take a relatively small amount of time (as compared to current frame rates).
 +
        }); // worker.postMessage
 +
        gl.controls.update(); // Allows for orbiting, panning, and zooming.
 +
        requestAnimationFrameID = requestAnimationFrame(run); // Allow for the cancellation of this requestAnimationFrame request.
 +
      }; // run()
 +
      that.run = run;
 +
 +
      return that; // The object returned by the constructor.
 +
    } // Simulation
 +
 +
    function handleSubmitButton(evt) {
 +
      var m1 = InitialCondition(document.getElementById('mass1').querySelectorAll('input')); // A constructor returning an initial condition object.
 +
      var m2 = InitialCondition(document.getElementById('mass2').querySelectorAll('input'));
 +
      var m3 = InitialCondition(document.getElementById('mass3').querySelectorAll('input'));
 +
 +
      evt.preventDefault(); // Don't refresh the page when the user clicks this form button.
 +
 +
      if (!window.WebGLRenderingContext) { displayCanvasRendererWarning(); } // If necessary, warn the user that they're using a canvas-based Three.js renderer and that they should upgrade their browser so that a faster WebGL-based renderer can be used instead.
 +
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
      simulation.init([m1, m2, m3]);
 +
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////   
 +
simulation.run(); // The images have been preloaded so this works immediately.
 +
 +
      function InitialCondition(inputElements) {
 +
        var mass = parseFloat(inputElements[0].value);
 +
 +
        return {
 +
          mass: mass,
 +
          radius: calculateRadius(mass),
 +
          rotation: calculateRotation(mass),
 +
          position: { x: parseFloat(inputElements[1].value), y: parseFloat(inputElements[2].value) },
 +
          velocity: { x: parseFloat(inputElements[3].value), y: parseFloat(inputElements[4].value) },
 +
          bitmap: inputElements[5].value // This is a string value (hence the non-use of parseFloat).
 +
        };
 +
 +
        function calculateRadius(mass) {
 +
          /*
 +
            Mass equals density times volume or m = D * V = D * (4/3 * PI * r^3), and solving for r = [(3 * m)/(4 * PI * D)]^(1/3)
 +
          */
 +
          var radicand = (3 * mass) / (4 * Math.PI * DENSITY); // Only change the value of DENSITY to affect the value returned by this function.
 +
 +
          return Math.pow(radicand, 1 / 3);
 +
        } // calculateRadius
 +
 +
        function calculateRotation(mass) {
 +
          /*
 +
            Using a power model, let the x-axis represent the radius and the y-axis the rotational rate of the sphere.
 +
            The power model is y = a * x^b, where a and b are constants (which were empirically derived).
 +
          */
 +
          var radius = calculateRadius(mass);
 +
 +
          return 1.7 * Math.pow(radius, -1.9); // Rotational rate as a function of the sphere's radius.
 +
        } // calculateRotation
 +
      } // InitialCondition
 +
    } // handleSubmitButton
 +
 +
    function handleReloadButton(evt) {
 +
      /* 
 +
        Clicking a form button automatically refreshes the page, which is exactly the behavior we want (i.e., location.reload() is not necessary here).
 +
      */
 +
    } // handleReloadButton
 +
 +
    function handleInfoButton(evt) {
 +
      /*
 +
        Note that when the info page covers up the animation, the animation stops because this is how requestAnimationFrame works. In this sense, we get a free pause feature.
 +
      */
 +
      evt.preventDefault(); // Don't refresh the page when the user clicks this form button.
 +
      window.open("info.html"); // Open the info.html page in another tab.
 +
    } // handleInfoButton
 +
 +
    function displayCanvasRendererWarning() { // This assumes that the user's browser at least supports canvas.
 +
      var articleElement = document.getElementsByTagName('article')[0];
 +
 +
      articleElement.innerHTML = "<h2>WebGL not supported, using canvas-based renderer, please upgrade your browser.</h2>";
 +
      articleElement.style.display = "block";
 +
    }
 +
  </script>
 +
</body>
 +
</html>
 +
</syntaxhighlight>
 +
</div>
  
 
В случае трех материальных тел на каждое из них действуют две силы со стороны двух других тел. Например, на тело m₁ действуют следующие силы (F₂ и F₃):
 
В случае трех материальных тел на каждое из них действуют две силы со стороны двух других тел. Например, на тело m₁ действуют следующие силы (F₂ и F₃):

Версия 21:46, 2 июня 2015

А.М. Кривцов > Теоретическая механика > Курсовые проекты ТМ 2015 > Движение спутника в двойной системе


Курсовой проект по Теоретической механике

Исполнитель: Мущак Никита

Группа: 09 (23604)

Семестр: весна 2015

Модель системы

Формулировка задачи

Исследовать движение спутника двойной системы. Двойная система состоит из 2 неподвижных планет и спутника вращающегося вокруг них как показано на рисунке сверху. Определить стационарные орбиты спутника, а также устойчивость движения спутника.

Общие сведения по теме

Задачи подобного рода можно решать разными способами. Но решать данную задачу будем 2 способами :

с помощью уравнения Лагража 2-ого рода и как упрощенная задача 3-х тел

1 способ: уравнение Лагранжа 2-ого рода:

Lagrange.png




,где L - функция Лагранжа (лагранжиан),q- обобщенная координата, t — время, i— число степеней свободы механической системы

Функцию Лагранжа будем считать как разность кинетической и потенциальной энергий системы.

Дальнейшим дифференцированием получаем уравнение движения.

2 способ:записываем 2-ой закон Ньютона для данной задачи и получаем:

2newton.jpg



,где Gamma.png - гравитационная постоянная,m- массы планет,q - координаты планет.

Решение

Ланранжиан будет иметь вид: LA.png, где m - масса спутника, q - обобщенная координата, Phi.png- потенциал гравитационного поля.

Подставляя полученное выражение в уравнение Лагранжа, можно получить уравнение движения: Equ.png

Как можно заметить из уравнения движения масса спутника никак не влияет на траекторию.

Отдельного рассмотрения заслуживает конфигурация потенциального гравитационного поля.

Оно будет иметь вид: Phi.jpg

При этом графики такого поля будут выглядеть:

Контурный график
Сравнение с овалами Кассини
3D график



































Стационарные орбиты спутника будут близки к овалам Кассини

-это семейство кривых, которые задаются уравнением Oval.png , где 2c-расстояние между фокусами, а- некоторая константа.

графики овалов Кассини: Cass.png



Частным случаем овалов Кассини является лемниската Бернулли, которая выглядит как знак бесконечности или восьмерка


Программа: скачать

Текст программы на языке JavaScript:

Файл "K3.html"

  1 <!DOCTYPE html>
  2 
  3 <html>
  4 <head>
  5   <meta charset="utf-8" />
  6   <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <!-- For IE on an intranet. -->
  7   <title>Moon in Binary System</title>
  8   <style>
  9     html, body {
 10       margin: 0;
 11       padding: 0;
 12     }
 13 
 14     html {
 15       overflow-y: scroll; /* There's an issue with the scrollbar "randomly" appearing - this just keeps it always visible in case the user is using a very wide and narrow monitor. */
 16     }
 17 
 18     body {
 19       width: 1024px; /* Currently, most screens can handle this. */
 20       margin: auto; /* Center the page content. */
 21       background-color: #777;
 22       font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; /* Start screen font. */
 23     }
 24 
 25     header {
 26       color: #FFF;
 27       text-shadow: 5px 5px 10px #333;
 28     }
 29 
 30     section {
 31       position: relative; /* Float children relative to this element. */
 32     }
 33 
 34       section form {
 35         width: 210px; /* This is a bit less than the "section #WebGLCanvasElementContainer margin-left" value to provide a nice space between the form and the viewport. */
 36         float: left;
 37         text-align: center; /* Center the button elements. */
 38       }
 39 
 40         section form fieldset {
 41           text-align: left; /* Undo the button center aligning trick for the text in the form. */
 42           margin-bottom: 1.25em; /* Adjust this so that the height of the form is about the same height as the WebGL Three.js viewport element. */
 43         }
 44 
 45           section form fieldset input {
 46             width: 100%;
 47           }
 48 
 49         section form td {
 50           white-space: nowrap; /* Don't let words like "x-position" break at the hyphen (which occurs in Chrome). */
 51         }
 52 
 53       section #WebGLCanvasElementContainer {
 54         border: 1px solid #DDD; /* Match the native color of the fieldset border. */
 55         width: 800px; /* The assumed fixed width of the WebGL Three.js viewport element. */
 56         height: 600px; /* The assumed fixed height of the WebGL Three.js viewport element. */
 57         margin-left: 224px; /* This is "body width" minus "section #WebGLCanvasElementContainer width" or 1024px - 800px = 224px. */
 58         background-image: url('starField.jpg'); /* 0.15 opacity value. */
 59       }
 60 
 61       section article {
 62         padding: 0 1em;
 63         color: white;
 64       }
 65 
 66       section button {
 67         width: 4.5em;
 68       }
 69   </style>
 70   <script>
 71     /*// Preload all images/bitmaps.
 72     var preloadImages = [];
 73     var preloadImagePaths = ["jupiter.png", "saturn.png", "moon.png", "starField.jpg", "starField.jpg"];
 74     
 75     for (var i = 0; i < preloadImagePaths.length; i++) {
 76       preloadImages[i] = new Image();
 77       
 78       preloadImages[i].onerror = function() { 
 79         if (console) {
 80           console.error(this.src + " error.");
 81         } // if
 82       }; // onerror
 83       
 84       preloadImages[i].src = preloadImagePaths[i]; // Preload images to improve perceived app speed.
 85     } // for  
 86   */</script>
 87 </head>
 88 
 89 <body>
 90   <header>
 91     <h1>Moon in Binary System </h1>
 92   </header>
 93   <section>
 94     <form id="initialConditions">
 95       <fieldset>
 96         <legend>Moon</legend>
 97         <table id="mass1">
 98           <tr>
 99             <td>mass:</td>
100             <td><input id="m1_mass" type="number" value="1E18" required="required" /></td>
101           </tr>
102           <tr>
103             <td>x-position:</td>
104             <td><input id="m1_position_x" type="number" value="-141" required="required" /></td>
105           </tr>
106           <tr>
107             <td>y-position:</td>
108             <td><input id="m1_position_y" type="number" value="0" required="required" /></td>
109           </tr>
110           <tr>
111             <td>x-velocity:</td>
112             <td><input id="m1_velocity_x" type="number" value="0" required="required" /></td>
113           </tr>
114           <tr>
115             <td>y-velocity:</td>
116             <td><input id="m1_velocity_y" type="number" value="2" required="required" /></td>
117           </tr>
118           <tr style="display: none;">
119             <td>bitmap:</td>
120             <td><input type="text" value="moon.png" required="required" /></td>
121           </tr>
122         </table>
123       </fieldset>
124       <fieldset>
125         <legend>1st star</legend>
126         <table id="mass2">
127           <tr>
128             <td>mass:</td>
129             <td><input type="number" value="1E19" required="required" /></td>
130           </tr>
131           <tr>
132             <td>x-position:</td>
133             <td><input type="number" value="-100" required="required" /></td>
134           </tr>
135           <tr>
136             <td>y-position:</td>
137             <td><input type="number" value="0" required="required" /></td>
138           </tr>
139           <tr>
140             <td>x-velocity:</td>
141             <td><input type="number" value="0" required="required" /></td>
142           </tr>
143           <tr>
144             <td>y-velocity:</td>
145             <td><input type="number" value="0" required="required" /></td>
146           </tr>
147           <tr style="display: none;">
148             <td>bitmap:</td>
149             <td><input type="text" value="jupiter.png" required="required" /></td>
150           </tr>
151         </table>
152       </fieldset>
153       <fieldset>
154         <legend>2nd star</legend>
155         <table id="mass3">
156           <tr>
157             <td>mass:</td>
158             <td><input type="number" value="1E19" required="required" /></td>
159           </tr>
160           <tr>
161             <td>x-position:</td>
162             <td><input type="number" value="100" required="required" /></td>
163           </tr>
164           <tr>
165             <td>y-position:</td>
166             <td><input type="number" value="0" required="required" /></td>
167           </tr>
168           <tr>
169             <td>x-velocity:</td>
170             <td><input type="number" value="0"  required="required" /></td>
171           </tr>
172           <tr>
173             <td>y-velocity:</td>
174             <td><input type="number" value="0" required="required" /></td>
175           </tr>
176           <tr style="display: none;">
177             <td>bitmap:</td>
178             <td><input type="text" value="saturn.png" required="required" /></td>
179           </tr>
180         </table>
181       </fieldset>
182       <button id="submitButton">Submit</button>
183       <button id="reloadButton">Reload</button>
184       
185     </form>
186     <div id="WebGLCanvasElementContainer">
187       <!-- Three.js will add a canvas element to the DOM here. -->
188       <!-- The following <article> element (along with its content) will be removed via JavaScript just before the simulation starts: -->
189       <article>
190         <h2></h2>
191         <p>
192           
193         </p>
194         <h2>Running the simulation</h2>
195         <ul>
196           <li>To start the simulation with the current set of initial conditions, click the <strong>Submit</strong> button.</li>
197           <li>To orbit, left-click and drag the mouse.</li>
198           <li>To pan, right-click and drag the mouse.</li>
199           <li>To zoom, roll the mouse wheel.</li>
200           <li>To enter your own initial conditions, enter numeric values of your choice (in the form to the left) and click <strong>Submit</strong>. 
201           Note that large values such as 10<sup>18</sup> can be entered as 1E18.</li>
202           <li>To restart the simulation from scratch, click the <strong>Reload</strong> button (equivalent to refreshing the page).</li>
203           <li>For additional information and resources, click the <strong>Info</strong> button.</li>
204         </ul>
205       </article>
206     </div>
207   </section>
208   <script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script> <!-- The "CDN" for Three.js  -->
209   <script src="https://rawgithub.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script> <!-- Allows for orbiting, panning, and zooming. -->
210   <script>
211     var  DENSITY= 1.38E14; // This value determined qualitatively by observing how large the spheres look onscreen (i.e., their radii).
212 
213     document.getElementById('submitButton').addEventListener('click', handleSubmitButton, false);
214     document.getElementById('reloadButton').addEventListener('click', handleReloadButton, false);
215     
216 
217     var simulation = Simulation(); // Call the Simulation constructor to create a new simulation object.
218 
219     function Simulation() { // A constructor.
220       var that = {}; // The object returned by this constructor.
221       var worker; // Will contain a reference to a fast number-chrunching worker thread that runs outside of this UR/animation thread.
222       var requestAnimationFrameID = null; // Used to cancel a prior requestAnimationFrame request.
223       var gl = {}; // Will contain WebGL related items.
224 
225       gl.viewportWidth = 800; // The width of the Three.js viewport.
226       gl.viewportHeight = 600; // The height of the Three.js viewport.
227 
228       gl.cameraSpecs = {
229         aspectRatio: gl.viewportWidth / gl.viewportHeight, // Camera frustum aspect ratio.
230         viewAngle: 50 // Camera frustum vertical field of view, in degrees.
231       };
232 
233       gl.clippingPlane = {
234         near: 0.1, // The distance of the near clipping plane (which always coincides with the monitor).
235         far: 1000 // The distance of the far clipping plane (note that you get a negative far clipping plane for free, which occurs at the negative of this value).
236       };
237 
238       gl.quads = 32; // Represents both the number of vertical segments and the number of horizontal rings for each mass's sphere wireframe.
239 
240       gl.renderer = window.WebGLRenderingContext ? new THREE.WebGLRenderer({ alpha: true }) : new THREE.CanvasRenderer({ alpha: true }); // If WebGL isn't supported, fallback to using the canvas-based renderer (which most browsers support). Note that passing in "{ antialias: true }" is unnecessary in that this is the default behavior. However, we pass in "{ alpha: true }" in order to let the background PNG image shine through.
241       gl.renderer.setClearColor(0x000000, 0); // Make the background completely transparent (the actual color, black in this case, does not matter) so that the PNG background image can shine through.
242       gl.renderer.setSize(gl.viewportWidth, gl.viewportHeight); // Set the size of the renderer.
243 
244       gl.scene = new THREE.Scene(); // Create a Three.js scene.
245 
246       gl.camera = new THREE.PerspectiveCamera(gl.cameraSpecs.viewAngle, gl.cameraSpecs.aspectRatio, gl.clippingPlane.near, gl.clippingPlane.far); // Set up the viewer's eye position.
247       gl.camera.position.set(0, 450, 0); // The camera starts at the origin, so move it to a good position.
248       gl.camera.lookAt(gl.scene.position); // Make the camera look at the origin of the xyz-coordinate system.
249 
250       gl.controls = new THREE.OrbitControls(gl.camera, gl.renderer.domElement); // Allows for orbiting, panning, and zooming via OrbitsControls.js by http://threejs.org. For an example, see http://threejs.org/examples/misc_controls_orbit.html.
251 
252       gl.pointLight = new THREE.PointLight(0xFFFFFF); // Set the color of the light source (white).
253       gl.pointLight.position.set(0, 250, 250); // Position the light source at (x, y, z).
254       gl.scene.add(gl.pointLight); // Add the light source to the scene.
255 
256       gl.spheres = []; // Will contain WebGL sphere mesh objects representing the point masses.
257 
258       var init = function (initialConditions) { // Public method, resets everything when called.
259         if (requestAnimationFrameID) {
260           cancelAnimationFrame(requestAnimationFrameID); // Cancel the previous requestAnimationFrame request.
261         }
262 
263         if (worker) {
264           worker.terminate(); // Terminate the previously running worker thread to ensure a responsive UI.
265         }
266         worker = new Worker('K3.js'); // Spawn a fast number-chrunching thread that runs outside of this UR/animation thread.
267 
268         document.getElementById('WebGLCanvasElementContainer').style.backgroundImage = "url('starField.jpg')"; // Switch back to the non-opaque PNG background image.
269         document.getElementsByTagName('article')[0].style.display = "none"; // Remove from page-flow the one (and only) article element (along with all of its content).
270         document.getElementById('WebGLCanvasElementContainer').appendChild(gl.renderer.domElement); // Append renderer element to DOM.
271 
272         while (gl.spheres.length) { // Remove any prior spheres from the scene and empty the gl.spheres array:
273           gl.scene.remove(gl.spheres.pop());
274         } // while
275 
276         for (var i = 0; i < initialConditions.length; i++) { // Set the sphere objects in gl.spheres to initial conditions.
277           initializeMesh(initialConditions[i]); // This call sets the gl.spheres array.
278         } // for
279 
280         worker.postMessage({
281           cmd: 'init', // Pass the initialization command to the web worker.
282           initialConditions: initialConditions // Send a copy of the initial conditions to the web worker, so it can initialize its persistent global variables.
283         }); // worker.postMessage
284 
285         worker.onmessage = function (evt) { // Process the results of the "crunch" command sent to the web worker (via this UI thread).
286           for (var i = 0; i < evt.data.length; i++) {
287             gl.spheres[i].position.x = evt.data[i].p.x;
288             gl.spheres[i].position.z = evt.data[i].p.y;
289             gl.spheres[i].position.y = 0; // 3BodyWorker.js is 2D (i.e., the physics are constrained to a plane).
290             gl.spheres[i].rotation.y += initialConditions[i].rotation; // Place worker.onmessage in the init method in order to access its initialConditions array.
291           }
292           gl.renderer.render(gl.scene, gl.camera); // Update the positions of the masses (sphere meshes) onscreen based on the data returned by 3BodyWorker.js.
293         }; // worker.onmessage
294 
295         function initializeMesh(initialCondition) {
296           var texture = THREE.ImageUtils.loadTexture(initialCondition.bitmap); // Create texture object based on the given bitmap path.
297           var material = new THREE.MeshPhongMaterial({ map: texture }); // Create a material (for the spherical mesh) that reflects light, potentially causing sphere surface shadows.
298           var geometry = new THREE.SphereGeometry(initialCondition.radius, gl.quads, gl.quads); // Radius size, number of vertical segments, number of horizontal rings.
299           var mesh = new THREE.Mesh(geometry, material); // A mesh represents the object (typically composed of many tiny triangles) to be displayed - in this case a hollow sphere with a bitmap on its surface.
300 
301           mesh.position.x = initialCondition.position.x;
302           mesh.position.z = initialCondition.position.y; // Convert from 2D to "3D".
303           mesh.position.y = 0; // The physics are constrained to the xz-plane (i.e., the xy-plane in 3BodyWorker.js).
304 
305           gl.scene.add(mesh); // Add the sphere to the Three.js scene.
306           gl.spheres.push(mesh); // Make the Three.js mesh sphere objects accessible outside of this helper function.
307         } // initializeMesh
308       } // init
309       that.init = init; // This is what makes the method public.
310 
311       var run = function () { // Public method.
312         worker.postMessage({
313           cmd: 'crunch' // This processing occurs between animation frames and, therefore, is assumed to take a relatively small amount of time (as compared to current frame rates).
314         }); // worker.postMessage
315         gl.controls.update(); // Allows for orbiting, panning, and zooming.
316         requestAnimationFrameID = requestAnimationFrame(run); // Allow for the cancellation of this requestAnimationFrame request.
317       }; // run()
318       that.run = run;
319 
320       return that; // The object returned by the constructor.
321     } // Simulation
322 
323     function handleSubmitButton(evt) {
324       var m1 = InitialCondition(document.getElementById('mass1').querySelectorAll('input')); // A constructor returning an initial condition object.
325       var m2 = InitialCondition(document.getElementById('mass2').querySelectorAll('input'));
326       var m3 = InitialCondition(document.getElementById('mass3').querySelectorAll('input'));
327 
328       evt.preventDefault(); // Don't refresh the page when the user clicks this form button.
329 
330       if (!window.WebGLRenderingContext) { displayCanvasRendererWarning(); } // If necessary, warn the user that they're using a canvas-based Three.js renderer and that they should upgrade their browser so that a faster WebGL-based renderer can be used instead.
331 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
332       simulation.init([m1, m2, m3]);
333 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////     
334 	 simulation.run(); // The images have been preloaded so this works immediately.
335 
336       function InitialCondition(inputElements) {
337         var mass = parseFloat(inputElements[0].value);
338 
339         return {
340           mass: mass,
341           radius: calculateRadius(mass),
342           rotation: calculateRotation(mass),
343           position: { x: parseFloat(inputElements[1].value), y: parseFloat(inputElements[2].value) },
344           velocity: { x: parseFloat(inputElements[3].value), y: parseFloat(inputElements[4].value) },
345           bitmap: inputElements[5].value // This is a string value (hence the non-use of parseFloat).
346         };
347 
348         function calculateRadius(mass) {
349           /*
350             Mass equals density times volume or m = D * V = D * (4/3 * PI * r^3), and solving for r = [(3 * m)/(4 * PI * D)]^(1/3)
351           */
352           var radicand = (3 * mass) / (4 * Math.PI * DENSITY); // Only change the value of DENSITY to affect the value returned by this function.
353 
354           return Math.pow(radicand, 1 / 3);
355         } // calculateRadius
356 
357         function calculateRotation(mass) {
358           /*
359             Using a power model, let the x-axis represent the radius and the y-axis the rotational rate of the sphere. 
360             The power model is y = a * x^b, where a and b are constants (which were empirically derived).
361           */
362           var radius = calculateRadius(mass);
363 
364           return 1.7 * Math.pow(radius, -1.9); // Rotational rate as a function of the sphere's radius.
365         } // calculateRotation
366       } // InitialCondition
367     } // handleSubmitButton
368 
369     function handleReloadButton(evt) {
370       /*  
371         Clicking a form button automatically refreshes the page, which is exactly the behavior we want (i.e., location.reload() is not necessary here).
372       */
373     } // handleReloadButton
374 
375     function handleInfoButton(evt) {
376       /*
377         Note that when the info page covers up the animation, the animation stops because this is how requestAnimationFrame works. In this sense, we get a free pause feature.
378       */
379       evt.preventDefault(); // Don't refresh the page when the user clicks this form button.
380       window.open("info.html"); // Open the info.html page in another tab.
381     } // handleInfoButton
382 
383     function displayCanvasRendererWarning() { // This assumes that the user's browser at least supports canvas.
384       var articleElement = document.getElementsByTagName('article')[0];
385 
386       articleElement.innerHTML = "<h2>WebGL not supported, using canvas-based renderer, please upgrade your browser.</h2>";
387       articleElement.style.display = "block";
388     }
389   </script>
390 </body>
391 </html>

В случае трех материальных тел на каждое из них действуют две силы со стороны двух других тел. Например, на тело m₁ действуют следующие силы (F₂ и F₃): IC694.png




Сначала заметим, что результирующая силаF₁, действующая на тело m₁, будет суммой сил F₂ и F₃. Это значит, что F₁ = m₁a₁ = F₂ + F₃.

Обсуждение результатов и выводы


Скачать отчет:
Скачать презентацию:Движение спутника в двойной системе

Ссылки по теме

См. также