Sailing Simulation Engine - leeboardtools/bythelee GitHub Wiki

NOTE: This is very out of date!

The sailing simulation engine's source files are found in public_html/js/leeboard/sailsim.

LBSailSim.Env

Every simulation needs a LBSailSim.Env object, which defines the overall environment. This includes:

  • A list of the available boats.
  • A wind engine.
  • A water engine.
  • A list of the available aerodynamic dynamic coefficient curves.

If you're using Phaser to provide the 2D physics, the simulation should use an LBSailSim.P2Env object instead of LBSailSim.Env. LBSailSim.P2Env extends LBSailSim.Env with stuff for connecting the Phaser P2 physics engine with the sailing simulator engine.

LBSailSim.Env must be set up from JSON files via the methods:

  • LBSailSim.Env#loadClCdCurves
  • LBSailSim.Env#loadBoatDatas

The Cl/Cd curves define the lift/drag coefficients used for the aerodynamic and hydrodynamic forces on sails and foils. These curves are represented by LBFoil.ClCdCurve objects. In the sailing simulator you normally do not need to access LBFoil.ClCdCurve directly, instead LBFoil.Foil handles all interactions with LBFoil.ClCdCurve.

Boats are represented by LBSailSim.Vessel objects. LBSailSim.Env#checkoutBoat is used to obtain an individual instance of a LBSailSim.Vessel. LBSailSim.Env#checkoutBoat in fact tracks how many instances of a given boat are allowed, and when one has been checked out.

When done with a boat, LBSailSim.Env#returnBoat returns the boat, allowing it to be checked out again.

LBSailSim.Vessel

LBSailSim.Vessel is an LBPhysics.RigidBody, which means it has 3D rigid body properties. Vessels have the following key properties:

  • An array of airfoils (i.e. sails)
  • An array of hydrofoils (i.e. keels and rudders)
  • An array of propulsors (i.e. propellers and waterjets)
  • An array of ballast (i.e. crew)
  • An array of controllers

These are all loaded based on the data in the JSON file. LBSailSim.SailEnv#_createBoatInstance calls LBSailSim.Vessel.createFromData to handle the creating and loading of the vessel object.

TODO: Document the JSON file format!

With the exception of the controllers, these objects are all LBPhysics.RigidBody objects.

Everything in a vessel is described relative to the vessel's local coordinate system. By convention, the origin is the waterline point at the bow, with the stern along the +x-axis.

The key method of a vessel is LBSailSim.Vessel#updateForces. This is called each simulation cycle to update the forces applied to the vessel by its components. This is where the sails and hydrofoils figure out the aerodynamic and hydrodynamic forces.

The forces are only calculated and stored, they are not actually applied to the vessel. It is up to the physics engine used to apply the forces. The forces are retrievable via LBPhysics.RigidBody#getResultant, which returns a force resultant LBPhysics.Resultant3D (a force, application point, and moment).

Using Phaser P2 Physics as the Physics Engine

LBSailSim.P2Env automatically uses the Phaser P2 Physics engine for the sailing simulation. It does this by maintaining and managing a LBPhaser.P2Link object.

LBPhaser.P2Link basically keeps track of a set of rigid bodies, each of which should have a property with the name LBPhaser.P2Link.p2BodyProperty containing the Phaser.Physics.P2.Body object associated with the rigid body. LBSailSim.P2Env handles this in its LBSailSim.P2Env#_createBoatInstance override.

There are two main phases in LBPhaser.P2Link's operation:

  • LBPhaser.P2Link#updateFromP2, which updates the rigid body object's 3D state (i.e. position and orientation) from the P2 body's state.
  • LBPhaser.P2Link#applyToP2 which applies the rigid body's forces to the P2 body.

LBSailSim.P2Env#update conveniently handles both these calls.

Of course, since P2 is a 2D physics engine, only the x-y plane is used when passing information between the LBPhysics.RigidBody and Phaser.Physics.P2.Body objects.

LBPhaser.P2Link also provides some additional handy-dandy functionality:

  • Phaser display objects may be attached to child rigid bodies
  • Force arrows may be displayed for the rigid bodies and their children.
  • A callback object may be assigned to child rigid bodies, which has methods that are called whenever the display objects are updated.

These features apply to the main rigid body as well as the child rigid bodies.

To associate a Phaser display object such as a Phaser.Sprite with a child rigid body, add a property to the child rigid body with the name LBPhaser.P2Link.spriteProperty whose value is the Phaser display object. LBPhaser.P2Link will then update the position and rotation of the display object with the world x-y plane position and z-axis rotation of the child rigid body.

To associate a force arrow with a child rigid body, add a property to the child rigid body with the name LBPhaser.P2Link.forceArrowProperty whose value is a LBPhaser.Arrow object.

To associate a callback object with a child rigid body, add a property to the child rigid body with the name LBPhaser.P2Link.callbackProperty. This object should have the following functions:

displayObjectsUpdated = function(topRigidBody, rigidBody) {
}

where topRigidBody is the top-level rigid body, that is, the one that was added to the LBPhaser.P2Link object, while rigidBody is the child rigid body the function is being called on, which may be topRigidBody.

LBSailSim.P2Env takes care of associating display objects with the boat components, setting up force arrows, and installing a hull resistance object.

TODO

  • Add drawing of the 3D vessel as a Phaser drawing object.
  • Update LBPhaser.P2Link to apply and resolve forces in the z direction, updating the rigid body's z dimension accordingly.