diff --git a/build/Vessel.js b/build/Vessel.js index 0501576..a6d8494 100644 --- a/build/Vessel.js +++ b/build/Vessel.js @@ -1,4 +1,4 @@ -//Vessel.js library, built 2017-10-17 12:23:09.339097, Checksum: 5b20e5739dc8e9c7a5c69904053ad53c +//Vessel.js library, built 2017-11-10 12:21:12.376049, Checksum: 3162da26a8bf9803d2eabf6c27b72fb4 /* Import like this in HTML: @@ -33,11 +33,16 @@ function vecNormSquared(v) { return v.x**2+v.y**2+v.z**2; } +/*Adds two or more vectors given as individual parameters, +and returns a new vector that is the component-wise +sum of the input vectors.*/ function addVec(u,v, ...rest) { if (rest.length > 0) return sumVec([u,v]+rest); return {x: u.x+v.x, y: u.y+v.y, z: u.z+v.z}; } +//Takes an array of vectors as input, and returns a new vector +//that is the component-wise sum of the input vectors. function sumVec(vectors) { let S = {x:0, y:0, z:0}; for (let i = 0; i < vectors.length; i++) { @@ -49,6 +54,12 @@ function sumVec(vectors) { return S; } +//Takes two vector parameters u,v, and returns the vector u-v. +function subVec(u,v) { + //return addVec(u, scaleVec(v, -1)); //equivalent + return {x: u.x-v.x, y: u.y-v.y, z: u.z-v.z}; +} + function dotProduct(u,v) { return u.x*v.x + u.y*v.y + u.z*v.z; } @@ -63,22 +74,6 @@ function crossProduct(u,v) { //Some interpolation helpers. Only linear and bilinear for now. -//linear interpolation -//Defaults are not finally decided -//returns NaN if a and b are NaN or mu is NaN. -function lerp(a, b, mu=0.5) { - if (isNaN(a)) return b; - if (isNaN(b)) return a; - return (1-mu)*a+mu*b; -} - -//Test. Not safe yet. -function linearFromArrays(xx, yy, x) { - let {index, mu} = bisectionSearch(xx, x); - if (index === undefined || mu === undefined) return 0; - return lerp(yy[index], yy[index+1], mu); -} - /*Function that takes a sorted array as input, and finds the last index that holds a numerical value less than, or equal to, a given value. Returns an object with the index and an interpolation parameter mu that gives the position of value between index and index+1. */ @@ -105,11 +100,29 @@ function bisectionSearch(array, value) { return {index, mu}; } +//linear interpolation +//Defaults are not finally decided +//returns NaN if a and b are NaN or mu is NaN. +function lerp(a, b, mu=0.5) { + if (isNaN(a)) return b; + if (isNaN(b)) return a; + return (1-mu)*a+mu*b; +} + +//Test. Not safe yet. +function linearFromArrays(xx, yy, x) { + let {index, mu} = bisectionSearch(xx, x); + if (index === undefined || mu === undefined) return 0; + return lerp(yy[index], yy[index+1], mu); +} + +//Source: https://en.wikipedia.org/wiki/Bilinear_interpolation +//(I have used other sources too) function bilinearUnitSquareCoeffs(z00, z01, z10, z11) { - let a00 = z00; - let a10 = z10-z00; - let a01 = z01-z00; - let a11 = z11+z00-z01-z10; + let a00 = z00; //mux=muy=0 + let a10 = z10-z00; //mux=1, muy=0 + let a01 = z01-z00; //mux=0, muy=1 + let a11 = z11+z00-z01-z10; //mux=muy=1 return [a00,a10,a01,a11]; } @@ -120,7 +133,7 @@ function bilinearUnitSquare(z00, z01, z10, z11, mux, muy) { //Find coefficients for 1, x, y, xy. //This doesn't yet handle zero-lengths well. -function bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22) { +function bilinearCoeffs(x1, x2, y1, y2, z00, z01, z10, z11) { let X = (x2-x1); let Y = (y2-y1); @@ -132,13 +145,13 @@ function bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22) { let Ainv = 1/(X*Y); //constant coeff: - let b00 = Ainv*(z11*x2*y2 - z21*x1*y2 - z12*x2*y1 + z22*x1*y1); + let b00 = Ainv*(z00*x2*y2 - z10*x1*y2 - z01*x2*y1 + z11*x1*y1); //x coeff: - let b10 = Ainv*(-z11*y2 + z21*y2 + z12*y1 - z22*y1); + let b10 = Ainv*(-z00*y2 + z10*y2 + z01*y1 - z11*y1); //y coeff: - let b01 = Ainv*(-z11*x2 + z21*x1 + z12*x2 -z22*x1); + let b01 = Ainv*(-z00*x2 + z10*x1 + z01*x2 -z11*x1); //xy coeff: - let b11 = Ainv*(z11-z21-z12+z22); + let b11 = Ainv*(z00-z10-z01+z11); return [b00,b10,b01,b11]; } @@ -149,17 +162,22 @@ function bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22) { function bilinear(x1, x2, y1, y2, z11, z12, z21, z22, x, y) { let [b00, b10, b01, b11] = bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22); - return b00 + b10*x + b01*y + b11*x*y; - //The following is supposed to be equivalent. Maybe I should compare, to make sure that the current calculation is correct. + let fromCoeffs = b00 + b10*x + b01*y + b11*x*y; + + //The following is supposed to be equivalent. Some tests yielding identical results (and no tests so far yielding different results) suggest that the calculations are in fact equivalent. /*let mux = (x-x1)/(x2-x1); let muy = (y-y1)/(y2-y1); - return bilinearUnitSquare(z11, z12, z21, z22, mux, muy);*/ + let fromUnitSquare = bilinearUnitSquare(z11, z12, z21, z22, mux, muy); + + console.log("fromCoeffs=", fromCoeffs, ", fromUnitSquare=", fromUnitSquare);*/ + + return fromCoeffs; } //@EliasHasle //All inputs are numbers. The axes are given by a single coordinate. function steiner(I, A, sourceAxis, targetAxis) { - return I + A*(sourceAxis-targetAxis)^2; + return I + A*(sourceAxis-targetAxis)**2; } //Calculate area, center, Ix, Iy. @@ -174,18 +192,18 @@ function trapezoidCalculation(xbase0, xbase1, xtop0, xtop1, ybase, ytop) { let yc = (a==0 && b==0) ? ybase+0.5*h : ybase + h*(2*a+b)/(3*(a+b)); let d = xbase0+0.5*a; //shorthand let xc = h===0 ? 0.25*(xbase0+xbase1+xtop0+xtop1) : d + (xtop0+0.5*b-d)*(yc-ybase)/h; - let Ix = (a==0 && b== 0) ? 0 : h^3*(a^2+4*a*b+b^2)/(36*(a+b)); + let Ix = (a==0 && b== 0) ? 0 : h**3*(a**2+4*a*b+b**2)/(36*(a+b)); //For Iy I must decompose (I think negative results will work fine): let Art1 = 0.5*(xtop0-xbase0)*h; let xcrt1 = xbase0 + (xtop0-xbase0)/3; - let Iyrt1 = (xtop0-xbase0)^3*h/36; + let Iyrt1 = (xtop0-xbase0)**3*h/36; let Arec = (xbase1-xtop0)*h; let xcrec = 0.5*(xtop0+xbase1); - let Iyrec = (xbase1-xtop0)^3*h/12; + let Iyrec = (xbase1-xtop0)**3*h/12; let Art2 = 0.5*(xbase1-xtop1)*h; let xcrt2 = (xtop1 + (xbase1-xtop1)/3); - let Iyrt2 = (xbase1-xtop1)^3*h/36; + let Iyrt2 = (xbase1-xtop1)**3*h/36; let Iy = steiner(Iyrt1, Art1, xcrt1, xc) + steiner(Iyrec, Arec, xcrec, xc) @@ -227,6 +245,7 @@ function combineAreas(array) { yc /= A; } else { console.warn("Zero area combination."); + console.trace(); xc /= L; yc /= L; } @@ -242,10 +261,8 @@ function combineAreas(array) { //x and y here refers to coordinates in the plane that is being calculated on. function sectionCalculation({xs, ymins, ymaxs}) { - console.groupCollapsed("sectionCalculation"); + console.group/*Collapsed*/("sectionCalculation"); console.info("Arguments (xs, ymins, ymaxs): ", arguments[0]); - - //Needed for Cwp (not a very efficient calculation, maybe): let calculations = []; for (let i = 0; i < xs.length-1; i++) { @@ -265,71 +282,11 @@ function sectionCalculation({xs, ymins, ymaxs}) { console.info("Output: ", output); console.groupEnd(); return output; -}//@EliasHasle - -function bilinearPatchColumnCalculation(x1, x2, y1, y2, z11, z12, z21, z22) { - let X = x2-x1; - let Y = y2-y1; - let [a00, a10, a01, a11] = bilinearUnitSquareCoeffs(z11, z12, z21, z22); - /* - From here I call mux for x, and muy for y. - Integral over unit square: - INT[x from 0 to 1, INT[y from 0 to 1, (a00 + a10*x + a01*y + a11*x*y) dy] dx] - = INT[x from 0 to 1, (a00+a10*x+0.5*a01+0.5*a11*x) dx] - = a00 + 0.5*a10 + 0.5*a01 + 0.25*a11 - */ - let Ab = X*Y; - let zAvg = (a00 + 0.5*a10 + 0.5*a01 + 0.25*a11); - let V = Math.abs(Ab*zAvg); //new: absolute value - let zc = 0.5*zAvg; - /* - To find xc, I need to integrate x*z over the unit square, and scale and translate to world coordinates afterwards: - INT[x from 0 to 1, (a00+a10*x+0.5*a01+0.5*a11*x)*x dx] - = 0.5*a00 + a10/3 + 0.25*a01 + a11/6 - Scale and translate:*/ - let xc = y1 + X*(0.5*a00 + a10/3 + 0.25*a01 + a11/6) - - //Similar for yc: - let yc = y1 + Y*(0.5*a00 + 0.25*a10 + a01/3 + a11/6) - - //new: absolute value (OK?) - let As = Math.abs(bilinearArea(x1, x2, y1, y2, z11, z12, z21, z22)); - - return {Ab: Ab, As: As, V: V, Cv: {x: xc, y: yc, z: zc}}; -} - -//Input: array of objects with calculation results for elements. -//Output: the combined results. -function combineVolumes(array) { - let V = 0; - let As = 0; - let Cv = {x:0, y:0, z:0}; - let L = array.length; - if (L===0) return {V,As,Cv}; - for (let i = 0; i < L; i++) { - let e = array[i]; - V += e.V; - As += e.As; //typically wetted area - Cv.x += e.Cv.x*e.V; - Cv.y += e.Cv.y*e.V; - Cv.z += e.Cv.z*e.V; - } - //Safe zero check? - if (V!==0) { - Cv.x /= V; - Cv.y /= V; - Cv.z /= V; - } else { - console.warn("Zero volume combination."); - Cv.x /= L; - Cv.y /= L; - Cv.z /= L; - } - - return {V,As,Cv};//{V: V, As: As, Cv: Cv}; } //For wetted area. I think this is right, but it is not tested. +//The numerical integral will not scale well with larger geometries. +//Then the full analytical solution is needed. function bilinearArea(x1, x2, y1, y2, z11, z12, z21, z22, segs=10) { let [b00,b10,b01,b11] = bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22); /* @@ -343,6 +300,8 @@ function bilinearArea(x1, x2, y1, y2, z11, z12, z21, z22, segs=10) { Tx X Ty = (-(b10+b11*y), -(b01+b11*x), 1) |Tx X Ty| = sqrt((b10+b11*y)^2 + (b01+b11*x)^2 + 1) + Now, to get the area I need to integrate |Tx X Ty| over X,Y. + Wolfram Alpha gave me this for the inner integral using x (indefinite): integral sqrt((b01 + b11 x)^2 + 1 + (b10+b11*y)^2) dx = ((b01 + b11*x) sqrt((b01 + b11*x)^2 + 1 + (b10+b11*y)^2) + (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x))/(2*b11) + constant That means this for the definite integral: @@ -381,7 +340,112 @@ function bilinearArea(x1, x2, y1, y2, z11, z12, z21, z22, segs=10) { A *= X*Y/(N*M); //dx dy return A; -}//@MrEranwe +} + +/*Calculates the (arithmetic) average of the area of the two possible triangulations of the quad element (using two triangles). +This requires the base of the quad to be convex. If the base is arrowhead shaped, +The calculation will fail in undefined ways. +*/ +function elementArea(v1,v2,v3,v4) { + let A1 = Math.abs(signedTriangleArea(v1,v2,v3)) + Math.abs(signedTriangleArea(v3,v4,v1)); + let A2 = Math.abs(signedTriangleArea(v2,v3,v4)) + Math.abs(signedTriangleArea(v4,v1,v2)); + let A = 0.5*(A1+A2); + return A; +} + +function signedTriangleArea(v1,v2,v3) { + let u = subVec(v2,v1); + let v = subVec(v3,v1); + let c = crossProduct(u,v); + let A = 0.5*vecNorm(c); + return A; +}//@EliasHasle + +//I have been doing some tests here of a simplified calculation. +//The results so far indicate that, for the prism hull, the results are almost identical, except that with the simple calculation the center of volume is almost right (but wrong enough to disqualify such a simple calculation). +/*Note that the coordinate system used here has xy as a grid, with z as heights on the grid, but in the intended application, which is calculations on transverse hull offsets, this z corresponds to the vessel y axis, and y corresponds to the vessel z axis. In any application of this function, the conversion between coordinate systems must be taken care of appropriately.*/ + // xy +function patchColumnCalculation(x1, x2, y1, y2, z00, z01, z10, z11) { + //VOLUME: + //Analysis based on a bilinear patch: + // /* + // From here I call mux for x, and muy for y. + // Integral over unit square: + // INT[x from 0 to 1, INT[y from 0 to 1, (a00 + a10*x + a01*y + a11*x*y) dy] dx] + // = INT[x from 0 to 1, (a00+a10*x+0.5*a01+0.5*a11*x) dx] + // = a00 + 0.5*a10 + 0.5*a01 + 0.25*a11 + // Note that by expanding a00,a10,a01,a11, it is demonstrated that this (rather unsurprisingly) is exactly equivalent to taking the average z offset of the control points. + // */ + let X = x2-x1; + let Y = y2-y1; + let Ab = X*Y; //area of base of patch column + //let zAvg = (a00 + 0.5*a10 + 0.5*a01 + 0.25*a11); + let zAvg = 0.25*(z00+z01+z10+z11); //equivalent + let V = Math.abs(Ab*zAvg); //works + + //CENTER OF VOLUME + let zc = 0.5*zAvg; + + //Very approximate center of volume + //(does not account for different signs on z values, + //but that should be OK for hull offsets) + //let xc = (x1*(z00+z01)+x2*(z10+z11))/((z00+z01+z10+z11) || 1); + //let yc = (y1*(z00+z10)+y2*(z01+z11))/((z00+z01+z10+z11) || 1); + + // /* + // To find xc properly, I need to integrate x*z over the unit square, divide by zAvg(?) and scale and translate to ship coordinates afterwards: + // INT[x from 0 to 1, INT[y from 0 to 1, x*(a00 + a10*x + a01*y + a11*x*y) dy] dx] = + // INT[x from 0 to 1, INT[y from 0 to 1, (a00*x + a10*x^2 + a01*xy + a11*x^2*y) dy] dx] = + // INT[x from 0 to 1, (a00*x + a10*x^2 + 0.5*a01*x + 0.5*a11*x^2) dx] + // = (0.5*a00 + a10/3 + 0.25*a01 + a11/6) + //Trying to expand the coeffs to original z offsets: + // = (0.5*z00 + (z10-z00)/3 + 0.25*(z01-z00) + (z00+z00-z01-z10)/6) + // = ((1/12)*z00 + (1/6)*z10 + (1/12)*z01 + (1/6)*z00) + //Divide by zAvg to get muxc, then scale and translate to xc. + let xc = x1+X*(((1/12)*z00 + (1/6)*z10 + (1/12)*z01 + (1/6)*z11) / (zAvg || 1)); + //console.log("x1=%.2f, X=%.2f, muxc = %.2f", x1, X, (((1/12)*z00 + (1/6)*z10 + (1/12)*z01 + (1/6)*z11) / (zAvg || 1))); + //Similar for yc (modified symmetrically) + let yc = y1+Y*(((1/12)*z00 + (1/12)*z10 + (1/6)*z01 + (1/6)*z11) / (zAvg || 1)); + let [a00, a10, a01, a11] = bilinearUnitSquareCoeffs(z00, z01, z10, z11); + + //console.log("Patch column Cv = (%.2f, %.2f, %.2f)", xc,yc,zc); + + //AREA + //These two methods give very similar results, within about 1% difference for the fishing boat hull (used in PX121.json). + //Simple triangle average approximation for area (works) + /*let As = elementArea( + {x: x1, y: y1, z: z00}, + {x: x1, y: y2, z: z01}, + {x: x2, y: y1, z: z10}, + {x: x2, y: y2, z: z11});*/ + //Bilinear area calculation. Works too, but is currently numerical, and quite complex (which means it is bug-prone and hard to maintain). But it is more exact, even with just a few segments for numerical integration (the last, optional, parameter) + let As = Math.abs(bilinearArea(x1, x2, y1, y2, z00, z01, z10, z11, 10)); + + return {Ab: Ab, As: As, V: V, Cv: {x: xc, y: yc, z: zc}}; +} + +//Input: array of objects with calculation results for elements. +//Output: the combined results. +function combineVolumes(array) { + let V = 0; + let As = 0; + let Cv = {x:0, y:0, z:0}; + let L = array.length; + //if (L===0) return {V,As,Cv}; + for (let i = 0; i < L; i++) { + let e = array[i]; + V += e.V; + As += e.As; //typically wetted area + //console.log(e.Cv); + Cv = addVec(Cv, scaleVec(e.Cv, e.V)); + } + Cv = scaleVec(Cv, 1/(V || L || 1)); + + //console.info("combineVolumes: Combined Cv is (" + Cv.x + ", " + Cv.y + ", " + Cv.z + ")."); + + return {V,As,Cv};//{V: V, As: As, Cv: Cv}; +} +//@MrEranwe //@EliasHasle "use strict"; @@ -624,7 +688,7 @@ Object.assign(Ship.prototype, { constructor: Ship, setFromSpecification: function(specification) { this.attributes = specification.attributes || {}; - this.structure = new Structure(specification.structure,this); + this.structure = new Structure(specification.structure/*,this*/); //baseObjects and derivedObjects are arrays in the specification, but are objects (hashmaps) in the constructed ship object: this.baseObjects = {}; for (let i = 0; i < specification.baseObjects.length; i++) { @@ -652,6 +716,8 @@ Object.assign(Ship.prototype, { return specification; }, + //This should probably be separated in lightweight and deadweight + //Then this function should be replaced by a getDisplacement getWeight: function(shipState) { shipState = shipState || this.designState; @@ -672,6 +738,7 @@ Object.assign(Ship.prototype, { console.info("Calculated weight object: ", W); return W; }, + //This should just take displacement as parameter instead. (later, soon) calculateDraft(shipState, epsilon=0.001) { let w = this.getWeight(shipState); let M = w.mass; @@ -690,27 +757,25 @@ Object.assign(Ship.prototype, { console.info("Calculated draft: %.2f", t); return t; }, + //Should separate between longitudinal and transverse GM too calculateStability(shipState){ let T = this.calculateDraft(shipState); let ha = this.structure.hull.calculateAttributesAtDraft(T); let vol = ha.Vs; - if (vol === 0){ - let Lwl = this.designState.calculationParameters.LWL_design; - let B = this.structure.hull.attributes.BOA; - let cb = this.designState.calculationParameters.Cb_design; - vol = Lwl * B * T * cb; - } let KG = this.getWeight(shipState).cg.z; - let I = ha.Iywp * 1000; - let KB = 0.52 * T; - let BM = I / vol; - let GM = KB + BM - KG; - return {GM, KB, BM, KG}; + let Ix = ha.Ixwp; + let Iy = ha.Iywp; + let KB = ha.Cv.z; + let BMT = Ix / vol; + let BML = Iy / vol; + let GMT = KB + BMT - KG; + let GML = KB + BML - KG; + return {GMT, GML, GM: T, KB, BMT, BML, BM: BMT, KG}; } });//@EliasHasle -function Structure(spec, ship) { - this.ship = ship; +function Structure(spec/*, ship*/) { + //this.ship = ship; JSONSpecObject.call(this, spec); } Structure.prototype = Object.create(JSONSpecObject.prototype); @@ -855,107 +920,99 @@ Object.assign(Hull.prototype, { return output; }, /* + Testing new version without nanCorrectionMode parameter, that defaults to setting lower NaNs to 0 and extrapolating highest data entry for upper NaNs (if existant, else set to 0). Inner NaNs will also be set to zero. + Input: z: level from bottom of ship (absolute value in meters) - nanCorrectionMode: 0 to set all NaNs to zero, 1 to output NaNs, set all NaNs to zero, 2 to replace NaNs with interpolated or extrapolated values. + + Output: + Array representing waterline offsets for a given height from the keel (typically a draft). */ - getWaterline: function(z, nanCorrectionMode=1) { + getWaterline: function(z) { let ha = this.attributes; - let zr = z/ha.Depth; - let wls = this.halfBreadths.waterlines; + let zr = z/ha.Depth; //using zr requires fewer operations and less memory than a scaled copy of wls. + let wls = this.halfBreadths.waterlines;//.map(wl=>wl*ha.Depth); let sts = this.halfBreadths.stations; let tab = this.halfBreadths.table; - let {index: a, mu: mu} = bisectionSearch(wls, zr); - let wl; - if (a<0) { - if (nanCorrectionMode===0) { - console.warn("getWaterLine: z below lowest defined waterline. Defaulting to zeros."); + if (zr/*=*/wls.length-1) { - if (nanCorrectionMode===0) { - console.warn("getWaterLine: z above highest defined waterline. Defaulting to zeros."); - return new Array(sts.length).fill(0); - } - if (nanCorrectionMode===1) { - console.warn("getWaterLine: z above highest defined waterline. Outputting NaNs."); - return new Array(sts.length).fill(null); - } - else /*nanCorrectionMode===2*/ { - console.warn("getWaterLine: z above highest defined waterline. Proceeding with highest data entry."); + } else { + let a, mu; + if (zr>wls[wls.length-1]) { + console.warn("getWaterLine: z above highest defined waterline. Proceeding with highest data entries."); a = wls.length-2; //if this level is defined... mu=1; //wl = tab[a].slice(); - } - } - - //Linear interpolation between data waterlines - wl = new Array(sts.length); - for (let j = 0; j < wl.length; j++) { - if (nanCorrectionMode === 0) { - if (a+1 > wls.length-1) { - wl[j] = lerp(tab[a][j], 0, 0.5); - } else { - wl[j] = lerp(tab[a][j] || 0, tab[a+1][j] || 0, mu || 0.5); - } - } else if (nanCorrectionMode === 1) { - if (a+1 > wls.length-1) { - wl[j] = lerp(tab[a][j], null, mu); - } else { - wl[j] = lerp(tab[a][j], tab[a+1][j], mu); - } } else { - //If necessary, sample from below - let b = a; - while (b>0 && isNaN(tab[b][j])) { - b--; + ({index: a, mu: mu} = bisectionSearch(wls, zr)); + if (a === wls.length-1) { + a = wls.length-2; + mu = 1; } - let lower; - if (b===0 && isNaN(tab[b][j])) { - lower = 0; + } + + //Try to do linear interpolation between closest data waterlines, but handle null values well: + let wl = new Array(sts.length); + for (let j = 0; j < wl.length; j++) { + let lower, upper; + let b = a; + //Find lower value for interpolation + if (!isNaN(tab[b][j])) { + lower = tab[b][j]; } else { - lower = tab[b][j]; + b = a+1; + while(b < wls.length && isNaN(tab[b][j])) { + b++; + } + if (b !== wls.length) { + //Inner NaN + lower = 0; + } else { + //Upper NaN, search below: + b = a-1; + while (b >= 0 && isNaN(tab[b][j])) { + b--; + } + if (b===-1) { + //No number found: + lower = 0; + upper = 0; + } else { + lower = tab[b][j]; + upper = lower; + } + } } - //If necesary, sample from above + //Find upper value for interpolation let c = a+1; - let upper; - if (c>wls.length-1) { - c = b; - upper = lower; + if (upper !== undefined) {/*upper found above*/} + else if (!isNaN(tab[c][j])) { + upper = tab[c][j]; } else { - while (cwls.length-1 before the loop. - if (c===wls.length-1 && isNaN(tab[c][j])) { - //Fall back all the way to b - c = b; - upper = lower; - } else { + if (c === wls.length) upper = lower; + else { upper = tab[c][j]; } } - mu = c===b ? 0 : (a+(mu||0.5)-b)/(c-b); + //Linear interpolation wl[j] = lerp(lower, upper, mu); + //Scale numerical values + if (!isNaN(wl[j])) wl[j] *= 0.5*ha.BOA; } - - //Scale numerical values - if (!isNaN(wl[j])) wl[j] *= 0.5*ha.BOA; - } - return wl; + } }, getStation: function(x) { let ha = this.attributes; @@ -990,14 +1047,14 @@ Object.assign(Hull.prototype, { //THIS is a candidate for causing wrong Ix, Iy values. //Much logic that can go wrong. - //typically deck bounds + //typically deck bounds waterlineCalculation: function(z, bounds) { let {minX, maxX, minY, maxY} = bounds || {}; - console.groupCollapsed("waterlineCalculation."); + console.group/*Collapsed*/("waterlineCalculation."); console.info("Arguments: z=", z, " Boundaries: ", arguments[1]); - let wl = this.getWaterline(z, 0); + let wl = this.getWaterline(z); console.info("wl: ", wl); //DEBUG let LOA = this.attributes.LOA; @@ -1007,8 +1064,8 @@ Object.assign(Hull.prototype, { sts[i] *= LOA; } - let hasMinX = (minX !== undefined); - let hasMaxX = (maxX !== undefined); + let hasMinX = (minX !== undefined) && minX!==sts[0]; + let hasMaxX = (maxX !== undefined) && maxX!==sts[sts.length-1]; if (hasMinX || hasMaxX) { let first=0; let wlpre; @@ -1050,7 +1107,7 @@ Object.assign(Hull.prototype, { } } - //This does not yet account for undefined minY, maxY. Or does it? + //This does not yet account properly for undefined minY, maxY. let port = [], star = []; for (let i=0; ithis.attributes.Depth*wl); let port = this.getStation(x); + if (!isNaN(maxZ)) { + let {index, mu} = bisectionSearch(wls, maxZ); + if (index < wls.length-1) { + wls[index+1] = lerp(wls[index], wls[index+1], mu); + port[index+1] = lerp(port[index], port[index+1], mu); + wls = wls.slice(0,index+2); + port = port.slice(0,index+2); + } + } let star = port.map(hb=>-hb); + let sc = sectionCalculation({xs: wls, ymins: star, ymaxs: port}); return { x: x, //or xc? or cg.. Hm. @@ -1107,14 +1175,15 @@ Object.assign(Hull.prototype, { A: sc.A, Iz: sc.Ix, Iy: sc.Iy, - maxX: sc.maxX, - minX: sc.minX, + maxZ: sc.maxX, + minZ: sc.minX, maxY: sc.maxY, minY: sc.minY }; }, - //Unoptimized, some redundant repetitions of calculations. - //NOT DONE YET. Outputs lots of NaN values. + + //NOT DONE YET. Many bugs are fixed, but the volume center calculation is broken. The bilinear volume and area calculations have been temporarily replaced with simpler (and worse) calculations, and at least the volume and volume center calculations should be revived soon. + //Important: calculateAttributesAtDraft takes one mandatory parameter T. (The function defined here is immediately called during construction of the prototype, and returns the proper function.) calculateAttributesAtDraft: function() { function levelCalculation(hull, z, @@ -1133,61 +1202,97 @@ Object.assign(Hull.prototype, { Cv: {x:0, y:0, z:0} }) { - let wlc = hull.waterlineCalculation(z); + let wlc = hull.waterlineCalculation(z,{}); let lev = {}; Object.assign(lev, wlc); //Projected area calculation (approximate): - lev.prMinY = wlc.minY || 0; - lev.prMaxY = wlc.maxY || 0; //|| 0 right? - lev.Ap = prev.Ap - + trapezoidCalculation(prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, lev.z)["A"]; + lev.prMinY = wlc.minY; + lev.prMaxY = wlc.maxY; + //DEBUG: + //console.info("prev.Ap = ", prev.Ap); + //console.info("Parameters to trapezoidCalculation: (%.2f, %.2f, %.2f, %.2f, %.2f, %.2f)", prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, z); + let AT = trapezoidCalculation(prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, z)["A"]; + //console.log("Calculated area of trapezoid: ", AT); + lev.Ap = prev.Ap + AT; + //lev.Ap = prev.Ap + // + trapezoidCalculation(prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, z)["A"]; + //DEBUG END + //level bounds are for the bounding box of the submerged part of the hull - if (!isNaN(prev.minX) && prev.minX<=wlc.minX) + if (!isNaN(wlc.minX) && wlc.minX<=prev.minX) + lev.minX = wlc.minX; + else lev.minX = prev.minX; - if (!isNaN(prev.maxX) && prev.maxX>=wlc.maxX) + if (!isNaN(wlc.maxX) && wlc.maxX>=prev.maxX) + lev.maxX = wlc.maxX; + else lev.maxX = prev.maxX; - if (!isNaN(prev.minY) && prev.minY<=wlc.minY) + if (!isNaN(wlc.minY) && wlc.minY<=prev.minY) + lev.minY = wlc.minY; + else lev.minY = prev.minY; - if (!isNaN(prev.maxY) && prev.maxY>=wlc.maxY) + if (!isNaN(wlc.maxY) && wlc.maxY>=prev.maxY) + lev.maxY = wlc.maxY; + else lev.maxY = prev.maxY; + lev.Vbb = (lev.maxX-lev.minX)*(lev.maxY-lev.minY)*z; + //Keep level maxX and minX for finding end cap areas: + lev.maxXwp = wlc.maxX; + lev.minXwp = wlc.minX; + //Find bilinear patches in the slice, and combine them. //Many possibilities for getting the coordinate systems wrong. let calculations = []; - //let wls = hull.halfBreadths.waterlines.map(wl=>wl*hull.attributes.Depth); let sts = hull.halfBreadths.stations.map(st=>st*hull.attributes.LOA); - let wl = hull.getWaterline(z,0); - let prwl = hull.getWaterline(prev.z,0); + let wl = hull.getWaterline(z); + let prwl = hull.getWaterline(prev.z); for (let j = 0; j < sts.length-1; j++) { let port = - bilinearPatchColumnCalculation(sts[j], sts[j+1], prev.z, z, -prwl[j], -wl[j], -prwl[j+1], -wl[j+1]); + patchColumnCalculation(sts[j], sts[j+1], prev.z, z, -prwl[j], -wl[j], -prwl[j+1], -wl[j+1]); calculations.push(port); let star = - bilinearPatchColumnCalculation(sts[j], sts[j+1], prev.z, z, prwl[j], wl[j], prwl[j+1], wl[j+1]); + patchColumnCalculation(sts[j], sts[j+1], prev.z, z, prwl[j], wl[j], prwl[j+1], wl[j+1]); calculations.push(star); } + console.log(calculations); //DEBUG let C = combineVolumes(calculations); + //Cv of slice. Note that switching of yz must + //be done before combining with previous level + let Cv = {x: C.Cv.x, y: C.Cv.z, z: C.Cv.y}; + lev.Vs = prev.Vs + C.V; //hull volume below z lev.As = prev.As + C.As; //outside surface below z - //center of volume below z (some potential for accumulated rounding error): - let Cv = addVec(scaleVec(prev.Cv,prev.Vs), - scaleVec(C.Cv,C.V)); - let V = prev.Vs+C.V; - if (V!==0) { - Cv = scaleVec(Cv, 1/(prev.Vs+C.V)); - } - //Note switching of yz - lev.Cv = {x: Cv.x, y: Cv.z, z: Cv.y}; + //End caps: + if (lev.minXwp <= sts[0]) + lev.As += hull.stationCalculation(lev.minXwp, z)["A"]; + if (lev.maxXwp >= sts[sts.length-1]) + lev.As += hull.stationCalculation(lev.maxXwp, z)["A"]; + + //center of volume below z (some potential for accumulated rounding error when calculating an accumulated average like this): + lev.Cv = scaleVec(addVec( + scaleVec(prev.Cv,prev.Vs), + scaleVec(Cv,C.V) + ), 1/(lev.Vs || 2)); lev.Cb = lev.Vs/lev.Vbb; + lev.Cp = lev.Vs/(lev.Ap*(lev.maxX-lev.minX)); return lev; } + //Here is the returned function calculateAttributesAtDraft(T): return function(T) { + if (isNaN(T)) { + console.error("Hull.prototype.calculateAttributesAtDraft(T): No draft specified. Returning undefined."); + return; + } else if (T<0 || T>this.attributes.Depth) { + console.error("Hull.prototype.calculateAttributesAtDraft(T): Draft parameter " + T + "outside valid range of [0,Depth]. Returning undefined."); + } + let wls = this.halfBreadths.waterlines.map(wl=>this.attributes.Depth*wl); //This is the part that can be reused as long as the geometry remains unchanged: @@ -1201,14 +1306,18 @@ Object.assign(Hull.prototype, { this.levelsNeedUpdate = false; } - //Find highest data waterline below water: - let {index: previ} = bisectionSearch(wls, T); + //Find highest data waterline below or at water level: + let {index, mu} = bisectionSearch(wls, T); - let lc = levelCalculation(this, T, this.levels[previ]); + console.info("Highest data waterline below or at water level: " + index); + console.log(this.levels); + let lc; + if (mu===0) lc = this.levels[index]; + else lc = levelCalculation(this, T, this.levels[index]); //Filter and rename for output return { - xcwp: lc.xc, + xcwp: lc.xc, //water plane values ycwp: lc.yc, Awp: lc.Awp, Ixwp: lc.Ix, @@ -1221,12 +1330,13 @@ Object.assign(Hull.prototype, { LWL: lc.LWL, LBP: lc.LBP, BWL: lc.BWL, - Ap: lc.Ap, + Ap: lc.Ap, //projected area in length direction + Cp: lc.Cp, //prismatic coefficient //Vbb: lc.Vbb, - Vs: lc.Vs, + Vs: lc.Vs, //volume of submerged part of the hull Cb: lc.Cb, - As: lc.As, - Cv: lc.Cv + As: lc.As, //wetted area + Cv: lc.Cv //center of buoyancy } }; }() @@ -1646,7 +1756,8 @@ Object.assign(Vessel, { loadShip: loadShip, downloadShip: downloadShip, f: { - linearFromArrays: linearFromArrays + linearFromArrays: linearFromArrays, + bilinear: bilinear } }); })(); diff --git a/build/archive/Vessel_201710180913.98f5c.js b/build/archive/Vessel_201710180913.98f5c.js new file mode 100644 index 0000000..c684278 --- /dev/null +++ b/build/archive/Vessel_201710180913.98f5c.js @@ -0,0 +1,1653 @@ +//Vessel.js library, built 2017-10-18 09:13:35.951607, Checksum: 98f5cf6e023f4efb329738cead04ff77 +/* +Import like this in HTML: + +Then in javascript use classes and functions with a ShipDesign prefix. Example: +let ship = new Vessel.Ship(someSpecification); +*/ + +"use strict"; + +var Vessel = {}; +(function() { +//@EliasHasle + +//Some small helpers for operations on 3D vectors +//A vector is simply defined as an object with properties x,y,z. +//Written by Elias Hasle + +function scaleVec(v, s) { + return {x: s*v.x, y: s*v.y, z: s*v.z}; +} + +function vecNorm(v) { + return Math.sqrt(v.x**2+v.y**2+v.z**2); +} + +function normalizeVec(v) { + let l = vectorLength(v); + return {x: v.x/l, y: v.y/l, z: v.z/l}; +} + +function vecNormSquared(v) { + return v.x**2+v.y**2+v.z**2; +} + +function addVec(u,v, ...rest) { + if (rest.length > 0) return sumVec([u,v]+rest); + return {x: u.x+v.x, y: u.y+v.y, z: u.z+v.z}; +} + +function sumVec(vectors) { + let S = {x:0, y:0, z:0}; + for (let i = 0; i < vectors.length; i++) { + let v = vectors[i]; + S.x += v.x; + S.y += v.y; + S.z += v.z; + } + return S; +} + +function dotProduct(u,v) { + return u.x*v.x + u.y*v.y + u.z*v.z; +} + +function crossProduct(u,v) { + return { + x: u.y*v.z-u.z*v.y, + y: u.z*v.x-u.x*v.z, + z: u.x*v.y-u.y*v.x + }; +}//@EliasHasle + +//Some interpolation helpers. Only linear and bilinear for now. + +//linear interpolation +//Defaults are not finally decided +//returns NaN if a and b are NaN or mu is NaN. +function lerp(a, b, mu=0.5) { + if (isNaN(a)) return b; + if (isNaN(b)) return a; + return (1-mu)*a+mu*b; +} + +//Test. Not safe yet. +function linearFromArrays(xx, yy, x) { + let {index, mu} = bisectionSearch(xx, x); + if (index === undefined || mu === undefined) return 0; + return lerp(yy[index], yy[index+1], mu); +} + +/*Function that takes a sorted array as input, and finds the last index that holds a numerical value less than, or equal to, a given value. +Returns an object with the index and an interpolation parameter mu that gives the position of value between index and index+1. +*/ +function bisectionSearch(array, value) { + if (value < array[0]) { + console.warn("bisectionSearch: requested value below lowest array element. Returning undefined."); + return {index: undefined, mu: undefined}; + } + let index = 0, upper = array.length; + while (upper > index+1) { + let c = Math.floor(0.5*(index+upper)); + if (array[c] === value) return {index: c, mu: 0}; + else if (array[c] < value) index = c; + else upper = c; + } + /*if (index === array.length) { + console.error("bisectionSearch: index===array.length. This should never happen."); + }*/ + let mu = (value-array[index])/(array[index+1]-array[index]); + if (index === array.length-1) { + console.warn("bisectionSearch: Reached end of array. Simple interpolation will result in NaN."); + mu = undefined; + } + return {index, mu}; +} + +function bilinearUnitSquareCoeffs(z00, z01, z10, z11) { + let a00 = z00; + let a10 = z10-z00; + let a01 = z01-z00; + let a11 = z11+z00-z01-z10; + return [a00,a10,a01,a11]; +} + +function bilinearUnitSquare(z00, z01, z10, z11, mux, muy) { + let [a00, a10, a01, a11] = bilinearUnitSquareCoeffs(z00, z01, z10, z11); + return a00 + a10*mux + a01*muy + a11*mux*muy; +} + +//Find coefficients for 1, x, y, xy. +//This doesn't yet handle zero-lengths well. +function bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22) { + let X = (x2-x1); + let Y = (y2-y1); + + if (X===0 || Y=== 0) { + console.warn("bilinearCoeffs: Zero base area. Setting coefficients to zero."); + return [0,0,0,0]; + } + + let Ainv = 1/(X*Y); + + //constant coeff: + let b00 = Ainv*(z11*x2*y2 - z21*x1*y2 - z12*x2*y1 + z22*x1*y1); + //x coeff: + let b10 = Ainv*(-z11*y2 + z21*y2 + z12*y1 - z22*y1); + //y coeff: + let b01 = Ainv*(-z11*x2 + z21*x1 + z12*x2 -z22*x1); + //xy coeff: + let b11 = Ainv*(z11-z21-z12+z22); + + return [b00,b10,b01,b11]; +} + +//Maybe I could do some simple linear interpolation in collapsed cases. +//But then I have to be sure what the z values and coefficients mean. +//I have apparently not documented this well. +function bilinear(x1, x2, y1, y2, z11, z12, z21, z22, x, y) { + let [b00, b10, b01, b11] = + bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22); + return b00 + b10*x + b01*y + b11*x*y; + //The following is supposed to be equivalent. Maybe I should compare, to make sure that the current calculation is correct. + /*let mux = (x-x1)/(x2-x1); + let muy = (y-y1)/(y2-y1); + return bilinearUnitSquare(z11, z12, z21, z22, mux, muy);*/ +} +//@EliasHasle + +//All inputs are numbers. The axes are given by a single coordinate. +function steiner(I, A, sourceAxis, targetAxis) { + return I + A*(sourceAxis-targetAxis)^2; +} + +//Calculate area, center, Ix, Iy. +function trapezoidCalculation(xbase0, xbase1, xtop0, xtop1, ybase, ytop) { + let a = xbase1-xbase0; + let b = xtop1-xtop0; + let h = ytop-ybase; + if (a<0 || b<0 || h<0) { + console.warn("trapezoidCalculation: Unsupported input. Possibly not a valid trapezoid."); + } + let A = 0.5*(a+b)*h; + let yc = (a==0 && b==0) ? ybase+0.5*h : ybase + h*(2*a+b)/(3*(a+b)); + let d = xbase0+0.5*a; //shorthand + let xc = h===0 ? 0.25*(xbase0+xbase1+xtop0+xtop1) : d + (xtop0+0.5*b-d)*(yc-ybase)/h; + let Ix = (a==0 && b== 0) ? 0 : h^3*(a^2+4*a*b+b^2)/(36*(a+b)); + + //For Iy I must decompose (I think negative results will work fine): + let Art1 = 0.5*(xtop0-xbase0)*h; + let xcrt1 = xbase0 + (xtop0-xbase0)/3; + let Iyrt1 = (xtop0-xbase0)^3*h/36; + let Arec = (xbase1-xtop0)*h; + let xcrec = 0.5*(xtop0+xbase1); + let Iyrec = (xbase1-xtop0)^3*h/12; + let Art2 = 0.5*(xbase1-xtop1)*h; + let xcrt2 = (xtop1 + (xbase1-xtop1)/3); + let Iyrt2 = (xbase1-xtop1)^3*h/36; + + let Iy = steiner(Iyrt1, Art1, xcrt1, xc) + + steiner(Iyrec, Arec, xcrec, xc) + + steiner(Iyrt2, Art2, xcrt2, xc); + + let maxX = Math.max.apply(null, [xbase0, xbase1, xtop0, xtop1]); + let minX = Math.min.apply(null, [xbase0, xbase1, xtop0, xtop1]); + let maxY = Math.max(ybase, ytop); + let minY = Math.min(ybase, ytop); + + return {A: A, xc: xc, yc: yc, Ix: Ix, Iy: Iy, maxX: maxX, minX: minX, maxY: maxY, minY: minY}; +} + +function combineAreas(array) { + let A = 0; + let xc = 0; + let yc = 0; + let maxX = 0, minX = 0, maxY = 0, minY = 0; + let L = array.length; + for (let i = 0; i < L; i++) { + let e = array[i]; + A += e.A; + xc += e.xc*e.A; + yc += e.yc*e.A; + if (!isNaN(e.maxX) && e.maxX>maxX) + maxX = e.maxX; + if (!isNaN(e.minX) && e.minXmaxY) + maxY = e.maxY; + if (!isNaN(e.minY) && e.minY 10){ + Wlo = 15; + } + else { + Wlo = 20 + } + let Wfw = 0.17 * person; // Weight of fresh water + let Wce = 0.17 * person; // Weight of crew and effects + let Wpr = 0.01 * person * day; // Weight of provisions and stores + let W = Wfo + Wlo + Wfw + Wce + Wpr; // Total weigth + + + // VCGOut is the Vertical Center of Gravity of the Deadweight. Depends on designer + // LCGOut is the Longitudinal Center of Gravity of the Deadweight. Depends on designer + + // Returns the object + + return {mass: W}; + } + +// This function estimates the structural weight of the machinery, main engine(s) and the remainder of the machinery weight. +// +// +// Inputs +// MCR is the total capacity of all generators in kW. +// hdb is the innerbootom height of the engine room +// Der is the height og the overhead of the engine room +// L is LWL or LBP +// B is molded beam +// T is molded draft +// +// Return +// It returns an object with the properties mass and the VCG. + + function parametricWeightMachinery(MCR, hdb, Der, B, T, L, test){ + // Calculates estimated machinery weight + let W = 0.72 * Math.pow(MCR, 0.78); + // Calculates LCG and VCG + + // req1 and req2 are the Coast Guard requirements for the hdb + let req1 = (32 * B + 190 * Math.sqrt(T)) / 1000; + let req2 = (45.7 + 0.417 * L) / 100; + let reqmax = Math.max(req1, req2, hdb); + + // VCGMach is the Vertical Center of Gravity of the machinery + let VCGMach = hdb + 0.35 * (Der - hdb); + + // LCGMach is the Longitudinal Center of Gravity of the machinery. Depends on designer + + // Returns the object + + return {mass: W, VCG: VCGMach}; + } + + +// This function estimates the remainder of the Light Ship Weight. It includes outfit: electrical plant, distributive auxiliary systems and hull engineering: bits, chocks, hatch covers... +// +// +// Inputs +// Co is the outfit weight coefficient. Parsons Chapter 11 Figure 11.17. Pag 24. +// LBP is the Lenght Between Perpendiculars. +// D is molded depth +// +// Return +// It returns an object with the properties mass and VCG. + + function parametricWeightOutfit(Co, LBP, D){ + + // Calculates estimated weight + let W = Co * LBP; + + // VCGOut is the Vertical Center of Gravity of the outfits + let VCGOut = 0; + if (LBP < 125){ + VCGOut = D + 1.25 + } + else if (LBP < 250){ + VCGOut = D + 1.25 + 0.01 * (LBP - 125) + } + else { + VCGOut = D + 2.5 + } + + // LCGOut is the Longitudinal Center of Gravity of the Outfits. Depends on designer + + // Returns the object + + return {mass: W, VCG: VCGOut}; + }//@EliasHasle + +//Very unoptimized for now. +function combineWeights(array) { + let M = array.reduce((sum,e)=>sum+e.mass,0); + let cgms = array.map(e=>scaleVec(e.cg, e.mass)); + let CG = scaleVec(sumVec(cgms), 1/M); + + return {mass: M, cg: CG}; +}//@EliasHasle + +/*Base class for objects that are constructed from +a literal object, (//or optionally from a JSON string). + +Constructors can take more parameters than the specification, but the specification must be the first parameter. + +setFromSpecification will typically be overridden by derived classes. Overriding implementations will typically do some sanity checking. + +getSpecification will also typically be overridden. The default implementation here is just a sketch. Maybe not even correct for the simplest subclasses. + +Maybe this can be improved by implementing fromJSON and to toJSON methods. +*/ + +function JSONSpecObject(specification) { + if (specification === null) { + console.warn("JSONSpecObject: null specification provided. Defaulting to empty specification."); + specification = {}; + } + else if (typeof specification === "object") {} + /*else if (typeof specification === "string") { + try { + specification = JSON.parse(specification); + } catch(e) { + console.error("JSONSpecObject: "+ e.message + "\n Defaulting to empty specification."); + specification = {}; + } + }*/ + else { + if (typeof specification !== "undefined") { + console.error("JSONSpecObject: Invalid constructor parameter. Defaulting to empty specification."); + } + specification = {}; + } + this.setFromSpecification(specification); +} +JSONSpecObject.prototype = Object.create(Object.prototype); +Object.assign(JSONSpecObject.prototype, { + constructor: JSONSpecObject, + setFromSpecification: function(specification) { + //No sanity checking by default. + Object.assign(this, specification); + }, + getSpecification: function() { + let spec = {}; + for (k of Object.keys(this)) { + if (this.hasOwnProperty(k)) spec[k] = this[k]; + } + return spec; + }, + toJSON: function() { + //First test: + return JSON.stringify(this); + } +});//@EliasHasle + +/* +Notes: +For calculated values, I envision a lazy calculation pattern, where all properties involved in calculations are only accessed by specialized getters and setters, and calculated properties have some kind of needsUpdate flag or version number (that is set by any setters that will directly or indirectly affect the property). When, and only when, running the getter for the given property, the flag/version is checked, and if false (same version as in cache) the getter just returns the stored value. If true, the getter starts the calculation of the value, invoking other getters. + +Suggested calculations to do: +- Resistance at given speed (based on Holtrop). +- Inertia matrix (will need more detailed properties of parts). +*/ + +function Ship(specification) { + JSONSpecObject.call(this,specification); +} +Ship.prototype = Object.create(JSONSpecObject.prototype); +Object.assign(Ship.prototype, { + constructor: Ship, + setFromSpecification: function(specification) { + this.attributes = specification.attributes || {}; + this.structure = new Structure(specification.structure,this); + //baseObjects and derivedObjects are arrays in the specification, but are objects (hashmaps) in the constructed ship object: + this.baseObjects = {}; + for (let i = 0; i < specification.baseObjects.length; i++) { + let os = specification.baseObjects[i]; + this.baseObjects[os.id] = new BaseObject(os); + } + + this.derivedObjects = {}; + for (let i = 0; i < specification.derivedObjects.length; i++) { + let os = specification.derivedObjects[i]; + this.derivedObjects[os.id] = new DerivedObject(os, this.baseObjects); + } + + this.designState = new ShipState(specification.designState); + }, + getSpecification: function() { + let specification = {}; + specification.attributes = this.attributes; + specification.structure = this.structure.getSpecification(); + + specification.baseObjects = Object.values(this.baseObjects).map(o=>o.getSpecification()); + specification.derivedObjects = Object.values(this.derivedObjects).map(o=>o.getSpecification()); + + specification.designState = this.designState.getSpecification(); + + return specification; + }, + getWeight: function(shipState) { + shipState = shipState || this.designState; + + let components = []; + + components.push( + this.structure.getWeight(this.designState) + ); + + //DEBUG + console.log(components); + + for (let o of Object.values(this.derivedObjects)) { + components.push(o.getWeight(shipState)); + } + + var W = combineWeights(components); + console.info("Calculated weight object: ", W); + return W; + }, + calculateDraft(shipState, epsilon=0.001) { + let w = this.getWeight(shipState); + let M = w.mass; + let VT = M/1025; //Target submerged volume (1025=rho_seawater) + //Interpolation: + let a = 0; + let b = this.structure.hull.attributes.Depth; + let t = 0.5*b; + while (b-a>epsilon) { + t = 0.5*(a+b); + let V = this.structure.hull.calculateAttributesAtDraft(t)["Vs"]; + console.log(V); //DEBUG + if (V>VT) b = t; + else a = t; + } + console.info("Calculated draft: %.2f", t); + return t; + }, + //Should separate between longitudinal and transverse GM too + calculateStability(shipState){ + let T = this.calculateDraft(shipState); + let ha = this.structure.hull.calculateAttributesAtDraft(T); + let vol = ha.Vs; + if (vol === 0){ + let Lwl = this.designState.calculationParameters.LWL_design; + let B = this.structure.hull.attributes.BOA; + let cb = this.designState.calculationParameters.Cb_design; + vol = Lwl * B * T * cb; + } + let KG = this.getWeight(shipState).cg.z; + let I = ha.Iywp; + let KB = 0.52 * T; + let BM = I / vol; + let GM = KB + BM - KG; + return {GM, KB, BM, KG}; + } +});//@EliasHasle + +function Structure(spec, ship) { + this.ship = ship; + JSONSpecObject.call(this, spec); +} +Structure.prototype = Object.create(JSONSpecObject.prototype); +Object.assign(Structure.prototype, { + setFromSpecification: function(spec) { + this.hull = new Hull(spec.hull/*, this.ship*/); + this.decks = spec.decks;/*{}; + let dspecs = spec.decks; + let decks = this.decks; + let dnames = Object.keys(dspecs); + for (let i = 0; i < dnames.length; i++) { + let name = dnames[i]; + let dspec = dspecs[name]; + decks[name] = new Deck(dspec,this.ship); + }*/ + this.bulkheads = spec.bulkheads;/*{}; + let bhspecs = spec.bulkheads; + let bulkheads = this.bulkheads; + let bhnames = Object.keys(bhspecs); + for (let i = 0; i < bhnames.length; i++) { + let name = bhnames[i]; + let bhspec = bhspecs[name]; + bulkheads[name] = new Bulkhead(bhspec,this.ship); + }*/ + }, + getSpecification: function() { + let spec = { + hull: this.hull.getSpecification(), + decks: this.decks, + bulkheads: this.bulkheads + };/*{decks: {}, bulkheads: {}}; + + spec.hull = this.hull.getSpecification(); + + let sd = spec.decks; + let dk = Object.keys(this.decks); + for (let i = 0; i < dk.length; i++) { + sd[dk[i]] = this.decks[dk[i]].getSpecification(); + } + + let sbh = spec.bulkheads; + let bhk = Object.keys(this.bulkheads); + for (let i = 0; i < bhk.length; i++) { + sbh[bhk[i]] = this.bulkheads[bhk[i]].getSpecification(); + }*/ + + return spec; + }, + //Alejandro is working on a more proper calculation of this + getWeight: function(designState) { + let components = []; + //Hull + components.push(this.hull.getWeight(designState)); + + //structure: + let decks = Object.values(this.decks); + for (let i=0; i < decks.length; i++) { + let d = decks[i]; + let zc = d.zFloor+0.5*d.thickness; + let yc = d.yCentre; + let b = d.breadth; + let wlc = this.hull.waterlineCalculation(zc, {minX: d.xAft, maxX: d.xFwd, minY: yc-0.5*b, maxY: yc+0.5*b}); + components.push({ + //approximation + mass: wlc.Awp*d.thickness*d.density, + cg: { + x: wlc.xc, + y: wlc.yc, + z: zc + } + }); + } + + let bulkheads = Object.values(this.bulkheads); + for (let i=0; i < bulkheads.length; i++) { + let bh = bulkheads[i]; + let xc = bh.xAft+0.5*bh.thickness; + let sc = this.hull.stationCalculation(xc); + components.push({ + //approximation + mass: sc.A*bh.thickness*bh.density, + cg: { + x: xc, + y: sc.yc, + z: sc.zc + } + }); + } + + let output = combineWeights(components); + console.info("Total structural weight: ", output); + return output; + } +});//@EliasHasle + +/*When having a class for this, the specification can possibly be in one of several formats, and the handling will be contained in this class. + +I have tried to remove the dependency on the ship object here. This is in order to be able to optimize updates. + +This class needs more comments, for shure. + +And the geometric calculations are faulty. +*/ + +function Hull(spec) { + JSONSpecObject.call(this, spec); +} +Hull.prototype = Object.create(JSONSpecObject.prototype); +Object.assign(Hull.prototype, { + setFromSpecification: function(spec) { + this.halfBreadths = spec.halfBreadths; + //this.buttockHeights = spec.buttockHeights; + this.attributes = spec.attributes; //this could/should include LOA, BOA, Depth + this.levelsNeedUpdate = true; + }, + getSpecification: function() { + return { + halfBreadths: this.halfBreadths, + //buttockHeights: this.buttockHeights + attributes: this.attributes + }; + }, + //to facilitate economical caching, it may be best to have a few numerical parameters to this function instead of letting it depend on the whole designState. Or maybe the designState is static enough. + getWeight: function(designState) { + let ha = this.attributes; + let B = ha.BOA; + let D = ha.Depth; + let cp = designState.calculationParameters; + let K = cp.K; + let L = cp.LWL_design; + let T = cp.Draft_design; + let Cb = cp.Cb_design; + let vsm = 0.514444*cp.speed; // Convert the design speed from knots to m/s + let Fn = vsm / Math.pow(9.81 * L, 0.5); // Calculates Froude number + + //This is not a good way to estimate the hull weight. + let parsons = parametricWeightHull(K, L, B, T, D, Cb, Fn); + parsons.mass *= 1000; //ad hoc conversion to kg, because the example K value is aimed at ending with tonnes. + + let output = parsons; + console.info("Hull weight:", output); + return output; + }, + /* + Input: + z: level from bottom of ship (absolute value in meters) + nanCorrectionMode: 0 to set all NaNs to zero, 1 to output NaNs, set all NaNs to zero, 2 to replace NaNs with interpolated or extrapolated values. + */ + getWaterline: function(z, nanCorrectionMode=1) { + let ha = this.attributes; + let zr = z/ha.Depth; + let wls = this.halfBreadths.waterlines; + let sts = this.halfBreadths.stations; + let tab = this.halfBreadths.table; + + let {index: a, mu: mu} = bisectionSearch(wls, zr); + let wl; + if (a<0) { + if (nanCorrectionMode===0) { + console.warn("getWaterLine: z below lowest defined waterline. Defaulting to zeros."); + return new Array(sts.length).fill(0); + } + if (nanCorrectionMode===1) { + console.warn("getWaterLine: z below lowest defined waterline. Outputting NaNs."); + return new Array(sts.length).fill(null); + } + else /*nanCorrectionMode===2*/ { + console.warn("getWaterLine: z below lowest defined waterline. Extrapolating lowest data entry."); + a=0; + mu=0; + //wl = tab[a].slice(); + } + } else if (a>/*=*/wls.length-1) { + if (nanCorrectionMode===0) { + console.warn("getWaterLine: z above highest defined waterline. Defaulting to zeros."); + return new Array(sts.length).fill(0); + } + if (nanCorrectionMode===1) { + console.warn("getWaterLine: z above highest defined waterline. Outputting NaNs."); + return new Array(sts.length).fill(null); + } + else /*nanCorrectionMode===2*/ { + console.warn("getWaterLine: z above highest defined waterline. Proceeding with highest data entry."); + a = wls.length-2; //if this level is defined... + mu=1; + //wl = tab[a].slice(); + } + } + + //Linear interpolation between data waterlines + wl = new Array(sts.length); + for (let j = 0; j < wl.length; j++) { + if (nanCorrectionMode === 0) { + if (a+1 > wls.length-1) { + wl[j] = lerp(tab[a][j], 0, 0.5); + } else { + wl[j] = lerp(tab[a][j] || 0, tab[a+1][j] || 0, mu || 0.5); + } + } else if (nanCorrectionMode === 1) { + if (a+1 > wls.length-1) { + wl[j] = lerp(tab[a][j], null, mu); + } else { + wl[j] = lerp(tab[a][j], tab[a+1][j], mu); + } + } else { + //If necessary, sample from below + let b = a; + while (b>0 && isNaN(tab[b][j])) { + b--; + } + let lower; + if (b===0 && isNaN(tab[b][j])) { + lower = 0; + } else { + lower = tab[b][j]; + } + //If necesary, sample from above + let c = a+1; + let upper; + if (c>wls.length-1) { + c = b; + upper = lower; + } else { + while (cwls.length-1 before the loop. + if (c===wls.length-1 && isNaN(tab[c][j])) { + //Fall back all the way to b + c = b; + upper = lower; + } else { + upper = tab[c][j]; + } + } + mu = c===b ? 0 : (a+(mu||0.5)-b)/(c-b); + wl[j] = lerp(lower, upper, mu); + } + + //Scale numerical values + if (!isNaN(wl[j])) wl[j] *= 0.5*ha.BOA; + } + + return wl; + }, + getStation: function(x) { + let ha = this.attributes; + let xr = x/ha.LOA; + let sts = this.halfBreadths.stations; + let wls = this.halfBreadths.waterlines; + let tab = this.halfBreadths.table; + + let {index: a, mu: mu} = bisectionSearch(sts, xr); + + let st; + if (a<0 || a>=sts.length) st = new Array(wls.length).fill(null); + else if (a+1===sts.length) st = tab.map(row=>row[wls.length-1]); + else { + st = []; + for (let j = 0; j < wls.length; j++) { + let after = tab[j][a]; + let forward = tab[j][a+1]; + if (isNaN(after) && isNaN(forward)) { + st.push(null); + } else { + st.push(lerp(after || 0, forward || 0, mu)); + } + } + } + for (let j=0; jthis.attributes.Depth*wl); + let port = this.getStation(x); + let star = port.map(hb=>-hb); + let sc = sectionCalculation({xs: wls, ymins: star, ymaxs: port}); + return { + x: x, //or xc? or cg.. Hm. + yc: sc.yc, + zc: sc.xc, + A: sc.A, + Iz: sc.Ix, + Iy: sc.Iy, + maxX: sc.maxX, + minX: sc.minX, + maxY: sc.maxY, + minY: sc.minY + }; + }, + //Unoptimized, some redundant repetitions of calculations. + //NOT DONE YET. Outputs lots of NaN values. + calculateAttributesAtDraft: function() { + function levelCalculation(hull, + z, + prev={ + z: 0, + Vs: 0, + Vbb: 0, + As: 0, + minX: 0, + maxX: 0, + minY: 0, + maxY: 0, + prMinY: 0, + prMaxY: 0, + Ap: 0, + Cv: {x:0, y:0, z:0} + }) { + + let wlc = hull.waterlineCalculation(z); + let lev = {}; + Object.assign(lev, wlc); + //Projected area calculation (approximate): + lev.prMinY = wlc.minY || 0; + lev.prMaxY = wlc.maxY || 0; //|| 0 right? + lev.Ap = prev.Ap + + trapezoidCalculation(prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, lev.z)["A"]; + + //level bounds are for the bounding box of the submerged part of the hull + if (!isNaN(prev.minX) && prev.minX<=wlc.minX) + lev.minX = prev.minX; + if (!isNaN(prev.maxX) && prev.maxX>=wlc.maxX) + lev.maxX = prev.maxX; + if (!isNaN(prev.minY) && prev.minY<=wlc.minY) + lev.minY = prev.minY; + if (!isNaN(prev.maxY) && prev.maxY>=wlc.maxY) + lev.maxY = prev.maxY; + lev.Vbb = (lev.maxX-lev.minX)*(lev.maxY-lev.minY)*z; + + //Find bilinear patches in the slice, and combine them. + //Many possibilities for getting the coordinate systems wrong. + let calculations = []; + //let wls = hull.halfBreadths.waterlines.map(wl=>wl*hull.attributes.Depth); + let sts = hull.halfBreadths.stations.map(st=>st*hull.attributes.LOA); + let wl = hull.getWaterline(z,0); + let prwl = hull.getWaterline(prev.z,0); + for (let j = 0; j < sts.length-1; j++) { + let port = + bilinearPatchColumnCalculation(sts[j], sts[j+1], prev.z, z, -prwl[j], -wl[j], -prwl[j+1], -wl[j+1]); + calculations.push(port); + let star = + bilinearPatchColumnCalculation(sts[j], sts[j+1], prev.z, z, prwl[j], wl[j], prwl[j+1], wl[j+1]); + calculations.push(star); + } + let C = combineVolumes(calculations); + lev.Vs = prev.Vs + C.V; //hull volume below z + lev.As = prev.As + C.As; //outside surface below z + + //center of volume below z (some potential for accumulated rounding error): + let Cv = addVec(scaleVec(prev.Cv,prev.Vs), + scaleVec(C.Cv,C.V)); + let V = prev.Vs+C.V; + if (V!==0) { + Cv = scaleVec(Cv, 1/(prev.Vs+C.V)); + } + //Note switching of yz + lev.Cv = {x: Cv.x, y: Cv.z, z: Cv.y}; + + lev.Cb = lev.Vs/lev.Vbb; + + return lev; + } + + return function(T) { + let wls = this.halfBreadths.waterlines.map(wl=>this.attributes.Depth*wl); + + //This is the part that can be reused as long as the geometry remains unchanged: + if (this.levelsNeedUpdate) { + this.levels = []; + for (let i = 0; i < wls.length; i++) { + let z = wls[i]; + let lev = levelCalculation(this, z, this.levels[i-1]); + this.levels.push(lev); + } + this.levelsNeedUpdate = false; + } + + //Find highest data waterline below water: + let {index: previ} = bisectionSearch(wls, T); + + let lc = levelCalculation(this, T, this.levels[previ]); + + //Filter and rename for output + return { + xcwp: lc.xc, + ycwp: lc.yc, + Awp: lc.Awp, + Ixwp: lc.Ix, + Iywp: lc.Iy, + maxXs: lc.maxX, //boundaries of the submerged part of the hull + minXs: lc.minX, + maxYs: lc.maxY, + minYs: lc.minY, + Cwp: lc.Cwp, + LWL: lc.LWL, + LBP: lc.LBP, + BWL: lc.BWL, + Ap: lc.Ap, + //Vbb: lc.Vbb, + Vs: lc.Vs, + Cb: lc.Cb, + As: lc.As, + Cv: lc.Cv + } + }; + }() +});//@EliasHasle + +/* +Depends on JSONSpecObject.js +*/ + +function BaseObject(specification) { + this.weightCache = {}; + JSONSpecObject.call(this,specification); +} +BaseObject.prototype = Object.create(JSONSpecObject.prototype); +Object.assign(BaseObject.prototype, { + constructor: BaseObject, + setFromSpecification: function(spec) { + this.id = spec.id; + this.affiliations = spec.affiliations || {}; + this.boxDimensions = spec.boxDimensions || {length: undefined, width: undefined, height: undefined}; + this.weightInformation = spec.weightInformation; + this.cost = spec.cost || {currency: undefined, value: undefined}; + this.capabilities = spec.capabilities || {}; + this.file3D = spec.file3D; + this.baseState = spec.baseState; + }, + getSpecification: function() { + return { + id: this.id, + affiliations: this.affiliations, + boxDimensions: this.boxDimensions, + weightInformation: this.weightInformation, + cost: this.cost, + capabilities: this.capabilities, + file3D: this.file3D, + baseState: this.baseState + }; + }, + //Maybe this will take more state parameters than just fullness. + getWeight: function(fullness) { + fullness = fullness || 0; + + let wi = this.weightInformation; + //Should maybe have been this.capabilities.weightInformation? + + //(Fluid) container properties default to no content: + let d = wi.contentDensity || 0; + let v = wi.volumeCapacity || 0; + //Maybe we should have another handling of cargo (with variable density) + + let m = wi.lightweight + d*v*fullness; + let cg; + if (wi.fullnessCGMapping !== undefined) { + let fcgm = wi.fullnessCGMapping; + let fs = fcgm.fullnesses; + let cgs = fcgm.cgs; + //Find closest entries: + let {index: i, mu: mu} = bisectionSearch(fs, fullness); + cg = []; + for (let j = 0; j < 3; j++) { + let c; + if (i!!e); + for (let i = 0; i < sources.length; i++) { + if (sources[i][k] !== undefined) return sources[i][k]; + } + return; //undefined*/ + }, + //Sets this state exclusively from parameter. + setFromSpecification: function(spec) { + this.objectCache = {}; //reset cache + if (!spec) { + Object.assign(this, { + calculationParameters: {}, + //Named overrides because only existing corresponding properties will be set + objectOverrides: { + commmon: {}, + //baseByGroup: {}, + baseByID: {}, + derivedByGroup: {}, + derivedByID: {} + } + }); + return; + } + + this.calculationParameters = spec.calculationParameters || {}; + this.objectOverrides = {}; + let oo = this.objectOverrides; + let soo = spec.objectOverrides || {}; + oo.common = soo.common || {}; + oo.baseByID = soo.baseByID || {}; + oo.derivedByGroup = soo.derivedByGroup || {}; + oo.derivedByID = soo.derivedByID || {}; + + this.version++; + }, + //Overrides existing directives and adds new ones. + extend: function(spec) { + Object.assign(this.calculationParameters, spec.calculationParameters); + this.calculatedProperties = {}; + let oo = this.objectOverrides; + let soo = spec.objectOverrides || {}; + Object.assign(oo.common, soo.common); + let sources = [soo.baseByID, soo.derivedByGroup, soo.derivedByID]; + let targets = [oo.baseByID, oo.derivedByGroup, oo.derivedByID]; + for (let i = 0; i < sources.length; i++) { + if (!sources[i]) continue; + let sk = Object.keys(sources[i]); + for (let k of sk) { + if (targets[i][k] !== undefined) { + Object.assign(targets[i][k], sources[i][k]); + } else { + targets[i][k] = sources[i][k]; + } + } + } + + this.version++; + }, + //Applies only directives of spec that have a corresponding directive in this. + override: function(spec) { + let oo = this.objectOverrides; + let soo = spec.objectOverrides; + + let sources = [spec.calculationParameters, soo.common]; + let targets = [this.calculationParameters, oo.common]; + for (let i = 0; i < sources.length; i++) { + if (!sources[i]) continue; + let sk = Object.keys(sources[i]); + for (let k of sk) { + if (targets[i][k] !== undefined) { + targets[i][k] = sources[i][k]; + } + } + } + + sources = [soo.common, soo.baseByID, soo.derivedByGroup, soo.derivedByID]; + targets = [oo.common, oo.baseByID, oo.derivedByGroup, oo.derivedByID]; + + for (let i = 0; i < sources.length; i++) { + if (!sources[i]) continue; + let specKeys = Object.keys(sources[i]); + for (let key of specKeys) { + if (targets[i][key] !== undefined) { + let t = targets[i][key]; + let s = sources[i][key]; + if (!s) continue; + let sk = Object.keys(s); + //Loop over individual properties in assignments, and override only: + for (let k of sk) { + if (t[k] !== undefined) { + t[k] = s[k]; + } + } + } + } + } + + this.version++; + } +});//@EliasHasle + +//Depends on Ship and the other core classes. + +/* +Handy function for letting the user load a ship design from a local file. (Based on Elias Hasles browseFile function.) + +Typical usage: +Click here +where useShip takes the loaded ship design as a parameter adn does something with it. + +According to the ECMAScript standard, it is required that the file browsing is initiated by the user. Google Chrome seems to handle indirect initiation very well, such as having this function in a click handler. +*/ + +"use strict"; +var browseShip = function() { + var browseButton; + return function (callback) { + browseButton = document.createElement("input"); + Object.assign(browseButton, { + type: "file", + multiple: false, + style: "display: none", + accept: ".json, application/json", + onchange: function(e) { + //console.log("Change event triggered on browse."); + let file = browseButton.files[0]; + let reader = new FileReader(); + reader.onload = function(event) { + let result = event.target.result; + let specification = JSON.parse(result); + let ship = new Ship(specification); + callback(ship); + } + reader.readAsText(file); + } + }); + browseButton.click(); + }; +}();//@EliasHasle + +//Depends on Ship and the other core classes. + +/* +Handy function for loading a ship design from file. + +Typical usage: +var myShip; +var filePath = "ships/myShip.json"; +loadShip(filePath, function(ship) { + myShip = ship; + doSomething(); +}); + +*/ + +function loadShip(url, callback) { + var request = new XMLHttpRequest(); + request.open( 'GET', url, true ); + request.addEventListener("load", function(event) { + var response = event.target.response; + var specification = JSON.parse(response); + var ship = new Ship(specification); + callback(ship); + }); + request.send(null); +}//@EliasHasle + +//Very simple download of the specification of a given ship design. Depends on a working getSpecification method. + +function downloadShip(ship) { + let specification = ship.getSpecification(); + let output = JSON.stringify(specification); + let link = document.createElement("a"); + link.href = "data:application/json," + encodeURI(output); + link.download = "shipdesignspecification.json"; + link.target = "_blank"; + link.click(); +} +Object.assign(Vessel, { + /*JSONSpecObject: JSONSpecObject,*/ + Ship: Ship, + Structure: Structure, + Hull: Hull, + BaseObject: BaseObject, + DerivedObject: DerivedObject, + ShipState: ShipState, + browseShip: browseShip, + loadShip: loadShip, + downloadShip: downloadShip, + f: { + linearFromArrays: linearFromArrays + } +}); +})(); diff --git a/build/makeBuild.py b/build/makeBuild.py index 86b0cfb..67b67a5 100644 --- a/build/makeBuild.py +++ b/build/makeBuild.py @@ -43,7 +43,8 @@ loadShip: loadShip, downloadShip: downloadShip, f: { - linearFromArrays: linearFromArrays + linearFromArrays: linearFromArrays, + bilinear: bilinear } }); })(); diff --git a/examples/Hull_hydrostatics.html b/examples/Hull_hydrostatics.html new file mode 100644 index 0000000..e107c89 --- /dev/null +++ b/examples/Hull_hydrostatics.html @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + Hull Hydrostatics + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+

