import * as THREE from 'three';
/**
* Represents the variable state of the submarine during simulation.
* @class
*/
class SubmarineState {
/**
* Creates an instance of SubmarineState.
* @param {number} currentTotalWaterMass - The initial current total water mass inside the submarine.
* @param {number} currentWaterMassFrontTank - The initial current water mass in the front tank.
* @param {number} currentWaterMassBackTank - The initial current water mass in the back tank.
* @param {number} currentRotorRPS - The initial current rotor rounds per second (RPS).
* @param {number} submergedVolume - The initial submerged volume of the submarine.
* @param {number} currentDepth - The initial current depth of the submarine.
* @param {THREE.Vector3} currentSpeed - The initial current speed of the submarine.
* @param {THREE.Vector3} currentAcceleration - The initial current acceleration of the submarine.
* @param {THREE.Vector3} currentPosition - The initial current position of the submarine.
* @param {THREE.Quaternion} currentOrientation - The initial current orientation of the submarine.
* @param {THREE.Vector3} angularVelocity - The initial angular velocity of the submarine.
* @param {THREE.Vector3} angularAcceleration - The initial angular acceleration of the submarine.
* @param {number} weight - The initial weight of the submarine.
* @param {number} buoyancy - The initial buoyancy force acting on the submarine.
* @param {number} drag - The initial drag force acting on the submarine.
* @param {number} thrust - The initial thrust force produced by the submarine.
* @param {number} sternAngle - The initial angle of the stern plane.
* @param {number} rudderAngle - The initial angle of the rudder plane.
* @param {number} fairwaterAngle - The initial angle of the fairwater plane.
* @param {THREE.Matrix3} momentOfInertia - The moment of inertia of the submarine.
* @param {THREE.Vector3} centerOfMass - The center of mass of the submarine.
* @param {SubmarineConstants} submarineConstants - The submarine constants for calculations.
*/
constructor(currentTotalWaterMass, currentWaterMassFrontTank, currentWaterMassBackTank, currentRotorRPS, submergedVolume, currentDepth, currentSpeed, currentAcceleration, currentPosition, currentOrientation, angularVelocity, angularAcceleration, weight, buoyancy, drag, thrust, sternAngle, rudderAngle, fairwaterAngle, momentOfInertia, centerOfMass, submarineConstants) {
this.currentTotalWaterMass = currentTotalWaterMass;
this.currentWaterMassFrontTank = currentWaterMassFrontTank;
this.currentWaterMassBackTank = currentWaterMassBackTank;
this.currentRotorRPS = currentRotorRPS;
this.submergedVolume = submergedVolume;
this.currentDepth = currentDepth;
this.currentSpeed = currentSpeed;
this.currentAcceleration = currentAcceleration;
this.currentPosition = currentPosition;
this.currentOrientation = currentOrientation;
this.angularVelocity = angularVelocity;
this.angularAcceleration = angularAcceleration;
this.weight = weight;
this.buoyancy = buoyancy;
this.drag = drag;
this.thrust = thrust;
this.sternAngle = sternAngle;
this.rudderAngle = rudderAngle;
this.fairwaterAngle = fairwaterAngle;
this.momentOfInertia = momentOfInertia;
this.centerOfMass = centerOfMass;
this.submarineConstants = submarineConstants;
}
/**
* Gets the current total water mass inside the submarine.
* @returns {number} The current total water mass inside the submarine in cubic meters (m³).
*/
getCurrentTotalWaterMass() {
return this.currentTotalWaterMass;
}
/**
* Sets the current total water mass inside the submarine.
* @param {number} currentTotalWaterMass - The new current total water mass inside the submarine.
*/
setCurrentTotalWaterMass(currentTotalWaterMass) {
const maxTankCapacity = this.submarineConstants.getBallastTankCapacity() / 2;
const oldTotalWater = this.currentWaterMassFrontTank + this.currentWaterMassBackTank;
const totalAddedWater = currentTotalWaterMass - oldTotalWater;
// Distribute water change evenly
let newFrontTankWater = this.currentWaterMassFrontTank + totalAddedWater / 2;
let newBackTankWater = this.currentWaterMassBackTank + totalAddedWater / 2;
// Handle overflow and underflow for the front tank
if (newFrontTankWater > maxTankCapacity) {
const overflow = newFrontTankWater - maxTankCapacity;
newFrontTankWater = maxTankCapacity;
newBackTankWater += overflow;
}
else if (newFrontTankWater < 0) {
const underflow = newFrontTankWater;
newFrontTankWater = 0;
newBackTankWater += underflow;
}
// Handle overflow and underflow for the back tank
if (newBackTankWater > maxTankCapacity) {
const overflow = newBackTankWater - maxTankCapacity;
newBackTankWater = maxTankCapacity;
newFrontTankWater += overflow;
}
else if (newBackTankWater < 0) {
const underflow = newBackTankWater;
newBackTankWater = 0;
newFrontTankWater += underflow;
}
// Ensure tanks do not go below zero or above max capacity
this.currentWaterMassFrontTank = Math.min(Math.max(newFrontTankWater, 0), maxTankCapacity);
this.currentWaterMassBackTank = Math.min(Math.max(newBackTankWater, 0), maxTankCapacity);
this.currentTotalWaterMass = currentTotalWaterMass;
this.autoSetCenterOfMass();
}
/**
* Gets the current water mass in the front ballast tank.
* @returns {number} The current water mass in the front ballast tank in cubic meters (m³).
*/
getCurrentWaterMassFrontTank() {
return this.currentWaterMassFrontTank;
}
/**
* Sets the current water mass in the front ballast tank.
* @param {number} currentWaterMassFrontTank - The new current water mass in the front ballast tank.
*/
setCurrentWaterMassFrontTank(currentWaterMassFrontTank) {
this.currentTotalWaterMass = currentWaterMassFrontTank + this.getCurrentWaterMassBackTank();
this.currentWaterMassFrontTank = currentWaterMassFrontTank;
this.autoSetCenterOfMass();
}
/**
* Gets the current water mass in the back ballast tank.
* @returns {number} The current water mass in the back ballast tank in cubic meters (m³).
*/
getCurrentWaterMassBackTank() {
return this.currentWaterMassBackTank;
}
/**
* Sets the current water mass in the back ballast tank.
* @param {number} currentWaterMassBackTank - The new current water mass in the back ballast tank.
*/
setCurrentWaterMassBackTank(currentWaterMassBackTank) {
this.currentTotalWaterMass = currentWaterMassBackTank + this.getCurrentWaterMassFrontTank();
this.currentWaterMassBackTank = currentWaterMassBackTank;
this.autoSetCenterOfMass();
}
/**
* Automatically sets the center of mass of the submarine based on the water mass in ballast tanks.
* The center of mass is adjusted relative to the submarine's length and the difference in water mass
* between the front and back ballast tanks.
* This method calculates the center of mass based on the difference in water mass between the front
* and back ballast tanks. It adjusts the submarine's center of mass along the longitudinal axis (z-axis)
* to maintain stability and balance.
* @returns {void}
* @private
*/
autoSetCenterOfMass() {
const waterInFront = this.currentWaterMassFrontTank;
const waterInBack = this.currentWaterMassBackTank;
const max = this.submarineConstants.getBallastTankCapacity() / 2;
const diff = waterInFront - waterInBack;
const ratio = diff / max;
const position = ratio * (this.submarineConstants.getLength() / 4);
if (waterInFront >= waterInBack) {
this.setCenterOfMass(this.centerOfMass.set(0, 0, position));
}
else {
this.setCenterOfMass(this.centerOfMass.set(0, 0, position));
}
}
/**
* Gets the current rounds per second (RPS) of the rotor.
* @returns {number} The current rotor rounds per second (RPS).
*/
getCurrentRotorRPS() {
return this.currentRotorRPS;
}
/**
* Sets the current rounds per second (RPS) of the rotor.
* @param {number} currentRotorRPS - The new current rotor rounds per second (RPS).
*/
setCurrentRotorRPS(currentRotorRPS) {
this.currentRotorRPS = currentRotorRPS;
}
/**
* Gets the submerged volume of the submarine.
* @returns {number} The submerged volume of the submarine in cubic meters (m³).
*/
getSubmergedVolume() {
return this.submergedVolume;
}
/**
* Sets the submerged volume of the submarine.
* @param {number} submergedVolume - The new submerged volume of the submarine.
*/
setSubmergedVolume(submergedVolume) {
this.submergedVolume = submergedVolume;
}
/**
* Gets the current depth of the submarine.
* @returns {number} The current depth of the submarine in meters (m).
*/
getCurrentDepth() {
return this.currentDepth;
}
/**
* Sets the current depth of the submarine.
* @param {number} currentDepth - The new current depth of the submarine.
*/
setCurrentDepth(currentDepth) {
this.currentDepth = currentDepth;
}
/**
* Gets the current speed of the submarine.
* @returns {THREE.Vector3} The current speed of the submarine as a Vector3.
*/
getCurrentSpeed() {
return this.currentSpeed.clone();
}
/**
* Sets the current speed of the submarine.
* @param {THREE.Vector3} currentSpeed - The new current speed of the submarine as a Vector3.
*/
setCurrentSpeed(currentSpeed) {
this.currentSpeed.copy(currentSpeed);
}
/**
* Gets the current acceleration of the submarine.
* @returns {THREE.Vector3} The current acceleration of the submarine as a Vector3.
*/
getCurrentAcceleration() {
return this.currentAcceleration.clone();
}
/**
* Sets the current acceleration of the submarine.
* @param {THREE.Vector3} currentAcceleration - The new current acceleration of the submarine as a Vector3.
*/
setCurrentAcceleration(currentAcceleration) {
this.currentAcceleration.copy(currentAcceleration);
}
/**
* Gets the current position of the submarine.
* @returns {THREE.Vector3} The current position of the submarine in 3D space as a Vector3.
*/
getCurrentPosition() {
return this.currentPosition.clone();
}
/**
* Sets the current position of the submarine.
* @param {THREE.Vector3} currentPosition - The new current position of the submarine in 3D space as a Vector3.
*/
setCurrentPosition(currentPosition) {
this.currentPosition.copy(currentPosition);
}
/**
* Gets the current orientation of the submarine.
* @returns {THREE.Quaternion} The current orientation of the submarine.
*/
getCurrentOrientation() {
return this.currentOrientation.clone();
}
/**
* Sets the current orientation of the submarine.
* @param {THREE.Quaternion} currentOrientation - The new current orientation of the submarine.
*/
setCurrentOrientation(currentOrientation) {
this.currentOrientation.copy(currentOrientation);
}
/**
* Gets the current angular velocity of the submarine.
* @returns {THREE.Vector3} The current angular velocity of the submarine in radians per second (rad/s) as a Vector3.
*/
getAngularVelocity() {
return this.angularVelocity.clone();
}
/**
* Sets the current angular velocity of the submarine.
* @param {THREE.Vector3} angularVelocity - The new current angular velocity of the submarine in radians per second (rad/s) as a Vector3.
*/
setAngularVelocity(angularVelocity) {
this.angularVelocity.copy(angularVelocity);
}
/**
* Gets the current angular acceleration of the submarine.
* @returns {THREE.Vector3} The current angular acceleration of the submarine in radians per second squared (rad/s²) as a Vector3.
*/
getAngularAcceleration() {
return this.angularAcceleration.clone();
}
/**
* Sets the current angular acceleration of the submarine.
* @param {THREE.Vector3} angularAcceleration - The new current angular acceleration of the submarine in radians per second squared (rad/s²) as a Vector3.
*/
setAngularAcceleration(angularAcceleration) {
this.angularAcceleration.copy(angularAcceleration);
}
/**
* Gets the weight of the submarine.
* @returns {number} The weight of the submarine in newtons (N).
*/
getWeight() {
return this.weight;
}
/**
* Sets the weight of the submarine.
* @param {number} weight - The new weight of the submarine in newtons (N).
*/
setWeight(weight) {
this.weight = weight;
}
/**
* Gets the buoyancy force acting on the submarine.
* @returns {number} The buoyancy force acting on the submarine in newtons (N).
*/
getBuoyancy() {
return this.buoyancy;
}
/**
* Sets the buoyancy force acting on the submarine.
* @param {number} buoyancy - The new buoyancy force acting on the submarine in newtons (N).
*/
setBuoyancy(buoyancy) {
this.buoyancy = buoyancy;
}
/**
* Gets the drag force acting on the submarine.
* @returns {number} The drag force acting on the submarine in newtons (N).
*/
getDrag() {
return this.drag;
}
/**
* Sets the drag force acting on the submarine.
* @param {number} drag - The new drag force acting on the submarine in newtons (N).
*/
setDrag(drag) {
this.drag = drag;
}
/**
* Gets the thrust force produced by the submarine.
* @returns {number} The thrust force produced by the submarine in newtons (N).
*/
getThrust() {
return this.thrust;
}
/**
* Sets the thrust force produced by the submarine.
* @param {number} thrust - The new thrust force produced by the submarine in newtons (N).
*/
setThrust(thrust) {
this.thrust = thrust;
}
/**
* Gets the angle of the stern plane.
* @returns {number} The angle of the stern plane in radians (rad).
*/
getSternAngle() {
return this.sternAngle;
}
/**
* Sets the angle of the stern plane.
* @param {number} sternAngle - The new angle of the stern plane in radians (rad).
*/
setSternAngle(sternAngle) {
this.sternAngle = sternAngle;
}
/**
* Gets the angle of the rudder plane.
* @returns {number} The angle of the rudder plane in radians (rad).
*/
getRudderAngle() {
return this.rudderAngle;
}
/**
* Sets the angle of the rudder plane.
* @param {number} rudderAngle - The new angle of the rudder plane in radians (rad).
*/
setRudderAngle(rudderAngle) {
this.rudderAngle = rudderAngle;
}
/**
* Gets the angle of the fairwater plane.
* @returns {number} The angle of the fairwater plane in radians (rad).
*/
getFairwaterAngle() {
return this.fairwaterAngle;
}
/**
* Sets the angle of the fairwater plane.
* @param {number} fairwaterAngle - The new angle of the fairwater plane in radians (rad).
*/
setFairwaterAngle(fairwaterAngle) {
this.fairwaterAngle = fairwaterAngle;
}
/**
* Gets the moment of inertia of the submarine.
* @returns {THREE.Matrix3} The moment of inertia.
*/
getMomentOfInertia() {
return this.momentOfInertia;
}
/**
* Sets the moment of inertia of the submarine.
* @param {THREE.Matrix3} momentOfInertia - The new moment of inertia.
*/
setMomentOfInertia(momentOfInertia) {
this.momentOfInertia = momentOfInertia;
}
/**
* Gets the center of mass of the submarine.
* @returns {THREE.Vector3} The center of mass.
*/
getCenterOfMass() {
return this.centerOfMass;
}
/**
* Sets the center of mass of the submarine.
* @param {THREE.Vector3} centerOfMass - The new center of mass.
*/
setCenterOfMass(centerOfMass) {
this.centerOfMass = centerOfMass;
}
/**
* Gets the forward axis of the submarine in its current orientation.
*
* This method defines a unit vector in the direction of the submarine's forward axis (typically along the +z-axis),
* then rotates this vector according to the submarine's current orientation.
* @returns {THREE.Vector3} The forward axis of the submarine as a Vector3.
*/
getForwardAxis() {
// Define a unit vector in the direction of the submarine's forward axis
const forwardDirection = new THREE.Vector3(0, 0, 1); // Assuming initial forward is along +z-axis
// Rotate the forward direction vector by the submarine's orientation
forwardDirection.applyQuaternion(this.getCurrentOrientation());
return forwardDirection;
}
/**
* Gets the up axis of the submarine in its current orientation.
*
* This method defines a unit vector in the direction of the submarine's up axis (typically along the +y-axis),
* then rotates this vector according to the submarine's current orientation.
* @returns {THREE.Vector3} The up axis of the submarine as a Vector3.
*/
getUpAxis() {
// Define a unit vector in the direction of the submarine's forward axis
const upDirection = new THREE.Vector3(0, 1, 0); // Assuming initial forward is along +z-axis
// Rotate the forward direction vector by the submarine's orientation
upDirection.applyQuaternion(this.getCurrentOrientation());
return upDirection;
}
/**
* Gets the right axis of the submarine based on its current orientation.
*
* This method calculates the right axis (perpendicular to both the forward and up axes)
* by computing the cross product of the up and forward axes after rotation.
* @returns {THREE.Vector3} The right axis of the submarine as a Vector3.
*/
getRightAxis() {
const upAxis = this.getUpAxis();
const forwardAxis = this.getForwardAxis();
const rightAxis = upAxis.cross(forwardAxis);
return rightAxis;
}
/**
* Calculates the current mass of the submarine.
*
* This method computes the total mass of the submarine, which includes the current total water mass
* and the empty mass of the submarine defined by constants.
* @returns {number} The current mass of the submarine in newtons (N).
*/
getCurrentMass() {
return this.currentTotalWaterMass + this.submarineConstants.getEmptyMass();
}
/**
* Calculates the difference in water mass between the front and back ballast tanks.
*
* This method computes the absolute difference in water mass between the front and back ballast tanks.
* @returns {number} The difference in water mass between the front and back ballast tanks in cubic meters (m³).
*/
getTanksDifferenceMass() {
return Math.max(this.currentWaterMassFrontTank, this.currentWaterMassBackTank) - Math.min(this.currentWaterMassFrontTank, this.currentWaterMassBackTank);
}
}
export default SubmarineState;