diff --git a/src/app/component/settings-panel/settings-panel.component.html b/src/app/component/settings-panel/settings-panel.component.html index 3978b0a..90bb3c2 100644 --- a/src/app/component/settings-panel/settings-panel.component.html +++ b/src/app/component/settings-panel/settings-panel.component.html @@ -38,7 +38,7 @@ type='number' [formGroup]='this.settingsForm' _formControl='speed' - tooltip='The speed that the animation will run at. (rpm - I think)' + tooltip='The speed that the animation will run at rpm' >Input Speed diff --git a/src/app/component/settings-panel/settings-panel.component.ts b/src/app/component/settings-panel/settings-panel.component.ts index 7a51839..dae820a 100644 --- a/src/app/component/settings-panel/settings-panel.component.ts +++ b/src/app/component/settings-panel/settings-panel.component.ts @@ -1,13 +1,11 @@ import { Component } from '@angular/core'; import { SettingsService } from 'src/app/services/settings.service'; -import { LengthUnit, AngleUnit, ForceUnit, GlobalUnit } from 'src/app/model/utils'; +import { AngAccUnit, AngleUnit, AngVelUnit, ForceUnit, GlobalUnit, LengthUnit } from 'src/app/model/utils'; import { FormBuilder, Validators } from '@angular/forms'; import { NewGridComponent } from '../new-grid/new-grid.component'; import { MechanismService } from '../../services/mechanism.service'; import { Link, RealLink } from '../../model/link'; import { SvgGridService } from '../../services/svg-grid.service'; -import { AnimationBarComponent } from '../animation-bar/animation-bar.component'; -import { ToolbarComponent } from '../toolbar/toolbar.component'; import { NumberUnitParserService } from '../../services/number-unit-parser.service'; import { Coord } from '../../model/coord'; import { MatDialog } from '@angular/material/dialog'; @@ -35,6 +33,8 @@ export class SettingsPanelComponent { currentAngleUnit!: AngleUnit; // currentTorqueUnit!: TorqueUnit; currentGlobalUnit!: GlobalUnit; + currentAngVelUnit!: AngVelUnit; + currentAngAccUnit!: AngAccUnit; rotateDirection!: boolean; currentSpeedSetting!: number; currentObjectScaleSetting!: number; @@ -43,6 +43,8 @@ export class SettingsPanelComponent { this.currentLengthUnit = this.settingsService.lengthUnit.value; this.currentAngleUnit = this.settingsService.angleUnit.value; this.currentGlobalUnit = this.settingsService.globalUnit.value; + this.currentAngVelUnit = this.settingsService.angVelUnit.value; + this.currentAngAccUnit = this.settingsService.angAccUnit.value; this.rotateDirection = this.settingsService.isInputCW.value; this.currentSpeedSetting = this.settingsService.inputSpeed.value; this.currentObjectScaleSetting = SettingsService.objectScale; @@ -65,7 +67,10 @@ export class SettingsPanelComponent { this.currentObjectScaleSetting = val; this.settingsForm.patchValue( { objectScale: this.currentObjectScaleSetting.toString() }, - { emitEvent: false } + { emitEvent: false }, + ); + this.settingsForm.patchValue( + { speed: this.nup.formatValueAndUnit(this.currentSpeedSetting, this.settingsService.angVelUnit.getValue()) } ); //Werid place to put this but @@ -79,6 +84,22 @@ export class SettingsPanelComponent { this.onChanges(); } + numRegex = '^-?[0-9]+(.[0-9]{0,10})?$'; + settingsForm = this.fb.group( + { + speed: ['', [Validators.required]], + objectScale: ['', [Validators.required, Validators.pattern(this.numRegex)]], + rotation: ['', { updateOn: 'change' }], + lengthunit: ['', { updateOn: 'change' }], + angleunit: ['', { updateOn: 'change' }], + torqueunit: ['', { updateOn: 'change' }], + globalunit: ['', { updateOn: 'change' }], + showMinorGrid: [true, { updateOn: 'change' }], + showMajorGrid: [true, { updateOn: 'change' }], + }, + { updateOn: 'blur' } + ); + onChanges(): void { this.settingsForm.controls['rotation'].valueChanges.subscribe((val) => { this.rotateDirection = String(val) === '0'; @@ -86,13 +107,28 @@ export class SettingsPanelComponent { this.mechanismSrv.updateMechanism(); }); this.settingsForm.controls['speed'].valueChanges.subscribe((val) => { - if (this.settingsForm.controls['speed'].invalid) { - this.settingsForm.patchValue({ speed: this.currentSpeedSetting.toString() }); - } else { - this.currentSpeedSetting = Number(val); - this.settingsService.inputSpeed.next(this.currentSpeedSetting); + if (val?.includes('-')) { + this.sendNotification("Input Speed is a magnitude. Change cw or ccw from Input Direction"); } + const [success, value] = this.nup.parseAngVelString( + val!, + this.settingsService.angVelUnit.getValue() + ); + if (!success) { + this.settingsForm.patchValue( + { speed: this.nup.formatValueAndUnit(this.currentSpeedSetting, this.settingsService.angVelUnit.getValue()) }, + { emitEvent: false }, + ); + } else { + this.currentSpeedSetting = value; + this.settingsService.inputSpeed.next(value); + this.settingsForm.patchValue( + {speed: this.nup.formatValueAndUnit(value, this.settingsService.angVelUnit.getValue())}, + { emitEvent: false }, + ); + } this.mechanismSrv.updateMechanism(); + this.mechanismSrv.onMechUpdateState.next(2); }); this.settingsForm.controls['objectScale'].valueChanges.subscribe((val) => { if (this.settingsForm.controls['objectScale'].invalid) { @@ -106,7 +142,19 @@ export class SettingsPanelComponent { this.settingsForm.controls['angleunit'].valueChanges.subscribe((val) => { this.currentAngleUnit = ParseAngleUnit(String(val)); this.settingsService.angleUnit.next(this.currentAngleUnit); + if (this.settingsService.angVelUnit.value === AngVelUnit.DPS) { + this.currentAngleUnit = AngleUnit.DEGREE; + this.currentAngVelUnit = AngVelUnit.DPS; + this.currentAngAccUnit = AngAccUnit.DPS_square; + } else { + this.currentAngleUnit = AngleUnit.RADIAN; + this.currentAngVelUnit = AngVelUnit.RPS; + this.currentAngAccUnit = AngAccUnit.RPS_square; + } + this.mechanismSrv.updateMechanism(); + + this.mechanismSrv.onMechUpdateState.next(2); }); this.settingsForm.controls['globalunit'].valueChanges.subscribe((val) => { this.currentGlobalUnit = ParseGlobalUnit(val); @@ -213,26 +261,14 @@ export class SettingsPanelComponent { } } - numRegex = '^-?[0-9]+(.[0-9]{0,10})?$'; - settingsForm = this.fb.group( - { - speed: ['', [Validators.required, Validators.pattern(this.numRegex)]], - objectScale: ['', [Validators.required, Validators.pattern(this.numRegex)]], - rotation: ['', { updateOn: 'change' }], - lengthunit: ['', { updateOn: 'change' }], - angleunit: ['', { updateOn: 'change' }], - torqueunit: ['', { updateOn: 'change' }], - globalunit: ['', { updateOn: 'change' }], - showMinorGrid: [true, { updateOn: 'change' }], - showMajorGrid: [true, { updateOn: 'change' }], - }, - { updateOn: 'blur' } - ); - sendComingSoon(): void { NewGridComponent.sendNotification('This feature is coming soon!'); } + sendNotification(message: string): void { + NewGridComponent.sendNotification(message); + } + updateObjectScale() { this.svgGrid.updateObjectScale(); } diff --git a/src/app/model/utils.ts b/src/app/model/utils.ts index ee5567d..1001cc3 100644 --- a/src/app/model/utils.ts +++ b/src/app/model/utils.ts @@ -21,6 +21,17 @@ export enum AngleUnit { NULL = 12, } +export enum AngVelUnit { + RPM = 15, // revolutions per minute + DPS = 16, // degrees per second + RPS = 17, // Radians per second +} + +export enum AngAccUnit { + RPS_square = 18, // rad per second square (rad/s^2) + DPS_square = 19, // degrees per second square (deg/s^2) +} + export enum ForceUnit { LBF = 20, NEWTON = 21, diff --git a/src/app/services/mechanism.service.ts b/src/app/services/mechanism.service.ts index 6ff0161..ea5cd4b 100644 --- a/src/app/services/mechanism.service.ts +++ b/src/app/services/mechanism.service.ts @@ -164,7 +164,7 @@ export class MechanismService { } updateLinkageUnits(fromUnits: LengthUnit, toUnits: LengthUnit) { - //Scale the linkage based on teh units + //Scale the linkage based on the units // For each joint, move the joint this.joints.forEach((joint) => { //If joint is of type Rev joint only, move the joint @@ -179,7 +179,7 @@ export class MechanismService { ); } }); - this.updateMechanism(); + // this.updateMechanism(); // this.settingsService.lengthUnit.subscribe((val) => { //For each jo // let unit = this.settingsService.lengthUnit.value; diff --git a/src/app/services/number-unit-parser.service.ts b/src/app/services/number-unit-parser.service.ts index fd91c66..735bf94 100644 --- a/src/app/services/number-unit-parser.service.ts +++ b/src/app/services/number-unit-parser.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { LengthUnit, AngleUnit, ForceUnit } from '../model/utils'; +import { AngleUnit, AngVelUnit, ForceUnit, LengthUnit } from '../model/utils'; @Injectable({ providedIn: 'root', @@ -7,7 +7,7 @@ import { LengthUnit, AngleUnit, ForceUnit } from '../model/utils'; export class NumberUnitParserService { constructor() {} - public formatValueAndUnit(value: number, units: LengthUnit | AngleUnit | ForceUnit): string { + public formatValueAndUnit(value: number, units: LengthUnit | AngleUnit | ForceUnit | AngVelUnit): string { switch (units) { case LengthUnit.CM: return value.toFixed(2) + ' cm'; @@ -23,6 +23,12 @@ export class NumberUnitParserService { return value.toFixed(2) + ' lbf'; case ForceUnit.NEWTON: return value.toFixed(2) + ' N'; + case AngVelUnit.RPM: + return value.toFixed(2) + ' rpm'; + case AngVelUnit.RPS: + return value.toFixed(2) + ' rev/s'; + case AngVelUnit.DPS: + return value.toFixed(2) + ' deg/s'; } return 'Error in formatValueAndUnit()'; } @@ -109,6 +115,36 @@ export class NumberUnitParserService { } } + public parseAngVelString(input: string, desiredUnits: AngVelUnit): [boolean, number] { + let [value, unit] = this.preProcessInput(input); + + if (isNaN(value)) return [false, 0]; //If the value is not a number, return fail + if (unit.length == 0) return [true, value]; //No units means imply that we have the desired units + + let givenUnits: AngVelUnit; + + switch (unit) { + case 'rad/s': + case 'rps': + givenUnits = AngVelUnit.RPS; + break; + case 'rpm': + case 'rev/min': + givenUnits = AngVelUnit.RPM; + break; + case 'degree/second': + case 'degree/s': + case 'dps': + givenUnits = AngVelUnit.DPS; + break; + default: + return [false, value]; + } + if (givenUnits == desiredUnits) return [true, value]; + value = this.convertAngVel(value, givenUnits, desiredUnits); + return [true, value]; + } + public parseLengthString(input: string, desiredUnits: LengthUnit): [boolean, number] { let [value, unit] = this.preProcessInput(input); @@ -231,6 +267,43 @@ export class NumberUnitParserService { return value; } + private convertAngVel(value: number, givenUnits: AngVelUnit, desiredUnits: AngVelUnit) { + if (givenUnits == desiredUnits) return value; + switch (givenUnits) { + case AngVelUnit.DPS: + switch (desiredUnits) { + case AngVelUnit.RPM: + return (value / 360) * 60; + case AngVelUnit.RPS: + return value * (Math.PI / 180); + } + break; + case AngVelUnit.RPM: + switch (desiredUnits) { + case AngVelUnit.DPS: + return (value * 360) / 60; + case AngVelUnit.RPS: + return value * (2 * Math.PI) / 60; + } + break; + case AngVelUnit.RPS: + switch (desiredUnits) { + case AngVelUnit.RPM: + return value * (60 / ( 2 * Math.PI)); + case AngVelUnit.DPS: + return value * (180 / Math.PI); + } + break; + } + console.error( + 'Error in NumberUnitParserService.convertAngVel(): No valid conversion found between ' + + AngVelUnit[givenUnits] + + ' and ' + + AngVelUnit[desiredUnits] + ); + return value; + } + private convertForce(value: number, givenUnits: ForceUnit, desiredUnits: ForceUnit): number { if (givenUnits == desiredUnits) return value; switch (givenUnits) { diff --git a/src/app/services/settings.service.ts b/src/app/services/settings.service.ts index a2a243c..bfdac6f 100644 --- a/src/app/services/settings.service.ts +++ b/src/app/services/settings.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; -import { LengthUnit, AngleUnit, GlobalUnit, ForceUnit } from '../model/utils'; +import { LengthUnit, AngleUnit, GlobalUnit, ForceUnit, AngVelUnit, AngAccUnit } from '../model/utils'; @Injectable({ providedIn: 'root', @@ -9,6 +9,8 @@ export class SettingsService { lengthUnit = new BehaviorSubject(LengthUnit.CM); angleUnit = new BehaviorSubject(AngleUnit.DEGREE); forceUnit = new BehaviorSubject(ForceUnit.NEWTON); + angVelUnit = new BehaviorSubject(AngVelUnit.RPM); + angAccUnit = new BehaviorSubject(AngAccUnit.RPS_square); // inputTorque = new BehaviorSubject(TorqueUnit.CM_N); globalUnit = new BehaviorSubject(GlobalUnit.METRIC); isInputCW = new BehaviorSubject(true);