Hull Hydrostatics

+
+ +
+ + + +

Interactive calculation of hull hydrostatic properties.

+ +

Developed by: Elias Hasle, Vicente Alejandro Iváñez Encinas and Henrique M. Gaspar. Visualization made using three.js.

+ +
+ +
+

Input

+ +

Contents of the file:

+

+                
+
+ +
+

3D orbit view of hull

+
+
+
+ +
+
+

Hydrostatic Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableResults
Draft Amidships (m)
Displacement (t)
Waterline Length (m)
Maximum Waterline Breadth (m)
Waterplane Area (m2)
Cb
KB (m) WRONG VALUE
BM (m) WRONG VALUE
+
+
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/blockCase_compare.html b/examples/blockCase_compare.html new file mode 100644 index 0000000..3549f23 --- /dev/null +++ b/examples/blockCase_compare.html @@ -0,0 +1,633 @@ + + + + + + + + + + + + + Ship visualization with specification + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+

Ship as object

+
+ +
+ + + +

This app asks for a JSON file + and gives back the pretty form of the JSON element. It also plots a 3D image of the ship. Sample data is loaded at startup.

+ +

Developed by: Elias Hasle, Vicente Alejandro Iváñez Encinas and Henrique M. Gaspar. Visualization made using three.js.

+ +
+ +
+

