From d5f06bae7d23ce9fb09d7902068fdf6177fd4ea0 Mon Sep 17 00:00:00 2001 From: Ramesh Kumar <ramesh.p@matriotsolutions.com> Date: Wed, 31 Mar 2021 20:35:16 +0530 Subject: [PATCH] TMSS-577: Angle fields allowed to enter dms,degrees, hms, hours & radians. --- .../src/components/JSONEditor/JEditor.js | 76 ++---------- .../components/Spreadsheet/DegreeInputmask.js | 7 +- .../components/Spreadsheet/TimeInputmask.js | 7 +- .../Scheduling/excelview.schedulingset.js | 8 +- .../tmss_webapp/src/utils/unit.converter.js | 113 ++++++++++++++++-- .../tmss_webapp/src/utils/validator.js | 38 ++---- 6 files changed, 138 insertions(+), 111 deletions(-) diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js b/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js index 7581c8e1765..5af6f357d38 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js @@ -5,7 +5,8 @@ /* eslint-disable react-hooks/exhaustive-deps */ import React, {useEffect, useRef} from 'react'; import _ from 'lodash'; -import UnitConverter from '../../utils/unit.converter' +import UnitConverter from '../../utils/unit.converter'; +import Validator from '../../utils/validator'; import $RefParser from "@apidevtools/json-schema-ref-parser"; import "@fortawesome/fontawesome-free/css/all.css"; import flatpickr from 'flatpickr'; @@ -137,8 +138,8 @@ function Jeditor(props) { getCustomProperties(schema.definitions); schema.title = props.title; const subbandValidator = validateSubbandOutput; - const timeValidator = validateTime; - const angleValidator = validateAngle; + const timeValidator = Validator.validateTime; + const angleValidator = Validator.validateAngle; JSONEditor.defaults.custom_validators.push((schema, value, path) => { const errors = []; if (schema.validationType === "subband_list") { @@ -154,7 +155,7 @@ function Jeditor(props) { errors.push({ path: path, property: 'validationType', - message: 'Not a valid input. Mimimum: 00:00:00.0000, Maximum:23:59:59.9999' + message: 'Not a valid input. Mimimum: 00:00:00.0000hours or 0, Maximum:23:59:59.9999hours or 6.2831' }); } } else if (schema.validationType === "angle") { @@ -162,7 +163,7 @@ function Jeditor(props) { errors.push({ path: path, property: 'validationType', - message: 'Not a valid input. Mimimum: 00:00:00.0000, Maximum:90:00:00.0000' + message: 'Not a valid input. Mimimum: 00:00:00.0000degrees 0r 0, Maximum:90:00:00.0000degrees or 1.5708' }); } } else if (schema.validationType === "distanceOnSky") { @@ -265,19 +266,15 @@ function Jeditor(props) { let newProperty = { type: "string", title: defProperty.title, - description: (defProperty.description + (isDegree?'(Degrees:Minutes:Seconds.MilliSeconds)':'(Hours:Minutes:Seconds.MilliSeconds)')), - default: "00:00:00.0000", + description: (defProperty.description + (isDegree? + "(Supported Formats: '10d15m10.1234s', '10:15:10.1234degrees', '10.2528degrees', '0.1789')": + "(Supported Formats: '10h15m10.1234s', '10:15:10.1234hours', '10.4187hours', '2.7276')")), + default: "0", validationType: isDegree?'angle':'time', options: { "grid_columns": 4, "inputAttributes": { - "placeholder": isDegree?"DD:mm:ss.ssss":"HH:mm:ss.ssss" - }, - "cleave": { - numericOnly: true, - blocks: [2, 2, 2, 4], - delimiters: isDegree ? [':', ':','.'] : [':', ':', '.'], - delimiterLazyShow: true + "placeholder": isDegree?"Degrees or Radian":"Hours or Radian" } } } @@ -391,8 +388,8 @@ function Jeditor(props) { let outputValue = editorOutput[outputKey]; if (outputValue instanceof Object) { if (_.indexOf(pointingProps, outputKey) >= 0) { - outputValue.angle1 = UnitConverter.getAngleOutput(outputValue.angle1, false); - outputValue.angle2 = UnitConverter.getAngleOutput(outputValue.angle2, true); + outputValue.angle1 = UnitConverter.parseAngle(outputValue.angle1); + outputValue.angle2 = UnitConverter.parseAngle(outputValue.angle2); } else { updateOutput(outputValue); } @@ -443,53 +440,6 @@ function Jeditor(props) { return (hh<10?`0${hh}`:`${hh}`) + ':' + (mm<10?`0${mm}`:`${mm}`) + ':' + (ss<10?`0${ss}`:`${ss}`); } - /** - * Validate time entered as string in HH:mm:ss format - * @param {String} prpOutput - */ - function validateTime(prpOutput) { - const splitOutput = prpOutput.split(':'); - const seconds = splitOutput[2]?splitOutput[2].split('.')[0].split('.')[0]:splitOutput[2]; - let milliSeconds = prpOutput.split('.')[1] || '0000'; - milliSeconds = milliSeconds.padEnd(4,0); - if (splitOutput.length < 3) { - return false; - } else { - if (parseInt(splitOutput[0]) > 23 || parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59 ) - { - return false; - } - const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(seconds) + milliSeconds/10000; - if (timeValue >= 86400) { - return false; - } - } - return true; - } - - /** - * Validate angle input to not exceed 90 degrees - * @param {String} prpOutput - */ - function validateAngle(prpOutput) { - const splitOutput = prpOutput.split(':'); - const seconds = splitOutput[2]?splitOutput[2].split('.')[0].split('.')[0]:splitOutput[2]; - let milliSeconds = prpOutput.split('.')[1] || '0000'; - milliSeconds = milliSeconds.padEnd(4,0); - if (splitOutput.length < 3) { - return false; - } else { - if (parseInt(splitOutput[0]) > 90 || parseInt(splitOutput[1])>59 || parseInt(seconds)>59) { - return false; - } - const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(seconds) + milliSeconds/10000; - if (timeValue > 324000) { - return false; - } - } - return true; - } - /** * Validates if the subband list custom field * @param {String} prpOutput diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/DegreeInputmask.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/DegreeInputmask.js index 16e5057bdf3..4fd0b705175 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/DegreeInputmask.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/DegreeInputmask.js @@ -1,5 +1,4 @@ import React, { Component } from 'react'; -import { InputMask } from 'primereact/inputmask'; import Validator from '../../utils/validator'; import Cleave from 'cleave.js/react'; @@ -35,10 +34,8 @@ export default class DegreeInputMask extends Component { render() { return ( - <Cleave placeholder="DD:mm:ss.ssss" value={this.props.value} - options={{numericOnly: true, blocks: [2, 2, 2, 4], - delimiters: [':', ':', '.'], - delimiterLazyShow: false}} + <Cleave placeholder="Degree/Radian" value={this.props.value} + title="Enter in dms or degrees or radians" className="inputmask" htmlRef={(ref) => this.input = ref } onChange={this.callbackUpdateAngle} /> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js index 540f276baf8..3a7fe62f3a1 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js @@ -1,5 +1,4 @@ import React, { Component } from 'react'; -import { InputMask } from 'primereact/inputmask'; import Validator from '../../utils/validator'; import Cleave from 'cleave.js/react'; @@ -33,10 +32,8 @@ export default class TimeInputMask extends Component { render() { return ( - <Cleave placeholder="HH:mm:ss.ssss" value={this.props.value} - options={{numericOnly: true, blocks: [2, 2, 2, 4], - delimiters: [':', ':', '.'], - delimiterLazyShow: false}} + <Cleave placeholder="Hour/Radian" value={this.props.value} + title="Enter in hms or hours or radians" className="inputmask" htmlRef={(ref) => this.input = ref } onChange={this.callbackUpdateAngle} /> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js index 6e8e565a824..01fee2c2d75 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js @@ -1337,7 +1337,7 @@ export class SchedulingSetCreate extends Component { row = this.state.commonRowData[0]; row[field] = value; row['isValid'] = isValid; - row[field+'value'] = UnitConverter.getAngleOutput(value,isDegree); + row[field+'value'] = UnitConverter.parseAngle(value); tmpRowData = this.state.commonRowData; tmpRowData[0] = row; await this.setState({ @@ -1348,7 +1348,7 @@ export class SchedulingSetCreate extends Component { row = this.state.rowData[rowIndex]; row[field] = value; row['isValid'] = isValid; - row[field+'value'] = UnitConverter.getAngleOutput(value,isDegree); + row[field+'value'] = UnitConverter.parseAngle(value); tmpRowData = this.state.rowData; tmpRowData[rowIndex] = row; await this.setState({ @@ -1752,13 +1752,13 @@ export class SchedulingSetCreate extends Component { validRow = false; return; } - paramOutput[key] = UnitConverter.getAngleOutput(suRow[result[key]],false); + paramOutput[key] = UnitConverter.parseAngle(suRow[result[key]]); } else if (key === 'angle2'){ if (!Validator.validateAngle(suRow[result[key]])){ validRow = false; return; } - paramOutput[key] = UnitConverter.getAngleOutput(suRow[result[key]],true); + paramOutput[key] = UnitConverter.parseAngle(suRow[result[key]]); } else if (key === 'angle3'){ paramOutput[key] = Number(suRow[result[key]]); diff --git a/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js b/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js index 471818ef7f1..17569078541 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js @@ -69,17 +69,13 @@ const UnitConverter = { if (isDegree) { const dd = Math.floor(prpInput * 180 / Math.PI); const mm = Math.floor((degrees-dd) * 60); - const ss = Math.floor((degrees-dd-(mm/60)) * 3600); - const ssss = round(((degrees - dd - (mm/60) - (ss/3600)) * 36000000), 4); - const milliSeconds = String(ssss).padStart(4,0); - return (dd<10?`0${dd}`:`${dd}`) + ':' + (mm<10?`0${mm}`:`${mm}`) + ':' + (ss<10?`0${ss}`:`${ss}`) + '.' + milliSeconds; + const ss = round((degrees-dd-(mm/60)) * 3600,4); + return (dd<10?`0${dd}`:`${dd}`) + 'd' + (mm<10?`0${mm}`:`${mm}`) + 'm' + (ss<10?`0${ss}`:`${ss}`) + 's'; } else { const hh = Math.floor(degrees/15); const mm = Math.floor((degrees - (hh*15))/15 * 60 ); - const ss = Math.floor((degrees -(hh*15)-(mm*15/60))/15 * 3600); - const ssss = round(((degrees - (hh*15) - (mm/4) - (ss/240)) *2400000),4); - const milliSeconds = String(ssss).padStart(4,0); - return (hh<10?`0${hh}`:`${hh}`) + ':' + (mm<10?`0${mm}`:`${mm}`) + ':' + (ss<10?`0${ss}`:`${ss}`) + '.' + milliSeconds; + const ss = round((degrees -(hh*15)-(mm*15/60))/15 * 3600, 4); + return (hh<10?`0${hh}`:`${hh}`) + 'h' + (mm<10?`0${mm}`:`${mm}`) + 'm' + (ss<10?`0${ss}`:`${ss}`) + 's'; } } else { return "00:00:00"; @@ -103,6 +99,107 @@ const UnitConverter = { }else{ return "00:00:00.0000"; } + }, + /** + * Function to check the input type/format based on the matching predeifined regular expression. It can be any of the supported format + * like dms, hms, degrees, hours, radians. Example values are 10h10m10s, 10h10m10.1234s, 10:10:10 hour, 10:10:10.1234 hours, + * 10.1234 hours, 15d15m15s, 15d15m15.1515s, 15:15:15 degree, 15:15:15.1515 degrees, 15.1515 degrees. If only number is entered, it will + * be considered as radians. + * @param {String} input - value entered in the angle field. + * @returns String - the format of the input identified. If no format is identified, returns null. + */ + getAngleInputType(input) { + if (input.match(/^\-?((\d0?d(0?0m)(0?0(\.\d{1,4})?s))|(([0-8]?\d)d(([0-5]?\d)m)(([0-5]?\d)(\.\d{1,4})?s)))$/)) { + return 'dms'; + } else if (input.match(/^([0-1]?\d|2[0-3])h([0-5]?\d)m([0-5]?\d)(\.\d{1,4})?s$/)) { + return 'hms'; + } else if (input.match(/^-?((\d0(.0{1,4})?)|([0-8]?\d)(.\d{1,4})?) ?d(egree)?s?$/)) { + return 'degrees'; + } else if (input.match(/^([0-1]?\d|2[0-3])(.\d{1,4})? ?h(our)?s?$/)) { + return 'hours'; + } else if (input.match(/^\-?((\d0?:(00:)(00))|(([0-8]\d):(([0-5]\d):)(([0-5]\d)(\.\d{1,4})?))) ?d(egree)?s?$/)) { + return 'deg_format'; + } else if (input.match(/^([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d)(\.\d{1,4})? ?h(our)?s?$/)) { + return 'hour_format'; + } else if (input.match(/^[0-6](.\d+)?$/)) { + return 'radians'; + } else { + return null; + } + }, + /** + * Function to validate an angle input value based on the format entered and converrt to radians + * @param {String} angle - value to be parsed to radians. + * @returns number - radian value. + */ + parseAngle(angle) { + let radians = 0; + const angleType = this.getAngleInputType(angle); + switch(angleType) { + case 'dms' : { + radians = this.convertAngleToRadian(angle); + break; + } + case 'hms' : { + radians = this.convertAngleToRadian(angle); + break; + } + case 'degrees' : { + radians = this.convertToRadians(angle.replace('d','').replace('egree','').replace('s','').replace(' ','')); + break; + } + case 'hours' : { + radians = this.convertToRadians(angle.replace('h','').replace('our','').replace('s','').replace(' ','') * 15); + break; + } + case 'deg_format' : { + radians = this.getAngleOutput(angle.replace('d','').replace('egree','').replace('s','').replace(' ',''), true); + break; + } + case 'hour_format' : { + radians = this.getAngleOutput(angle.replace('h','').replace('our','').replace('s','').replace(' ',''), false); + break; + } + case 'radians': { + radians = parseFloat(angle); + break; + } + default: { + break; + } + } + return radians; + }, + /** + * Convert a degree value to radian + * @param {*} angle + * @returns + */ + convertToRadians(angle) { + return angle * Math.PI /180; + }, + /** + * Converts a formatted string to a radian value + * @param {String} angle + * @returns + */ + convertAngleToRadian(angle) { + let radian = 0; + const isDegree = angle.indexOf('d') > 0; + const degreeHourSplit = isDegree?angle.split("d"):angle.split("h"); + let degreeHour = degreeHourSplit[0]; + const isNegativeAngle = parseInt(degreeHour)<0; + degreeHour = isNegativeAngle?degreeHour*-1:degreeHour; + const minuteSplit = degreeHourSplit[1].split('m'); + const minute = minuteSplit[0]; + const second = minuteSplit[1].replace('s',''); + if (isDegree) { + radian = this.convertToRadians((degreeHour*1 + minute/60 + second/3600)); + radian = isNegativeAngle?radian*-1:radian; + } else { + radian = this.convertToRadians((degreeHour*15 + minute/4 + second/240)); + } + return radian; } }; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js b/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js index c3101bd69b6..876f4574c47 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js @@ -1,39 +1,25 @@ +import UnitConverter from "./unit.converter"; + const Validator = { validateTime(value) { - const splitOutput = value.split(':'); - const seconds = splitOutput[2]?splitOutput[2].split('.')[0]:splitOutput[2]; - let milliSeconds = value.split('.')[1] || '0000'; - milliSeconds = milliSeconds.padEnd(4,0); - if (splitOutput.length < 3) { - return false; - } else { - if (parseInt(splitOutput[0]) > 23 || parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59) { - return false; - } - const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(seconds) + milliSeconds/10000; - if (timeValue >= 86400) { + const angleType = UnitConverter.getAngleInputType(value); + if (angleType && ['hms', 'hours', 'hour_format', 'radians'].indexOf(angleType)>=0) { + if (angleType === 'radians' && parseFloat(value) > 6.2830) { return false; } + return true; } - return true; + return false; }, validateAngle(value) { - const splitOutput = value.split(':'); - const seconds = splitOutput[2]?splitOutput[2].split('.')[0]:splitOutput[2]; - let milliSeconds = value.split('.')[1] || '0000'; - milliSeconds = milliSeconds.padEnd(4,0); - if (splitOutput.length < 3) { - return false; - } else { - if (parseInt(splitOutput[0]) > 90 || parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59) { - return false; - } - const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(seconds) + milliSeconds/10000; - if (timeValue > 324000) { + const angleType = UnitConverter.getAngleInputType(value); + if (angleType && ['dms', 'degrees', 'deg_format', 'radians'].indexOf(angleType)>=0) { + if (angleType === 'radians' && parseFloat(value) > 1.5707) { return false; } + return true; } - return true; + return false; }, /** * Validates whether any of the given property values is modified comparing the old and new object. -- GitLab