Imagery compass rose enhancements (#6140)

* Fixes 6139
- Markup changes and improvements in CompassRose.vue.
- Improved sun and edge gradients.
- Related CSS styles updated.
- Changed compass key color from cyan to white to avoid conflict with staleness color.

* change var def to avoid collision

* compass rose should size itself based on image

* allow heading or camera pan for fixed cameras

* suppress HUD if no camera pan

* allow image to display compass rose for other cams

* update example imagery to accept transformations

* remove comments

Co-authored-by: David Tsay <david.e.tsay@nasa.gov>
Co-authored-by: David Tsay <3614296+davetsay@users.noreply.github.com>
This commit is contained in:
Charles Hacskaylo 2023-01-20 23:21:57 -08:00 committed by GitHub
parent 4d84b16d8b
commit 986c596d90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 152 additions and 64 deletions

View File

@ -242,6 +242,13 @@ function pointForTimestamp(timestamp, name, imageSamples, delay) {
const url = imageSamples[Math.floor(timestamp / delay) % imageSamples.length];
const urlItems = url.split('/');
const imageDownloadName = `example.imagery.${urlItems[urlItems.length - 1]}`;
const navCamTransformations = {
"translateX": 0,
"translateY": 18,
"rotation": 0,
"scale": 0.3,
"cameraAngleOfView": 70
};
return {
name,
@ -251,6 +258,7 @@ function pointForTimestamp(timestamp, name, imageSamples, delay) {
sunOrientation: getCompassValues(0, 360),
cameraPan: getCompassValues(0, 360),
heading: getCompassValues(0, 360),
transformations: navCamTransformations,
imageDownloadName
};
}

View File

@ -26,19 +26,18 @@
:style="`width: 100%; height: 100%`"
>
<CompassHUD
v-if="hasCameraFieldOfView"
v-if="showCompassHUD"
:sun-heading="sunHeading"
:camera-angle-of-view="cameraAngleOfView"
:camera-pan="cameraPan"
/>
<CompassRose
v-if="hasCameraFieldOfView"
:camera-angle-of-view="cameraAngleOfView"
v-if="showCompassRose"
:camera-pan="cameraPan"
:compass-rose-sizing-classes="compassRoseSizingClasses"
:heading="heading"
:sized-image-dimensions="sizedImageDimensions"
:sun-heading="sunHeading"
:transformations="transformations"
/>
</div>
</template>
@ -47,18 +46,12 @@
import CompassHUD from './CompassHUD.vue';
import CompassRose from './CompassRose.vue';
const CAMERA_ANGLE_OF_VIEW = 70;
export default {
components: {
CompassHUD,
CompassRose
},
props: {
compassRoseSizingClasses: {
type: String,
required: true
},
image: {
type: Object,
required: true
@ -69,13 +62,19 @@ export default {
}
},
computed: {
hasCameraFieldOfView() {
return this.cameraPan !== undefined && this.cameraAngleOfView > 0;
showCompassHUD() {
return this.hasCameraPan && this.cameraAngleOfView > 0;
},
showCompassRose() {
return (this.hasCameraPan || this.hasHeading) && this.cameraAngleOfView > 0;
},
// horizontal rotation from north in degrees
heading() {
return this.image.heading;
},
hasHeading() {
return this.heading !== undefined;
},
// horizontal rotation from north in degrees
sunHeading() {
return this.image.sunOrientation;
@ -84,8 +83,14 @@ export default {
cameraPan() {
return this.image.cameraPan;
},
hasCameraPan() {
return this.cameraPan !== undefined;
},
cameraAngleOfView() {
return CAMERA_ANGLE_OF_VIEW;
return this.transformations?.cameraAngleOfView;
},
transformations() {
return this.image.transformations;
}
},
methods: {

View File

@ -64,14 +64,14 @@
class="c-cr__edge"
width="100"
height="100"
fill="url(#paint0_radial)"
fill="url(#gradient_edge)"
/>
<rect
v-if="hasSunHeading"
class="c-cr__sun"
width="100"
height="100"
fill="url(#paint1_radial)"
fill="url(#gradient_sun)"
:style="sunHeadingStyle"
/>
@ -107,9 +107,26 @@
height="100"
/>
</mask>
<!-- Equipment (spacecraft) body holder. Transforms relative to the camera position. -->
<g
v-if="hasHeading"
class="cr-vrover"
:style="camAngleAndPositionStyle"
>
<!-- Equipment body. Rotates relative to the camera gimbal value for cams that gimbal. -->
<path
class="cr-vrover__body"
:style="camGimbalAngleStyle"
fill-rule="evenodd"
clip-rule="evenodd"
d="M5 0C2.23858 0 0 2.23858 0 5V95C0 97.7614 2.23858 100 5 100H95C97.7614 100 100 97.7614 100 95V5C100 2.23858 97.7614 0 95 0H5ZM85 59L50 24L15 59H33V75H67.0455V59H85Z"
/>
</g>
<g
class="c-cr__cam-fov"
:style="cameraPanStyle"
:style="cameraHeadingStyle"
>
<g mask="url(#mask2)">
<rect
@ -128,19 +145,13 @@
:style="cameraFOVStyleLeftHalf"
/>
</g>
<polygon
class="c-cr__cam"
points="0,0 100,0 70,40 70,100 30,100 30,40"
/>
</g>
</g>
<!-- Spacecraft body -->
<path
v-if="hasHeading"
class="c-cr__spacecraft-body"
fill-rule="evenodd"
clip-rule="evenodd"
d="M37 49C35.3431 49 34 50.3431 34 52V82C34 83.6569 35.3431 85 37 85H63C64.6569 85 66 83.6569 66 82V52C66 50.3431 64.6569 49 63 49H37ZM50 52L58 60H55V67H45V60H42L50 52Z"
:style="headingStyle"
/>
<!-- NSEW and ticks -->
<g
class="c-cr__nsew"
@ -193,7 +204,7 @@
</g>
<defs>
<radialGradient
id="paint0_radial"
id="gradient_edge"
cx="0"
cy="0"
r="1"
@ -201,7 +212,7 @@
gradientTransform="translate(50 50) rotate(90) scale(50)"
>
<stop
offset="0.751387"
offset="0.6"
stop-opacity="0"
/>
<stop
@ -210,7 +221,7 @@
/>
</radialGradient>
<radialGradient
id="paint1_radial"
id="gradient_sun"
cx="0"
cy="0"
r="1"
@ -218,12 +229,17 @@
gradientTransform="translate(50 -7) rotate(-90) scale(18.5)"
>
<stop
offset="0.716377"
offset="0.7"
stop-color="#FFCC00"
/>
<stop
offset="0.7"
stop-color="#FFCC00"
stop-opacity="0.6"
/>
<stop
offset="1"
stop-color="#FF9900"
stop-color="#FF6600"
stop-opacity="0"
/>
</radialGradient>
@ -238,10 +254,6 @@ import { throttle } from 'lodash';
export default {
props: {
compassRoseSizingClasses: {
type: String,
required: true
},
heading: {
type: Number,
required: true,
@ -253,16 +265,13 @@ export default {
type: Number,
default: undefined
},
cameraAngleOfView: {
cameraPan: {
type: Number,
default: undefined
},
cameraPan: {
type: Number,
required: true,
default() {
return 0;
}
transformations: {
type: Object,
default: undefined
},
sizedImageDimensions: {
type: Object,
@ -275,11 +284,38 @@ export default {
};
},
computed: {
cameraHeading() {
return this.cameraPan ?? this.heading;
},
cameraAngleOfView() {
const cameraAngleOfView = this.transformations?.cameraAngleOfView;
if (!cameraAngleOfView) {
console.warn('No Camera Angle of View provided');
}
return cameraAngleOfView;
},
camAngleAndPositionStyle() {
const translateX = this.transformations?.translateX;
const translateY = this.transformations?.translateY;
const rotation = this.transformations?.rotation;
const scale = this.transformations?.scale;
return { transform: `translate(${translateX}%, ${translateY}%) rotate(${rotation}deg) scale(${scale})` };
},
camGimbalAngleStyle() {
const rotation = rotate(this.north, this.heading);
return {
transform: `rotate(${ rotation }deg)`
};
},
compassRoseStyle() {
return { transform: `rotate(${ this.north }deg)` };
},
north() {
return this.lockCompass ? rotate(-this.cameraPan) : 0;
return this.lockCompass ? rotate(-this.cameraHeading) : 0;
},
cardinalTextRotateN() {
return { transform: `translateY(-27%) rotate(${ -this.north }deg)` };
@ -297,6 +333,7 @@ export default {
return this.heading !== undefined;
},
headingStyle() {
/* Replaced with computed camGimbalStyle, but left here just in case. */
const rotation = rotate(this.north, this.heading);
return {
@ -313,8 +350,8 @@ export default {
transform: `rotate(${ rotation }deg)`
};
},
cameraPanStyle() {
const rotation = rotate(this.north, this.cameraPan);
cameraHeadingStyle() {
const rotation = rotate(this.north, this.cameraHeading);
return {
transform: `rotate(${ rotation }deg)`
@ -333,6 +370,24 @@ export default {
return {
transform: `rotate(${ -this.cameraAngleOfView / 2 }deg)`
};
},
compassRoseSizingClasses() {
let compassRoseSizingClasses = '';
if (this.sizedImageWidth < 300) {
compassRoseSizingClasses = '--rose-small --rose-min';
} else if (this.sizedImageWidth < 500) {
compassRoseSizingClasses = '--rose-small';
} else if (this.sizedImageWidth > 1000) {
compassRoseSizingClasses = '--rose-max';
}
return compassRoseSizingClasses;
},
sizedImageWidth() {
return this.sizedImageDimensions.width;
},
sizedImageHeight() {
return this.sizedImageDimensions.height;
}
},
watch: {

View File

@ -1,5 +1,5 @@
/***************************** THEME/UI CONSTANTS AND MIXINS */
$interfaceKeyColor: #00B9C5;
$interfaceKeyColor: #fff;
$elemBg: rgba(black, 0.7);
@mixin sun($position: 'circle closest-side') {
@ -100,13 +100,19 @@ $elemBg: rgba(black, 0.7);
}
&__edge {
opacity: 0.1;
opacity: 0.2;
}
&__sun {
opacity: 0.7;
}
&__cam {
fill: $interfaceKeyColor;
transform-origin: center;
transform: scale(0.15);
}
&__cam-fov-l,
&__cam-fov-r {
// Cam FOV indication
@ -115,7 +121,6 @@ $elemBg: rgba(black, 0.7);
}
&__nsew-text,
&__spacecraft-body,
&__ticks-major,
&__ticks-minor {
fill: $color;
@ -166,3 +171,15 @@ $elemBg: rgba(black, 0.7);
padding-top: $s;
}
}
/************************** ROVER */
.cr-vrover {
$scale: 0.4;
transform-origin: center;
&__body {
fill: $interfaceKeyColor;
opacity: 0.3;
transform-origin: center 7% !important; // Places rotation center at mast position
}
}

View File

@ -93,7 +93,6 @@
></div>
<Compass
v-if="shouldDisplayCompass"
:compass-rose-sizing-classes="compassRoseSizingClasses"
:image="focusedImage"
:natural-aspect-ratio="focusedImageNaturalAspectRatio"
:sized-image-dimensions="sizedImageDimensions"
@ -298,18 +297,6 @@ export default {
};
},
computed: {
compassRoseSizingClasses() {
let compassRoseSizingClasses = '';
if (this.sizedImageWidth < 300) {
compassRoseSizingClasses = '--rose-small --rose-min';
} else if (this.sizedImageWidth < 500) {
compassRoseSizingClasses = '--rose-small';
} else if (this.sizedImageWidth > 1000) {
compassRoseSizingClasses = '--rose-max';
}
return compassRoseSizingClasses;
},
displayThumbnails() {
return (
this.forceShowThumbnails
@ -432,7 +419,6 @@ export default {
shouldDisplayCompass() {
const imageHeightAndWidth = this.sizedImageHeight !== 0
&& this.sizedImageWidth !== 0;
const display = this.focusedImage !== undefined
&& this.focusedImageNaturalAspectRatio !== undefined
&& this.imageContainerWidth !== undefined
@ -440,8 +426,9 @@ export default {
&& imageHeightAndWidth
&& this.zoomFactor === 1
&& this.imagePanned !== true;
const hasCameraConfigurations = this.focusedImage?.transformations !== undefined;
return display;
return display && hasCameraConfigurations;
},
isSpacecraftPositionFresh() {
let isFresh = undefined;
@ -626,6 +613,7 @@ export default {
this.spacecraftOrientationKeys = ['heading'];
this.cameraKeys = ['cameraPan', 'cameraTilt'];
this.sunKeys = ['sunOrientation'];
this.transformationsKeys = ['transformations'];
// related telemetry
await this.initializeRelatedTelemetry();
@ -728,7 +716,13 @@ export default {
this.relatedTelemetry = new RelatedTelemetry(
this.openmct,
this.domainObject,
[...this.spacecraftPositionKeys, ...this.spacecraftOrientationKeys, ...this.cameraKeys, ...this.sunKeys]
[
...this.spacecraftPositionKeys,
...this.spacecraftOrientationKeys,
...this.cameraKeys,
...this.sunKeys,
...this.transformationsKeys
]
);
if (this.relatedTelemetry.hasRelatedTelemetry) {
@ -837,6 +831,15 @@ export default {
this.$set(this.focusedImageRelatedTelemetry, key, value);
}
}
// set configuration for compass
this.transformationsKeys.forEach(key => {
const transformations = this.relatedTelemetry[key];
if (transformations !== undefined) {
this.$set(this.imageHistory[this.focusedImageIndex], key, transformations);
}
});
},
trackLatestRelatedTelemetry() {
[...this.spacecraftPositionKeys, ...this.spacecraftOrientationKeys, ...this.cameraKeys, ...this.sunKeys].forEach(key => {