Input

+ +

Contents of the file:

+

+                
+
+ +
+

3D orbit view of hull and parts

+
+
+
+ +
+

Whole ship

+

Ship specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableValue
Lenght Overall m
Breadth Overall m
Depth m
Design Draft m
Design speed knots
Lightweight kg
+

Calculations

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableHand valueCalculated value% diff
Draft Amidships (m)
Draft at FP (m)
Draft AP (m)
Displacement (t)
Waterline Lenght (m)
Maximum Waterline Breath (m)
Wetted area (m2)
Waterplane Area (m2)
Cb
LCBx (m)
LCFx (m)
KB (m)
KG (m)
BM (m)
GM (m) +
Trim (m) +
Trim (º) +
Heel (m) +
Maximum moment (ton m) +
Shear (t) +
+

General arrangement

+

Specification

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDLenghtBreadthHeightDeadweight
Block0 m m m kg
Block0 m m m kg
Block2 m m m kg
+

Calculations

+ + + + + + + + + + + + + + + + + + + + + + + + +
VariableHand valueCalculated value
Deadweight (kg) +
Total area (m2) +
Total Volume (m3) +
+ +
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/blockCase_compare_json.html b/examples/blockCase_compare_json.html new file mode 100644 index 0000000..ec75779 --- /dev/null +++ b/examples/blockCase_compare_json.html @@ -0,0 +1,157 @@ + + + + + Comparison of manually calculations and library calculations + + + + + +
    + + + + \ No newline at end of file diff --git a/examples/data/ship_specifications/PX121.json b/examples/data/ship_specifications/PX121.json index 37eac5e..9c5f32e 100644 --- a/examples/data/ship_specifications/PX121.json +++ b/examples/data/ship_specifications/PX121.json @@ -1,125 +1,4027 @@ { -"attributes": { -}, -"designState": { - "calculationParameters": { - "LWL_design": 80, - "Draft_design": 6.5, - "Cb_design": 0.68, - "speed": 10, - "crew" : 20, - "K" : 0.032, - "MCR" : 10000, - "SFC" : 0.000215, - "Co" : 0.3, - "tripDuration": 40 + "attributes": {}, + "designState": { + "calculationParameters": { + "LWL_design": 80, + "Draft_design": 6.5, + "Cb_design": 0.68, + "speed": 10, + "crew": 20, + "K": 0.032, + "MCR": 10000, + "SFC": 0.000215, + "Co": 0.3, + "tripDuration": 40 + }, + "objectOverrides": { + "common": { + "fullness": 0.7 + } + } }, - "objectOverrides": { - "common": { - "fullness": 0.7 - } - } -}, -"structure": { - "hull": { - "attributes": { - "LOA": 82, - "BOA": 18, - "Depth": 8, - "APP": 2 - }, - "halfBreadths": { - "waterlines": [0, 0.1111111111111111, 0.2222222222222222, 0.3333333333333333, 0.4444444444444444, 0.5555555555555556, 0.6666666666666666, 0.7777777777777778, 0.8888888888888888, 1], - "stations": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], - "table": [[0,0,0,0,0,0,0,0,0,0,null],[0,0,0,0.07017543859649122,0.4789473684210526,0.5605263157894737,0.513157894736842,0.38947368421052636,0.21403508771929824,0.06315789473684211,null],[0.27017543859649124,0.637719298245614,0.7456140350877193,0.8114035087719298,0.8482456140350877,0.8464912280701754,0.7789473684210527,0.6342105263157894,0.40350877192982454,0.15789473684210525,null],[0.7929824561403508,0.8385964912280702,0.874561403508772,0.9052631578947369,0.9263157894736842,0.9342105263157895,0.8903508771929824,0.7728070175438597,0.5482456140350876,0.25789473684210523,0],[0.8464912280701754,0.8833333333333333,0.9131578947368421,0.9350877192982456,0.9535087719298244,0.9631578947368421,0.9333333333333333,0.8447368421052632,0.6517543859649122,0.3570175438596491,0.04035087719298246],[0.863157894736842,0.900877192982456,0.9289473684210526,0.9508771929824561,0.9692982456140351,0.9798245614035087,0.9587719298245614,0.8956140350877193,0.7359649122807018,0.45526315789473687,0.08508771929824561],[0.8789473684210526,0.9166666666666666,0.943859649122807,0.9666666666666666,0.9833333333333334,0.9929824561403509,0.981578947368421,0.9385964912280701,0.8070175438596491,0.5491228070175438,0.1385964912280702],[0.8850877192982456,0.9236842105263157,0.9508771929824561,0.9710526315789474,0.987719298245614,1,0.9991228070175439,0.9736842105263157,0.8710526315789473,0.6456140350877193,0.21140350877192984],[null,null,null,null,null,null,null,0.9780701754385965,0.8885964912280702,0.6947368421052631,0.2807017543859649],[null,null,null,null,null,null,null,null,null,null,0.3263157894736842]] - }, - "buttockHeights": {} + "structure": { + "hull": { + "attributes": { + "LOA": 82, + "BOA": 18, + "Depth": 8, + "APP": 2 + }, + "halfBreadths": { + "waterlines": [0, 0.1111111111111111, 0.2222222222222222, 0.3333333333333333, 0.4444444444444444, 0.5555555555555556, 0.6666666666666666, 0.7777777777777778, 0.8888888888888888, 1], + "stations": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], + "table": [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null], + [0, 0, 0, 0.07017543859649122, 0.4789473684210526, 0.5605263157894737, 0.513157894736842, 0.38947368421052636, 0.21403508771929824, 0.06315789473684211, null], + [0.27017543859649124, 0.637719298245614, 0.7456140350877193, 0.8114035087719298, 0.8482456140350877, 0.8464912280701754, 0.7789473684210527, 0.6342105263157894, 0.40350877192982454, 0.15789473684210525, null], + [0.7929824561403508, 0.8385964912280702, 0.874561403508772, 0.9052631578947369, 0.9263157894736842, 0.9342105263157895, 0.8903508771929824, 0.7728070175438597, 0.5482456140350876, 0.25789473684210523, 0], + [0.8464912280701754, 0.8833333333333333, 0.9131578947368421, 0.9350877192982456, 0.9535087719298244, 0.9631578947368421, 0.9333333333333333, 0.8447368421052632, 0.6517543859649122, 0.3570175438596491, 0.04035087719298246], + [0.863157894736842, 0.900877192982456, 0.9289473684210526, 0.9508771929824561, 0.9692982456140351, 0.9798245614035087, 0.9587719298245614, 0.8956140350877193, 0.7359649122807018, 0.45526315789473687, 0.08508771929824561], + [0.8789473684210526, 0.9166666666666666, 0.943859649122807, 0.9666666666666666, 0.9833333333333334, 0.9929824561403509, 0.981578947368421, 0.9385964912280701, 0.8070175438596491, 0.5491228070175438, 0.1385964912280702], + [0.8850877192982456, 0.9236842105263157, 0.9508771929824561, 0.9710526315789474, 0.987719298245614, 1, 0.9991228070175439, 0.9736842105263157, 0.8710526315789473, 0.6456140350877193, 0.21140350877192984], + [null, null, null, null, null, null, null, 0.9780701754385965, 0.8885964912280702, 0.6947368421052631, 0.2807017543859649], + [null, null, null, null, null, null, null, null, null, null, 0.3263157894736842] + ] + }, + "buttockHeights": {} + }, + "decks": { + "WheelHouseTop": { + "zFloor": 23.4, + "thickness": 0.3, + "xAft": 52, + "xFwd": 80, + "yCentre": 0, + "breadth": 18, + "density": 1500 + }, + "BridgeDeck": { + "zFloor": 19.2, + "thickness": 0.3, + "xAft": 52, + "xFwd": 80, + "yCentre": 0, + "breadth": 18, + "density": 1500 + }, + "Cdeck": { + "zFloor": 16.5, + "thickness": 0.3, + "xAft": 44, + "xFwd": 82, + "yCentre": 0, + "breadth": 18, + "density": 1500 + }, + "Bdeck": { + "zFloor": 13.8, + "thickness": 0.3, + "xAft": 44, + "xFwd": 82, + "yCentre": 0, + "breadth": 18, + "density": 1500 + }, + "Adeck": { + "zFloor": 10.9, + "thickness": 0.3, + "xAft": 0, + "xFwd": 82, + "yCentre": 0, + "breadth": 18, + "density": 1500 + }, + "MainDeck": { + "zFloor": 8, + "thickness": 0.3, + "xAft": 0, + "xFwd": 82, + "yCentre": 0, + "breadth": 18, + "density": 1500 + }, + "TweenDeck": { + "zFloor": 5.3, + "thickness": 0.3, + "xAft": 0, + "xFwd": 82, + "yCentre": 0, + "breadth": 18, + "density": 1500 + }, + "TankTop": { + "zFloor": 1, + "thickness": 0.3, + "xAft": 0, + "xFwd": 82, + "yCentre": 0, + "breadth": 18, + "density": 1500 + } + }, + "bulkheads": { + "AB": { + "xAft": 50, + "thickness": 0.1, + "density": 7850 + } + } }, - "decks": { - "WheelHouseTop": { - "zFloor": 23.4, - "thickness": 0.3, - "xAft": 52, - "xFwd": 80, + "baseObjects": [{ + "id": "TankL2.1B6.13H4.3fdundefinedFtank1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.1, + "breadth": 6.13, + "height": 4.3 + }, + "capabilities": {}, + "file3D": "tank1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 43.47485139688601, + "lightweight": 553.539, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.15], + [0, 0, 0.6449999999999999], + [0, 0, 1.2899999999999998], + [0, 0, 1.72], + [0, 0, 2.15] + ] + } + } + }, { + "id": "TankL2.1B6.13H4.3fdundefinedFundefined", + "affiliations": {}, + "boxDimensions": { + "length": 2.1, + "breadth": 6.13, + "height": 4.3 + }, + "capabilities": {}, + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 43.47485139688601, + "lightweight": 553.539, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.15], + [0, 0, 0.6449999999999999], + [0, 0, 1.2899999999999998], + [0, 0, 1.72], + [0, 0, 2.15] + ] + } + } + }, { + "id": "TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4.199999999999999, + "breadth": 6.7, + "height": 4.3 + }, + "capabilities": {}, + "file3D": "tank2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 95.03474856741802, + "lightweight": 1210.0199999999998, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.15], + [0, 0, 0.6449999999999999], + [0, 0, 1.2899999999999998], + [0, 0, 1.72], + [0, 0, 2.15] + ] + } + } + }, { + "id": "TankL4.8999999999999995B6.1H4.3fdundefinedFtank3.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4.8999999999999995, + "breadth": 6.1, + "height": 4.3 + }, + "capabilities": {}, + "file3D": "tank3.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 100.94486974698383, + "lightweight": 1285.2699999999995, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.15], + [0, 0, 0.6449999999999999], + [0, 0, 1.2899999999999998], + [0, 0, 1.72], + [0, 0, 2.15] + ] + } + } + }, { + "id": "TankL6.699999999999999B5.5H4.3fdundefinedFtank4.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6.699999999999999, + "breadth": 5.5, + "height": 4.3 + }, + "capabilities": {}, + "file3D": "tank4.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 124.45026598114265, + "lightweight": 1584.55, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.15], + [0, 0, 0.6449999999999999], + [0, 0, 1.2899999999999998], + [0, 0, 1.72], + [0, 0, 2.15] + ] + } + } + }, { + "id": "PropulsionroomL3.5B4H4.3fdundefinedFPropulsionRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 4, + "height": 4.3 + }, + "capabilities": {}, + "file3D": "PropulsionRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6020, + "cg": [0, 0, 2.15] + } + }, { + "id": "TankL4.200000000000003B1.5H5.3fdundefinedFtank5.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4.200000000000003, + "breadth": 1.5, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank5.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 26.224444675840815, + "lightweight": 333.9000000000002, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "DryBulkL3.6999999999999993B3.5H5.3fdundefinedFDryBulk.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.6999999999999993, + "breadth": 3.5, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "DryBulk.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6863.499999999998, + "cg": [0, 0, 2.65] + } + }, { + "id": "DryBulkL3.5B3.5H5.3fdundefinedFDryBulk.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 3.5, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "DryBulk.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6492.5, + "cg": [0, 0, 2.65] + } + }, { + "id": "FOOverFlowL3.5B3H4.3fdundefinedFFOOverFlow.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 3, + "height": 4.3 + }, + "capabilities": {}, + "file3D": "FOOverFlow.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 4515, + "cg": [0, 0, 2.15] + } + }, { + "id": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 5.5, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "MudBrineOroSlop.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 10202.5, + "cg": [0, 0, 2.65] + } + }, { + "id": "TankL6.5B1H5.3fdundefinedFtank6.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6.5, + "breadth": 1, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank6.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 27.056966729042095, + "lightweight": 344.5, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "TankL3.5B2.5H5.3fdundefinedFtank7.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 2.5, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank7.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 36.422839827556665, + "lightweight": 463.75, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "TankL1B1.5H5.3fdundefinedFtank8.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1, + "breadth": 1.5, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank8.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 6.243915399009714, + "lightweight": 79.5, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "SewageL3.5B3H5.3fdundefinedFsewage.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 3, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "sewage.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 5565, + "cg": [0, 0, 2.65] + } + }, { + "id": "TankL6B3H5.3fdundefinedFtank10.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 3, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank10.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 74.92698478811657, + "lightweight": 954, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "TankL3.5B1.5H5.3fdundefinedFtank9.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 1.5, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank9.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 21.853703896534, + "lightweight": 278.25, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "TankL10.5B3H5.3fdundefinedFtank11.stl", + "affiliations": {}, + "boxDimensions": { + "length": 10.5, + "breadth": 3, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank11.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 131.122223379204, + "lightweight": 1669.5, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "TankL6.5B10H9.5fdundefinedFtank12.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6.5, + "breadth": 10, + "height": 9.5 + }, + "capabilities": {}, + "file3D": "tank12.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 484.98336589792433, + "lightweight": 6175, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 4.75], + [0, 0, 1.425], + [0, 0, 2.85], + [0, 0, 3.8000000000000003], + [0, 0, 4.75] + ] + } + } + }, { + "id": "EngineRoomLowerL12B7H3.9fdundefinedFEngineRoomLower.stl", + "affiliations": {}, + "boxDimensions": { + "length": 12, + "breadth": 7, + "height": 3.9 + }, + "capabilities": {}, + "file3D": "EngineRoomLower.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 32760, + "cg": [0, 0, 1.95] + } + }, { + "id": "BowThrusterRoomL12B3H3.9fdundefinedFBowThrusterRoom1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 12, + "breadth": 3, + "height": 3.9 + }, + "capabilities": {}, + "file3D": "BowThrusterRoom1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 14040, + "cg": [0, 0, 1.95] + } + }, { + "id": "TankL3B9H2.7fdundefinedFtank13.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3, + "breadth": 9, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "tank13.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 57.25552611167398, + "lightweight": 729, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.35], + [0, 0, 0.405], + [0, 0, 0.81], + [0, 0, 1.08], + [0, 0, 1.35] + ] + } + } + }, { + "id": "TankL4B3H2.7fdundefinedFtank14.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4, + "breadth": 3, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "tank14.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 25.446900494077326, + "lightweight": 324, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.35], + [0, 0, 0.405], + [0, 0, 0.81], + [0, 0, 1.08], + [0, 0, 1.35] + ] + } + } + }, { + "id": "MotorLeftL6B4H2.7fdundefinedFMotors.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "Motors.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6480, + "cg": [0, 0, 1.35] + } + }, { + "id": "MotorRightL6B4H2.7fdundefinedFMotors.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "Motors.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6480, + "cg": [0, 0, 1.35] + } + }, { + "id": "PropulsionRoomUpperL6B4H2.7fdundefinedFPropulsionRoomUpper.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "PropulsionRoomUpper.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6480, + "cg": [0, 0, 1.35] + } + }, { + "id": "TankL3B18H2.7fdundefinedFtank15.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3, + "breadth": 18, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "tank15.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 114.51105222334796, + "lightweight": 1458, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.35], + [0, 0, 0.405], + [0, 0, 0.81], + [0, 0, 1.08], + [0, 0, 1.35] + ] + } + } + }, { + "id": "TankL4.5B7H2.4fdundefinedFtank17.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4.5, + "breadth": 7, + "height": 2.4 + }, + "capabilities": {}, + "file3D": "tank17.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 59.37610115284709, + "lightweight": 756, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.2], + [0, 0, 0.36], + [0, 0, 0.72], + [0, 0, 0.96], + [0, 0, 1.2] + ] + } + } + }, { + "id": "TankL6B1H2.4fdundefinedFtank16.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 1, + "height": 2.4 + }, + "capabilities": {}, + "file3D": "tank16.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 11.309733552923255, + "lightweight": 144, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.2], + [0, 0, 0.36], + [0, 0, 0.72], + [0, 0, 0.96], + [0, 0, 1.2] + ] + } + } + }, { + "id": "SwitchBoardRoomL3.5B9H2.4fdundefinedFSwitchBoardRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 9, + "height": 2.4 + }, + "capabilities": {}, + "file3D": "SwitchBoardRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 7560, + "cg": [0, 0, 1.2] + } + }, { + "id": "EngineRoomUpperL8.5B7H2.4fdundefinedFEngineRoomUpper.stl", + "affiliations": {}, + "boxDimensions": { + "length": 8.5, + "breadth": 7, + "height": 2.4 + }, + "capabilities": {}, + "file3D": "EngineRoomUpper.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 14280, + "cg": [0, 0, 1.2] + } + }, { + "id": "BowThrusterRoomL12B3H2.7fdundefinedFBowThursterRoom2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 12, + "breadth": 3, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "BowThursterRoom2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 9720, + "cg": [0, 0, 1.35] + } + }, { + "id": "WorkShopL3B2H2.4fdundefinedFWorkshop.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3, + "breadth": 2, + "height": 2.4 + }, + "capabilities": {}, + "file3D": "Workshop.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1440, + "cg": [0, 0, 1.2] + } + }, { + "id": "ChainTankL1.5B1.5H5.6fdundefinedFChainTank.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 1.5, + "height": 5.6 + }, + "capabilities": {}, + "file3D": "ChainTank.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 9.896016858807847, + "lightweight": 125.99999999999999, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.8], + [0, 0, 0.84], + [0, 0, 1.68], + [0, 0, 2.2399999999999998], + [0, 0, 2.8] + ] + } + } + }, { + "id": "CoverL53B15H2.9fdundefinedFcover1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 53, + "breadth": 15, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "cover1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 230550, + "cg": [0, 0, 1.45] + } + }, { + "id": "TankL7B1.5H2.9fdundefinedFtank18.stl", + "affiliations": {}, + "boxDimensions": { + "length": 7, + "breadth": 1.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "tank18.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 23.915374075452302, + "lightweight": 304.5, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.45], + [0, 0, 0.435], + [0, 0, 0.87], + [0, 0, 1.16], + [0, 0, 1.45] + ] + } + } + }, { + "id": "TankL1B2H2.9fdundefinedFtank19.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1, + "breadth": 2, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "tank19.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 4.5553093477052, + "lightweight": 58, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.45], + [0, 0, 0.435], + [0, 0, 0.87], + [0, 0, 1.16], + [0, 0, 1.45] + ] + } + } + }, { + "id": "FiremStoreL2.5B1.5H2.9fdundefinedFFiremStore.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 1.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "FiremStore.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1087.5, + "cg": [0, 0, 1.45] + } + }, { + "id": "DeckWorkshopL2.5B3.5H2.9fdundefinedFDeckWorkshop.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 3.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "DeckWorkshop.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 2537.5, + "cg": [0, 0, 1.45] + } + }, { + "id": "TankL2B1.5H2.9fdundefinedFtank20.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2, + "breadth": 1.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "tank20.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 6.8329640215578, + "lightweight": 87, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.45], + [0, 0, 0.435], + [0, 0, 0.87], + [0, 0, 1.16], + [0, 0, 1.45] + ] + } + } + }, { + "id": "StoreL2B2H2.9fdundefinedFStore1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2, + "breadth": 2, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "Store1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1160, + "cg": [0, 0, 1.45] + } + }, { + "id": "ChemL2.5B1.5H2.9fdundefinedFchem.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 1.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "chem.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1087.5, + "cg": [0, 0, 1.45] + } + }, { + "id": "PaintL2.5B1.5H2.9fdundefinedFpaint.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 1.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "paint.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1087.5, + "cg": [0, 0, 1.45] + } + }, { + "id": "Inc&GarbRoomL5B4.5H2.9fdundefinedFInc&GarbRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5, + "breadth": 4.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "Inc&GarbRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6525, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL3.5B4.5H2.9fdundefinedFroom1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 4.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 4567.5, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL3.5B6H2.9fdundefinedFroom2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 6, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6090, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL1.5B4.5H2.9fdundefinedFroom3.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 4.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room3.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1957.5, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL4B2H2.9fdundefinedFroom4.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4, + "breadth": 2, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room4.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 2320, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL4B3.5H2.9fdundefinedFroom5.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4, + "breadth": 3.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room5.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 4060, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL3.5B5H2.9fdundefinedFroom6.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room6.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 5075, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL3.5B6H2.9fdundefinedFroom7.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 6, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room7.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6090, + "cg": [0, 0, 1.45] + } + }, { + "id": "TankL1.5B4.5H2.9fdundefinedFtank21.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 4.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "tank21.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 15.374169048505049, + "lightweight": 195.75, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.45], + [0, 0, 0.435], + [0, 0, 0.87], + [0, 0, 1.16], + [0, 0, 1.45] + ] + } + } + }, { + "id": "RoomL7B5H2.9fdundefinedFroom8.stl", + "affiliations": {}, + "boxDimensions": { + "length": 7, + "breadth": 5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room8.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 10150, + "cg": [0, 0, 1.45] + } + }, { + "id": "StairsL6B3H2.9fdundefinedFstairs1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 3, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "stairs1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 5220, + "cg": [0, 0, 1.45] + } + }, { + "id": "ToiletsL1B2.5H2.9fdundefinedFtoilets1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1, + "breadth": 2.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "toilets1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 725, + "cg": [0, 0, 1.45] + } + }, { + "id": "DeckOfficeL2.5B6.5H2.9fdundefinedFDeckOffice1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 6.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "DeckOffice1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 4712.5, + "cg": [0, 0, 1.45] + } + }, { + "id": "CoverL53.5B15H2fdundefinedFcover2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 53.5, + "breadth": 15, + "height": 2 + }, + "capabilities": {}, + "file3D": "cover2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 160500, + "cg": [0, 0, 1] + } + }, { + "id": "StabTankL3.5B18H2.9fdundefinedFStabTank.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 18, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "StabTank.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 143.4922444527138, + "lightweight": 1827, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 1.45], + [0, 0, 0.435], + [0, 0, 0.87], + [0, 0, 1.16], + [0, 0, 1.45] + ] + } + } + }, { + "id": "FreezerL3.5B2H2.9fdundefinedFfreezer.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 2, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "freezer.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 2030, + "cg": [0, 0, 1.45] + } + }, { + "id": "FridgeL4B1.5H2.9fdundefinedFfridge.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4, + "breadth": 1.5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "fridge.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1740, + "cg": [0, 0, 1.45] + } + }, { + "id": "DryRoomL7.5B3H2.9fdundefinedFDryRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 7.5, + "breadth": 3, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "DryRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6525, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL2.5B8H2.9fdundefinedFroom9.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 8, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room9.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 5800, + "cg": [0, 0, 1.45] + } + }, { + "id": "ACRoomL7.5B5H2.9fdundefinedFACRoom1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 7.5, + "breadth": 5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "ACRoom1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 10875, + "cg": [0, 0, 1.45] + } + }, { + "id": "RoomL5B5H2.9fdundefinedFroom10.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5, + "breadth": 5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "room10.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 7250, + "cg": [0, 0, 1.45] + } + }, { + "id": "CLL2.5B2H2.9fdundefinedFCL1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 2, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "CL1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1450, + "cg": [0, 0, 1.45] + } + }, { + "id": "ToiletsL2.5B2H2.9fdundefinedFtoilets2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 2, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "toilets2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1450, + "cg": [0, 0, 1.45] + } + }, { + "id": "GalleryL5.5B5H2.9fdundefinedFgallery1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5.5, + "breadth": 5, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "gallery1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 7975, + "cg": [0, 0, 1.45] + } + }, { + "id": "StairsL5.5B4H2.9fdundefinedFstairs1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5.5, + "breadth": 4, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "stairs1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6380, + "cg": [0, 0, 1.45] + } + }, { + "id": "DayRoomL5.5B6H2.9fdundefinedFDayRoom1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5.5, + "breadth": 6, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "DayRoom1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 9570, + "cg": [0, 0, 1.45] + } + }, { + "id": "MessRoomL4B13H2.9fdundefinedFMessRoom1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4, + "breadth": 13, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "MessRoom1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 15080, + "cg": [0, 0, 1.45] + } + }, { + "id": "RopeBinL1.5B3H2.9fdundefinedFRopeBin1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 3, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "RopeBin1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1305, + "cg": [0, 0, 1.45] + } + }, { + "id": "StoreL1.5B4H2.9fdundefinedFstore.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 4, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "store.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1740, + "cg": [0, 0, 1.45] + } + }, { + "id": "StoreL6.5B10H2.9fdundefinedFstore2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6.5, + "breadth": 10, + "height": 2.9 + }, + "capabilities": {}, + "file3D": "store2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 18850, + "cg": [0, 0, 1.45] + } + }, { + "id": "SafetyBoatL6.5B3H1fdundefinedFSafetyBoat.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6.5, + "breadth": 3, + "height": 1 + }, + "capabilities": {}, + "file3D": "SafetyBoat.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1950, + "cg": [0, 0, 0.5] + } + }, { + "id": "HoistBaseL3B3H5.4fdundefinedFHoistBase.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3, + "breadth": 3, + "height": 5.4 + }, + "capabilities": {}, + "file3D": "HoistBase.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 4860, + "cg": [0, 0, 2.7] + } + }, { + "id": "StairsL5.5B4H2.7fdundefinedFstairs1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5.5, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "stairs1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 5940, + "cg": [0, 0, 1.35] + } + }, { + "id": "CableRoomL10.5B14H2.7fdundefinedFCableRoom1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 10.5, + "breadth": 14, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "CableRoom1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 39690, + "cg": [0, 0, 1.35] + } + }, { + "id": "CabinL2.5B4H2.7fdundefinedFcabin1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "cabin1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 2700, + "cg": [0, 0, 1.35] + } + }, { + "id": "CabinL4.5B4H2.7fdundefinedFcabin2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4.5, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "cabin2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 4860, + "cg": [0, 0, 1.35] + } + }, { + "id": "TankL5.5B4H5.3fdundefinedFtank22.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5.5, + "breadth": 4, + "height": 5.3 + }, + "capabilities": {}, + "file3D": "tank22.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "contentDensity": 1000, + "volumeCapacity": 91.57742585214245, + "lightweight": 1166, + "fullnessCGMapping": { + "fullnesses": [0, 0.25, 0.5, 0.75, 1], + "cgs": [ + [0, 0, 2.65], + [0, 0, 0.7949999999999999], + [0, 0, 1.5899999999999999], + [0, 0, 2.12], + [0, 0, 2.65] + ] + } + } + }, { + "id": "RoomL4.5B8H2.7fdundefinedFroom11.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4.5, + "breadth": 8, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "room11.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 9720, + "cg": [0, 0, 1.35] + } + }, { + "id": "CabinL5B4.5H2.7fdundefinedFcabin3.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5, + "breadth": 4.5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "cabin3.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 6075, + "cg": [0, 0, 1.35] + } + }, { + "id": "CabinL5B6.5H2.7fdundefinedFcabin5.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5, + "breadth": 6.5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "cabin5.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 8775, + "cg": [0, 0, 1.35] + } + }, { + "id": "CabinL2.5B5H2.7fdundefinedFcabin4.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "cabin4.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 3375, + "cg": [0, 0, 1.35] + } + }, { + "id": "CorridorExtL3.5B13.5H2.7fdundefinedFcorridor.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3.5, + "breadth": 13.5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "corridor.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 12757.5, + "cg": [0, 0, 1.35] + } + }, { + "id": "InstrumentRoomL5.5B3.5H2.7fdundefinedFInstrumentRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 5.5, + "breadth": 3.5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "InstrumentRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 5197.5, + "cg": [0, 0, 1.35] + } + }, { + "id": "CaptainCabinL6B5H2.7fdundefinedFCaptainCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "CaptainCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 8100.000000000001, + "cg": [0, 0, 1.35] + } + }, { + "id": "ChiefOfficerCabinL3B4.5H2.7fdundefinedFChiefOfficerCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3, + "breadth": 4.5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "ChiefOfficerCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 3645.0000000000005, + "cg": [0, 0, 1.35] + } + }, { + "id": "FirstOfficerCabinL3B4H2.7fdundefinedFFirstOfficerCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 3, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "FirstOfficerCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 3240, + "cg": [0, 0, 1.35] + } + }, { + "id": "ChiefStewardCabinL6B6H2.7fdundefinedFChiefStewardCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 6, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "ChiefStewardCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 9720, + "cg": [0, 0, 1.35] + } + }, { + "id": "ElectricianCabinL6B6H2.7fdundefinedFElectricianCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 6, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "ElectricianCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 9720, + "cg": [0, 0, 1.35] + } + }, { + "id": "StairsL4.5B4H2.7fdundefinedFstairs2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4.5, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "stairs2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 4860, + "cg": [0, 0, 1.35] + } + }, { + "id": "CleanLockerL1.5B2H2.7fdundefinedFSmallRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 2, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "SmallRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 810, + "cg": [0, 0, 1.35] + } + }, { + "id": "BondStoreL1.5B2H2.7fdundefinedFSmallRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 2, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "SmallRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 810, + "cg": [0, 0, 1.35] + } + }, { + "id": "LinenL1.5B2H2.7fdundefinedFSmallRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1.5, + "breadth": 2, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "SmallRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 810, + "cg": [0, 0, 1.35] + } + }, { + "id": "ChiefCabinL6B5H2.7fdundefinedFChiefCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 6, + "breadth": 5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "ChiefCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 8100.000000000001, + "cg": [0, 0, 1.35] + } + }, { + "id": "FirstEngineerCabinL2.5B4H2.7fdundefinedFFirstEngineerCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2.5, + "breadth": 4, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "FirstEngineerCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 2700, + "cg": [0, 0, 1.35] + } + }, { + "id": "SecondEngineerCabinL2B3.5H2.7fdundefinedFSecondEngineerCabin.stl", + "affiliations": {}, + "boxDimensions": { + "length": 2, + "breadth": 3.5, + "height": 2.7 + }, + "capabilities": {}, + "file3D": "SecondEngineerCabin.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 1890.0000000000002, + "cg": [0, 0, 1.35] + } + }, { + "id": "HoistL1B9H4.15fdundefinedFhoist.stl", + "affiliations": {}, + "boxDimensions": { + "length": 1, + "breadth": 9, + "height": 4.15 + }, + "capabilities": {}, + "file3D": "hoist.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 3735.0000000000005, + "cg": [0, 0, 2.075] + } + }, { + "id": "AccessStairsL4B5H4.15fdundefinedFAccessStairs1.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4, + "breadth": 5, + "height": 4.15 + }, + "capabilities": {}, + "file3D": "AccessStairs1.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 8300, + "cg": [0, 0, 2.075] + } + }, { + "id": "AccessStairsL4B5H4.15fdundefinedFAccessStairs2.stl", + "affiliations": {}, + "boxDimensions": { + "length": 4, + "breadth": 5, + "height": 4.15 + }, + "capabilities": {}, + "file3D": "AccessStairs2.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 8300, + "cg": [0, 0, 2.075] + } + }, { + "id": "ShipHandingL7B8H4.15fdundefinedFShipHanding.stl", + "affiliations": {}, + "boxDimensions": { + "length": 7, + "breadth": 8, + "height": 4.15 + }, + "capabilities": {}, + "file3D": "ShipHanding.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 23240.000000000004, + "cg": [0, 0, 2.075] + } + }, { + "id": "MainRoomL8B16H4.15fdundefinedFMainRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 8, + "breadth": 16, + "height": 4.15 + }, + "capabilities": {}, + "file3D": "MainRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 53120.00000000001, + "cg": [0, 0, 2.075] + } + }, { + "id": "NavigationRoomL9B8H4.15fdundefinedFNavigationRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 9, + "breadth": 8, + "height": 4.15 + }, + "capabilities": {}, + "file3D": "NavigationRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 29880.000000000004, + "cg": [0, 0, 2.075] + } + }, { + "id": "EmGenRoomL11B6H5fdundefinedFEmGenRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 11, + "breadth": 6, + "height": 5 + }, + "capabilities": {}, + "file3D": "EmGenRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 33000, + "cg": [0, 0, 2.5] + } + }, { + "id": "CommunicationL11B3H5fdundefinedFCommunicationRoom.stl", + "affiliations": {}, + "boxDimensions": { + "length": 11, + "breadth": 3, + "height": 5 + }, + "capabilities": {}, + "file3D": "CommunicationRoom.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 16500, + "cg": [0, 0, 2.5] + } + }, { + "id": "AerialL0.5B0.5H2fdundefinedFaerial.stl", + "affiliations": {}, + "boxDimensions": { + "length": 0.5, + "breadth": 0.5, + "height": 2 + }, + "capabilities": {}, + "file3D": "aerial.stl", + "baseState": { + "fullness": 0.5 + }, + "weightInformation": { + "lightweight": 50, + "cg": [0, 0, 1] + } + }], + + "derivedObjects": [{ + "id": "Tank1", + "baseObject": "TankL2.1B6.13H4.3fdundefinedFtank1.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "101" + }, + "referenceState": { + "xCentre": 1.05, + "yCentre": 2.9, + "zBase": 1 + } + }, { + "id": "Tank2", + "baseObject": "TankL2.1B6.13H4.3fdundefinedFundefined", + "affiliations": { + "Deck": "TankTop", + "SFI": "102" + }, + "referenceState": { + "xCentre": 1.05, + "yCentre": -2.9, + "zBase": 1 + } + }, { + "id": "Tank3", + "baseObject": "TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "103" + }, + "referenceState": { + "xCentre": 4.2, + "yCentre": 3.25, + "zBase": 1 + } + }, { + "id": "Tank4", + "baseObject": "TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "104" + }, + "referenceState": { + "xCentre": 4.2, + "yCentre": -3.25, + "zBase": 1 + } + }, { + "id": "Tank5", + "baseObject": "TankL4.8999999999999995B6.1H4.3fdundefinedFtank3.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "105" + }, + "referenceState": { + "xCentre": 8.75, + "yCentre": 4, + "zBase": 1 + } + }, { + "id": "Tank6", + "baseObject": "TankL4.8999999999999995B6.1H4.3fdundefinedFtank3.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "106" + }, + "referenceState": { + "xCentre": 8.75, + "yCentre": -4, + "zBase": 1 + } + }, { + "id": "Tank7", + "baseObject": "TankL6.699999999999999B5.5H4.3fdundefinedFtank4.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "107" + }, + "referenceState": { + "xCentre": 14.549999999999999, + "yCentre": 5.25, + "zBase": 1 + } + }, { + "id": "Tank8", + "baseObject": "TankL6.699999999999999B5.5H4.3fdundefinedFtank4.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "108" + }, + "referenceState": { + "xCentre": 14.549999999999999, + "yCentre": -5.25, + "zBase": 1 + } + }, { + "id": "Propulsion room", + "baseObject": "PropulsionroomL3.5B4H4.3fdundefinedFPropulsionRoom.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "109" + }, + "referenceState": { + "xCentre": 13.25, + "yCentre": 0, + "zBase": 1 + } + }, { + "id": "Tank9", + "baseObject": "TankL4.200000000000003B1.5H5.3fdundefinedFtank5.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "110" + }, + "referenceState": { + "xCentre": 20, + "yCentre": 6.25, + "zBase": 1 + } + }, { + "id": "Tank10", + "baseObject": "TankL4.200000000000003B1.5H5.3fdundefinedFtank5.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "111" + }, + "referenceState": { + "xCentre": 20, + "yCentre": -6.25, + "zBase": 1 + } + }, { + "id": "DryBulk1", + "baseObject": "DryBulkL3.6999999999999993B3.5H5.3fdundefinedFDryBulk.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "112" + }, + "referenceState": { + "xCentre": 20.35, + "yCentre": 3.25, + "zBase": 1 + } + }, { + "id": "DryBulk2", + "baseObject": "DryBulkL3.6999999999999993B3.5H5.3fdundefinedFDryBulk.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "113" + }, + "referenceState": { + "xCentre": 20.35, + "yCentre": -3, + "zBase": 1 + } + }, { + "id": "DryBulk3", + "baseObject": "DryBulkL3.5B3.5H5.3fdundefinedFDryBulk.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "114" + }, + "referenceState": { + "xCentre": 24.05, + "yCentre": 4.75, + "zBase": 1 + } + }, { + "id": "DryBulk4", + "baseObject": "DryBulkL3.5B3.5H5.3fdundefinedFDryBulk.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "115" + }, + "referenceState": { + "xCentre": 24.05, + "yCentre": -4.75, + "zBase": 1 + } + }, { + "id": "FOOverFlow1", + "baseObject": "FOOverFlowL3.5B3H4.3fdundefinedFFOOverFlow.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "116" + }, + "referenceState": { + "xCentre": 24.25, + "yCentre": 0, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop1", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "117" + }, + "referenceState": { + "xCentre": 29.25, + "yCentre": 3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop2", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "118" + }, + "referenceState": { + "xCentre": 29.25, + "yCentre": -3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop3", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "119" + }, + "referenceState": { + "xCentre": 33.25, + "yCentre": 3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop4", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "120" + }, + "referenceState": { + "xCentre": 33.25, + "yCentre": -3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop5", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "121" + }, + "referenceState": { + "xCentre": 37.25, + "yCentre": 3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop6", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "122" + }, + "referenceState": { + "xCentre": 37.25, + "yCentre": -3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop7", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "123" + }, + "referenceState": { + "xCentre": 41.25, + "yCentre": 3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop8", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "124" + }, + "referenceState": { + "xCentre": 41.25, + "yCentre": -3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop9", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "125" + }, + "referenceState": { + "xCentre": 45.25, + "yCentre": 3.75, + "zBase": 1 + } + }, { + "id": "MudBrineOroSlop10", + "baseObject": "MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "126" + }, + "referenceState": { + "xCentre": 45.25, + "yCentre": -3.75, + "zBase": 1 + } + }, { + "id": "Tank11", + "baseObject": "TankL6.5B1H5.3fdundefinedFtank6.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "127" + }, + "referenceState": { + "xCentre": 29.25, + "yCentre": 7.5, + "zBase": 1 + } + }, { + "id": "Tank12", + "baseObject": "TankL6.5B1H5.3fdundefinedFtank6.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "128" + }, + "referenceState": { + "xCentre": 29.25, + "yCentre": -7.5, + "zBase": 1 + } + }, { + "id": "Tank13", + "baseObject": "TankL6.5B1H5.3fdundefinedFtank6.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "129" + }, + "referenceState": { + "xCentre": 35.75, + "yCentre": 7.5, + "zBase": 1 + } + }, { + "id": "Tank14", + "baseObject": "TankL6.5B1H5.3fdundefinedFtank6.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "130" + }, + "referenceState": { + "xCentre": 35.75, + "yCentre": -7.5, + "zBase": 1 + } + }, { + "id": "Tank15", + "baseObject": "TankL6.5B1H5.3fdundefinedFtank6.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "131" + }, + "referenceState": { + "xCentre": 42.25, + "yCentre": 7.5, + "zBase": 1 + } + }, { + "id": "Tank16", + "baseObject": "TankL6.5B1H5.3fdundefinedFtank6.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "132" + }, + "referenceState": { + "xCentre": 42.25, + "yCentre": -7.5, + "zBase": 1 + } + }, { + "id": "Tank17", + "baseObject": "TankL3.5B2.5H5.3fdundefinedFtank7.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "133" + }, + "referenceState": { + "xCentre": 51.75, + "yCentre": 5.75, + "zBase": 1.4 + } + }, { + "id": "Tank18", + "baseObject": "TankL3.5B2.5H5.3fdundefinedFtank7.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "134" + }, + "referenceState": { + "xCentre": 51.75, + "yCentre": -5.75, + "zBase": 1.4 + } + }, { + "id": "Tank18", + "baseObject": "TankL1B1.5H5.3fdundefinedFtank8.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "135" + }, + "referenceState": { + "xCentre": 54, + "yCentre": 5.75, + "zBase": 1.4 + } + }, { + "id": "Tank19", + "baseObject": "TankL1B1.5H5.3fdundefinedFtank8.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "136" + }, + "referenceState": { + "xCentre": 55, + "yCentre": 5.75, + "zBase": 1.4 + } + }, { + "id": "Sewage1", + "baseObject": "SewageL3.5B3H5.3fdundefinedFsewage.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "137" + }, + "referenceState": { + "xCentre": 57.25, + "yCentre": 5.75, + "zBase": 1.4 + } + }, { + "id": "Tank20", + "baseObject": "TankL6B3H5.3fdundefinedFtank10.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "138" + }, + "referenceState": { + "xCentre": 62, + "yCentre": 5, + "zBase": 1.4 + } + }, { + "id": "Tank21", + "baseObject": "TankL6B3H5.3fdundefinedFtank10.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "139" + }, + "referenceState": { + "xCentre": 62, + "yCentre": -5, + "zBase": 1.4 + } + }, { + "id": "Tank122", + "baseObject": "TankL1B1.5H5.3fdundefinedFtank8.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "140" + }, + "referenceState": { + "xCentre": 54, + "yCentre": -5.75, + "zBase": 1.4 + } + }, { + "id": "Tank22", + "baseObject": "TankL1B1.5H5.3fdundefinedFtank8.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "141" + }, + "referenceState": { + "xCentre": 55, + "yCentre": -5.75, + "zBase": 1.4 + } + }, { + "id": "Tank23", + "baseObject": "TankL3.5B1.5H5.3fdundefinedFtank9.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "142" + }, + "referenceState": { + "xCentre": 57.25, + "yCentre": -5.25, + "zBase": 1.4 + } + }, { + "id": "Tank24", + "baseObject": "TankL10.5B3H5.3fdundefinedFtank11.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "143" + }, + "referenceState": { + "xCentre": 70.25, + "yCentre": 3, + "zBase": 1.4 + } + }, { + "id": "Tank25", + "baseObject": "TankL10.5B3H5.3fdundefinedFtank11.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "144" + }, + "referenceState": { + "xCentre": 70.25, + "yCentre": -3, + "zBase": 1.4 + } + }, { + "id": "Tank26", + "baseObject": "TankL6.5B10H9.5fdundefinedFtank12.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "145" + }, + "referenceState": { + "xCentre": 78.75, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 1.4 + } + }, { + "id": "EngineRoomLower1", + "baseObject": "EngineRoomLowerL12B7H3.9fdundefinedFEngineRoomLower.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "146" }, - "BridgeDeck": { - "zFloor": 19.2, - "thickness": 0.3, - "xAft": 52, - "xFwd": 80, + "referenceState": { + "xCentre": 56, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 1.4 + } + }, { + "id": "BowThrusterRoom1", + "baseObject": "BowThrusterRoomL12B3H3.9fdundefinedFBowThrusterRoom1.stl", + "affiliations": { + "Deck": "TankTop", + "SFI": "147" }, - "Cdeck": { - "zFloor": 16.5, - "thickness": 0.3, - "xAft": 44, - "xFwd": 82, + "referenceState": { + "xCentre": 68, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 1.4 + } + }, { + "id": "Tank27", + "baseObject": "TankL3B9H2.7fdundefinedFtank13.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "201" + }, + "referenceState": { + "xCentre": 1.5, + "yCentre": 4.5, + "zBase": 5.3 + } + }, { + "id": "Tank28", + "baseObject": "TankL3B9H2.7fdundefinedFtank13.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "202" + }, + "referenceState": { + "xCentre": 1.5, + "yCentre": -4.5, + "zBase": 5.3 + } + }, { + "id": "Tank28", + "baseObject": "TankL4B3H2.7fdundefinedFtank14.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "203" + }, + "referenceState": { + "xCentre": 5, + "yCentre": 7.5, + "zBase": 5.3 + } + }, { + "id": "Tank29", + "baseObject": "TankL4B3H2.7fdundefinedFtank14.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "204" + }, + "referenceState": { + "xCentre": 5, + "yCentre": -7.5, + "zBase": 5.3 + } + }, { + "id": "MotorLeft1", + "baseObject": "MotorLeftL6B4H2.7fdundefinedFMotors.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "205" + }, + "referenceState": { + "xCentre": 6, + "yCentre": 4, + "zBase": 5.3 + } + }, { + "id": "MotorRight1", + "baseObject": "MotorRightL6B4H2.7fdundefinedFMotors.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "206" + }, + "referenceState": { + "xCentre": 6, + "yCentre": -4, + "zBase": 5.3 + } + }, { + "id": "PropulsionRoomUpper", + "baseObject": "PropulsionRoomUpperL6B4H2.7fdundefinedFPropulsionRoomUpper.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "207" }, - "Bdeck": { - "zFloor": 13.8, - "thickness": 0.3, - "xAft": 44, - "xFwd": 82, + "referenceState": { + "xCentre": 6, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 5.3 + } + }, { + "id": "Tank30", + "baseObject": "TankL3B18H2.7fdundefinedFtank15.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "208" }, - "Adeck": { - "zFloor": 10.9, - "thickness": 0.3, - "xAft": 0, - "xFwd": 82, + "referenceState": { + "xCentre": 10.5, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 5.3 + } + }, { + "id": "Tank31", + "baseObject": "TankL4.5B7H2.4fdundefinedFtank17.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "209" + }, + "referenceState": { + "xCentre": 14.75, + "yCentre": 4.5, + "zBase": 5.3 + } + }, { + "id": "Tank32", + "baseObject": "TankL4.5B7H2.4fdundefinedFtank17.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "210" + }, + "referenceState": { + "xCentre": 14.75, + "yCentre": -4.5, + "zBase": 5.3 + } + }, { + "id": "Tank33", + "baseObject": "TankL6B1H2.4fdundefinedFtank16.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "211" }, - "MainDeck": { - "zFloor": 8, - "thickness": 0.3, - "xAft": 0, - "xFwd": 82, + "referenceState": { + "xCentre": 15, + "yCentre": 8.5, + "zBase": 5.3 + } + }, { + "id": "Tank34", + "baseObject": "TankL6B1H2.4fdundefinedFtank16.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "212" + }, + "referenceState": { + "xCentre": 15, + "yCentre": -8.5, + "zBase": 5.3 + } + }, { + "id": "SwitchBoardRoom1", + "baseObject": "SwitchBoardRoomL3.5B9H2.4fdundefinedFSwitchBoardRoom.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "213" + }, + "referenceState": { + "xCentre": 51.75, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 5.3 + } + }, { + "id": "EngineRoomUpper1", + "baseObject": "EngineRoomUpperL8.5B7H2.4fdundefinedFEngineRoomUpper.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "214" }, - "TweenDeck": { - "zFloor": 5.3, - "thickness": 0.3, - "xAft": 0, - "xFwd": 82, + "referenceState": { + "xCentre": 57.75, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 5.3 + } + }, { + "id": "BowThrusterRoom2", + "baseObject": "BowThrusterRoomL12B3H2.7fdundefinedFBowThursterRoom2.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "215" }, - "TankTop": { - "zFloor": 1, - "thickness": 0.3, - "xAft": 0, - "xFwd": 82, + "referenceState": { + "xCentre": 68, "yCentre": 0, - "breadth": 18, - "density": 1500 + "zBase": 5.3 } - }, - "bulkheads": { - "AB": { - "xAft": 50, - "thickness":0.1, - "density": 7850 - } - } -}, -"baseObjects": -[{"id":"TankL2.1B6.13H4.3fdundefinedFtank1.stl","affiliations":{},"boxDimensions":{"length":2.1,"breadth":6.13,"height":4.3},"capabilities":{},"file3D":"tank1.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":43.47485139688601,"lightweight":553.539,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}},{"id":"TankL2.1B6.13H4.3fdundefinedFundefined","affiliations":{},"boxDimensions":{"length":2.1,"breadth":6.13,"height":4.3},"capabilities":{},"baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":43.47485139688601,"lightweight":553.539,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}},{"id":"TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl","affiliations":{},"boxDimensions":{"length":4.199999999999999,"breadth":6.7,"height":4.3},"capabilities":{},"file3D":"tank2.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":95.03474856741802,"lightweight":1210.0199999999998,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}},{"id":"TankL4.8999999999999995B6.1H4.3fdundefinedFtank3.stl","affiliations":{},"boxDimensions":{"length":4.8999999999999995,"breadth":6.1,"height":4.3},"capabilities":{},"file3D":"tank3.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":100.94486974698383,"lightweight":1285.2699999999995,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}},{"id":"TankL6.699999999999999B5.5H4.3fdundefinedFtank4.stl","affiliations":{},"boxDimensions":{"length":6.699999999999999,"breadth":5.5,"height":4.3},"capabilities":{},"file3D":"tank4.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":124.45026598114265,"lightweight":1584.55,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}},{"id":"PropulsionroomL3.5B4H4.3fdundefinedFPropulsionRoom.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":4,"height":4.3},"capabilities":{},"file3D":"PropulsionRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6020,"cg":[0,0,2.15]}},{"id":"TankL4.200000000000003B1.5H5.3fdundefinedFtank5.stl","affiliations":{},"boxDimensions":{"length":4.200000000000003,"breadth":1.5,"height":5.3},"capabilities":{},"file3D":"tank5.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":26.224444675840815,"lightweight":333.9000000000002,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"DryBulkL3.6999999999999993B3.5H5.3fdundefinedFDryBulk.stl","affiliations":{},"boxDimensions":{"length":3.6999999999999993,"breadth":3.5,"height":5.3},"capabilities":{},"file3D":"DryBulk.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6863.499999999998,"cg":[0,0,2.65]}},{"id":"DryBulkL3.5B3.5H5.3fdundefinedFDryBulk.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":3.5,"height":5.3},"capabilities":{},"file3D":"DryBulk.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6492.5,"cg":[0,0,2.65]}},{"id":"FOOverFlowL3.5B3H4.3fdundefinedFFOOverFlow.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":3,"height":4.3},"capabilities":{},"file3D":"FOOverFlow.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":4515,"cg":[0,0,2.15]}},{"id":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":5.5,"height":5.3},"capabilities":{},"file3D":"MudBrineOroSlop.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":10202.5,"cg":[0,0,2.65]}},{"id":"TankL6.5B1H5.3fdundefinedFtank6.stl","affiliations":{},"boxDimensions":{"length":6.5,"breadth":1,"height":5.3},"capabilities":{},"file3D":"tank6.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":27.056966729042095,"lightweight":344.5,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"TankL3.5B2.5H5.3fdundefinedFtank7.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":2.5,"height":5.3},"capabilities":{},"file3D":"tank7.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":36.422839827556665,"lightweight":463.75,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"TankL1B1.5H5.3fdundefinedFtank8.stl","affiliations":{},"boxDimensions":{"length":1,"breadth":1.5,"height":5.3},"capabilities":{},"file3D":"tank8.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":6.243915399009714,"lightweight":79.5,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"SewageL3.5B3H5.3fdundefinedFsewage.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":3,"height":5.3},"capabilities":{},"file3D":"sewage.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":5565,"cg":[0,0,2.65]}},{"id":"TankL6B3H5.3fdundefinedFtank10.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":3,"height":5.3},"capabilities":{},"file3D":"tank10.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":74.92698478811657,"lightweight":954,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"TankL3.5B1.5H5.3fdundefinedFtank9.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":1.5,"height":5.3},"capabilities":{},"file3D":"tank9.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":21.853703896534,"lightweight":278.25,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"TankL10.5B3H5.3fdundefinedFtank11.stl","affiliations":{},"boxDimensions":{"length":10.5,"breadth":3,"height":5.3},"capabilities":{},"file3D":"tank11.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":131.122223379204,"lightweight":1669.5,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"TankL6.5B10H9.5fdundefinedFtank12.stl","affiliations":{},"boxDimensions":{"length":6.5,"breadth":10,"height":9.5},"capabilities":{},"file3D":"tank12.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":484.98336589792433,"lightweight":6175,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,4.75],[0,0,1.425],[0,0,2.85],[0,0,3.8000000000000003],[0,0,4.75]]}}},{"id":"EngineRoomLowerL12B7H3.9fdundefinedFEngineRoomLower.stl","affiliations":{},"boxDimensions":{"length":12,"breadth":7,"height":3.9},"capabilities":{},"file3D":"EngineRoomLower.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":32760,"cg":[0,0,1.95]}},{"id":"BowThrusterRoomL12B3H3.9fdundefinedFBowThrusterRoom1.stl","affiliations":{},"boxDimensions":{"length":12,"breadth":3,"height":3.9},"capabilities":{},"file3D":"BowThrusterRoom1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":14040,"cg":[0,0,1.95]}},{"id":"TankL3B9H2.7fdundefinedFtank13.stl","affiliations":{},"boxDimensions":{"length":3,"breadth":9,"height":2.7},"capabilities":{},"file3D":"tank13.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":57.25552611167398,"lightweight":729,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.35],[0,0,0.405],[0,0,0.81],[0,0,1.08],[0,0,1.35]]}}},{"id":"TankL4B3H2.7fdundefinedFtank14.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":3,"height":2.7},"capabilities":{},"file3D":"tank14.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":25.446900494077326,"lightweight":324,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.35],[0,0,0.405],[0,0,0.81],[0,0,1.08],[0,0,1.35]]}}},{"id":"MotorLeftL6B4H2.7fdundefinedFMotors.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":4,"height":2.7},"capabilities":{},"file3D":"Motors.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6480,"cg":[0,0,1.35]}},{"id":"MotorRightL6B4H2.7fdundefinedFMotors.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":4,"height":2.7},"capabilities":{},"file3D":"Motors.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6480,"cg":[0,0,1.35]}},{"id":"PropulsionRoomUpperL6B4H2.7fdundefinedFPropulsionRoomUpper.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":4,"height":2.7},"capabilities":{},"file3D":"PropulsionRoomUpper.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6480,"cg":[0,0,1.35]}},{"id":"TankL3B18H2.7fdundefinedFtank15.stl","affiliations":{},"boxDimensions":{"length":3,"breadth":18,"height":2.7},"capabilities":{},"file3D":"tank15.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":114.51105222334796,"lightweight":1458,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.35],[0,0,0.405],[0,0,0.81],[0,0,1.08],[0,0,1.35]]}}},{"id":"TankL4.5B7H2.4fdundefinedFtank17.stl","affiliations":{},"boxDimensions":{"length":4.5,"breadth":7,"height":2.4},"capabilities":{},"file3D":"tank17.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":59.37610115284709,"lightweight":756,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.2],[0,0,0.36],[0,0,0.72],[0,0,0.96],[0,0,1.2]]}}},{"id":"TankL6B1H2.4fdundefinedFtank16.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":1,"height":2.4},"capabilities":{},"file3D":"tank16.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":11.309733552923255,"lightweight":144,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.2],[0,0,0.36],[0,0,0.72],[0,0,0.96],[0,0,1.2]]}}},{"id":"SwitchBoardRoomL3.5B9H2.4fdundefinedFSwitchBoardRoom.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":9,"height":2.4},"capabilities":{},"file3D":"SwitchBoardRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":7560,"cg":[0,0,1.2]}},{"id":"EngineRoomUpperL8.5B7H2.4fdundefinedFEngineRoomUpper.stl","affiliations":{},"boxDimensions":{"length":8.5,"breadth":7,"height":2.4},"capabilities":{},"file3D":"EngineRoomUpper.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":14280,"cg":[0,0,1.2]}},{"id":"BowThrusterRoomL12B3H2.7fdundefinedFBowThursterRoom2.stl","affiliations":{},"boxDimensions":{"length":12,"breadth":3,"height":2.7},"capabilities":{},"file3D":"BowThursterRoom2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":9720,"cg":[0,0,1.35]}},{"id":"WorkShopL3B2H2.4fdundefinedFWorkshop.stl","affiliations":{},"boxDimensions":{"length":3,"breadth":2,"height":2.4},"capabilities":{},"file3D":"Workshop.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1440,"cg":[0,0,1.2]}},{"id":"ChainTankL1.5B1.5H5.6fdundefinedFChainTank.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":1.5,"height":5.6},"capabilities":{},"file3D":"ChainTank.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":9.896016858807847,"lightweight":125.99999999999999,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.8],[0,0,0.84],[0,0,1.68],[0,0,2.2399999999999998],[0,0,2.8]]}}},{"id":"CoverL53B15H2.9fdundefinedFcover1.stl","affiliations":{},"boxDimensions":{"length":53,"breadth":15,"height":2.9},"capabilities":{},"file3D":"cover1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":230550,"cg":[0,0,1.45]}},{"id":"TankL7B1.5H2.9fdundefinedFtank18.stl","affiliations":{},"boxDimensions":{"length":7,"breadth":1.5,"height":2.9},"capabilities":{},"file3D":"tank18.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":23.915374075452302,"lightweight":304.5,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.45],[0,0,0.435],[0,0,0.87],[0,0,1.16],[0,0,1.45]]}}},{"id":"TankL1B2H2.9fdundefinedFtank19.stl","affiliations":{},"boxDimensions":{"length":1,"breadth":2,"height":2.9},"capabilities":{},"file3D":"tank19.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":4.5553093477052,"lightweight":58,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.45],[0,0,0.435],[0,0,0.87],[0,0,1.16],[0,0,1.45]]}}},{"id":"FiremStoreL2.5B1.5H2.9fdundefinedFFiremStore.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":1.5,"height":2.9},"capabilities":{},"file3D":"FiremStore.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1087.5,"cg":[0,0,1.45]}},{"id":"DeckWorkshopL2.5B3.5H2.9fdundefinedFDeckWorkshop.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":3.5,"height":2.9},"capabilities":{},"file3D":"DeckWorkshop.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":2537.5,"cg":[0,0,1.45]}},{"id":"TankL2B1.5H2.9fdundefinedFtank20.stl","affiliations":{},"boxDimensions":{"length":2,"breadth":1.5,"height":2.9},"capabilities":{},"file3D":"tank20.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":6.8329640215578,"lightweight":87,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.45],[0,0,0.435],[0,0,0.87],[0,0,1.16],[0,0,1.45]]}}},{"id":"StoreL2B2H2.9fdundefinedFStore1.stl","affiliations":{},"boxDimensions":{"length":2,"breadth":2,"height":2.9},"capabilities":{},"file3D":"Store1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1160,"cg":[0,0,1.45]}},{"id":"ChemL2.5B1.5H2.9fdundefinedFchem.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":1.5,"height":2.9},"capabilities":{},"file3D":"chem.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1087.5,"cg":[0,0,1.45]}},{"id":"PaintL2.5B1.5H2.9fdundefinedFpaint.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":1.5,"height":2.9},"capabilities":{},"file3D":"paint.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1087.5,"cg":[0,0,1.45]}},{"id":"Inc&GarbRoomL5B4.5H2.9fdundefinedFInc&GarbRoom.stl","affiliations":{},"boxDimensions":{"length":5,"breadth":4.5,"height":2.9},"capabilities":{},"file3D":"Inc&GarbRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6525,"cg":[0,0,1.45]}},{"id":"RoomL3.5B4.5H2.9fdundefinedFroom1.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":4.5,"height":2.9},"capabilities":{},"file3D":"room1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":4567.5,"cg":[0,0,1.45]}},{"id":"RoomL3.5B6H2.9fdundefinedFroom2.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":6,"height":2.9},"capabilities":{},"file3D":"room2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6090,"cg":[0,0,1.45]}},{"id":"RoomL1.5B4.5H2.9fdundefinedFroom3.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":4.5,"height":2.9},"capabilities":{},"file3D":"room3.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1957.5,"cg":[0,0,1.45]}},{"id":"RoomL4B2H2.9fdundefinedFroom4.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":2,"height":2.9},"capabilities":{},"file3D":"room4.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":2320,"cg":[0,0,1.45]}},{"id":"RoomL4B3.5H2.9fdundefinedFroom5.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":3.5,"height":2.9},"capabilities":{},"file3D":"room5.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":4060,"cg":[0,0,1.45]}},{"id":"RoomL3.5B5H2.9fdundefinedFroom6.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":5,"height":2.9},"capabilities":{},"file3D":"room6.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":5075,"cg":[0,0,1.45]}},{"id":"RoomL3.5B6H2.9fdundefinedFroom7.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":6,"height":2.9},"capabilities":{},"file3D":"room7.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6090,"cg":[0,0,1.45]}},{"id":"TankL1.5B4.5H2.9fdundefinedFtank21.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":4.5,"height":2.9},"capabilities":{},"file3D":"tank21.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":15.374169048505049,"lightweight":195.75,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.45],[0,0,0.435],[0,0,0.87],[0,0,1.16],[0,0,1.45]]}}},{"id":"RoomL7B5H2.9fdundefinedFroom8.stl","affiliations":{},"boxDimensions":{"length":7,"breadth":5,"height":2.9},"capabilities":{},"file3D":"room8.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":10150,"cg":[0,0,1.45]}},{"id":"StairsL6B3H2.9fdundefinedFstairs1.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":3,"height":2.9},"capabilities":{},"file3D":"stairs1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":5220,"cg":[0,0,1.45]}},{"id":"ToiletsL1B2.5H2.9fdundefinedFtoilets1.stl","affiliations":{},"boxDimensions":{"length":1,"breadth":2.5,"height":2.9},"capabilities":{},"file3D":"toilets1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":725,"cg":[0,0,1.45]}},{"id":"DeckOfficeL2.5B6.5H2.9fdundefinedFDeckOffice1.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":6.5,"height":2.9},"capabilities":{},"file3D":"DeckOffice1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":4712.5,"cg":[0,0,1.45]}},{"id":"CoverL53.5B15H2fdundefinedFcover2.stl","affiliations":{},"boxDimensions":{"length":53.5,"breadth":15,"height":2},"capabilities":{},"file3D":"cover2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":160500,"cg":[0,0,1]}},{"id":"StabTankL3.5B18H2.9fdundefinedFStabTank.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":18,"height":2.9},"capabilities":{},"file3D":"StabTank.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":143.4922444527138,"lightweight":1827,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,1.45],[0,0,0.435],[0,0,0.87],[0,0,1.16],[0,0,1.45]]}}},{"id":"FreezerL3.5B2H2.9fdundefinedFfreezer.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":2,"height":2.9},"capabilities":{},"file3D":"freezer.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":2030,"cg":[0,0,1.45]}},{"id":"FridgeL4B1.5H2.9fdundefinedFfridge.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":1.5,"height":2.9},"capabilities":{},"file3D":"fridge.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1740,"cg":[0,0,1.45]}},{"id":"DryRoomL7.5B3H2.9fdundefinedFDryRoom.stl","affiliations":{},"boxDimensions":{"length":7.5,"breadth":3,"height":2.9},"capabilities":{},"file3D":"DryRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6525,"cg":[0,0,1.45]}},{"id":"RoomL2.5B8H2.9fdundefinedFroom9.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":8,"height":2.9},"capabilities":{},"file3D":"room9.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":5800,"cg":[0,0,1.45]}},{"id":"ACRoomL7.5B5H2.9fdundefinedFACRoom1.stl","affiliations":{},"boxDimensions":{"length":7.5,"breadth":5,"height":2.9},"capabilities":{},"file3D":"ACRoom1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":10875,"cg":[0,0,1.45]}},{"id":"RoomL5B5H2.9fdundefinedFroom10.stl","affiliations":{},"boxDimensions":{"length":5,"breadth":5,"height":2.9},"capabilities":{},"file3D":"room10.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":7250,"cg":[0,0,1.45]}},{"id":"CLL2.5B2H2.9fdundefinedFCL1.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":2,"height":2.9},"capabilities":{},"file3D":"CL1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1450,"cg":[0,0,1.45]}},{"id":"ToiletsL2.5B2H2.9fdundefinedFtoilets2.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":2,"height":2.9},"capabilities":{},"file3D":"toilets2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1450,"cg":[0,0,1.45]}},{"id":"GalleryL5.5B5H2.9fdundefinedFgallery1.stl","affiliations":{},"boxDimensions":{"length":5.5,"breadth":5,"height":2.9},"capabilities":{},"file3D":"gallery1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":7975,"cg":[0,0,1.45]}},{"id":"StairsL5.5B4H2.9fdundefinedFstairs1.stl","affiliations":{},"boxDimensions":{"length":5.5,"breadth":4,"height":2.9},"capabilities":{},"file3D":"stairs1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6380,"cg":[0,0,1.45]}},{"id":"DayRoomL5.5B6H2.9fdundefinedFDayRoom1.stl","affiliations":{},"boxDimensions":{"length":5.5,"breadth":6,"height":2.9},"capabilities":{},"file3D":"DayRoom1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":9570,"cg":[0,0,1.45]}},{"id":"MessRoomL4B13H2.9fdundefinedFMessRoom1.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":13,"height":2.9},"capabilities":{},"file3D":"MessRoom1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":15080,"cg":[0,0,1.45]}},{"id":"RopeBinL1.5B3H2.9fdundefinedFRopeBin1.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":3,"height":2.9},"capabilities":{},"file3D":"RopeBin1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1305,"cg":[0,0,1.45]}},{"id":"StoreL1.5B4H2.9fdundefinedFstore.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":4,"height":2.9},"capabilities":{},"file3D":"store.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1740,"cg":[0,0,1.45]}},{"id":"StoreL6.5B10H2.9fdundefinedFstore2.stl","affiliations":{},"boxDimensions":{"length":6.5,"breadth":10,"height":2.9},"capabilities":{},"file3D":"store2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":18850,"cg":[0,0,1.45]}},{"id":"SafetyBoatL6.5B3H1fdundefinedFSafetyBoat.stl","affiliations":{},"boxDimensions":{"length":6.5,"breadth":3,"height":1},"capabilities":{},"file3D":"SafetyBoat.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1950,"cg":[0,0,0.5]}},{"id":"HoistBaseL3B3H5.4fdundefinedFHoistBase.stl","affiliations":{},"boxDimensions":{"length":3,"breadth":3,"height":5.4},"capabilities":{},"file3D":"HoistBase.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":4860,"cg":[0,0,2.7]}},{"id":"StairsL5.5B4H2.7fdundefinedFstairs1.stl","affiliations":{},"boxDimensions":{"length":5.5,"breadth":4,"height":2.7},"capabilities":{},"file3D":"stairs1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":5940,"cg":[0,0,1.35]}},{"id":"CableRoomL10.5B14H2.7fdundefinedFCableRoom1.stl","affiliations":{},"boxDimensions":{"length":10.5,"breadth":14,"height":2.7},"capabilities":{},"file3D":"CableRoom1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":39690,"cg":[0,0,1.35]}},{"id":"CabinL2.5B4H2.7fdundefinedFcabin1.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":4,"height":2.7},"capabilities":{},"file3D":"cabin1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":2700,"cg":[0,0,1.35]}},{"id":"CabinL4.5B4H2.7fdundefinedFcabin2.stl","affiliations":{},"boxDimensions":{"length":4.5,"breadth":4,"height":2.7},"capabilities":{},"file3D":"cabin2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":4860,"cg":[0,0,1.35]}},{"id":"TankL5.5B4H5.3fdundefinedFtank22.stl","affiliations":{},"boxDimensions":{"length":5.5,"breadth":4,"height":5.3},"capabilities":{},"file3D":"tank22.stl","baseState":{"fullness":0.5},"weightInformation":{"contentDensity":1000,"volumeCapacity":91.57742585214245,"lightweight":1166,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.65],[0,0,0.7949999999999999],[0,0,1.5899999999999999],[0,0,2.12],[0,0,2.65]]}}},{"id":"RoomL4.5B8H2.7fdundefinedFroom11.stl","affiliations":{},"boxDimensions":{"length":4.5,"breadth":8,"height":2.7},"capabilities":{},"file3D":"room11.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":9720,"cg":[0,0,1.35]}},{"id":"CabinL5B4.5H2.7fdundefinedFcabin3.stl","affiliations":{},"boxDimensions":{"length":5,"breadth":4.5,"height":2.7},"capabilities":{},"file3D":"cabin3.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":6075,"cg":[0,0,1.35]}},{"id":"CabinL5B6.5H2.7fdundefinedFcabin5.stl","affiliations":{},"boxDimensions":{"length":5,"breadth":6.5,"height":2.7},"capabilities":{},"file3D":"cabin5.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":8775,"cg":[0,0,1.35]}},{"id":"CabinL2.5B5H2.7fdundefinedFcabin4.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":5,"height":2.7},"capabilities":{},"file3D":"cabin4.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":3375,"cg":[0,0,1.35]}},{"id":"CorridorExtL3.5B13.5H2.7fdundefinedFcorridor.stl","affiliations":{},"boxDimensions":{"length":3.5,"breadth":13.5,"height":2.7},"capabilities":{},"file3D":"corridor.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":12757.5,"cg":[0,0,1.35]}},{"id":"InstrumentRoomL5.5B3.5H2.7fdundefinedFInstrumentRoom.stl","affiliations":{},"boxDimensions":{"length":5.5,"breadth":3.5,"height":2.7},"capabilities":{},"file3D":"InstrumentRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":5197.5,"cg":[0,0,1.35]}},{"id":"CaptainCabinL6B5H2.7fdundefinedFCaptainCabin.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":5,"height":2.7},"capabilities":{},"file3D":"CaptainCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":8100.000000000001,"cg":[0,0,1.35]}},{"id":"ChiefOfficerCabinL3B4.5H2.7fdundefinedFChiefOfficerCabin.stl","affiliations":{},"boxDimensions":{"length":3,"breadth":4.5,"height":2.7},"capabilities":{},"file3D":"ChiefOfficerCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":3645.0000000000005,"cg":[0,0,1.35]}},{"id":"FirstOfficerCabinL3B4H2.7fdundefinedFFirstOfficerCabin.stl","affiliations":{},"boxDimensions":{"length":3,"breadth":4,"height":2.7},"capabilities":{},"file3D":"FirstOfficerCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":3240,"cg":[0,0,1.35]}},{"id":"ChiefStewardCabinL6B6H2.7fdundefinedFChiefStewardCabin.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":6,"height":2.7},"capabilities":{},"file3D":"ChiefStewardCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":9720,"cg":[0,0,1.35]}},{"id":"ElectricianCabinL6B6H2.7fdundefinedFElectricianCabin.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":6,"height":2.7},"capabilities":{},"file3D":"ElectricianCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":9720,"cg":[0,0,1.35]}},{"id":"StairsL4.5B4H2.7fdundefinedFstairs2.stl","affiliations":{},"boxDimensions":{"length":4.5,"breadth":4,"height":2.7},"capabilities":{},"file3D":"stairs2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":4860,"cg":[0,0,1.35]}},{"id":"CleanLockerL1.5B2H2.7fdundefinedFSmallRoom.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":2,"height":2.7},"capabilities":{},"file3D":"SmallRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":810,"cg":[0,0,1.35]}},{"id":"BondStoreL1.5B2H2.7fdundefinedFSmallRoom.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":2,"height":2.7},"capabilities":{},"file3D":"SmallRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":810,"cg":[0,0,1.35]}},{"id":"LinenL1.5B2H2.7fdundefinedFSmallRoom.stl","affiliations":{},"boxDimensions":{"length":1.5,"breadth":2,"height":2.7},"capabilities":{},"file3D":"SmallRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":810,"cg":[0,0,1.35]}},{"id":"ChiefCabinL6B5H2.7fdundefinedFChiefCabin.stl","affiliations":{},"boxDimensions":{"length":6,"breadth":5,"height":2.7},"capabilities":{},"file3D":"ChiefCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":8100.000000000001,"cg":[0,0,1.35]}},{"id":"FirstEngineerCabinL2.5B4H2.7fdundefinedFFirstEngineerCabin.stl","affiliations":{},"boxDimensions":{"length":2.5,"breadth":4,"height":2.7},"capabilities":{},"file3D":"FirstEngineerCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":2700,"cg":[0,0,1.35]}},{"id":"SecondEngineerCabinL2B3.5H2.7fdundefinedFSecondEngineerCabin.stl","affiliations":{},"boxDimensions":{"length":2,"breadth":3.5,"height":2.7},"capabilities":{},"file3D":"SecondEngineerCabin.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":1890.0000000000002,"cg":[0,0,1.35]}},{"id":"HoistL1B9H4.15fdundefinedFhoist.stl","affiliations":{},"boxDimensions":{"length":1,"breadth":9,"height":4.15},"capabilities":{},"file3D":"hoist.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":3735.0000000000005,"cg":[0,0,2.075]}},{"id":"AccessStairsL4B5H4.15fdundefinedFAccessStairs1.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":5,"height":4.15},"capabilities":{},"file3D":"AccessStairs1.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":8300,"cg":[0,0,2.075]}},{"id":"AccessStairsL4B5H4.15fdundefinedFAccessStairs2.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":5,"height":4.15},"capabilities":{},"file3D":"AccessStairs2.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":8300,"cg":[0,0,2.075]}},{"id":"ShipHandingL7B8H4.15fdundefinedFShipHanding.stl","affiliations":{},"boxDimensions":{"length":7,"breadth":8,"height":4.15},"capabilities":{},"file3D":"ShipHanding.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":23240.000000000004,"cg":[0,0,2.075]}},{"id":"MainRoomL8B16H4.15fdundefinedFMainRoom.stl","affiliations":{},"boxDimensions":{"length":8,"breadth":16,"height":4.15},"capabilities":{},"file3D":"MainRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":53120.00000000001,"cg":[0,0,2.075]}},{"id":"NavigationRoomL9B8H4.15fdundefinedFNavigationRoom.stl","affiliations":{},"boxDimensions":{"length":9,"breadth":8,"height":4.15},"capabilities":{},"file3D":"NavigationRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":29880.000000000004,"cg":[0,0,2.075]}},{"id":"EmGenRoomL11B6H5fdundefinedFEmGenRoom.stl","affiliations":{},"boxDimensions":{"length":11,"breadth":6,"height":5},"capabilities":{},"file3D":"EmGenRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":33000,"cg":[0,0,2.5]}},{"id":"CommunicationL11B3H5fdundefinedFCommunicationRoom.stl","affiliations":{},"boxDimensions":{"length":11,"breadth":3,"height":5},"capabilities":{},"file3D":"CommunicationRoom.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":16500,"cg":[0,0,2.5]}},{"id":"AerialL0.5B0.5H2fdundefinedFaerial.stl","affiliations":{},"boxDimensions":{"length":0.5,"breadth":0.5,"height":2},"capabilities":{},"file3D":"aerial.stl","baseState":{"fullness":0.5},"weightInformation":{"lightweight":50,"cg":[0,0,1]}}], - -"derivedObjects": [{"id":"Tank1","baseObject":"TankL2.1B6.13H4.3fdundefinedFtank1.stl","affiliations":{"Deck":"TankTop","SFI":"101"},"referenceState":{"xCentre":1.05,"yCentre":2.9,"zBase":1}},{"id":"Tank2","baseObject":"TankL2.1B6.13H4.3fdundefinedFundefined","affiliations":{"Deck":"TankTop","SFI":"102"},"referenceState":{"xCentre":1.05,"yCentre":-2.9,"zBase":1}},{"id":"Tank3","baseObject":"TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl","affiliations":{"Deck":"TankTop","SFI":"103"},"referenceState":{"xCentre":4.2,"yCentre":3.25,"zBase":1}},{"id":"Tank4","baseObject":"TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl","affiliations":{"Deck":"TankTop","SFI":"104"},"referenceState":{"xCentre":4.2,"yCentre":-3.25,"zBase":1}},{"id":"Tank5","baseObject":"TankL4.8999999999999995B6.1H4.3fdundefinedFtank3.stl","affiliations":{"Deck":"TankTop","SFI":"105"},"referenceState":{"xCentre":8.75,"yCentre":4,"zBase":1}},{"id":"Tank6","baseObject":"TankL4.8999999999999995B6.1H4.3fdundefinedFtank3.stl","affiliations":{"Deck":"TankTop","SFI":"106"},"referenceState":{"xCentre":8.75,"yCentre":-4,"zBase":1}},{"id":"Tank7","baseObject":"TankL6.699999999999999B5.5H4.3fdundefinedFtank4.stl","affiliations":{"Deck":"TankTop","SFI":"107"},"referenceState":{"xCentre":14.549999999999999,"yCentre":5.25,"zBase":1}},{"id":"Tank8","baseObject":"TankL6.699999999999999B5.5H4.3fdundefinedFtank4.stl","affiliations":{"Deck":"TankTop","SFI":"108"},"referenceState":{"xCentre":14.549999999999999,"yCentre":-5.25,"zBase":1}},{"id":"Propulsion room","baseObject":"PropulsionroomL3.5B4H4.3fdundefinedFPropulsionRoom.stl","affiliations":{"Deck":"TankTop","SFI":"109"},"referenceState":{"xCentre":13.25,"yCentre":0,"zBase":1}},{"id":"Tank9","baseObject":"TankL4.200000000000003B1.5H5.3fdundefinedFtank5.stl","affiliations":{"Deck":"TankTop","SFI":"110"},"referenceState":{"xCentre":20,"yCentre":6.25,"zBase":1}},{"id":"Tank10","baseObject":"TankL4.200000000000003B1.5H5.3fdundefinedFtank5.stl","affiliations":{"Deck":"TankTop","SFI":"111"},"referenceState":{"xCentre":20,"yCentre":-6.25,"zBase":1}},{"id":"DryBulk1","baseObject":"DryBulkL3.6999999999999993B3.5H5.3fdundefinedFDryBulk.stl","affiliations":{"Deck":"TankTop","SFI":"112"},"referenceState":{"xCentre":20.35,"yCentre":3.25,"zBase":1}},{"id":"DryBulk2","baseObject":"DryBulkL3.6999999999999993B3.5H5.3fdundefinedFDryBulk.stl","affiliations":{"Deck":"TankTop","SFI":"113"},"referenceState":{"xCentre":20.35,"yCentre":-3,"zBase":1}},{"id":"DryBulk3","baseObject":"DryBulkL3.5B3.5H5.3fdundefinedFDryBulk.stl","affiliations":{"Deck":"TankTop","SFI":"114"},"referenceState":{"xCentre":24.05,"yCentre":4.75,"zBase":1}},{"id":"DryBulk4","baseObject":"DryBulkL3.5B3.5H5.3fdundefinedFDryBulk.stl","affiliations":{"Deck":"TankTop","SFI":"115"},"referenceState":{"xCentre":24.05,"yCentre":-4.75,"zBase":1}},{"id":"FOOverFlow1","baseObject":"FOOverFlowL3.5B3H4.3fdundefinedFFOOverFlow.stl","affiliations":{"Deck":"TankTop","SFI":"116"},"referenceState":{"xCentre":24.25,"yCentre":0,"zBase":1}},{"id":"MudBrineOroSlop1","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"117"},"referenceState":{"xCentre":29.25,"yCentre":3.75,"zBase":1}},{"id":"MudBrineOroSlop2","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"118"},"referenceState":{"xCentre":29.25,"yCentre":-3.75,"zBase":1}},{"id":"MudBrineOroSlop3","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"119"},"referenceState":{"xCentre":33.25,"yCentre":3.75,"zBase":1}},{"id":"MudBrineOroSlop4","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"120"},"referenceState":{"xCentre":33.25,"yCentre":-3.75,"zBase":1}},{"id":"MudBrineOroSlop5","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"121"},"referenceState":{"xCentre":37.25,"yCentre":3.75,"zBase":1}},{"id":"MudBrineOroSlop6","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"122"},"referenceState":{"xCentre":37.25,"yCentre":-3.75,"zBase":1}},{"id":"MudBrineOroSlop7","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"123"},"referenceState":{"xCentre":41.25,"yCentre":3.75,"zBase":1}},{"id":"MudBrineOroSlop8","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"124"},"referenceState":{"xCentre":41.25,"yCentre":-3.75,"zBase":1}},{"id":"MudBrineOroSlop9","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"125"},"referenceState":{"xCentre":45.25,"yCentre":3.75,"zBase":1}},{"id":"MudBrineOroSlop10","baseObject":"MudBrineOroSlopL3.5B5.5H5.3fdundefinedFMudBrineOroSlop.stl","affiliations":{"Deck":"TankTop","SFI":"126"},"referenceState":{"xCentre":45.25,"yCentre":-3.75,"zBase":1}},{"id":"Tank11","baseObject":"TankL6.5B1H5.3fdundefinedFtank6.stl","affiliations":{"Deck":"TankTop","SFI":"127"},"referenceState":{"xCentre":29.25,"yCentre":7.5,"zBase":1}},{"id":"Tank12","baseObject":"TankL6.5B1H5.3fdundefinedFtank6.stl","affiliations":{"Deck":"TankTop","SFI":"128"},"referenceState":{"xCentre":29.25,"yCentre":-7.5,"zBase":1}},{"id":"Tank13","baseObject":"TankL6.5B1H5.3fdundefinedFtank6.stl","affiliations":{"Deck":"TankTop","SFI":"129"},"referenceState":{"xCentre":35.75,"yCentre":7.5,"zBase":1}},{"id":"Tank14","baseObject":"TankL6.5B1H5.3fdundefinedFtank6.stl","affiliations":{"Deck":"TankTop","SFI":"130"},"referenceState":{"xCentre":35.75,"yCentre":-7.5,"zBase":1}},{"id":"Tank15","baseObject":"TankL6.5B1H5.3fdundefinedFtank6.stl","affiliations":{"Deck":"TankTop","SFI":"131"},"referenceState":{"xCentre":42.25,"yCentre":7.5,"zBase":1}},{"id":"Tank16","baseObject":"TankL6.5B1H5.3fdundefinedFtank6.stl","affiliations":{"Deck":"TankTop","SFI":"132"},"referenceState":{"xCentre":42.25,"yCentre":-7.5,"zBase":1}},{"id":"Tank17","baseObject":"TankL3.5B2.5H5.3fdundefinedFtank7.stl","affiliations":{"Deck":"TankTop","SFI":"133"},"referenceState":{"xCentre":51.75,"yCentre":5.75,"zBase":1.4}},{"id":"Tank18","baseObject":"TankL3.5B2.5H5.3fdundefinedFtank7.stl","affiliations":{"Deck":"TankTop","SFI":"134"},"referenceState":{"xCentre":51.75,"yCentre":-5.75,"zBase":1.4}},{"id":"Tank18","baseObject":"TankL1B1.5H5.3fdundefinedFtank8.stl","affiliations":{"Deck":"TankTop","SFI":"135"},"referenceState":{"xCentre":54,"yCentre":5.75,"zBase":1.4}},{"id":"Tank19","baseObject":"TankL1B1.5H5.3fdundefinedFtank8.stl","affiliations":{"Deck":"TankTop","SFI":"136"},"referenceState":{"xCentre":55,"yCentre":5.75,"zBase":1.4}},{"id":"Sewage1","baseObject":"SewageL3.5B3H5.3fdundefinedFsewage.stl","affiliations":{"Deck":"TankTop","SFI":"137"},"referenceState":{"xCentre":57.25,"yCentre":5.75,"zBase":1.4}},{"id":"Tank20","baseObject":"TankL6B3H5.3fdundefinedFtank10.stl","affiliations":{"Deck":"TankTop","SFI":"138"},"referenceState":{"xCentre":62,"yCentre":5,"zBase":1.4}},{"id":"Tank21","baseObject":"TankL6B3H5.3fdundefinedFtank10.stl","affiliations":{"Deck":"TankTop","SFI":"139"},"referenceState":{"xCentre":62,"yCentre":-5,"zBase":1.4}},{"id":"Tank122","baseObject":"TankL1B1.5H5.3fdundefinedFtank8.stl","affiliations":{"Deck":"TankTop","SFI":"140"},"referenceState":{"xCentre":54,"yCentre":-5.75,"zBase":1.4}},{"id":"Tank22","baseObject":"TankL1B1.5H5.3fdundefinedFtank8.stl","affiliations":{"Deck":"TankTop","SFI":"141"},"referenceState":{"xCentre":55,"yCentre":-5.75,"zBase":1.4}},{"id":"Tank23","baseObject":"TankL3.5B1.5H5.3fdundefinedFtank9.stl","affiliations":{"Deck":"TankTop","SFI":"142"},"referenceState":{"xCentre":57.25,"yCentre":-5.25,"zBase":1.4}},{"id":"Tank24","baseObject":"TankL10.5B3H5.3fdundefinedFtank11.stl","affiliations":{"Deck":"TankTop","SFI":"143"},"referenceState":{"xCentre":70.25,"yCentre":3,"zBase":1.4}},{"id":"Tank25","baseObject":"TankL10.5B3H5.3fdundefinedFtank11.stl","affiliations":{"Deck":"TankTop","SFI":"144"},"referenceState":{"xCentre":70.25,"yCentre":-3,"zBase":1.4}},{"id":"Tank26","baseObject":"TankL6.5B10H9.5fdundefinedFtank12.stl","affiliations":{"Deck":"TankTop","SFI":"145"},"referenceState":{"xCentre":78.75,"yCentre":0,"zBase":1.4}},{"id":"EngineRoomLower1","baseObject":"EngineRoomLowerL12B7H3.9fdundefinedFEngineRoomLower.stl","affiliations":{"Deck":"TankTop","SFI":"146"},"referenceState":{"xCentre":56,"yCentre":0,"zBase":1.4}},{"id":"BowThrusterRoom1","baseObject":"BowThrusterRoomL12B3H3.9fdundefinedFBowThrusterRoom1.stl","affiliations":{"Deck":"TankTop","SFI":"147"},"referenceState":{"xCentre":68,"yCentre":0,"zBase":1.4}},{"id":"Tank27","baseObject":"TankL3B9H2.7fdundefinedFtank13.stl","affiliations":{"Deck":"TweenDeck","SFI":"201"},"referenceState":{"xCentre":1.5,"yCentre":4.5,"zBase":5.3}},{"id":"Tank28","baseObject":"TankL3B9H2.7fdundefinedFtank13.stl","affiliations":{"Deck":"TweenDeck","SFI":"202"},"referenceState":{"xCentre":1.5,"yCentre":-4.5,"zBase":5.3}},{"id":"Tank28","baseObject":"TankL4B3H2.7fdundefinedFtank14.stl","affiliations":{"Deck":"TweenDeck","SFI":"203"},"referenceState":{"xCentre":5,"yCentre":7.5,"zBase":5.3}},{"id":"Tank29","baseObject":"TankL4B3H2.7fdundefinedFtank14.stl","affiliations":{"Deck":"TweenDeck","SFI":"204"},"referenceState":{"xCentre":5,"yCentre":-7.5,"zBase":5.3}},{"id":"MotorLeft1","baseObject":"MotorLeftL6B4H2.7fdundefinedFMotors.stl","affiliations":{"Deck":"TweenDeck","SFI":"205"},"referenceState":{"xCentre":6,"yCentre":4,"zBase":5.3}},{"id":"MotorRight1","baseObject":"MotorRightL6B4H2.7fdundefinedFMotors.stl","affiliations":{"Deck":"TweenDeck","SFI":"206"},"referenceState":{"xCentre":6,"yCentre":-4,"zBase":5.3}},{"id":"PropulsionRoomUpper","baseObject":"PropulsionRoomUpperL6B4H2.7fdundefinedFPropulsionRoomUpper.stl","affiliations":{"Deck":"TweenDeck","SFI":"207"},"referenceState":{"xCentre":6,"yCentre":0,"zBase":5.3}},{"id":"Tank30","baseObject":"TankL3B18H2.7fdundefinedFtank15.stl","affiliations":{"Deck":"TweenDeck","SFI":"208"},"referenceState":{"xCentre":10.5,"yCentre":0,"zBase":5.3}},{"id":"Tank31","baseObject":"TankL4.5B7H2.4fdundefinedFtank17.stl","affiliations":{"Deck":"TweenDeck","SFI":"209"},"referenceState":{"xCentre":14.75,"yCentre":4.5,"zBase":5.3}},{"id":"Tank32","baseObject":"TankL4.5B7H2.4fdundefinedFtank17.stl","affiliations":{"Deck":"TweenDeck","SFI":"210"},"referenceState":{"xCentre":14.75,"yCentre":-4.5,"zBase":5.3}},{"id":"Tank33","baseObject":"TankL6B1H2.4fdundefinedFtank16.stl","affiliations":{"Deck":"TweenDeck","SFI":"211"},"referenceState":{"xCentre":15,"yCentre":8.5,"zBase":5.3}},{"id":"Tank34","baseObject":"TankL6B1H2.4fdundefinedFtank16.stl","affiliations":{"Deck":"TweenDeck","SFI":"212"},"referenceState":{"xCentre":15,"yCentre":-8.5,"zBase":5.3}},{"id":"SwitchBoardRoom1","baseObject":"SwitchBoardRoomL3.5B9H2.4fdundefinedFSwitchBoardRoom.stl","affiliations":{"Deck":"TweenDeck","SFI":"213"},"referenceState":{"xCentre":51.75,"yCentre":0,"zBase":5.3}},{"id":"EngineRoomUpper1","baseObject":"EngineRoomUpperL8.5B7H2.4fdundefinedFEngineRoomUpper.stl","affiliations":{"Deck":"TweenDeck","SFI":"214"},"referenceState":{"xCentre":57.75,"yCentre":0,"zBase":5.3}},{"id":"BowThrusterRoom2","baseObject":"BowThrusterRoomL12B3H2.7fdundefinedFBowThursterRoom2.stl","affiliations":{"Deck":"TweenDeck","SFI":"215"},"referenceState":{"xCentre":68,"yCentre":0,"zBase":5.3}},{"id":"WorkShop1","baseObject":"WorkShopL3B2H2.4fdundefinedFWorkshop.stl","affiliations":{"Deck":"TweenDeck","SFI":"216"},"referenceState":{"xCentre":63.5,"yCentre":-2.5,"zBase":5.3}},{"id":"ChainTank1","baseObject":"ChainTankL1.5B1.5H5.6fdundefinedFChainTank.stl","affiliations":{"Deck":"TweenDeck","SFI":"217"},"referenceState":{"xCentre":74.75,"yCentre":0.75,"zBase":5.3}},{"id":"ChainTank2","baseObject":"ChainTankL1.5B1.5H5.6fdundefinedFChainTank.stl","affiliations":{"Deck":"TweenDeck","SFI":"218"},"referenceState":{"xCentre":74.75,"yCentre":-0.75,"zBase":5.3}},{"id":"Cover1","baseObject":"CoverL53B15H2.9fdundefinedFcover1.stl","affiliations":{"Deck":"MainDeck","SFI":"301"},"referenceState":{"xCentre":27,"yCentre":0,"zBase":8}},{"id":"Tank35","baseObject":"TankL7B1.5H2.9fdundefinedFtank18.stl","affiliations":{"Deck":"MainDeck","SFI":"302"},"referenceState":{"xCentre":30.5,"yCentre":8.25,"zBase":8}},{"id":"Tank36","baseObject":"TankL7B1.5H2.9fdundefinedFtank18.stl","affiliations":{"Deck":"MainDeck","SFI":"303"},"referenceState":{"xCentre":30.5,"yCentre":-8.25,"zBase":8}},{"id":"Tank37","baseObject":"TankL7B1.5H2.9fdundefinedFtank18.stl","affiliations":{"Deck":"MainDeck","SFI":"304"},"referenceState":{"xCentre":37.5,"yCentre":8.25,"zBase":8}},{"id":"Tank38","baseObject":"TankL7B1.5H2.9fdundefinedFtank18.stl","affiliations":{"Deck":"MainDeck","SFI":"305"},"referenceState":{"xCentre":37.5,"yCentre":-8.25,"zBase":8}},{"id":"Tank39","baseObject":"TankL1B2H2.9fdundefinedFtank19.stl","affiliations":{"Deck":"MainDeck","SFI":"306"},"referenceState":{"xCentre":54,"yCentre":0,"zBase":8}},{"id":"FiremStore","baseObject":"FiremStoreL2.5B1.5H2.9fdundefinedFFiremStore.stl","affiliations":{"Deck":"MainDeck","SFI":"307"},"referenceState":{"xCentre":58.25,"yCentre":8.25,"zBase":8}},{"id":"DeckWorkshop","baseObject":"DeckWorkshopL2.5B3.5H2.9fdundefinedFDeckWorkshop.stl","affiliations":{"Deck":"MainDeck","SFI":"308"},"referenceState":{"xCentre":58.25,"yCentre":5.75,"zBase":8}},{"id":"Tank40","baseObject":"TankL2B1.5H2.9fdundefinedFtank20.stl","affiliations":{"Deck":"MainDeck","SFI":"309"},"referenceState":{"xCentre":58.5,"yCentre":3.25,"zBase":8}},{"id":"Store1","baseObject":"StoreL2B2H2.9fdundefinedFStore1.stl","affiliations":{"Deck":"MainDeck","SFI":"310"},"referenceState":{"xCentre":58.5,"yCentre":1.5,"zBase":8}},{"id":"Tank40","baseObject":"TankL2B1.5H2.9fdundefinedFtank20.stl","affiliations":{"Deck":"MainDeck","SFI":"311"},"referenceState":{"xCentre":58.5,"yCentre":-3.25,"zBase":8}},{"id":"Chem","baseObject":"ChemL2.5B1.5H2.9fdundefinedFchem.stl","affiliations":{"Deck":"MainDeck","SFI":"312"},"referenceState":{"xCentre":58.25,"yCentre":-8.25,"zBase":8}},{"id":"Paint","baseObject":"PaintL2.5B1.5H2.9fdundefinedFpaint.stl","affiliations":{"Deck":"MainDeck","SFI":"313"},"referenceState":{"xCentre":58.25,"yCentre":-6.75,"zBase":8}},{"id":"Inc&GarbRoom","baseObject":"Inc&GarbRoomL5B4.5H2.9fdundefinedFInc&GarbRoom.stl","affiliations":{"Deck":"MainDeck","SFI":"314"},"referenceState":{"xCentre":62,"yCentre":6.25,"zBase":8}},{"id":"Room1","baseObject":"RoomL3.5B4.5H2.9fdundefinedFroom1.stl","affiliations":{"Deck":"MainDeck","SFI":"315"},"referenceState":{"xCentre":61.25,"yCentre":1.75,"zBase":8}},{"id":"Room2","baseObject":"RoomL3.5B6H2.9fdundefinedFroom2.stl","affiliations":{"Deck":"MainDeck","SFI":"316"},"referenceState":{"xCentre":61.25,"yCentre":-5,"zBase":8}},{"id":"Room3","baseObject":"RoomL1.5B4.5H2.9fdundefinedFroom3.stl","affiliations":{"Deck":"MainDeck","SFI":"317"},"referenceState":{"xCentre":63.75,"yCentre":1.75,"zBase":8}},{"id":"Room4","baseObject":"RoomL4B2H2.9fdundefinedFroom4.stl","affiliations":{"Deck":"MainDeck","SFI":"318"},"referenceState":{"xCentre":65,"yCentre":-3,"zBase":8}},{"id":"Room5","baseObject":"RoomL4B3.5H2.9fdundefinedFroom5.stl","affiliations":{"Deck":"MainDeck","SFI":"319"},"referenceState":{"xCentre":65,"yCentre":-5.5,"zBase":8}},{"id":"Room6","baseObject":"RoomL3.5B5H2.9fdundefinedFroom6.stl","affiliations":{"Deck":"MainDeck","SFI":"320"},"referenceState":{"xCentre":68.75,"yCentre":-4.75,"zBase":8}},{"id":"Room7","baseObject":"RoomL3.5B6H2.9fdundefinedFroom7.stl","affiliations":{"Deck":"MainDeck","SFI":"321"},"referenceState":{"xCentre":72.25,"yCentre":-3,"zBase":8}},{"id":"Tank41","baseObject":"TankL1.5B4.5H2.9fdundefinedFtank21.stl","affiliations":{"Deck":"MainDeck","SFI":"322"},"referenceState":{"xCentre":74.75,"yCentre":3.75,"zBase":8}},{"id":"Tank42","baseObject":"TankL1.5B4.5H2.9fdundefinedFtank21.stl","affiliations":{"Deck":"MainDeck","SFI":"323"},"referenceState":{"xCentre":74.75,"yCentre":-3.75,"zBase":8}},{"id":"Room8","baseObject":"RoomL7B5H2.9fdundefinedFroom8.stl","affiliations":{"Deck":"MainDeck","SFI":"324"},"referenceState":{"xCentre":68,"yCentre":5,"zBase":8}},{"id":"Stairs1","baseObject":"StairsL6B3H2.9fdundefinedFstairs1.stl","affiliations":{"Deck":"MainDeck","SFI":"325"},"referenceState":{"xCentre":67.5,"yCentre":1,"zBase":8}},{"id":"Toilets1","baseObject":"ToiletsL1B2.5H2.9fdundefinedFtoilets1.stl","affiliations":{"Deck":"MainDeck","SFI":"326"},"referenceState":{"xCentre":71,"yCentre":1.25,"zBase":8}},{"id":"DeckOffice1","baseObject":"DeckOfficeL2.5B6.5H2.9fdundefinedFDeckOffice1.stl","affiliations":{"Deck":"MainDeck","SFI":"327"},"referenceState":{"xCentre":72.75,"yCentre":3.25,"zBase":8}},{"id":"Cover2","baseObject":"CoverL53.5B15H2fdundefinedFcover2.stl","affiliations":{"Deck":"Adeck","SFI":"401"},"referenceState":{"xCentre":26.75,"yCentre":0,"zBase":10.9}},{"id":"StabTank1","baseObject":"StabTankL3.5B18H2.9fdundefinedFStabTank.stl","affiliations":{"Deck":"Adeck","SFI":"402"},"referenceState":{"xCentre":55.25,"yCentre":0,"zBase":10.9}},{"id":"Freezer1","baseObject":"FreezerL3.5B2H2.9fdundefinedFfreezer.stl","affiliations":{"Deck":"Adeck","SFI":"403"},"referenceState":{"xCentre":58.75,"yCentre":8,"zBase":10.9}},{"id":"Fridge1","baseObject":"FridgeL4B1.5H2.9fdundefinedFfridge.stl","affiliations":{"Deck":"Adeck","SFI":"404"},"referenceState":{"xCentre":62.5,"yCentre":8,"zBase":10.9}},{"id":"DryRoom1","baseObject":"DryRoomL7.5B3H2.9fdundefinedFDryRoom.stl","affiliations":{"Deck":"Adeck","SFI":"405"},"referenceState":{"xCentre":60.75,"yCentre":5.5,"zBase":10.9}},{"id":"Room9","baseObject":"RoomL2.5B8H2.9fdundefinedFroom9.stl","affiliations":{"Deck":"Adeck","SFI":"406"},"referenceState":{"xCentre":58.25,"yCentre":0,"zBase":10.9}},{"id":"ACRoom1","baseObject":"ACRoomL7.5B5H2.9fdundefinedFACRoom1.stl","affiliations":{"Deck":"Adeck","SFI":"407"},"referenceState":{"xCentre":60.75,"yCentre":-6.5,"zBase":10.9}},{"id":"Room10","baseObject":"RoomL5B5H2.9fdundefinedFroom10.stl","affiliations":{"Deck":"Adeck","SFI":"408"},"referenceState":{"xCentre":62,"yCentre":1.5,"zBase":10.9}},{"id":"CL1","baseObject":"CLL2.5B2H2.9fdundefinedFCL1.stl","affiliations":{"Deck":"Adeck","SFI":"409"},"referenceState":{"xCentre":60.75,"yCentre":-3,"zBase":10.9}},{"id":"Toilets2","baseObject":"ToiletsL2.5B2H2.9fdundefinedFtoilets2.stl","affiliations":{"Deck":"Adeck","SFI":"410"},"referenceState":{"xCentre":63.25,"yCentre":-3,"zBase":10.9}},{"id":"Gallery1","baseObject":"GalleryL5.5B5H2.9fdundefinedFgallery1.stl","affiliations":{"Deck":"Adeck","SFI":"411"},"referenceState":{"xCentre":67.25,"yCentre":5.25,"zBase":10.9}},{"id":"Stairs2","baseObject":"StairsL5.5B4H2.9fdundefinedFstairs1.stl","affiliations":{"Deck":"Adeck","SFI":"412"},"referenceState":{"xCentre":67.25,"yCentre":0.75,"zBase":10.9}},{"id":"DayRoom1","baseObject":"DayRoomL5.5B6H2.9fdundefinedFDayRoom1.stl","affiliations":{"Deck":"Adeck","SFI":"413"},"referenceState":{"xCentre":67.25,"yCentre":-5,"zBase":10.9}},{"id":"MessRoom1","baseObject":"MessRoomL4B13H2.9fdundefinedFMessRoom1.stl","affiliations":{"Deck":"Adeck","SFI":"414"},"referenceState":{"xCentre":72,"yCentre":0,"zBase":10.9}},{"id":"RopeBin1","baseObject":"RopeBinL1.5B3H2.9fdundefinedFRopeBin1.stl","affiliations":{"Deck":"Adeck","SFI":"415"},"referenceState":{"xCentre":74.75,"yCentre":0,"zBase":10.9}},{"id":"Store2","baseObject":"StoreL1.5B4H2.9fdundefinedFstore.stl","affiliations":{"Deck":"Adeck","SFI":"416"},"referenceState":{"xCentre":74.75,"yCentre":3.5,"zBase":10.9}},{"id":"Store3","baseObject":"StoreL1.5B4H2.9fdundefinedFstore.stl","affiliations":{"Deck":"Adeck","SFI":"417"},"referenceState":{"xCentre":74.75,"yCentre":-3.5,"zBase":10.9}},{"id":"Store4","baseObject":"StoreL6.5B10H2.9fdundefinedFstore2.stl","affiliations":{"Deck":"Adeck","SFI":"418"},"referenceState":{"xCentre":78.75,"yCentre":0,"zBase":10.9}},{"id":"SafetyBoat1","baseObject":"SafetyBoatL6.5B3H1fdundefinedFSafetyBoat.stl","affiliations":{"Deck":"Bdeck","SFI":"501"},"referenceState":{"xCentre":47.25,"yCentre":7.5,"zBase":13.8}},{"id":"SafetyBoat2","baseObject":"SafetyBoatL6.5B3H1fdundefinedFSafetyBoat.stl","affiliations":{"Deck":"Bdeck","SFI":"502"},"referenceState":{"xCentre":56.75,"yCentre":7.5,"zBase":13.8}},{"id":"HoistBase1","baseObject":"HoistBaseL3B3H5.4fdundefinedFHoistBase.stl","affiliations":{"Deck":"Bdeck","SFI":"503"},"referenceState":{"xCentre":54,"yCentre":-6.5,"zBase":13.8}},{"id":"Stairs3","baseObject":"StairsL5.5B4H2.7fdundefinedFstairs1.stl","affiliations":{"Deck":"Bdeck","SFI":"504"},"referenceState":{"xCentre":67.25,"yCentre":0.75,"zBase":13.8}},{"id":"CableRoom1","baseObject":"CableRoomL10.5B14H2.7fdundefinedFCableRoom1.stl","affiliations":{"Deck":"Bdeck","SFI":"505"},"referenceState":{"xCentre":76.75,"yCentre":0,"zBase":13.8}},{"id":"Cabin3","baseObject":"CabinL2.5B4H2.7fdundefinedFcabin1.stl","affiliations":{"Deck":"Bdeck","SFI":"506"},"referenceState":{"xCentre":70.25,"yCentre":6,"zBase":13.8}},{"id":"Cabin2","baseObject":"CabinL2.5B4H2.7fdundefinedFcabin1.stl","affiliations":{"Deck":"Bdeck","SFI":"507"},"referenceState":{"xCentre":67.75,"yCentre":6,"zBase":13.8}},{"id":"Cabin1","baseObject":"CabinL4.5B4H2.7fdundefinedFcabin2.stl","affiliations":{"Deck":"Bdeck","SFI":"508"},"referenceState":{"xCentre":64.25,"yCentre":6.5,"zBase":13.8}},{"id":"Tank43","baseObject":"TankL5.5B4H5.3fdundefinedFtank22.stl","affiliations":{"Deck":"Bdeck","SFI":"509"},"referenceState":{"xCentre":61.75,"yCentre":2,"zBase":13.8}},{"id":"Room11","baseObject":"RoomL4.5B8H2.7fdundefinedFroom11.stl","affiliations":{"Deck":"Bdeck","SFI":"510"},"referenceState":{"xCentre":56.75,"yCentre":0,"zBase":13.8}},{"id":"Cabin4","baseObject":"CabinL5B4.5H2.7fdundefinedFcabin3.stl","affiliations":{"Deck":"Bdeck","SFI":"511"},"referenceState":{"xCentre":59,"yCentre":-6.25,"zBase":13.8}},{"id":"Cabin5","baseObject":"CabinL5B6.5H2.7fdundefinedFcabin5.stl","affiliations":{"Deck":"Bdeck","SFI":"512"},"referenceState":{"xCentre":64,"yCentre":-5.25,"zBase":13.8}},{"id":"Cabin5","baseObject":"CabinL2.5B5H2.7fdundefinedFcabin4.stl","affiliations":{"Deck":"Bdeck","SFI":"513"},"referenceState":{"xCentre":70.25,"yCentre":-4.5,"zBase":13.8}},{"id":"Cabin6","baseObject":"CabinL2.5B5H2.7fdundefinedFcabin4.stl","affiliations":{"Deck":"Bdeck","SFI":"514"},"referenceState":{"xCentre":67.75,"yCentre":-4.5,"zBase":13.8}},{"id":"CorridorExt1","baseObject":"CorridorExtL3.5B13.5H2.7fdundefinedFcorridor.stl","affiliations":{"Deck":"Cdeck","SFI":"601"},"referenceState":{"xCentre":57.25,"yCentre":-2.25,"zBase":16.5}},{"id":"InstrumentRoom1","baseObject":"InstrumentRoomL5.5B3.5H2.7fdundefinedFInstrumentRoom.stl","affiliations":{"Deck":"Cdeck","SFI":"602"},"referenceState":{"xCentre":61.75,"yCentre":-1.75,"zBase":16.5}},{"id":"CaptainCabin1","baseObject":"CaptainCabinL6B5H2.7fdundefinedFCaptainCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"603"},"referenceState":{"xCentre":62,"yCentre":-6.5,"zBase":16.5}},{"id":"ChiefOfficerCabin1","baseObject":"ChiefOfficerCabinL3B4.5H2.7fdundefinedFChiefOfficerCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"604"},"referenceState":{"xCentre":66.5,"yCentre":-6,"zBase":16.5}},{"id":"FirstOfficerCabin1","baseObject":"FirstOfficerCabinL3B4H2.7fdundefinedFFirstOfficerCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"605"},"referenceState":{"xCentre":69.5,"yCentre":-6,"zBase":16.5}},{"id":"ChiefStewardCabin1","baseObject":"ChiefStewardCabinL6B6H2.7fdundefinedFChiefStewardCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"606"},"referenceState":{"xCentre":74,"yCentre":-3,"zBase":16.5}},{"id":"ElectricianCabin1","baseObject":"ElectricianCabinL6B6H2.7fdundefinedFElectricianCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"607"},"referenceState":{"xCentre":74,"yCentre":3,"zBase":16.5}},{"id":"Stairs4","baseObject":"StairsL4.5B4H2.7fdundefinedFstairs2.stl","affiliations":{"Deck":"Cdeck","SFI":"608"},"referenceState":{"xCentre":66.75,"yCentre":0.5,"zBase":16.5}},{"id":"CleanLocker1","baseObject":"CleanLockerL1.5B2H2.7fdundefinedFSmallRoom.stl","affiliations":{"Deck":"Cdeck","SFI":"609"},"referenceState":{"xCentre":65.25,"yCentre":-2,"zBase":16.5}},{"id":"BondStore1","baseObject":"BondStoreL1.5B2H2.7fdundefinedFSmallRoom.stl","affiliations":{"Deck":"Cdeck","SFI":"610"},"referenceState":{"xCentre":66.75,"yCentre":-2,"zBase":16.5}},{"id":"Linen1","baseObject":"LinenL1.5B2H2.7fdundefinedFSmallRoom.stl","affiliations":{"Deck":"Cdeck","SFI":"611"},"referenceState":{"xCentre":68.25,"yCentre":-2,"zBase":16.5}},{"id":"ChiefCabin1","baseObject":"ChiefCabinL6B5H2.7fdundefinedFChiefCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"612"},"referenceState":{"xCentre":63.5,"yCentre":6.5,"zBase":16.5}},{"id":"FirstEngineerCabin1","baseObject":"FirstEngineerCabinL2.5B4H2.7fdundefinedFFirstEngineerCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"613"},"referenceState":{"xCentre":67.75,"yCentre":6,"zBase":16.5}},{"id":"SecondEngineerCabin1","baseObject":"SecondEngineerCabinL2B3.5H2.7fdundefinedFSecondEngineerCabin.stl","affiliations":{"Deck":"Cdeck","SFI":"614"},"referenceState":{"xCentre":70,"yCentre":5.75,"zBase":16.5}},{"id":"Hoist1","baseObject":"HoistL1B9H4.15fdundefinedFhoist.stl","affiliations":{"Deck":"BridgeDeck","SFI":"701"},"referenceState":{"xCentre":54,"yCentre":-0.5,"zBase":19.2}},{"id":"AccessStairs1","baseObject":"AccessStairsL4B5H4.15fdundefinedFAccessStairs1.stl","affiliations":{"Deck":"BridgeDeck","SFI":"702"},"referenceState":{"xCentre":61,"yCentre":6.5,"zBase":19.2}},{"id":"AccessStairs2","baseObject":"AccessStairsL4B5H4.15fdundefinedFAccessStairs2.stl","affiliations":{"Deck":"BridgeDeck","SFI":"703"},"referenceState":{"xCentre":61,"yCentre":-6.5,"zBase":19.2}},{"id":"ShipHanding1","baseObject":"ShipHandingL7B8H4.15fdundefinedFShipHanding.stl","affiliations":{"Deck":"BridgeDeck","SFI":"704"},"referenceState":{"xCentre":59.5,"yCentre":0,"zBase":19.2}},{"id":"MainRoom1","baseObject":"MainRoomL8B16H4.15fdundefinedFMainRoom.stl","affiliations":{"Deck":"BridgeDeck","SFI":"705"},"referenceState":{"xCentre":67,"yCentre":0,"zBase":19.2}},{"id":"NavigationRoom1","baseObject":"NavigationRoomL9B8H4.15fdundefinedFNavigationRoom.stl","affiliations":{"Deck":"BridgeDeck","SFI":"706"},"referenceState":{"xCentre":75.5,"yCentre":0,"zBase":19.2}},{"id":"EmGenRoom1","baseObject":"EmGenRoomL11B6H5fdundefinedFEmGenRoom.stl","affiliations":{"Deck":"WheelHouseTop","SFI":"801"},"referenceState":{"xCentre":68.5,"yCentre":-1.5,"zBase":23.35}},{"id":"Communication1","baseObject":"CommunicationL11B3H5fdundefinedFCommunicationRoom.stl","affiliations":{"Deck":"WheelHouseTop","SFI":"802"},"referenceState":{"xCentre":68.5,"yCentre":3,"zBase":23.35}},{"id":"Aerial1","baseObject":"AerialL0.5B0.5H2fdundefinedFaerial.stl","affiliations":{"Deck":"WheelHouseTop","SFI":"803"},"referenceState":{"xCentre":63.75,"yCentre":3.75,"zBase":28.35}},{"id":"Aerial2","baseObject":"AerialL0.5B0.5H2fdundefinedFaerial.stl","affiliations":{"Deck":"WheelHouseTop","SFI":"804"},"referenceState":{"xCentre":64.75,"yCentre":3.75,"zBase":28.35}},{"id":"Aerial3","baseObject":"AerialL0.5B0.5H2fdundefinedFaerial.stl","affiliations":{"Deck":"WheelHouseTop","SFI":"805"},"referenceState":{"xCentre":63.75,"yCentre":2.5,"zBase":28.35}},{"id":"Aerial4","baseObject":"AerialL0.5B0.5H2fdundefinedFaerial.stl","affiliations":{"Deck":"WheelHouseTop","SFI":"806"},"referenceState":{"xCentre":64.75,"yCentre":2.5,"zBase":28.35}}] + }, { + "id": "WorkShop1", + "baseObject": "WorkShopL3B2H2.4fdundefinedFWorkshop.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "216" + }, + "referenceState": { + "xCentre": 63.5, + "yCentre": -2.5, + "zBase": 5.3 + } + }, { + "id": "ChainTank1", + "baseObject": "ChainTankL1.5B1.5H5.6fdundefinedFChainTank.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "217" + }, + "referenceState": { + "xCentre": 74.75, + "yCentre": 0.75, + "zBase": 5.3 + } + }, { + "id": "ChainTank2", + "baseObject": "ChainTankL1.5B1.5H5.6fdundefinedFChainTank.stl", + "affiliations": { + "Deck": "TweenDeck", + "SFI": "218" + }, + "referenceState": { + "xCentre": 74.75, + "yCentre": -0.75, + "zBase": 5.3 + } + }, { + "id": "Cover1", + "baseObject": "CoverL53B15H2.9fdundefinedFcover1.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "301" + }, + "referenceState": { + "xCentre": 27, + "yCentre": 0, + "zBase": 8 + } + }, { + "id": "Tank35", + "baseObject": "TankL7B1.5H2.9fdundefinedFtank18.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "302" + }, + "referenceState": { + "xCentre": 30.5, + "yCentre": 8.25, + "zBase": 8 + } + }, { + "id": "Tank36", + "baseObject": "TankL7B1.5H2.9fdundefinedFtank18.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "303" + }, + "referenceState": { + "xCentre": 30.5, + "yCentre": -8.25, + "zBase": 8 + } + }, { + "id": "Tank37", + "baseObject": "TankL7B1.5H2.9fdundefinedFtank18.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "304" + }, + "referenceState": { + "xCentre": 37.5, + "yCentre": 8.25, + "zBase": 8 + } + }, { + "id": "Tank38", + "baseObject": "TankL7B1.5H2.9fdundefinedFtank18.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "305" + }, + "referenceState": { + "xCentre": 37.5, + "yCentre": -8.25, + "zBase": 8 + } + }, { + "id": "Tank39", + "baseObject": "TankL1B2H2.9fdundefinedFtank19.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "306" + }, + "referenceState": { + "xCentre": 54, + "yCentre": 0, + "zBase": 8 + } + }, { + "id": "FiremStore", + "baseObject": "FiremStoreL2.5B1.5H2.9fdundefinedFFiremStore.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "307" + }, + "referenceState": { + "xCentre": 58.25, + "yCentre": 8.25, + "zBase": 8 + } + }, { + "id": "DeckWorkshop", + "baseObject": "DeckWorkshopL2.5B3.5H2.9fdundefinedFDeckWorkshop.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "308" + }, + "referenceState": { + "xCentre": 58.25, + "yCentre": 5.75, + "zBase": 8 + } + }, { + "id": "Tank40", + "baseObject": "TankL2B1.5H2.9fdundefinedFtank20.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "309" + }, + "referenceState": { + "xCentre": 58.5, + "yCentre": 3.25, + "zBase": 8 + } + }, { + "id": "Store1", + "baseObject": "StoreL2B2H2.9fdundefinedFStore1.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "310" + }, + "referenceState": { + "xCentre": 58.5, + "yCentre": 1.5, + "zBase": 8 + } + }, { + "id": "Tank40", + "baseObject": "TankL2B1.5H2.9fdundefinedFtank20.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "311" + }, + "referenceState": { + "xCentre": 58.5, + "yCentre": -3.25, + "zBase": 8 + } + }, { + "id": "Chem", + "baseObject": "ChemL2.5B1.5H2.9fdundefinedFchem.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "312" + }, + "referenceState": { + "xCentre": 58.25, + "yCentre": -8.25, + "zBase": 8 + } + }, { + "id": "Paint", + "baseObject": "PaintL2.5B1.5H2.9fdundefinedFpaint.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "313" + }, + "referenceState": { + "xCentre": 58.25, + "yCentre": -6.75, + "zBase": 8 + } + }, { + "id": "Inc&GarbRoom", + "baseObject": "Inc&GarbRoomL5B4.5H2.9fdundefinedFInc&GarbRoom.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "314" + }, + "referenceState": { + "xCentre": 62, + "yCentre": 6.25, + "zBase": 8 + } + }, { + "id": "Room1", + "baseObject": "RoomL3.5B4.5H2.9fdundefinedFroom1.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "315" + }, + "referenceState": { + "xCentre": 61.25, + "yCentre": 1.75, + "zBase": 8 + } + }, { + "id": "Room2", + "baseObject": "RoomL3.5B6H2.9fdundefinedFroom2.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "316" + }, + "referenceState": { + "xCentre": 61.25, + "yCentre": -5, + "zBase": 8 + } + }, { + "id": "Room3", + "baseObject": "RoomL1.5B4.5H2.9fdundefinedFroom3.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "317" + }, + "referenceState": { + "xCentre": 63.75, + "yCentre": 1.75, + "zBase": 8 + } + }, { + "id": "Room4", + "baseObject": "RoomL4B2H2.9fdundefinedFroom4.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "318" + }, + "referenceState": { + "xCentre": 65, + "yCentre": -3, + "zBase": 8 + } + }, { + "id": "Room5", + "baseObject": "RoomL4B3.5H2.9fdundefinedFroom5.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "319" + }, + "referenceState": { + "xCentre": 65, + "yCentre": -5.5, + "zBase": 8 + } + }, { + "id": "Room6", + "baseObject": "RoomL3.5B5H2.9fdundefinedFroom6.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "320" + }, + "referenceState": { + "xCentre": 68.75, + "yCentre": -4.75, + "zBase": 8 + } + }, { + "id": "Room7", + "baseObject": "RoomL3.5B6H2.9fdundefinedFroom7.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "321" + }, + "referenceState": { + "xCentre": 72.25, + "yCentre": -3, + "zBase": 8 + } + }, { + "id": "Tank41", + "baseObject": "TankL1.5B4.5H2.9fdundefinedFtank21.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "322" + }, + "referenceState": { + "xCentre": 74.75, + "yCentre": 3.75, + "zBase": 8 + } + }, { + "id": "Tank42", + "baseObject": "TankL1.5B4.5H2.9fdundefinedFtank21.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "323" + }, + "referenceState": { + "xCentre": 74.75, + "yCentre": -3.75, + "zBase": 8 + } + }, { + "id": "Room8", + "baseObject": "RoomL7B5H2.9fdundefinedFroom8.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "324" + }, + "referenceState": { + "xCentre": 68, + "yCentre": 5, + "zBase": 8 + } + }, { + "id": "Stairs1", + "baseObject": "StairsL6B3H2.9fdundefinedFstairs1.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "325" + }, + "referenceState": { + "xCentre": 67.5, + "yCentre": 1, + "zBase": 8 + } + }, { + "id": "Toilets1", + "baseObject": "ToiletsL1B2.5H2.9fdundefinedFtoilets1.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "326" + }, + "referenceState": { + "xCentre": 71, + "yCentre": 1.25, + "zBase": 8 + } + }, { + "id": "DeckOffice1", + "baseObject": "DeckOfficeL2.5B6.5H2.9fdundefinedFDeckOffice1.stl", + "affiliations": { + "Deck": "MainDeck", + "SFI": "327" + }, + "referenceState": { + "xCentre": 72.75, + "yCentre": 3.25, + "zBase": 8 + } + }, { + "id": "Cover2", + "baseObject": "CoverL53.5B15H2fdundefinedFcover2.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "401" + }, + "referenceState": { + "xCentre": 26.75, + "yCentre": 0, + "zBase": 10.9 + } + }, { + "id": "StabTank1", + "baseObject": "StabTankL3.5B18H2.9fdundefinedFStabTank.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "402" + }, + "referenceState": { + "xCentre": 55.25, + "yCentre": 0, + "zBase": 10.9 + } + }, { + "id": "Freezer1", + "baseObject": "FreezerL3.5B2H2.9fdundefinedFfreezer.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "403" + }, + "referenceState": { + "xCentre": 58.75, + "yCentre": 8, + "zBase": 10.9 + } + }, { + "id": "Fridge1", + "baseObject": "FridgeL4B1.5H2.9fdundefinedFfridge.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "404" + }, + "referenceState": { + "xCentre": 62.5, + "yCentre": 8, + "zBase": 10.9 + } + }, { + "id": "DryRoom1", + "baseObject": "DryRoomL7.5B3H2.9fdundefinedFDryRoom.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "405" + }, + "referenceState": { + "xCentre": 60.75, + "yCentre": 5.5, + "zBase": 10.9 + } + }, { + "id": "Room9", + "baseObject": "RoomL2.5B8H2.9fdundefinedFroom9.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "406" + }, + "referenceState": { + "xCentre": 58.25, + "yCentre": 0, + "zBase": 10.9 + } + }, { + "id": "ACRoom1", + "baseObject": "ACRoomL7.5B5H2.9fdundefinedFACRoom1.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "407" + }, + "referenceState": { + "xCentre": 60.75, + "yCentre": -6.5, + "zBase": 10.9 + } + }, { + "id": "Room10", + "baseObject": "RoomL5B5H2.9fdundefinedFroom10.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "408" + }, + "referenceState": { + "xCentre": 62, + "yCentre": 1.5, + "zBase": 10.9 + } + }, { + "id": "CL1", + "baseObject": "CLL2.5B2H2.9fdundefinedFCL1.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "409" + }, + "referenceState": { + "xCentre": 60.75, + "yCentre": -3, + "zBase": 10.9 + } + }, { + "id": "Toilets2", + "baseObject": "ToiletsL2.5B2H2.9fdundefinedFtoilets2.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "410" + }, + "referenceState": { + "xCentre": 63.25, + "yCentre": -3, + "zBase": 10.9 + } + }, { + "id": "Gallery1", + "baseObject": "GalleryL5.5B5H2.9fdundefinedFgallery1.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "411" + }, + "referenceState": { + "xCentre": 67.25, + "yCentre": 5.25, + "zBase": 10.9 + } + }, { + "id": "Stairs2", + "baseObject": "StairsL5.5B4H2.9fdundefinedFstairs1.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "412" + }, + "referenceState": { + "xCentre": 67.25, + "yCentre": 0.75, + "zBase": 10.9 + } + }, { + "id": "DayRoom1", + "baseObject": "DayRoomL5.5B6H2.9fdundefinedFDayRoom1.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "413" + }, + "referenceState": { + "xCentre": 67.25, + "yCentre": -5, + "zBase": 10.9 + } + }, { + "id": "MessRoom1", + "baseObject": "MessRoomL4B13H2.9fdundefinedFMessRoom1.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "414" + }, + "referenceState": { + "xCentre": 72, + "yCentre": 0, + "zBase": 10.9 + } + }, { + "id": "RopeBin1", + "baseObject": "RopeBinL1.5B3H2.9fdundefinedFRopeBin1.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "415" + }, + "referenceState": { + "xCentre": 74.75, + "yCentre": 0, + "zBase": 10.9 + } + }, { + "id": "Store2", + "baseObject": "StoreL1.5B4H2.9fdundefinedFstore.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "416" + }, + "referenceState": { + "xCentre": 74.75, + "yCentre": 3.5, + "zBase": 10.9 + } + }, { + "id": "Store3", + "baseObject": "StoreL1.5B4H2.9fdundefinedFstore.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "417" + }, + "referenceState": { + "xCentre": 74.75, + "yCentre": -3.5, + "zBase": 10.9 + } + }, { + "id": "Store4", + "baseObject": "StoreL6.5B10H2.9fdundefinedFstore2.stl", + "affiliations": { + "Deck": "Adeck", + "SFI": "418" + }, + "referenceState": { + "xCentre": 78.75, + "yCentre": 0, + "zBase": 10.9 + } + }, { + "id": "SafetyBoat1", + "baseObject": "SafetyBoatL6.5B3H1fdundefinedFSafetyBoat.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "501" + }, + "referenceState": { + "xCentre": 47.25, + "yCentre": 7.5, + "zBase": 13.8 + } + }, { + "id": "SafetyBoat2", + "baseObject": "SafetyBoatL6.5B3H1fdundefinedFSafetyBoat.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "502" + }, + "referenceState": { + "xCentre": 56.75, + "yCentre": 7.5, + "zBase": 13.8 + } + }, { + "id": "HoistBase1", + "baseObject": "HoistBaseL3B3H5.4fdundefinedFHoistBase.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "503" + }, + "referenceState": { + "xCentre": 54, + "yCentre": -6.5, + "zBase": 13.8 + } + }, { + "id": "Stairs3", + "baseObject": "StairsL5.5B4H2.7fdundefinedFstairs1.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "504" + }, + "referenceState": { + "xCentre": 67.25, + "yCentre": 0.75, + "zBase": 13.8 + } + }, { + "id": "CableRoom1", + "baseObject": "CableRoomL10.5B14H2.7fdundefinedFCableRoom1.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "505" + }, + "referenceState": { + "xCentre": 76.75, + "yCentre": 0, + "zBase": 13.8 + } + }, { + "id": "Cabin3", + "baseObject": "CabinL2.5B4H2.7fdundefinedFcabin1.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "506" + }, + "referenceState": { + "xCentre": 70.25, + "yCentre": 6, + "zBase": 13.8 + } + }, { + "id": "Cabin2", + "baseObject": "CabinL2.5B4H2.7fdundefinedFcabin1.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "507" + }, + "referenceState": { + "xCentre": 67.75, + "yCentre": 6, + "zBase": 13.8 + } + }, { + "id": "Cabin1", + "baseObject": "CabinL4.5B4H2.7fdundefinedFcabin2.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "508" + }, + "referenceState": { + "xCentre": 64.25, + "yCentre": 6.5, + "zBase": 13.8 + } + }, { + "id": "Tank43", + "baseObject": "TankL5.5B4H5.3fdundefinedFtank22.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "509" + }, + "referenceState": { + "xCentre": 61.75, + "yCentre": 2, + "zBase": 13.8 + } + }, { + "id": "Room11", + "baseObject": "RoomL4.5B8H2.7fdundefinedFroom11.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "510" + }, + "referenceState": { + "xCentre": 56.75, + "yCentre": 0, + "zBase": 13.8 + } + }, { + "id": "Cabin4", + "baseObject": "CabinL5B4.5H2.7fdundefinedFcabin3.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "511" + }, + "referenceState": { + "xCentre": 59, + "yCentre": -6.25, + "zBase": 13.8 + } + }, { + "id": "Cabin5", + "baseObject": "CabinL5B6.5H2.7fdundefinedFcabin5.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "512" + }, + "referenceState": { + "xCentre": 64, + "yCentre": -5.25, + "zBase": 13.8 + } + }, { + "id": "Cabin5", + "baseObject": "CabinL2.5B5H2.7fdundefinedFcabin4.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "513" + }, + "referenceState": { + "xCentre": 70.25, + "yCentre": -4.5, + "zBase": 13.8 + } + }, { + "id": "Cabin6", + "baseObject": "CabinL2.5B5H2.7fdundefinedFcabin4.stl", + "affiliations": { + "Deck": "Bdeck", + "SFI": "514" + }, + "referenceState": { + "xCentre": 67.75, + "yCentre": -4.5, + "zBase": 13.8 + } + }, { + "id": "CorridorExt1", + "baseObject": "CorridorExtL3.5B13.5H2.7fdundefinedFcorridor.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "601" + }, + "referenceState": { + "xCentre": 57.25, + "yCentre": -2.25, + "zBase": 16.5 + } + }, { + "id": "InstrumentRoom1", + "baseObject": "InstrumentRoomL5.5B3.5H2.7fdundefinedFInstrumentRoom.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "602" + }, + "referenceState": { + "xCentre": 61.75, + "yCentre": -1.75, + "zBase": 16.5 + } + }, { + "id": "CaptainCabin1", + "baseObject": "CaptainCabinL6B5H2.7fdundefinedFCaptainCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "603" + }, + "referenceState": { + "xCentre": 62, + "yCentre": -6.5, + "zBase": 16.5 + } + }, { + "id": "ChiefOfficerCabin1", + "baseObject": "ChiefOfficerCabinL3B4.5H2.7fdundefinedFChiefOfficerCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "604" + }, + "referenceState": { + "xCentre": 66.5, + "yCentre": -6, + "zBase": 16.5 + } + }, { + "id": "FirstOfficerCabin1", + "baseObject": "FirstOfficerCabinL3B4H2.7fdundefinedFFirstOfficerCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "605" + }, + "referenceState": { + "xCentre": 69.5, + "yCentre": -6, + "zBase": 16.5 + } + }, { + "id": "ChiefStewardCabin1", + "baseObject": "ChiefStewardCabinL6B6H2.7fdundefinedFChiefStewardCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "606" + }, + "referenceState": { + "xCentre": 74, + "yCentre": -3, + "zBase": 16.5 + } + }, { + "id": "ElectricianCabin1", + "baseObject": "ElectricianCabinL6B6H2.7fdundefinedFElectricianCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "607" + }, + "referenceState": { + "xCentre": 74, + "yCentre": 3, + "zBase": 16.5 + } + }, { + "id": "Stairs4", + "baseObject": "StairsL4.5B4H2.7fdundefinedFstairs2.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "608" + }, + "referenceState": { + "xCentre": 66.75, + "yCentre": 0.5, + "zBase": 16.5 + } + }, { + "id": "CleanLocker1", + "baseObject": "CleanLockerL1.5B2H2.7fdundefinedFSmallRoom.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "609" + }, + "referenceState": { + "xCentre": 65.25, + "yCentre": -2, + "zBase": 16.5 + } + }, { + "id": "BondStore1", + "baseObject": "BondStoreL1.5B2H2.7fdundefinedFSmallRoom.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "610" + }, + "referenceState": { + "xCentre": 66.75, + "yCentre": -2, + "zBase": 16.5 + } + }, { + "id": "Linen1", + "baseObject": "LinenL1.5B2H2.7fdundefinedFSmallRoom.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "611" + }, + "referenceState": { + "xCentre": 68.25, + "yCentre": -2, + "zBase": 16.5 + } + }, { + "id": "ChiefCabin1", + "baseObject": "ChiefCabinL6B5H2.7fdundefinedFChiefCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "612" + }, + "referenceState": { + "xCentre": 63.5, + "yCentre": 6.5, + "zBase": 16.5 + } + }, { + "id": "FirstEngineerCabin1", + "baseObject": "FirstEngineerCabinL2.5B4H2.7fdundefinedFFirstEngineerCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "613" + }, + "referenceState": { + "xCentre": 67.75, + "yCentre": 6, + "zBase": 16.5 + } + }, { + "id": "SecondEngineerCabin1", + "baseObject": "SecondEngineerCabinL2B3.5H2.7fdundefinedFSecondEngineerCabin.stl", + "affiliations": { + "Deck": "Cdeck", + "SFI": "614" + }, + "referenceState": { + "xCentre": 70, + "yCentre": 5.75, + "zBase": 16.5 + } + }, { + "id": "Hoist1", + "baseObject": "HoistL1B9H4.15fdundefinedFhoist.stl", + "affiliations": { + "Deck": "BridgeDeck", + "SFI": "701" + }, + "referenceState": { + "xCentre": 54, + "yCentre": -0.5, + "zBase": 19.2 + } + }, { + "id": "AccessStairs1", + "baseObject": "AccessStairsL4B5H4.15fdundefinedFAccessStairs1.stl", + "affiliations": { + "Deck": "BridgeDeck", + "SFI": "702" + }, + "referenceState": { + "xCentre": 61, + "yCentre": 6.5, + "zBase": 19.2 + } + }, { + "id": "AccessStairs2", + "baseObject": "AccessStairsL4B5H4.15fdundefinedFAccessStairs2.stl", + "affiliations": { + "Deck": "BridgeDeck", + "SFI": "703" + }, + "referenceState": { + "xCentre": 61, + "yCentre": -6.5, + "zBase": 19.2 + } + }, { + "id": "ShipHanding1", + "baseObject": "ShipHandingL7B8H4.15fdundefinedFShipHanding.stl", + "affiliations": { + "Deck": "BridgeDeck", + "SFI": "704" + }, + "referenceState": { + "xCentre": 59.5, + "yCentre": 0, + "zBase": 19.2 + } + }, { + "id": "MainRoom1", + "baseObject": "MainRoomL8B16H4.15fdundefinedFMainRoom.stl", + "affiliations": { + "Deck": "BridgeDeck", + "SFI": "705" + }, + "referenceState": { + "xCentre": 67, + "yCentre": 0, + "zBase": 19.2 + } + }, { + "id": "NavigationRoom1", + "baseObject": "NavigationRoomL9B8H4.15fdundefinedFNavigationRoom.stl", + "affiliations": { + "Deck": "BridgeDeck", + "SFI": "706" + }, + "referenceState": { + "xCentre": 75.5, + "yCentre": 0, + "zBase": 19.2 + } + }, { + "id": "EmGenRoom1", + "baseObject": "EmGenRoomL11B6H5fdundefinedFEmGenRoom.stl", + "affiliations": { + "Deck": "WheelHouseTop", + "SFI": "801" + }, + "referenceState": { + "xCentre": 68.5, + "yCentre": -1.5, + "zBase": 23.35 + } + }, { + "id": "Communication1", + "baseObject": "CommunicationL11B3H5fdundefinedFCommunicationRoom.stl", + "affiliations": { + "Deck": "WheelHouseTop", + "SFI": "802" + }, + "referenceState": { + "xCentre": 68.5, + "yCentre": 3, + "zBase": 23.35 + } + }, { + "id": "Aerial1", + "baseObject": "AerialL0.5B0.5H2fdundefinedFaerial.stl", + "affiliations": { + "Deck": "WheelHouseTop", + "SFI": "803" + }, + "referenceState": { + "xCentre": 63.75, + "yCentre": 3.75, + "zBase": 28.35 + } + }, { + "id": "Aerial2", + "baseObject": "AerialL0.5B0.5H2fdundefinedFaerial.stl", + "affiliations": { + "Deck": "WheelHouseTop", + "SFI": "804" + }, + "referenceState": { + "xCentre": 64.75, + "yCentre": 3.75, + "zBase": 28.35 + } + }, { + "id": "Aerial3", + "baseObject": "AerialL0.5B0.5H2fdundefinedFaerial.stl", + "affiliations": { + "Deck": "WheelHouseTop", + "SFI": "805" + }, + "referenceState": { + "xCentre": 63.75, + "yCentre": 2.5, + "zBase": 28.35 + } + }, { + "id": "Aerial4", + "baseObject": "AerialL0.5B0.5H2fdundefinedFaerial.stl", + "affiliations": { + "Deck": "WheelHouseTop", + "SFI": "806" + }, + "referenceState": { + "xCentre": 64.75, + "yCentre": 2.5, + "zBase": 28.35 + } + }] } diff --git a/examples/data/ship_specifications/blockCase.json b/examples/data/ship_specifications/blockCase.json new file mode 100644 index 0000000..3f201e1 --- /dev/null +++ b/examples/data/ship_specifications/blockCase.json @@ -0,0 +1,68 @@ +{ +"attributes": { +}, +"designState": { + "calculationParameters": { + "LWL_design": 20, + "Draft_design": 2, + "Cb_design": 0.5, + "speed": 12, + "crew" : 20, + "K" : 0.032, + "MCR" : 10000, + "SFR" : 0.000215, + "Co" : 0.3, + "tripDuration": 40 + }, + "objectOverrides": { + "common": { + "fullness": 0.7 + } + } +}, +"structure": { + "hull": { + "attributes": { + "LOA": 20, + "BOA": 10, + "Depth": 4, + "APP": 0, + "lightweight": 15000 + }, + "halfBreadths": { + "waterlines": [0, 1], + "stations": [0, 1], + "table": [[0, 0], [1, 1]] + }, + "buttockHeights": {} + }, + "decks": { + "WheelHouseTop": { + "zFloor": 4, + "thickness": 0.3, + "xAft": 0, + "xFwd": 20, + "yCentre": 0, + "breadth": 10, + "density": 1500 + }, + "BridgeDeck": { + "zFloor": 2, + "thickness": 0.3, + "xAft": 0, + "xFwd": 20, + "yCentre": 0, + "breadth": 5, + "density": 1500 + } + + }, + "bulkheads": { + } +}, +"baseObjects": +[{"id":"TankL2.1B6.13H4.3fdundefinedFtank1.stl","affiliations":{},"boxDimensions":{"length":4,"breadth":6,"height":5},"capabilities":{},"file3D":"tank1.stl","baseState":{"fullness":0},"weightInformation":{"contentDensity":0,"volumeCapacity":120,"lightweight":15000,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}},{"id":"TankL2.1B6.13H4.3fdundefinedFundefined","affiliations":{},"boxDimensions":{"length":5,"breadth":4,"height":2},"capabilities":{},"baseState":{"fullness":0},"weightInformation":{"contentDensity":0,"volumeCapacity":20,"lightweight":14000,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}},{"id":"TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl","affiliations":{},"boxDimensions":{"length":10,"breadth":4,"height":2},"capabilities":{},"file3D":"tank2.stl","baseState":{"fullness":0},"weightInformation":{"contentDensity":0,"volumeCapacity":48,"lightweight":56000,"fullnessCGMapping":{"fullnesses":[0,0.25,0.5,0.75,1],"cgs":[[0,0,2.15],[0,0,0.6449999999999999],[0,0,1.2899999999999998],[0,0,1.72],[0,0,2.15]]}}}], + +"derivedObjects": [{"id":"Tank1","baseObject":"TankL2.1B6.13H4.3fdundefinedFtank1.stl","affiliations":{"Deck":"WheelHouseTop","SFI":"101"},"referenceState":{"xCentre":2,"yCentre":0,"zBase":4}},{"id":"Tank2","baseObject":"TankL2.1B6.13H4.3fdundefinedFundefined","affiliations":{"Deck":"BridgeDeck","SFI":"102"},"referenceState":{"xCentre":5,"yCentre":0,"zBase":2}},{"id":"Tank3","baseObject":"TankL4.199999999999999B6.7H4.3fdundefinedFtank2.stl","affiliations":{"Deck":"BridgeDeck","SFI":"103"},"referenceState":{"xCentre":14,"yCentre":0,"zBase":2}}] + +} \ No newline at end of file diff --git a/examples/data/ship_specifications/prysmaticHull.json b/examples/data/ship_specifications/prysmaticHull.json new file mode 100644 index 0000000..8968b94 --- /dev/null +++ b/examples/data/ship_specifications/prysmaticHull.json @@ -0,0 +1,68 @@ +{ + "attributes": {}, + "designState": { + "calculationParameters": { + "LWL_design": 20, + "Draft_design": 2, + "Cb_design": 0.5, + "speed": 12, + "crew": 20, + "K": 0.032, + "MCR": 10000, + "SFR": 0.000215, + "Co": 0.3, + "tripDuration": 40 + }, + "objectOverrides": { + "common": { + "fullness": 0.7 + } + } + }, + "structure": { + "hull": { + "attributes": { + "LOA": 20, + "BOA": 10, + "Depth": 4, + "APP": 0, + "lightweight": 15000 + }, + "halfBreadths": { + "waterlines": [ + 0, + 1 + ], + "stations": [ + 0, + 1 + ], + "table": [ + [ + 0, + 0 + ], + [ + 1, + 1 + ] + ] + }, + "buttockHeights": {} + }, + "decks": { + "WheelHouseTop": { + "zFloor": 4, + "thickness": 0.3, + "xAft": 0, + "xFwd": 20, + "yCentre": 0, + "breadth": 10, + "density": 1500 + } + }, + "bulkheads": {} + }, + "baseObjects": [], + "derivedObjects": [] +} diff --git a/examples/index.html b/examples/index.html index c44ceb5..9a51796 100644 --- a/examples/index.html +++ b/examples/index.html @@ -27,7 +27,11 @@

    Examples

    Ship3D_with_pretty_JSON.html
    A 3D visualization of the provided ship specification, along with the specification data in a format with expand and collapse.
    Ship3D_test.html
    A fullscreen 3D visualization of the provided ship specification.
    +
    Ship3D_load_state_controls.html
    Very simple test of changing tank fullness with a slider to see change of draft.
    Vessel.js_test.html
    A script that does a few calculations based on the provided specification, and outputs to the screen and the console.
    +
    blockCase_compare.html
    Comparison between manual and automatic calculations on a very simple ship.
    +
    blockCase_compare_json.html
    Sketched alternative implementation of same comparison.
    +
    PX121_calculations.html
    Some calculations on a test specification partially based on an Ulstein vessel.
    diff --git a/examples/js/Ship3D.js b/examples/js/Ship3D.js index 67cd636..1be5b4f 100644 --- a/examples/js/Ship3D.js +++ b/examples/js/Ship3D.js @@ -154,8 +154,8 @@ function Ship3D(ship, stlPath) { console.log("d.zFloor=%.1f", d.zFloor); //DEBUG let zHigh = d.zFloor; let zLow = d.zFloor-d.thickness; - let wlHigh = ship.structure.hull.getWaterline(zHigh, 2); - let wlLow = ship.structure.hull.getWaterline(zLow, 2); + let wlHigh = ship.structure.hull.getWaterline(zHigh); + let wlLow = ship.structure.hull.getWaterline(zLow); let pos = deckGeom.getAttribute("position"); let pa = pos.array; for (let j = 0; j < stss.length+1; j++) { diff --git a/source/CoreClasses/Hull.js b/source/CoreClasses/Hull.js index d7c585d..2f9983d 100644 --- a/source/CoreClasses/Hull.js +++ b/source/CoreClasses/Hull.js @@ -49,107 +49,99 @@ Object.assign(Hull.prototype, { return output; }, /* + Testing new version without nanCorrectionMode parameter, that defaults to setting lower NaNs to 0 and extrapolating highest data entry for upper NaNs (if existant, else set to 0). Inner NaNs will also be set to zero. + Input: z: level from bottom of ship (absolute value in meters) - nanCorrectionMode: 0 to set all NaNs to zero, 1 to output NaNs, set all NaNs to zero, 2 to replace NaNs with interpolated or extrapolated values. + + Output: + Array representing waterline offsets for a given height from the keel (typically a draft). */ - getWaterline: function(z, nanCorrectionMode=1) { + getWaterline: function(z) { let ha = this.attributes; - let zr = z/ha.Depth; - let wls = this.halfBreadths.waterlines; + let zr = z/ha.Depth; //using zr requires fewer operations and less memory than a scaled copy of wls. + let wls = this.halfBreadths.waterlines;//.map(wl=>wl*ha.Depth); let sts = this.halfBreadths.stations; let tab = this.halfBreadths.table; - let {index: a, mu: mu} = bisectionSearch(wls, zr); - let wl; - if (a<0) { - if (nanCorrectionMode===0) { - console.warn("getWaterLine: z below lowest defined waterline. Defaulting to zeros."); + if (zr/*=*/wls.length-1) { - if (nanCorrectionMode===0) { - console.warn("getWaterLine: z above highest defined waterline. Defaulting to zeros."); - return new Array(sts.length).fill(0); - } - if (nanCorrectionMode===1) { - console.warn("getWaterLine: z above highest defined waterline. Outputting NaNs."); - return new Array(sts.length).fill(null); - } - else /*nanCorrectionMode===2*/ { - console.warn("getWaterLine: z above highest defined waterline. Proceeding with highest data entry."); + } else { + let a, mu; + if (zr>wls[wls.length-1]) { + console.warn("getWaterLine: z above highest defined waterline. Proceeding with highest data entries."); a = wls.length-2; //if this level is defined... mu=1; //wl = tab[a].slice(); - } - } - - //Linear interpolation between data waterlines - wl = new Array(sts.length); - for (let j = 0; j < wl.length; j++) { - if (nanCorrectionMode === 0) { - if (a+1 > wls.length-1) { - wl[j] = lerp(tab[a][j], 0, 0.5); - } else { - wl[j] = lerp(tab[a][j] || 0, tab[a+1][j] || 0, mu || 0.5); - } - } else if (nanCorrectionMode === 1) { - if (a+1 > wls.length-1) { - wl[j] = lerp(tab[a][j], null, mu); - } else { - wl[j] = lerp(tab[a][j], tab[a+1][j], mu); - } } else { - //If necessary, sample from below - let b = a; - while (b>0 && isNaN(tab[b][j])) { - b--; + ({index: a, mu: mu} = bisectionSearch(wls, zr)); + if (a === wls.length-1) { + a = wls.length-2; + mu = 1; } - let lower; - if (b===0 && isNaN(tab[b][j])) { - lower = 0; + } + + //Try to do linear interpolation between closest data waterlines, but handle null values well: + let wl = new Array(sts.length); + for (let j = 0; j < wl.length; j++) { + let lower, upper; + let b = a; + //Find lower value for interpolation + if (!isNaN(tab[b][j])) { + lower = tab[b][j]; } else { - lower = tab[b][j]; + b = a+1; + while(b < wls.length && isNaN(tab[b][j])) { + b++; + } + if (b !== wls.length) { + //Inner NaN + lower = 0; + } else { + //Upper NaN, search below: + b = a-1; + while (b >= 0 && isNaN(tab[b][j])) { + b--; + } + if (b===-1) { + //No number found: + lower = 0; + upper = 0; + } else { + lower = tab[b][j]; + upper = lower; + } + } } - //If necesary, sample from above + //Find upper value for interpolation let c = a+1; - let upper; - if (c>wls.length-1) { - c = b; - upper = lower; + if (upper !== undefined) {/*upper found above*/} + else if (!isNaN(tab[c][j])) { + upper = tab[c][j]; } else { - while (cwls.length-1 before the loop. - if (c===wls.length-1 && isNaN(tab[c][j])) { - //Fall back all the way to b - c = b; - upper = lower; - } else { + if (c === wls.length) upper = lower; + else { upper = tab[c][j]; } } - mu = c===b ? 0 : (a+(mu||0.5)-b)/(c-b); + //Linear interpolation wl[j] = lerp(lower, upper, mu); + //Scale numerical values + if (!isNaN(wl[j])) wl[j] *= 0.5*ha.BOA; } - - //Scale numerical values - if (!isNaN(wl[j])) wl[j] *= 0.5*ha.BOA; - } - return wl; + } }, getStation: function(x) { let ha = this.attributes; @@ -184,14 +176,14 @@ Object.assign(Hull.prototype, { //THIS is a candidate for causing wrong Ix, Iy values. //Much logic that can go wrong. - //typically deck bounds + //typically deck bounds waterlineCalculation: function(z, bounds) { let {minX, maxX, minY, maxY} = bounds || {}; - console.groupCollapsed("waterlineCalculation."); + console.group/*Collapsed*/("waterlineCalculation."); console.info("Arguments: z=", z, " Boundaries: ", arguments[1]); - let wl = this.getWaterline(z, 0); + let wl = this.getWaterline(z); console.info("wl: ", wl); //DEBUG let LOA = this.attributes.LOA; @@ -201,8 +193,8 @@ Object.assign(Hull.prototype, { sts[i] *= LOA; } - let hasMinX = (minX !== undefined); - let hasMaxX = (maxX !== undefined); + let hasMinX = (minX !== undefined) && minX!==sts[0]; + let hasMaxX = (maxX !== undefined) && maxX!==sts[sts.length-1]; if (hasMinX || hasMaxX) { let first=0; let wlpre; @@ -244,7 +236,7 @@ Object.assign(Hull.prototype, { } } - //This does not yet account for undefined minY, maxY. Or does it? + //This does not yet account properly for undefined minY, maxY. let port = [], star = []; for (let i=0; ithis.attributes.Depth*wl); let port = this.getStation(x); + if (!isNaN(maxZ)) { + let {index, mu} = bisectionSearch(wls, maxZ); + if (index < wls.length-1) { + wls[index+1] = lerp(wls[index], wls[index+1], mu); + port[index+1] = lerp(port[index], port[index+1], mu); + wls = wls.slice(0,index+2); + port = port.slice(0,index+2); + } + } let star = port.map(hb=>-hb); + let sc = sectionCalculation({xs: wls, ymins: star, ymaxs: port}); return { x: x, //or xc? or cg.. Hm. @@ -301,14 +304,15 @@ Object.assign(Hull.prototype, { A: sc.A, Iz: sc.Ix, Iy: sc.Iy, - maxX: sc.maxX, - minX: sc.minX, + maxZ: sc.maxX, + minZ: sc.minX, maxY: sc.maxY, minY: sc.minY }; }, - //Unoptimized, some redundant repetitions of calculations. - //NOT DONE YET. Outputs lots of NaN values. + + //NOT DONE YET. Many bugs are fixed, but the volume center calculation is broken. The bilinear volume and area calculations have been temporarily replaced with simpler (and worse) calculations, and at least the volume and volume center calculations should be revived soon. + //Important: calculateAttributesAtDraft takes one mandatory parameter T. (The function defined here is immediately called during construction of the prototype, and returns the proper function.) calculateAttributesAtDraft: function() { function levelCalculation(hull, z, @@ -327,61 +331,97 @@ Object.assign(Hull.prototype, { Cv: {x:0, y:0, z:0} }) { - let wlc = hull.waterlineCalculation(z); + let wlc = hull.waterlineCalculation(z,{}); let lev = {}; Object.assign(lev, wlc); //Projected area calculation (approximate): - lev.prMinY = wlc.minY || 0; - lev.prMaxY = wlc.maxY || 0; //|| 0 right? - lev.Ap = prev.Ap - + trapezoidCalculation(prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, lev.z)["A"]; + lev.prMinY = wlc.minY; + lev.prMaxY = wlc.maxY; + //DEBUG: + //console.info("prev.Ap = ", prev.Ap); + //console.info("Parameters to trapezoidCalculation: (%.2f, %.2f, %.2f, %.2f, %.2f, %.2f)", prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, z); + let AT = trapezoidCalculation(prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, z)["A"]; + //console.log("Calculated area of trapezoid: ", AT); + lev.Ap = prev.Ap + AT; + //lev.Ap = prev.Ap + // + trapezoidCalculation(prev.prMinY, prev.prMaxY, lev.prMinY, lev.prMaxY, prev.z, z)["A"]; + //DEBUG END + //level bounds are for the bounding box of the submerged part of the hull - if (!isNaN(prev.minX) && prev.minX<=wlc.minX) + if (!isNaN(wlc.minX) && wlc.minX<=prev.minX) + lev.minX = wlc.minX; + else lev.minX = prev.minX; - if (!isNaN(prev.maxX) && prev.maxX>=wlc.maxX) + if (!isNaN(wlc.maxX) && wlc.maxX>=prev.maxX) + lev.maxX = wlc.maxX; + else lev.maxX = prev.maxX; - if (!isNaN(prev.minY) && prev.minY<=wlc.minY) + if (!isNaN(wlc.minY) && wlc.minY<=prev.minY) + lev.minY = wlc.minY; + else lev.minY = prev.minY; - if (!isNaN(prev.maxY) && prev.maxY>=wlc.maxY) + if (!isNaN(wlc.maxY) && wlc.maxY>=prev.maxY) + lev.maxY = wlc.maxY; + else lev.maxY = prev.maxY; + lev.Vbb = (lev.maxX-lev.minX)*(lev.maxY-lev.minY)*z; + //Keep level maxX and minX for finding end cap areas: + lev.maxXwp = wlc.maxX; + lev.minXwp = wlc.minX; + //Find bilinear patches in the slice, and combine them. //Many possibilities for getting the coordinate systems wrong. let calculations = []; - //let wls = hull.halfBreadths.waterlines.map(wl=>wl*hull.attributes.Depth); let sts = hull.halfBreadths.stations.map(st=>st*hull.attributes.LOA); - let wl = hull.getWaterline(z,0); - let prwl = hull.getWaterline(prev.z,0); + let wl = hull.getWaterline(z); + let prwl = hull.getWaterline(prev.z); for (let j = 0; j < sts.length-1; j++) { let port = - bilinearPatchColumnCalculation(sts[j], sts[j+1], prev.z, z, -prwl[j], -wl[j], -prwl[j+1], -wl[j+1]); + patchColumnCalculation(sts[j], sts[j+1], prev.z, z, -prwl[j], -wl[j], -prwl[j+1], -wl[j+1]); calculations.push(port); let star = - bilinearPatchColumnCalculation(sts[j], sts[j+1], prev.z, z, prwl[j], wl[j], prwl[j+1], wl[j+1]); + patchColumnCalculation(sts[j], sts[j+1], prev.z, z, prwl[j], wl[j], prwl[j+1], wl[j+1]); calculations.push(star); } + console.log(calculations); //DEBUG let C = combineVolumes(calculations); + //Cv of slice. Note that switching of yz must + //be done before combining with previous level + let Cv = {x: C.Cv.x, y: C.Cv.z, z: C.Cv.y}; + lev.Vs = prev.Vs + C.V; //hull volume below z lev.As = prev.As + C.As; //outside surface below z - //center of volume below z (some potential for accumulated rounding error): - let Cv = addVec(scaleVec(prev.Cv,prev.Vs), - scaleVec(C.Cv,C.V)); - let V = prev.Vs+C.V; - if (V!==0) { - Cv = scaleVec(Cv, 1/(prev.Vs+C.V)); - } - //Note switching of yz - lev.Cv = {x: Cv.x, y: Cv.z, z: Cv.y}; + //End caps: + if (lev.minXwp <= sts[0]) + lev.As += hull.stationCalculation(lev.minXwp, z)["A"]; + if (lev.maxXwp >= sts[sts.length-1]) + lev.As += hull.stationCalculation(lev.maxXwp, z)["A"]; + + //center of volume below z (some potential for accumulated rounding error when calculating an accumulated average like this): + lev.Cv = scaleVec(addVec( + scaleVec(prev.Cv,prev.Vs), + scaleVec(Cv,C.V) + ), 1/(lev.Vs || 2)); lev.Cb = lev.Vs/lev.Vbb; + lev.Cp = lev.Vs/(lev.Ap*(lev.maxX-lev.minX)); return lev; } + //Here is the returned function calculateAttributesAtDraft(T): return function(T) { + if (isNaN(T)) { + console.error("Hull.prototype.calculateAttributesAtDraft(T): No draft specified. Returning undefined."); + return; + } else if (T<0 || T>this.attributes.Depth) { + console.error("Hull.prototype.calculateAttributesAtDraft(T): Draft parameter " + T + "outside valid range of [0,Depth]. Returning undefined."); + } + let wls = this.halfBreadths.waterlines.map(wl=>this.attributes.Depth*wl); //This is the part that can be reused as long as the geometry remains unchanged: @@ -395,14 +435,18 @@ Object.assign(Hull.prototype, { this.levelsNeedUpdate = false; } - //Find highest data waterline below water: - let {index: previ} = bisectionSearch(wls, T); + //Find highest data waterline below or at water level: + let {index, mu} = bisectionSearch(wls, T); - let lc = levelCalculation(this, T, this.levels[previ]); + console.info("Highest data waterline below or at water level: " + index); + console.log(this.levels); + let lc; + if (mu===0) lc = this.levels[index]; + else lc = levelCalculation(this, T, this.levels[index]); //Filter and rename for output return { - xcwp: lc.xc, + xcwp: lc.xc, //water plane values ycwp: lc.yc, Awp: lc.Awp, Ixwp: lc.Ix, @@ -415,12 +459,13 @@ Object.assign(Hull.prototype, { LWL: lc.LWL, LBP: lc.LBP, BWL: lc.BWL, - Ap: lc.Ap, + Ap: lc.Ap, //projected area in length direction + Cp: lc.Cp, //prismatic coefficient //Vbb: lc.Vbb, - Vs: lc.Vs, + Vs: lc.Vs, //volume of submerged part of the hull Cb: lc.Cb, - As: lc.As, - Cv: lc.Cv + As: lc.As, //wetted area + Cv: lc.Cv //center of buoyancy } }; }() diff --git a/source/CoreClasses/Ship.js b/source/CoreClasses/Ship.js index 1885542..f83854f 100644 --- a/source/CoreClasses/Ship.js +++ b/source/CoreClasses/Ship.js @@ -17,7 +17,7 @@ Object.assign(Ship.prototype, { constructor: Ship, setFromSpecification: function(specification) { this.attributes = specification.attributes || {}; - this.structure = new Structure(specification.structure,this); + this.structure = new Structure(specification.structure/*,this*/); //baseObjects and derivedObjects are arrays in the specification, but are objects (hashmaps) in the constructed ship object: this.baseObjects = {}; for (let i = 0; i < specification.baseObjects.length; i++) { @@ -45,6 +45,8 @@ Object.assign(Ship.prototype, { return specification; }, + //This should probably be separated in lightweight and deadweight + //Then this function should be replaced by a getDisplacement getWeight: function(shipState) { shipState = shipState || this.designState; @@ -65,6 +67,7 @@ Object.assign(Ship.prototype, { console.info("Calculated weight object: ", W); return W; }, + //This should just take displacement as parameter instead. (later, soon) calculateDraft(shipState, epsilon=0.001) { let w = this.getWeight(shipState); let M = w.mass; @@ -83,21 +86,19 @@ Object.assign(Ship.prototype, { console.info("Calculated draft: %.2f", t); return t; }, + //Should separate between longitudinal and transverse GM too calculateStability(shipState){ let T = this.calculateDraft(shipState); let ha = this.structure.hull.calculateAttributesAtDraft(T); let vol = ha.Vs; - if (vol === 0){ - let Lwl = this.designState.calculationParameters.LWL_design; - let B = this.structure.hull.attributes.BOA; - let cb = this.designState.calculationParameters.Cb_design; - vol = Lwl * B * T * cb; - } let KG = this.getWeight(shipState).cg.z; - let I = ha.Iywp * 1000; - let KB = 0.52 * T; - let BM = I / vol; - let GM = KB + BM - KG; - return {GM, KB, BM, KG}; + let Ix = ha.Ixwp; + let Iy = ha.Iywp; + let KB = ha.Cv.z; + let BMT = Ix / vol; + let BML = Iy / vol; + let GMT = KB + BMT - KG; + let GML = KB + BML - KG; + return {GMT, GML, GM: T, KB, BMT, BML, BM: BMT, KG}; } }); \ No newline at end of file diff --git a/source/CoreClasses/Structure.js b/source/CoreClasses/Structure.js index 3f42d2d..083c493 100644 --- a/source/CoreClasses/Structure.js +++ b/source/CoreClasses/Structure.js @@ -1,7 +1,7 @@ //@EliasHasle -function Structure(spec, ship) { - this.ship = ship; +function Structure(spec/*, ship*/) { + //this.ship = ship; JSONSpecObject.call(this, spec); } Structure.prototype = Object.create(JSONSpecObject.prototype); diff --git a/source/functions/areaCalculations.js b/source/functions/areaCalculations.js index 5f7db2f..0eb500a 100644 --- a/source/functions/areaCalculations.js +++ b/source/functions/areaCalculations.js @@ -2,7 +2,7 @@ //All inputs are numbers. The axes are given by a single coordinate. function steiner(I, A, sourceAxis, targetAxis) { - return I + A*(sourceAxis-targetAxis)^2; + return I + A*(sourceAxis-targetAxis)**2; } //Calculate area, center, Ix, Iy. @@ -17,18 +17,18 @@ function trapezoidCalculation(xbase0, xbase1, xtop0, xtop1, ybase, ytop) { let yc = (a==0 && b==0) ? ybase+0.5*h : ybase + h*(2*a+b)/(3*(a+b)); let d = xbase0+0.5*a; //shorthand let xc = h===0 ? 0.25*(xbase0+xbase1+xtop0+xtop1) : d + (xtop0+0.5*b-d)*(yc-ybase)/h; - let Ix = (a==0 && b== 0) ? 0 : h^3*(a^2+4*a*b+b^2)/(36*(a+b)); + let Ix = (a==0 && b== 0) ? 0 : h**3*(a**2+4*a*b+b**2)/(36*(a+b)); //For Iy I must decompose (I think negative results will work fine): let Art1 = 0.5*(xtop0-xbase0)*h; let xcrt1 = xbase0 + (xtop0-xbase0)/3; - let Iyrt1 = (xtop0-xbase0)^3*h/36; + let Iyrt1 = (xtop0-xbase0)**3*h/36; let Arec = (xbase1-xtop0)*h; let xcrec = 0.5*(xtop0+xbase1); - let Iyrec = (xbase1-xtop0)^3*h/12; + let Iyrec = (xbase1-xtop0)**3*h/12; let Art2 = 0.5*(xbase1-xtop1)*h; let xcrt2 = (xtop1 + (xbase1-xtop1)/3); - let Iyrt2 = (xbase1-xtop1)^3*h/36; + let Iyrt2 = (xbase1-xtop1)**3*h/36; let Iy = steiner(Iyrt1, Art1, xcrt1, xc) + steiner(Iyrec, Arec, xcrec, xc) @@ -70,6 +70,7 @@ function combineAreas(array) { yc /= A; } else { console.warn("Zero area combination."); + console.trace(); xc /= L; yc /= L; } @@ -85,10 +86,8 @@ function combineAreas(array) { //x and y here refers to coordinates in the plane that is being calculated on. function sectionCalculation({xs, ymins, ymaxs}) { - console.groupCollapsed("sectionCalculation"); + console.group/*Collapsed*/("sectionCalculation"); console.info("Arguments (xs, ymins, ymaxs): ", arguments[0]); - - //Needed for Cwp (not a very efficient calculation, maybe): let calculations = []; for (let i = 0; i < xs.length-1; i++) { @@ -108,4 +107,81 @@ function sectionCalculation({xs, ymins, ymaxs}) { console.info("Output: ", output); console.groupEnd(); return output; +} + +//For wetted area. I think this is right, but it is not tested. +//The numerical integral will not scale well with larger geometries. +//Then the full analytical solution is needed. +function bilinearArea(x1, x2, y1, y2, z11, z12, z21, z22, segs=10) { + let [b00,b10,b01,b11] = bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22); + /* + z(x,y) = b00 + b10*x + b01*y + b11*xy + Partial derivative in x: b10 + b11*y + Partial derivative in y: b01 + b11*x + I think this will be right: + Tx(y) = (1, 0, b10+b11*y) + Ty(x) = (0, 1, b01+b11*x) + Then: + Tx X Ty = (-(b10+b11*y), -(b01+b11*x), 1) + |Tx X Ty| = sqrt((b10+b11*y)^2 + (b01+b11*x)^2 + 1) + + Now, to get the area I need to integrate |Tx X Ty| over X,Y. + + Wolfram Alpha gave me this for the inner integral using x (indefinite): + integral sqrt((b01 + b11 x)^2 + 1 + (b10+b11*y)^2) dx = ((b01 + b11*x) sqrt((b01 + b11*x)^2 + 1 + (b10+b11*y)^2) + (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x))/(2*b11) + constant + That means this for the definite integral: + ((b01 + b11*x2)*sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + 1 + (b10+b11*y)^2*ln(sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x2))/(2*b11) - ((b01 + b11*x1)*sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x1))/(2*b11) + = + (b01 + b11*x2)*sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2)/(2*b11) + +(1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x2)/(2*b11)) + - (b01 + b11*x1)*sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2)/(2*b11) + - (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x1)/(2*b11) + = + (b01 + b11*x2)*sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2)/(2*b11) + - (b01 + b11*x1)*sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2)/(2*b11) + +(1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x2)/(2*b11)) + - (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x1)/(2*b11) + + The two first integrals are similar, and the two last are also similar. With A=+-(b01 + b11*xi)/(2*b11), B=(b01 + b11*xi)^2+1, C=b10 and D=b11 (where xi represents either x1 or x2, and +- represents + for x2 and - for x1), I can calculate the integral of sqrt(B+(C+D*y)^2) and multiply by A. That integral is on the same form as the first one. + + The two last integrals can be represented by setting A=+-1/(2*b11), B=(b01 + b11*xi)^2+1, C=b01+b11*xi, D=b10, E=b11, and calculating the integral of (1+(D+E*y)^2)*ln(sqrt(B+(D+E*y)^2)+C), and multiplying by A. + Here is the integration result from Wolfram Alpha: + integral(1 + (D + E y)^2) log(sqrt(B + (D + E y)^2) + C) dy = (-(6 (B^2 - 2 B C^2 - 3 B + C^4 + 3 C^2) tan^(-1)((D + E y)/sqrt(B - C^2)))/sqrt(B - C^2) + (6 (B^2 - 2 B C^2 - 3 B + C^4 + 3 C^2) tan^(-1)((C (D + E y))/(sqrt(B - C^2) sqrt(B + (D + E y)^2))))/sqrt(B - C^2) + 6 (B - C^2 - 3) (D + E y) + 3 C (-3 B + 2 C^2 + 6) log(sqrt(B + (D + E y)^2) + D + E y) + 3 C (D + E y) sqrt(B + (D + E y)^2) + 6 ((D + E y)^2 + 3) (D + E y) log(sqrt(B + (D + E y)^2) + C) - 2 (D + E y)^3)/(18 E) + constant + + I am glad I did not try to do this by hand. But combining these formulae, we can get an exact integral of the area of a bilinear patch. Later. Bilinear patches are not an exact representation anyway. We may opt for something else. + */ + + //Simple numerical calculation of double integral: + let A = 0; + let X = x2-x1, Y = y2-y1; + let N = segs, M = segs; + for (let i = 0; i < N; i++) { + let x = x1 + ((i+0.5)/N)*X; + for (let j = 0; j < M; j++) { + let y = y1 + ((j+0.5)/M)*Y; + A += Math.sqrt((b10+b11*y)**2 + (b01+b11*x)**2 + 1); + } + } + A *= X*Y/(N*M); //dx dy + + return A; +} + +/*Calculates the (arithmetic) average of the area of the two possible triangulations of the quad element (using two triangles). +This requires the base of the quad to be convex. If the base is arrowhead shaped, +The calculation will fail in undefined ways. +*/ +function elementArea(v1,v2,v3,v4) { + let A1 = Math.abs(signedTriangleArea(v1,v2,v3)) + Math.abs(signedTriangleArea(v3,v4,v1)); + let A2 = Math.abs(signedTriangleArea(v2,v3,v4)) + Math.abs(signedTriangleArea(v4,v1,v2)); + let A = 0.5*(A1+A2); + return A; +} + +function signedTriangleArea(v1,v2,v3) { + let u = subVec(v2,v1); + let v = subVec(v3,v1); + let c = crossProduct(u,v); + let A = 0.5*vecNorm(c); + return A; } \ No newline at end of file diff --git a/source/functions/interpolation.js b/source/functions/interpolation.js index ed95a78..abefab7 100644 --- a/source/functions/interpolation.js +++ b/source/functions/interpolation.js @@ -2,22 +2,6 @@ //Some interpolation helpers. Only linear and bilinear for now. -//linear interpolation -//Defaults are not finally decided -//returns NaN if a and b are NaN or mu is NaN. -function lerp(a, b, mu=0.5) { - if (isNaN(a)) return b; - if (isNaN(b)) return a; - return (1-mu)*a+mu*b; -} - -//Test. Not safe yet. -function linearFromArrays(xx, yy, x) { - let {index, mu} = bisectionSearch(xx, x); - if (index === undefined || mu === undefined) return 0; - return lerp(yy[index], yy[index+1], mu); -} - /*Function that takes a sorted array as input, and finds the last index that holds a numerical value less than, or equal to, a given value. Returns an object with the index and an interpolation parameter mu that gives the position of value between index and index+1. */ @@ -44,11 +28,29 @@ function bisectionSearch(array, value) { return {index, mu}; } +//linear interpolation +//Defaults are not finally decided +//returns NaN if a and b are NaN or mu is NaN. +function lerp(a, b, mu=0.5) { + if (isNaN(a)) return b; + if (isNaN(b)) return a; + return (1-mu)*a+mu*b; +} + +//Test. Not safe yet. +function linearFromArrays(xx, yy, x) { + let {index, mu} = bisectionSearch(xx, x); + if (index === undefined || mu === undefined) return 0; + return lerp(yy[index], yy[index+1], mu); +} + +//Source: https://en.wikipedia.org/wiki/Bilinear_interpolation +//(I have used other sources too) function bilinearUnitSquareCoeffs(z00, z01, z10, z11) { - let a00 = z00; - let a10 = z10-z00; - let a01 = z01-z00; - let a11 = z11+z00-z01-z10; + let a00 = z00; //mux=muy=0 + let a10 = z10-z00; //mux=1, muy=0 + let a01 = z01-z00; //mux=0, muy=1 + let a11 = z11+z00-z01-z10; //mux=muy=1 return [a00,a10,a01,a11]; } @@ -59,7 +61,7 @@ function bilinearUnitSquare(z00, z01, z10, z11, mux, muy) { //Find coefficients for 1, x, y, xy. //This doesn't yet handle zero-lengths well. -function bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22) { +function bilinearCoeffs(x1, x2, y1, y2, z00, z01, z10, z11) { let X = (x2-x1); let Y = (y2-y1); @@ -71,13 +73,13 @@ function bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22) { let Ainv = 1/(X*Y); //constant coeff: - let b00 = Ainv*(z11*x2*y2 - z21*x1*y2 - z12*x2*y1 + z22*x1*y1); + let b00 = Ainv*(z00*x2*y2 - z10*x1*y2 - z01*x2*y1 + z11*x1*y1); //x coeff: - let b10 = Ainv*(-z11*y2 + z21*y2 + z12*y1 - z22*y1); + let b10 = Ainv*(-z00*y2 + z10*y2 + z01*y1 - z11*y1); //y coeff: - let b01 = Ainv*(-z11*x2 + z21*x1 + z12*x2 -z22*x1); + let b01 = Ainv*(-z00*x2 + z10*x1 + z01*x2 -z11*x1); //xy coeff: - let b11 = Ainv*(z11-z21-z12+z22); + let b11 = Ainv*(z00-z10-z01+z11); return [b00,b10,b01,b11]; } @@ -88,9 +90,14 @@ function bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22) { function bilinear(x1, x2, y1, y2, z11, z12, z21, z22, x, y) { let [b00, b10, b01, b11] = bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22); - return b00 + b10*x + b01*y + b11*x*y; - //The following is supposed to be equivalent. Maybe I should compare, to make sure that the current calculation is correct. + let fromCoeffs = b00 + b10*x + b01*y + b11*x*y; + + //The following is supposed to be equivalent. Some tests yielding identical results (and no tests so far yielding different results) suggest that the calculations are in fact equivalent. /*let mux = (x-x1)/(x2-x1); let muy = (y-y1)/(y2-y1); - return bilinearUnitSquare(z11, z12, z21, z22, mux, muy);*/ + let fromUnitSquare = bilinearUnitSquare(z11, z12, z21, z22, mux, muy); + + console.log("fromCoeffs=", fromCoeffs, ", fromUnitSquare=", fromUnitSquare);*/ + + return fromCoeffs; } diff --git a/source/functions/vectorOperations.js b/source/functions/vectorOperations.js index 27227f7..c6c32dc 100644 --- a/source/functions/vectorOperations.js +++ b/source/functions/vectorOperations.js @@ -21,11 +21,16 @@ function vecNormSquared(v) { return v.x**2+v.y**2+v.z**2; } +/*Adds two or more vectors given as individual parameters, +and returns a new vector that is the component-wise +sum of the input vectors.*/ function addVec(u,v, ...rest) { if (rest.length > 0) return sumVec([u,v]+rest); return {x: u.x+v.x, y: u.y+v.y, z: u.z+v.z}; } +//Takes an array of vectors as input, and returns a new vector +//that is the component-wise sum of the input vectors. function sumVec(vectors) { let S = {x:0, y:0, z:0}; for (let i = 0; i < vectors.length; i++) { @@ -37,6 +42,12 @@ function sumVec(vectors) { return S; } +//Takes two vector parameters u,v, and returns the vector u-v. +function subVec(u,v) { + //return addVec(u, scaleVec(v, -1)); //equivalent + return {x: u.x-v.x, y: u.y-v.y, z: u.z-v.z}; +} + function dotProduct(u,v) { return u.x*v.x + u.y*v.y + u.z*v.z; } diff --git a/source/functions/volumeCalculations.js b/source/functions/volumeCalculations.js index 30c906b..e8891e5 100644 --- a/source/functions/volumeCalculations.js +++ b/source/functions/volumeCalculations.js @@ -1,32 +1,64 @@ //@EliasHasle -function bilinearPatchColumnCalculation(x1, x2, y1, y2, z11, z12, z21, z22) { - let X = x2-x1; - let Y = y2-y1; - let [a00, a10, a01, a11] = bilinearUnitSquareCoeffs(z11, z12, z21, z22); - /* - From here I call mux for x, and muy for y. - Integral over unit square: - INT[x from 0 to 1, INT[y from 0 to 1, (a00 + a10*x + a01*y + a11*x*y) dy] dx] - = INT[x from 0 to 1, (a00+a10*x+0.5*a01+0.5*a11*x) dx] - = a00 + 0.5*a10 + 0.5*a01 + 0.25*a11 - */ - let Ab = X*Y; - let zAvg = (a00 + 0.5*a10 + 0.5*a01 + 0.25*a11); - let V = Math.abs(Ab*zAvg); //new: absolute value - let zc = 0.5*zAvg; - /* - To find xc, I need to integrate x*z over the unit square, and scale and translate to world coordinates afterwards: - INT[x from 0 to 1, (a00+a10*x+0.5*a01+0.5*a11*x)*x dx] - = 0.5*a00 + a10/3 + 0.25*a01 + a11/6 - Scale and translate:*/ - let xc = y1 + X*(0.5*a00 + a10/3 + 0.25*a01 + a11/6) +//I have been doing some tests here of a simplified calculation. +//The results so far indicate that, for the prism hull, the results are almost identical, except that with the simple calculation the center of volume is almost right (but wrong enough to disqualify such a simple calculation). +/*Note that the coordinate system used here has xy as a grid, with z as heights on the grid, but in the intended application, which is calculations on transverse hull offsets, this z corresponds to the vessel y axis, and y corresponds to the vessel z axis. In any application of this function, the conversion between coordinate systems must be taken care of appropriately.*/ + // xy +function patchColumnCalculation(x1, x2, y1, y2, z00, z01, z10, z11) { + //VOLUME: + //Analysis based on a bilinear patch: + // /* + // From here I call mux for x, and muy for y. + // Integral over unit square: + // INT[x from 0 to 1, INT[y from 0 to 1, (a00 + a10*x + a01*y + a11*x*y) dy] dx] + // = INT[x from 0 to 1, (a00+a10*x+0.5*a01+0.5*a11*x) dx] + // = a00 + 0.5*a10 + 0.5*a01 + 0.25*a11 + // Note that by expanding a00,a10,a01,a11, it is demonstrated that this (rather unsurprisingly) is exactly equivalent to taking the average z offset of the control points. + // */ + let X = x2-x1; + let Y = y2-y1; + let Ab = X*Y; //area of base of patch column + //let zAvg = (a00 + 0.5*a10 + 0.5*a01 + 0.25*a11); + let zAvg = 0.25*(z00+z01+z10+z11); //equivalent + let V = Math.abs(Ab*zAvg); //works + + //CENTER OF VOLUME + let zc = 0.5*zAvg; + + //Very approximate center of volume + //(does not account for different signs on z values, + //but that should be OK for hull offsets) + //let xc = (x1*(z00+z01)+x2*(z10+z11))/((z00+z01+z10+z11) || 1); + //let yc = (y1*(z00+z10)+y2*(z01+z11))/((z00+z01+z10+z11) || 1); + + // /* + // To find xc properly, I need to integrate x*z over the unit square, divide by zAvg(?) and scale and translate to ship coordinates afterwards: + // INT[x from 0 to 1, INT[y from 0 to 1, x*(a00 + a10*x + a01*y + a11*x*y) dy] dx] = + // INT[x from 0 to 1, INT[y from 0 to 1, (a00*x + a10*x^2 + a01*xy + a11*x^2*y) dy] dx] = + // INT[x from 0 to 1, (a00*x + a10*x^2 + 0.5*a01*x + 0.5*a11*x^2) dx] + // = (0.5*a00 + a10/3 + 0.25*a01 + a11/6) + //Trying to expand the coeffs to original z offsets: + // = (0.5*z00 + (z10-z00)/3 + 0.25*(z01-z00) + (z00+z00-z01-z10)/6) + // = ((1/12)*z00 + (1/6)*z10 + (1/12)*z01 + (1/6)*z00) + //Divide by zAvg to get muxc, then scale and translate to xc. + let xc = x1+X*(((1/12)*z00 + (1/6)*z10 + (1/12)*z01 + (1/6)*z11) / (zAvg || 1)); + //console.log("x1=%.2f, X=%.2f, muxc = %.2f", x1, X, (((1/12)*z00 + (1/6)*z10 + (1/12)*z01 + (1/6)*z11) / (zAvg || 1))); + //Similar for yc (modified symmetrically) + let yc = y1+Y*(((1/12)*z00 + (1/12)*z10 + (1/6)*z01 + (1/6)*z11) / (zAvg || 1)); + let [a00, a10, a01, a11] = bilinearUnitSquareCoeffs(z00, z01, z10, z11); - //Similar for yc: - let yc = y1 + Y*(0.5*a00 + 0.25*a10 + a01/3 + a11/6) + //console.log("Patch column Cv = (%.2f, %.2f, %.2f)", xc,yc,zc); - //new: absolute value (OK?) - let As = Math.abs(bilinearArea(x1, x2, y1, y2, z11, z12, z21, z22)); + //AREA + //These two methods give very similar results, within about 1% difference for the fishing boat hull (used in PX121.json). + //Simple triangle average approximation for area (works) + /*let As = elementArea( + {x: x1, y: y1, z: z00}, + {x: x1, y: y2, z: z01}, + {x: x2, y: y1, z: z10}, + {x: x2, y: y2, z: z11});*/ + //Bilinear area calculation. Works too, but is currently numerical, and quite complex (which means it is bug-prone and hard to maintain). But it is more exact, even with just a few segments for numerical integration (the last, optional, parameter) + let As = Math.abs(bilinearArea(x1, x2, y1, y2, z00, z01, z10, z11, 10)); return {Ab: Ab, As: As, V: V, Cv: {x: xc, y: yc, z: zc}}; } @@ -38,80 +70,17 @@ function combineVolumes(array) { let As = 0; let Cv = {x:0, y:0, z:0}; let L = array.length; - if (L===0) return {V,As,Cv}; + //if (L===0) return {V,As,Cv}; for (let i = 0; i < L; i++) { let e = array[i]; V += e.V; As += e.As; //typically wetted area - Cv.x += e.Cv.x*e.V; - Cv.y += e.Cv.y*e.V; - Cv.z += e.Cv.z*e.V; - } - //Safe zero check? - if (V!==0) { - Cv.x /= V; - Cv.y /= V; - Cv.z /= V; - } else { - console.warn("Zero volume combination."); - Cv.x /= L; - Cv.y /= L; - Cv.z /= L; + //console.log(e.Cv); + Cv = addVec(Cv, scaleVec(e.Cv, e.V)); } + Cv = scaleVec(Cv, 1/(V || L || 1)); + + //console.info("combineVolumes: Combined Cv is (" + Cv.x + ", " + Cv.y + ", " + Cv.z + ")."); return {V,As,Cv};//{V: V, As: As, Cv: Cv}; } - -//For wetted area. I think this is right, but it is not tested. -function bilinearArea(x1, x2, y1, y2, z11, z12, z21, z22, segs=10) { - let [b00,b10,b01,b11] = bilinearCoeffs(x1, x2, y1, y2, z11, z12, z21, z22); - /* - z(x,y) = b00 + b10*x + b01*y + b11*xy - Partial derivative in x: b10 + b11*y - Partial derivative in y: b01 + b11*x - I think this will be right: - Tx(y) = (1, 0, b10+b11*y) - Ty(x) = (0, 1, b01+b11*x) - Then: - Tx X Ty = (-(b10+b11*y), -(b01+b11*x), 1) - |Tx X Ty| = sqrt((b10+b11*y)^2 + (b01+b11*x)^2 + 1) - - Wolfram Alpha gave me this for the inner integral using x (indefinite): - integral sqrt((b01 + b11 x)^2 + 1 + (b10+b11*y)^2) dx = ((b01 + b11*x) sqrt((b01 + b11*x)^2 + 1 + (b10+b11*y)^2) + (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x))/(2*b11) + constant - That means this for the definite integral: - ((b01 + b11*x2)*sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + 1 + (b10+b11*y)^2*ln(sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x2))/(2*b11) - ((b01 + b11*x1)*sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x1))/(2*b11) - = - (b01 + b11*x2)*sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2)/(2*b11) - +(1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x2)/(2*b11)) - - (b01 + b11*x1)*sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2)/(2*b11) - - (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x1)/(2*b11) - = - (b01 + b11*x2)*sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2)/(2*b11) - - (b01 + b11*x1)*sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2)/(2*b11) - +(1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x2)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x2)/(2*b11)) - - (1 + (b10+b11*y)^2)*ln(sqrt((b01 + b11*x1)^2 + 1 + (b10+b11*y)^2) + b01 + b11*x1)/(2*b11) - - The two first integrals are similar, and the two last are also similar. With A=+-(b01 + b11*xi)/(2*b11), B=(b01 + b11*xi)^2+1, C=b10 and D=b11 (where xi represents either x1 or x2, and +- represents + for x2 and - for x1), I can calculate the integral of sqrt(B+(C+D*y)^2) and multiply by A. That integral is on the same form as the first one. - - The two last integrals can be represented by setting A=+-1/(2*b11), B=(b01 + b11*xi)^2+1, C=b01+b11*xi, D=b10, E=b11, and calculating the integral of (1+(D+E*y)^2)*ln(sqrt(B+(D+E*y)^2)+C), and multiplying by A. - Here is the integration result from Wolfram Alpha: - integral(1 + (D + E y)^2) log(sqrt(B + (D + E y)^2) + C) dy = (-(6 (B^2 - 2 B C^2 - 3 B + C^4 + 3 C^2) tan^(-1)((D + E y)/sqrt(B - C^2)))/sqrt(B - C^2) + (6 (B^2 - 2 B C^2 - 3 B + C^4 + 3 C^2) tan^(-1)((C (D + E y))/(sqrt(B - C^2) sqrt(B + (D + E y)^2))))/sqrt(B - C^2) + 6 (B - C^2 - 3) (D + E y) + 3 C (-3 B + 2 C^2 + 6) log(sqrt(B + (D + E y)^2) + D + E y) + 3 C (D + E y) sqrt(B + (D + E y)^2) + 6 ((D + E y)^2 + 3) (D + E y) log(sqrt(B + (D + E y)^2) + C) - 2 (D + E y)^3)/(18 E) + constant - - I am glad I did not try to do this by hand. But combining these formulae, we can get an exact integral of the area of a bilinear patch. Later. Bilinear patches are not an exact representation anyway. We may opt for something else. - */ - - //Simple numerical calculation of double integral: - let A = 0; - let X = x2-x1, Y = y2-y1; - let N = segs, M = segs; - for (let i = 0; i < N; i++) { - let x = x1 + ((i+0.5)/N)*X; - for (let j = 0; j < M; j++) { - let y = y1 + ((j+0.5)/M)*Y; - A += Math.sqrt((b10+b11*y)**2 + (b01+b11*x)**2 + 1); - } - } - A *= X*Y/(N*M); //dx dy - - return A; -} \ No newline at end of file