export { AssessmentDatums };
import { JSPath } from "../../shared/path.mjs";
import { ProtocolDatum } from "./datums.mjs";
import { AssessmentType } from "../../shared/assessment_types.mjs";
/** Class representing datums for an assessment type */
class AssessmentDatums {
/**
*
* @param {ProtocolDatum[]} datums Array of ProtocolDatum instances
* @param {string} assessment Assessment type, e.g. AssessmentType.NECK_AXIAL
*/
constructor(datums, assessment) {
this.datums = datums;
this.assessment = assessment;
}
/* Class methods */
/**
* Reads assessment datums from a JSON file
* from the 'datums' directory
* @param {string} regulation Regulation, e.g. Regulation.CNCAP
* @param {string} crash_test Crash test type, e.g. CrashTest.ODB
* @param {string} version Protocol version, e.g. "7.1.2"
* @param {string} assessment_type Assessment type, e.g. AssessmentType.NECK_AXIAL
* @param {string} filename Filename to read from, e.g. "default"
* @returns {?AssessmentDatums}
* @example
* let assessment_datums = AssessmentDatums.ReadFromFile(Regulation.CNCAP,
* CrashTest.ODB,
* "7.1.2",
* AssessmentType.NECK_SHEAR_EXCEEDENCE,
* JSPath.WorkflowsDirectory(JSPath.POST),
* "default");
*/
static ReadFromFile(regulation, crash_test, version, assessment_type, filename) {
/* Get datums directory relative to the workflows directory */
let datums_dir = JSPath.GetDatumsDirectory();
/* Datums file should be in a sub-directory of the datums directory
*
* datums/[regulation]/[crash_test]/[version]/[assessment_type]
*/
datums_dir = `${datums_dir}/${regulation}/${crash_test}/${version}/${assessment_type}`;
/* File to read */
let datums_filename = `${datums_dir}/${filename}.json`;
/* Not an error if it doesn't exist, because datums files don't necessarily exist for all
* assessment types (e.g. HIC). So we silently return null */
if (!File.Exists(datums_filename)) {
return null;
}
/* Try and parse the JSON file to create the datums. Expected format is:
*
* {
* "name": "NECK_TENSION",
* "datums": [
* {
* "name": "GOOD",
* "value": 1.7,
* "line_colour": "GREEN",
* "colour_above": "ORANGE",
* "colour_below": "GREEN"
* },
* {
* "name": "MARGINAL",
* "value": 2.62,
* "line_colour": "ORANGE",
* "colour_above": "RED"
* }
* ]
* }
*
*/
try {
let f = new File(datums_filename, File.READ);
let text = f.ReadAll();
f.Close();
let json = JSON.parse(text);
let name_prefix = `${regulation}_${crash_test}_${json.name}`;
let datums = [];
for (let datum of json.datums) {
/* Colours will either be a string, e.g. "GREEN", "YELLOW", etc.
* or an array of RGB numbers. Convert them to a Colour class number. */
let line_colour = AssessmentDatums.Colour(datum.line_colour);
let colour_above = AssessmentDatums.Colour(datum.colour_above);
let colour_below = AssessmentDatums.Colour(datum.colour_below);
let colour_left = AssessmentDatums.Colour(datum.colour_left);
let colour_right = AssessmentDatums.Colour(datum.colour_right);
let pd = new ProtocolDatum(
datum.value,
`${name_prefix}_${datum.name}`,
line_colour,
colour_above,
colour_below,
colour_left,
colour_right
);
datums.push(pd);
}
return new AssessmentDatums(datums, assessment_type);
} catch (e) {
ErrorMessage(e);
return null;
}
}
/**
* Converts the string or array of RGB numbers to a Colour
* @param {string | number[]} colour
* @returns {?number}
*/
static Colour(colour) {
if (!colour) return null;
/* RGB array */
if (colour instanceof Array) {
return Colour.RGB(colour[0], colour[1], colour[2]);
/* Colour strings */
} else {
/* Use RGB colours for GREEN, YELLOW, ORANGE, BROWN and RED
* For any other string get it from the Colour class constant */
if (colour == "GREEN") {
return Colour.RGB(38, 155, 41);
} else if (colour == "YELLOW") {
return Colour.RGB(255, 204, 0);
} else if (colour == "ORANGE") {
return Colour.RGB(255, 151, 0);
} else if (colour == "BROWN") {
return Colour.RGB(117, 63, 42);
} else if (colour == "RED") {
return Colour.RGB(224, 7, 0);
/* Colour class constant */
} else {
return Colour[colour];
}
}
}
/* Instance property getter and setters */
/**
* Array of ProtocolDatum instances
* @type {ProtocolDatum[]}
*/
get datums() {
return this._datums;
}
set datums(new_datums) {
if (!(new_datums instanceof Array)) {
throw new Error("datums must be an Array");
}
for (let new_datum of new_datums) {
if (!(new_datum instanceof ProtocolDatum)) {
throw new Error("datums must be an array of ProtocolDatum instances");
}
}
this._datums = new_datums;
}
/**
* Assessment type
* @type {string}
*/
get assessment() {
return this._assessment;
}
set assessment(new_assessment) {
if (AssessmentType.GetAll().indexOf(new_assessment) == -1) {
throw new Error(`Invalid assessment: ${new_assessment}`);
}
this._assessment = new_assessment;
}
/* Instance methods */
/**
* Return the minimum X value for the assessment datums
* @returns {number}
*/
MinX() {
let min_x = Number.MAX_VALUE;
for (let datum of this.datums) {
min_x = Math.min(min_x, datum.MinX());
}
return min_x;
}
/**
* Return the maximum X value for the assessment datums
* @returns {number}
*/
MaxX() {
let max_x = -Number.MAX_VALUE;
for (let datum of this.datums) {
max_x = Math.max(max_x, datum.MaxX());
}
return max_x;
}
/**
* Return the minimum Y value for the assessment datums
* @returns {number}
*/
MinY() {
let min_y = Number.MAX_VALUE;
for (let datum of this.datums) {
min_y = Math.min(min_y, datum.MinY());
}
return min_y;
}
/**
* Return the maximum Y value for the assessment datums
* @returns {number}
*/
MaxY() {
let max_y = -Number.MAX_VALUE;
for (let datum of this.datums) {
max_y = Math.max(max_y, datum.MaxY());
}
return max_y;
}
/**
* Extends the last point on the datums to the specified X value
* @param {number} x X value to extend the datum to
*/
ExtendLastYValueToX(x) {
if (!this.datums) return;
for (let datum of this.datums) {
datum.ExtendLastYValueToX(x);
}
}
/**
* Plot all the datums on a graph
* @param {number} [graph] Index of graph to plot on. If not specified, it's plotted on all graphs
*/
Plot(graph) {
if (!this.datums) return;
for (let datum of this.datums) datum.Plot(graph);
}
}