Tutorial One - Simple Visualization

Welcome to the first tutorial in our series on using vessel.js – a powerful JavaScript library that combines the principles of data-driven design with a web-based, object-oriented approach for conceptual ship design and simulation.

This first tutorial will show you how to create a simple 3D ship using the vessels.js library. After the tutorial you you'll be equipped with the knowledge to:

  • Understand the fundamentals of vessels.js and its JSON database format.
  • Import a ship's design from a JSON file.
  • Integrate your ship into a Three.js scene for 3D visualization.

Getting Started

The process of inserting a typical ship into a digital scene can be divided into four steps: the import of the library, the load of the vessels.js JSON format, creating the 3D module, and the insertion on the ship.

// Importing the Library
import * as Vessel from "../build/vessel.module.js"

// Loading the Ship's Design JSON file
const ship = new Vessel.Ship("./blockCase.json")

// Creating the Ship3D module and adding it to a Scene
ship.createShip3D({
  stlPath: "../examples/3D_models/STL/various",
}, Ship3D)

// scene object derived from the Three.js library
scene.add(ship.ship3D);
          

The Ship method points toward a JSON file that contains the vessel information in the Vessel.js format. On JSON Format section we will discuss more about the Vessel.js format. For this example the blockCase.json file was initialized with the Vessel.Ship method.

The scene object is part of the Three.js library and it is used for displaying the 3D visualization. For a detailed explanation of how scenes work, please refer to the main documentation at https://threejs.org/docs/#manual/en/introduction/Creating-a-scene.

The following visualization shows how should be the visualization for the scene (click and drag under the scene to control the orbit view):

JSON Format

Vessel.js employs a JSON format to store the design of the ship. On the previous example the blockCase.json was imported using Vessel.Ship The JSON file is segmented into four sections, namely: designState, structure, baseObjects and derivedObjects. Presented here is a sample of a JSON file along with its data functions:
{
  "designState": {
    // Holds several parameters that affect calculations
  },
  "structure": {
    // Definition of the hull, decks and bulkheads
  },
  "baseObjects": [
    // Array of base objects as it is fetched from the provided specification.
    // It groups several elements,
    // for example (cargo holds, tanks, ballast tanks, etc.)
  ],
  "derivedObjects": [
    // Array of derived objects. A derived object is a base object
    // with information added on top of it. Derived objects are classified
    // as parts of baseObjects.
  ]
}         
          

designState

The designState contains several parameters that affect the calculations such as tank fillings. The object can be subdivided in two sections: calculationParameters and objectOverrides. Here is as simple example of a designState object format:
"designState": {
  "calculationParameters": {
    "LWL_design": 22.5,
    "BWL": 10,
    "Draft_design": 2,
    "Cb_design": 1,
    "speed": 12,
  },
  "objectOverrides": {
    "derivedByGroup": {
      "cargo tanks": {
        "fullness": 0
      },
      "ballast tanks": {
        "fullness": 1
      }
    }
  }
},       
    

The calculationParameters comprise a collection of specified ship parameters used for calculations. Certain parameters, such as LWL and Cb, can be calculated from load and hull geometry, while others are uncertain or not covered by existing calculations. For a full list of parameters information that can be stored in this list please refer to the Wiki (calculationParameters) .

The objectOverrides assign state information to a specific set of base object groups. This example shows a set of objects overrides for the "cargo tanks" and "ballast tanks". For a full overview of the object overrides types please refer to the Wiki (objectOverrides) .

structure

A ship structure consists of a hull, decks and bulkheads. The specification below defines a barge ship with a simple prismatic hull, one deck and one bulkhead. The hull is defined with a table of offsets, and the library creates a tessellated surface to cover the points on the table. The properties waterlines and stations define the position of the sections as fractions of the LOA and Depth, respectively. The points on the table are defined for one symmetry side of the hull. The arrays on the table define the waterlines, from lowest to highest. Each point in an array is associated to one station, from last to foremost.
"structure": {
  "hull": {
    "attributes": {
      "LOA": 22.5,
      "BOA": 10,
      "Depth": 2.5,
      "APP": 0
    },
    "halfBreadths": {
      "waterlines": [0, 0, 1],
      "stations": [0, 1],
      "table": [[0, 0], [1, 1], [1, 1]]
    },
    "buttockHeights": {},
    "affiliations": {
      "SBSD": "Hull",
      "group": "structure"
    }
  },
  "decks": {
    "BallastTop": {
      "zFloor": 0.4,
      "thickness": 0.01,
      "xAft": 0,
      "xFwd": 22.5,
      "yCentre": 0,
      "breadth": 10,
      "density": 7850,
      "affiliations": {
        "SBSD": "Hull",
        "group": "structure"
      }
    }
  },
  "bulkheads": {
    "AB": {
      "xAft": 11.25,
      "thickness": 0.01,
      "density": 7850,
      "affiliations": {
        "SBSD": "Hull",
        "group": "structure"
      }
    }
  }
}     
    
For a full explanation about the structure section please refer to the tutorial in https://observablehq.com/@icarofonseca/hull-definition-and-hydrostatics and Wiki (Structure)

baseObjects and derivedObjects

The baseObjects and derivedObjects define different elements of a ship such as equipment, tanks and compartments of the ship. On the base object it is possible to group several object states into a single supergroup. For instance, a cargo hold can be divided into several compartments, each one with a different state. Here is an example for the baseObjects for a specific cargo hold type:
"baseObjects": [
{
  "id": "cargo",
  "affiliations": {},
  "boxDimensions": {
    "length": 10.25,
    "breadth": 9,
    "height": 1.6
  },
  "capabilities": {},
  "baseState": {
    "fullness": 0
  },
  "weightInformation": {
    "contentDensity": 850,
    "volumeCapacity": 145,
    "lightweight": 10000,
    "fullnessCGMapping": {
      "fullnesses": [0, 0.25, 0.5, 0.75, 1],
      "cgs": [
        [0, 0, 0.8],
        [0, 0, 0.347013783],
        [0, 0, 0.455846422],
        [0, 0, 0.6195241],
        [0, 0, 0.8]
      ]
    }
  }
}]
    
This object can be connect to a specific derivedObjects allowing the compartment to inherit the specifications from the baseObjects group. Here is an example for a so called a cargo "Tank1" derived tank:
"derivedObjects": [
  {
    "id": "Tank1",
    "baseObject": "cargo",
    "affiliations": {
      "SBSD": "Liquid and dry bulk cargo",
      "group": "cargo tanks",
      "Deck": "CargoDeck",
      "SFI": "102"
    },
    "referenceState": {
      "xCentre": 16.875,
      "yCentre": 0,
      "zBase": 0.4
    }
  ]      
    
Note that the Tank1 will inherit the specifications from the cargo base object, containing for example the same dimensions and weight information (it will be a tank with 10.25 x 9 x 1.6 located at 16.875 x 0 x 0.4 m from the origin). For further references on baseObjects and derivedObjects please refer to the Wiki (BaseObject) and Wiki (DerivedObject) .