diff --git a/protobuf b/protobuf index 33f25a9ca2..9b3fe04538 160000 --- a/protobuf +++ b/protobuf @@ -1 +1 @@ -Subproject commit 33f25a9ca2d4b0eb4ae4b6ba7b3bfa1c13f4b06b +Subproject commit 9b3fe04538b1dd8bc1378d604e04c5217d58a625 diff --git a/src/components/HelpDrawer/HelpContent/SpatialProfilerSettingsComputationHelpContent.tsx b/src/components/HelpDrawer/HelpContent/SpatialProfilerSettingsComputationHelpContent.tsx new file mode 100644 index 0000000000..3a8dcc3fe2 --- /dev/null +++ b/src/components/HelpDrawer/HelpContent/SpatialProfilerSettingsComputationHelpContent.tsx @@ -0,0 +1,5 @@ +export const SPATIAL_PROFILER_SETTINGS_COMPUTATION_HELP_CONTENT = ( +
+

Computation

+
+); diff --git a/src/components/HelpDrawer/HelpContent/index.ts b/src/components/HelpDrawer/HelpContent/index.ts index f7bd0d761d..7716bb4ce3 100644 --- a/src/components/HelpDrawer/HelpContent/index.ts +++ b/src/components/HelpDrawer/HelpContent/index.ts @@ -19,6 +19,7 @@ export * from "./RenderConfigSettingsHelpContent"; export * from "./SpatialProfilerHelpContent"; export * from "./SpatialProfilerSettingsStylingHelpContent"; export * from "./SpatialProfilerSettingsSmoothingHelpContent"; +export * from "./SpatialProfilerSettingsComputationHelpContent"; export * from "./SpectralProfilerHelpContent"; export * from "./SpectralProfilerSettingsConversionHelpContent"; export * from "./SpectralProfilerSettingsStylingHelpContent"; diff --git a/src/components/HelpDrawer/HelpDrawerComponent.tsx b/src/components/HelpDrawer/HelpDrawerComponent.tsx index 99f7310c4e..7371dbe32a 100644 --- a/src/components/HelpDrawer/HelpDrawerComponent.tsx +++ b/src/components/HelpDrawer/HelpDrawerComponent.tsx @@ -30,6 +30,7 @@ import { SPATIAL_PROFILER_HELP_CONTENT, SPATIAL_PROFILER_SETTINGS_SMOOTHING_HELP_CONTENT, SPATIAL_PROFILER_SETTINGS_STYLING_HELP_CONTENT, + SPATIAL_PROFILER_SETTINGS_COMPUTATION_HELP_CONTENT, SPECTRAL_LINE_QUERY_HELP_CONTENT, SPECTRAL_PROFILER_HELP_CONTENT, SPECTRAL_PROFILER_SETTINGS_CONVERSION_HELP_CONTENT, @@ -74,6 +75,7 @@ const HELP_CONTENT_MAP = new Map([ [HelpType.SPATIAL_PROFILER, SPATIAL_PROFILER_HELP_CONTENT], [HelpType.SPATIAL_PROFILER_SETTINGS_STYLING, SPATIAL_PROFILER_SETTINGS_STYLING_HELP_CONTENT], [HelpType.SPATIAL_PROFILER_SETTINGS_SMOOTHING, SPATIAL_PROFILER_SETTINGS_SMOOTHING_HELP_CONTENT], + [HelpType.SPATIAL_PROFILER_SETTINGS_COMPUTATION, SPATIAL_PROFILER_SETTINGS_COMPUTATION_HELP_CONTENT], [HelpType.SPECTRAL_PROFILER, SPECTRAL_PROFILER_HELP_CONTENT], [HelpType.SPECTRAL_PROFILER_SETTINGS_CONVERSION, SPECTRAL_PROFILER_SETTINGS_CONVERSION_HELP_CONTENT], [HelpType.SPECTRAL_PROFILER_SETTINGS_STYLING, SPECTRAL_PROFILER_SETTINGS_STYLING_HELP_CONTENT], diff --git a/src/components/Shared/RegionSelector/RegionSelectorComponent.tsx b/src/components/Shared/RegionSelector/RegionSelectorComponent.tsx index c22fdf58e8..21924623c7 100644 --- a/src/components/Shared/RegionSelector/RegionSelectorComponent.tsx +++ b/src/components/Shared/RegionSelector/RegionSelectorComponent.tsx @@ -8,7 +8,7 @@ import {RegionWidgetStore, RegionsType, RegionId, ACTIVE_FILE_ID} from "stores/w import "./RegionSelectorComponent.scss"; @observer -export class RegionSelectorComponent extends React.Component<{widgetStore: RegionWidgetStore; disableClosedRegion?: boolean; onFrameChanged?: (newFrame: FrameStore) => void}> { +export class RegionSelectorComponent extends React.Component<{widgetStore: RegionWidgetStore; onFrameChanged?: (newFrame: FrameStore) => void}> { private handleFrameChanged = (changeEvent: React.ChangeEvent) => { const appStore = AppStore.Instance; const widgetStore = this.props.widgetStore; @@ -62,13 +62,16 @@ export class RegionSelectorComponent extends React.Component<{widgetStore: Regio case RegionsType.CLOSED_AND_POINT: fiteredRegions = regions.filter(r => !r.isTemporary && (r.isClosedRegion || r.regionType === CARTA.RegionType.POINT)); break; + case RegionsType.POINT_AND_LINES: + fiteredRegions = regions.filter(r => !r.isTemporary && (r.regionType === CARTA.RegionType.POINT || r.regionType === CARTA.RegionType.LINE || r.regionType === CARTA.RegionType.POLYLINE)); + break; default: fiteredRegions = regions; } regionOptions = regionOptions.concat( fiteredRegions.map(r => { - return {value: r.regionId, label: r.nameString, disabled: this.props.disableClosedRegion ? r.isClosedRegion : false}; + return {value: r.regionId, label: r.nameString}; }) ); diff --git a/src/components/SpatialProfiler/SpatialProfilerComponent.tsx b/src/components/SpatialProfiler/SpatialProfilerComponent.tsx index 721eafb07e..fcc7014a58 100644 --- a/src/components/SpatialProfiler/SpatialProfilerComponent.tsx +++ b/src/components/SpatialProfiler/SpatialProfilerComponent.tsx @@ -85,17 +85,26 @@ export class SpatialProfilerComponent extends React.Component { } else { let xMin: number; let xMax: number; - - if (this.widgetStore.isAutoScaledX) { - xMin = this.autoScaleHorizontalMin; - xMax = this.autoScaleHorizontalMax; + if (this.lineAxis) { + if (this.widgetStore.isAutoScaledX) { + xMin = this.autoScaleHorizontalMin; + xMax = this.autoScaleHorizontalMax; + } else { + xMin = clamp(this.widgetStore.minX, this.lineAxis.min, this.lineAxis.max); + xMax = clamp(this.widgetStore.maxX, this.lineAxis.min, this.lineAxis.max); + } } else { - xMin = clamp(this.widgetStore.minX, 0, this.frame.frameInfo.fileInfoExtended.width); - xMax = clamp(this.widgetStore.maxX, 0, this.widgetStore.isXProfile ? this.frame.frameInfo.fileInfoExtended.width : this.frame.frameInfo.fileInfoExtended.height); + if (this.widgetStore.isAutoScaledX) { + xMin = this.autoScaleHorizontalMin; + xMax = this.autoScaleHorizontalMax; + } else { + xMin = clamp(this.widgetStore.minX, 0, this.frame.frameInfo.fileInfoExtended.width); + xMax = clamp(this.widgetStore.maxX, 0, this.widgetStore.isXProfile ? this.frame.frameInfo.fileInfoExtended.width : this.frame.frameInfo.fileInfoExtended.height); + } + xMin = Math.floor(xMin); + xMax = Math.floor(xMax); } - xMin = Math.floor(xMin); - xMax = Math.floor(xMax); let yMin = Number.MAX_VALUE; let yMax = -Number.MAX_VALUE; let yMean; @@ -110,7 +119,38 @@ export class SpatialProfilerComponent extends React.Component { let smoothingValues: Array<{x: number; y: number}>; let N: number; - if (coordinateData.mip > 1 || coordinateData.start > 0 || coordinateData.end < xMax) { + if (this.lineAxis) { + N = coordinateData.values.length; + values = new Array(N); + let xArray: number[] = new Array(N); + const numPixels = this.width; + const decimationFactor = Math.round(N / numPixels); + let startIndex: number; + let endIndex: number; + for (let i = 0; i < N; i++) { + const y = coordinateData.values[i]; + const x = this.widgetStore.effectiveRegion?.regionType === CARTA.RegionType.LINE ? (i - coordinateData.lineAxis.crpix) * coordinateData.lineAxis.cdelt : i * coordinateData.lineAxis.cdelt; + if (x >= xMin && x <= xMax && isFinite(y)) { + yMin = Math.min(yMin, y); + yMax = Math.max(yMax, y); + yCount++; + ySum += y; + ySum2 += y * y; + if (startIndex === undefined) { + startIndex = i; + } + endIndex = i; + } + xArray[i] = x; + if (decimationFactor <= 1) { + values[i] = {x, y}; + } + } + if (decimationFactor > 1) { + values = this.widgetStore.smoothingStore.getDecimatedPoint2DArray(xArray, coordinateData.values, decimationFactor, startIndex, endIndex); + } + smoothingValues = this.widgetStore.smoothingStore.getSmoothingPoint2DArray(xArray, coordinateData.values); + } else if (coordinateData.mip > 1 || coordinateData.start > 0 || coordinateData.end < xMax) { N = coordinateData.values.length; values = new Array(N); for (let i = 0; i < N; i++) { @@ -182,20 +222,31 @@ export class SpatialProfilerComponent extends React.Component { yMin -= range * VERTICAL_RANGE_PADDING; yMax += range * VERTICAL_RANGE_PADDING; } + return {values: values, smoothingValues, xMin, xMax, yMin, yMax, yMean, yRms}; } } @computed get exportHeader(): string[] { - const appStore = AppStore.Instance; const headerString: string[] = []; - headerString.push(`region (pixel): Point[${toFixed(appStore.activeFrame.cursorInfo.posImageSpace.x)}, ${toFixed(appStore.activeFrame.cursorInfo.posImageSpace.y)}]`); - if (appStore.activeFrame.cursorInfo.infoWCS) { - headerString.push(`region (world): Point[${appStore.activeFrame.cursorInfo.infoWCS.x}, ${appStore.activeFrame.cursorInfo.infoWCS.y}]`); + if (this.widgetStore.effectiveRegion) { + headerString.push(...this.widgetStore.effectiveFrame.getRegionProperties(this.widgetStore.effectiveRegionId)); } return headerString; } + // displaying offset/distance in the x axis for line and polyline regions + @computed get lineAxis(): {label: string; min: number; max: number; unit: string} { + const coordinateData = this.profileStore?.getProfile(this.widgetStore.fullCoordinate); + if (coordinateData?.lineAxis && this.widgetStore.isLineOrPolyline) { + const lineAxis = coordinateData.lineAxis; + const min = lineAxis.axisType === CARTA.ProfileAxisType.Offset ? (0 - lineAxis.crpix) * lineAxis.cdelt : 0; + const max = lineAxis.axisType === CARTA.ProfileAxisType.Offset ? (coordinateData.end - lineAxis.crpix) * lineAxis.cdelt : coordinateData.end * lineAxis.cdelt; + return {label: lineAxis.axisType === CARTA.ProfileAxisType.Offset ? "Offset" : "Distance", min, max, unit: lineAxis.unit}; + } + return null; + } + constructor(props: WidgetProps) { super(props); makeObservable(this); @@ -218,9 +269,9 @@ export class SpatialProfilerComponent extends React.Component { const coordinate = this.widgetStore.coordinate; const currentData = this.plotData; if (appStore && coordinate) { - const coordinateString = `${coordinate.toUpperCase()} Profile`; + const coordinateString = this.widgetStore.isLineOrPolyline ? "" : coordinate.toUpperCase(); const regionString = this.widgetStore.effectiveRegionId === RegionId.CURSOR ? "Cursor" : `Region #${this.widgetStore.effectiveRegionId}`; - appStore.widgetsStore.setWidgetTitle(this.props.id, `${coordinateString}: ${regionString}`); + appStore.widgetsStore.setWidgetTitle(this.props.id, `${coordinateString} Profile: ${regionString}`); } if (currentData) { this.widgetStore.initXYBoundaries(currentData.xMin, currentData.xMax, currentData.yMin, currentData.yMax); @@ -235,7 +286,9 @@ export class SpatialProfilerComponent extends React.Component { if (!this.frame || !this.width) { return null; } - if (this.widgetStore.isXProfile) { + if (this.lineAxis) { + this.setAutoScaleBounds(this.lineAxis.min, this.lineAxis.max); + } else if (this.widgetStore.isXProfile) { this.setAutoScaleBounds(clamp(this.frame.requiredFrameView.xMin, 0, this.frame.frameInfo.fileInfoExtended.width), clamp(this.frame.requiredFrameView.xMax, 0, this.frame.frameInfo.fileInfoExtended.width)); } else { this.setAutoScaleBounds(clamp(this.frame.requiredFrameView.yMin, 0, this.frame.frameInfo.fileInfoExtended.height), clamp(this.frame.requiredFrameView.yMax, 0, this.frame.frameInfo.fileInfoExtended.height)); @@ -350,10 +403,10 @@ export class SpatialProfilerComponent extends React.Component { if (nearest?.point) { const pixelPoint = isXCoordinate ? {x: nearest.point.x, y: this.profileStore.y} : {x: this.profileStore.x, y: nearest.point.x}; const cursorInfo = this.frame.getCursorInfo(pixelPoint); - const wcsLabel = cursorInfo?.infoWCS ? `WCS: ${isXCoordinate ? cursorInfo.infoWCS.x : cursorInfo.infoWCS.y}, ` : ""; - const imageLabel = `Image: ${nearest.point.x} px, `; + const wcsLabel = cursorInfo?.infoWCS && !this.lineAxis ? `WCS: ${isXCoordinate ? cursorInfo.infoWCS.x : cursorInfo.infoWCS.y}, ` : ""; + const xLabel = this.lineAxis ? `${this.lineAxis.label}: ${formattedExponential(nearest.point.x, 5)} ${this.lineAxis.unit ?? ""}, ` : `Image: ${nearest.point.x} px, `; const valueLabel = `${nearest.point.y !== undefined ? formattedExponential(nearest.point.y, 5) : ""}`; - profilerInfo.push("Cursor: (" + wcsLabel + imageLabel + valueLabel + ")"); + profilerInfo.push("Cursor: (" + wcsLabel + xLabel + valueLabel + ")"); } } else if (this.widgetStore.effectiveRegion?.regionType === CARTA.RegionType.POINT) { // get value directly from point region @@ -384,10 +437,11 @@ export class SpatialProfilerComponent extends React.Component { } const isXProfile = widgetStore.isXProfile; + const xLabel = this.lineAxis ? `${this.lineAxis.label} (${this.lineAxis.unit ?? ""})` : `${isXProfile ? "X" : "Y"} coordinate`; const imageName = appStore.activeFrame ? appStore.activeFrame.filename : undefined; - const plotName = `${isXProfile ? "X" : "Y"} profile`; + const plotName = `${this.lineAxis ? "" : isXProfile ? "X " : "Y "}profile`; let linePlotProps: LinePlotComponentProps = { - xLabel: `${isXProfile ? "X" : "Y"} coordinate`, + xLabel: xLabel, yLabel: "Value", darkMode: appStore.darkTheme, imageName: imageName, @@ -422,11 +476,13 @@ export class SpatialProfilerComponent extends React.Component { linePlotProps.yLabel = `Value (${unit})`; } - if (this.frame.validWcs && widgetStore.wcsAxisVisible) { - linePlotProps.showTopAxis = true; - linePlotProps.topAxisTickFormatter = this.formatProfileAst; - } else { - linePlotProps.showTopAxis = false; + if (!this.widgetStore.isLineOrPolyline) { + if (this.frame.validWcs && widgetStore.wcsAxisVisible) { + linePlotProps.showTopAxis = true; + linePlotProps.topAxisTickFormatter = this.formatProfileAst; + } else { + linePlotProps.showTopAxis = false; + } } const currentPlotData = this.plotData; @@ -489,7 +545,8 @@ export class SpatialProfilerComponent extends React.Component { value: cursorX.image, id: "marker-image-cursor", draggable: false, - horizontal: false + horizontal: false, + opacity: this.widgetStore.isLineOrPolyline ? 0.1 : 1 } ]; linePlotProps.markers.push({ @@ -534,7 +591,7 @@ export class SpatialProfilerComponent extends React.Component {
- + {widgetStore.effectiveFrame?.hasStokes && ( widgetStore.setSelectedStokes(ev.currentTarget.value)} /> diff --git a/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.scss b/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.scss index 64681558d0..d4cb25ef00 100644 --- a/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.scss +++ b/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.scss @@ -5,6 +5,9 @@ &:first-of-type { margin-left: 0px; } + .bp3-input { + width: 88px; + } } .bp3-form-group .bp3-label { diff --git a/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.tsx b/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.tsx index a34263a6bf..c96340edee 100644 --- a/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.tsx +++ b/src/components/SpatialProfiler/SpatialProfilerSettingsPanelComponent/SpatialProfilerSettingsPanelComponent.tsx @@ -1,8 +1,8 @@ import * as React from "react"; import {computed, autorun} from "mobx"; import {observer} from "mobx-react"; -import {Tabs, Tab} from "@blueprintjs/core"; -import {LinePlotSettingsPanelComponentProps, LinePlotSettingsPanelComponent, SmoothingSettingsComponent} from "components/Shared"; +import {Tabs, Tab, FormGroup} from "@blueprintjs/core"; +import {LinePlotSettingsPanelComponentProps, LinePlotSettingsPanelComponent, SmoothingSettingsComponent, SafeNumericInput} from "components/Shared"; import {RegionId, SpatialProfileWidgetStore} from "stores/widgets"; import {WidgetProps, DefaultWidgetConfig, HelpType, WidgetsStore, AppStore} from "stores"; import {parseNumber} from "utilities"; @@ -13,7 +13,8 @@ const KEYCODE_ENTER = 13; export enum SpatialProfilerSettingsTabs { STYLING, - SMOOTHING + SMOOTHING, + COMPUTATION } @observer @@ -30,7 +31,7 @@ export class SpatialProfilerSettingsPanelComponent extends React.Component } /> } /> + + this.widgetStore.setLineRegionSampleWidth(value)} /> + + } + />
); diff --git a/src/stores/Frame/FrameStore.ts b/src/stores/Frame/FrameStore.ts index 487ce93697..ed2ae06b2d 100644 --- a/src/stores/Frame/FrameStore.ts +++ b/src/stores/Frame/FrameStore.ts @@ -1589,6 +1589,10 @@ export class FrameStore { switch (region.regionType) { case CARTA.RegionType.POINT: return `Point (wcs:${systemType}) [${center}]`; + case CARTA.RegionType.LINE: + const wcsStartPoint = getFormattedWCSPoint(this.wcsInfoForTransformation, region.controlPoints[0]); + const wcsEndPoint = getFormattedWCSPoint(this.wcsInfoForTransformation, region.controlPoints[1]); + return `Line (wcs:${systemType}) [[${wcsStartPoint.x}, ${wcsStartPoint.y}], [${wcsEndPoint.x}, ${wcsEndPoint.y}]]`; case CARTA.RegionType.RECTANGLE: return `rotbox(wcs:${systemType})[[${center}], [${size.x ?? ""}, ${size.y ?? ""}], ${toFixed(region.rotation, 6)}deg]`; case CARTA.RegionType.ELLIPSE: @@ -1601,6 +1605,14 @@ export class FrameStore { polygonWcsProperties += index !== region.controlPoints.length - 1 ? ", " : "]"; }); return polygonWcsProperties; + case CARTA.RegionType.POLYLINE: + let polylineWcsProperties = `Polyline (wcs:${systemType})[`; + region.controlPoints.forEach((point, index) => { + const wcsPoint = isFinite(point.x) && isFinite(point.y) ? getFormattedWCSPoint(this.wcsInfoForTransformation, point) : null; + polylineWcsProperties += wcsPoint ? `[${wcsPoint.x}, ${wcsPoint.y}]` : "[Invalid]"; + polylineWcsProperties += index !== region.controlPoints.length - 1 ? ", " : "]"; + }); + return polylineWcsProperties; default: return "Not Implemented"; } diff --git a/src/stores/Frame/RegionStore.ts b/src/stores/Frame/RegionStore.ts index 075e4f3d60..9f40e286dc 100644 --- a/src/stores/Frame/RegionStore.ts +++ b/src/stores/Frame/RegionStore.ts @@ -239,6 +239,13 @@ export class RegionStore { switch (this.regionType) { case CARTA.RegionType.POINT: return `Point (pixel) [${center}]`; + case CARTA.RegionType.LINE: + let lineProperties = "Line (pixel) ["; + this.controlPoints.forEach((point, index) => { + lineProperties += isFinite(point.x) && isFinite(point.y) ? `[${toFixed(point.x, 6)}pix, ${toFixed(point.y, 6)}pix]` : "[Invalid]"; + lineProperties += index !== this.controlPoints.length - 1 ? ", " : "]"; + }); + return lineProperties; case CARTA.RegionType.RECTANGLE: return `rotbox[[${center}], [${toFixed(this.size.x, 6)}pix, ${toFixed(this.size.y, 6)}pix], ${toFixed(this.rotation, 6)}deg]`; case CARTA.RegionType.ELLIPSE: @@ -250,6 +257,13 @@ export class RegionStore { polygonProperties += index !== this.controlPoints.length - 1 ? ", " : "]"; }); return polygonProperties; + case CARTA.RegionType.POLYLINE: + let polylineProperties = "Polyline (pixel) ["; + this.controlPoints.forEach((point, index) => { + polylineProperties += isFinite(point.x) && isFinite(point.y) ? `[${toFixed(point.x, 6)}pix, ${toFixed(point.y, 6)}pix]` : "[Invalid]"; + polylineProperties += index !== this.controlPoints.length - 1 ? ", " : "]"; + }); + return polylineProperties; default: return "Not Implemented"; } diff --git a/src/stores/HelpStore.ts b/src/stores/HelpStore.ts index c6739b27cb..e31966ff74 100644 --- a/src/stores/HelpStore.ts +++ b/src/stores/HelpStore.ts @@ -29,6 +29,7 @@ export enum HelpType { SPATIAL_PROFILER = "Spatial Profiler", SPATIAL_PROFILER_SETTINGS_STYLING = "Spatial Profiler Style Settings", SPATIAL_PROFILER_SETTINGS_SMOOTHING = "Spatial Profiler Smoothing Settings", + SPATIAL_PROFILER_SETTINGS_COMPUTATION = "Spatial Profiler Computation Settings", SPECTRAL_PROFILER = "Spectral Profiler", SPECTRAL_PROFILER_SETTINGS_CONVERSION = "Spectral Profiler Conversion Settings", SPECTRAL_PROFILER_SETTINGS_STYLING = "Spectral Profiler Style Settings", diff --git a/src/stores/widgets/RegionWidgetStore.ts b/src/stores/widgets/RegionWidgetStore.ts index 24b5dcf6bd..b58f013c9d 100644 --- a/src/stores/widgets/RegionWidgetStore.ts +++ b/src/stores/widgets/RegionWidgetStore.ts @@ -15,6 +15,7 @@ export enum RegionId { export enum RegionsType { CLOSED, CLOSED_AND_POINT, + POINT_AND_LINES, LINE } @@ -71,6 +72,7 @@ export class RegionWidgetStore { case RegionsType.CLOSED: return selectedRegion.isClosedRegion ? selectedRegion.regionId : this.defaultRegionId(); case RegionsType.CLOSED_AND_POINT: + case RegionsType.POINT_AND_LINES: return selectedRegion.regionId; case RegionsType.LINE: default: @@ -88,6 +90,7 @@ export class RegionWidgetStore { case RegionsType.CLOSED: return RegionId.IMAGE; case RegionsType.CLOSED_AND_POINT: + case RegionsType.POINT_AND_LINES: return RegionId.CURSOR; case RegionsType.LINE: default: diff --git a/src/stores/widgets/SpatialProfileWidgetStore.ts b/src/stores/widgets/SpatialProfileWidgetStore.ts index a20c2c33dc..d551436ef8 100644 --- a/src/stores/widgets/SpatialProfileWidgetStore.ts +++ b/src/stores/widgets/SpatialProfileWidgetStore.ts @@ -4,7 +4,7 @@ import * as _ from "lodash"; import {RegionWidgetStore, RegionId, RegionsType} from "./RegionWidgetStore"; import {CARTA} from "carta-protobuf"; import {AppStore, ProfileSmoothingStore} from "stores"; -import {FrameStore} from "stores/Frame"; +import {FrameStore, RegionStore} from "stores/Frame"; import {PlotType, LineSettings} from "components/Shared"; import {SpatialProfilerSettingsTabs} from "components"; import {clamp, isAutoColor} from "utilities"; @@ -33,6 +33,7 @@ export class SpatialProfileWidgetStore extends RegionWidgetStore { @observable linePlotInitXYBoundaries: {minXVal: number; maxXVal: number; minYVal: number; maxYVal: number}; readonly smoothingStore: ProfileSmoothingStore; @observable settingsTabId: SpatialProfilerSettingsTabs; + @observable lineRegionSampleWidth: number; @override setRegionId = (fileId: number, regionId: number) => { this.regionIdMap.set(fileId, regionId); @@ -109,10 +110,15 @@ export class SpatialProfileWidgetStore extends RegionWidgetStore { this.settingsTabId = val; }; + @action setLineRegionSampleWidth = (val: number) => { + this.lineRegionSampleWidth = val; + }; + constructor(coordinate: string = "x") { - super(RegionsType.CLOSED_AND_POINT); + super(RegionsType.POINT_AND_LINES); makeObservable(this); // Describes which data is being visualised + this.lineRegionSampleWidth = 3; this.coordinate = coordinate; this.selectedStokes = DEFAULT_STOKES; @@ -162,7 +168,11 @@ export class SpatialProfileWidgetStore extends RegionWidgetStore { if (frame?.hasStokes) { stokes = this.selectedStokes === DEFAULT_STOKES ? frame.requiredPolarizationInfo : this.selectedStokes; } - return `${stokes?.replace("Stokes ", "") ?? ""}${this.coordinate}`; + return `${stokes?.replace("Stokes ", "") ?? ""}${this.isLineOrPolyline ? "" : this.coordinate}`; + } + + @computed get isLineOrPolyline(): boolean { + return this.effectiveRegion?.regionType === CARTA.RegionType.LINE || this.effectiveRegion?.regionType === CARTA.RegionType.POLYLINE; } @computed get effectivePolarization(): POLARIZATIONS { @@ -173,8 +183,8 @@ export class SpatialProfileWidgetStore extends RegionWidgetStore { } } - private static GetSpatialConfig(frame: FrameStore, coordinate: string, isCursor: boolean): CARTA.SetSpatialRequirements.ISpatialConfig { - if (frame.cursorMoving && !AppStore.Instance.cursorFrozen && isCursor) { + private static GetSpatialConfig(frame: FrameStore, coordinate: string, region: RegionStore, lineRegionSampleWidth: number): CARTA.SetSpatialRequirements.ISpatialConfig { + if (frame.cursorMoving && !AppStore.Instance.cursorFrozen && region?.regionId === RegionId.CURSOR) { if (coordinate.includes("x")) { return { coordinate, @@ -193,7 +203,8 @@ export class SpatialProfileWidgetStore extends RegionWidgetStore { } else { return { coordinate, - mip: 1 + mip: 1, + width: region?.regionType === CARTA.RegionType.LINE || region?.regionType === CARTA.RegionType.POLYLINE ? lineRegionSampleWidth : undefined }; } } @@ -231,7 +242,7 @@ export class SpatialProfileWidgetStore extends RegionWidgetStore { if (existingConfig) { // TODO: Merge existing configs, rather than only allowing a single one } else { - regionRequirements.spatialProfiles.push(SpatialProfileWidgetStore.GetSpatialConfig(frame, widgetStore.fullCoordinate, regionId === RegionId.CURSOR)); + regionRequirements.spatialProfiles.push(SpatialProfileWidgetStore.GetSpatialConfig(frame, widgetStore.fullCoordinate, region, widgetStore.lineRegionSampleWidth)); } } }); diff --git a/src/utilities/Processed.ts b/src/utilities/Processed.ts index e73ac82f0a..8000d69e4f 100644 --- a/src/utilities/Processed.ts +++ b/src/utilities/Processed.ts @@ -41,7 +41,8 @@ export class ProtobufProcessing { start: profile.start, end: profile.end, mip: profile.mip, - values: new Float32Array(profile.rawValuesFp32.slice().buffer) + values: new Float32Array(profile.rawValuesFp32.slice().buffer), + lineAxis: profile.lineAxis }; } @@ -50,7 +51,8 @@ export class ProtobufProcessing { start: profile.start, end: profile.end, mip: profile.mip, - values: null + values: null, + lineAxis: profile.lineAxis }; }