-
+
+
文件列表
+
+
+
+
+

+ {{ node.label }}
+
+
+

+ {{ node.label }}
+
+
+
+
+
-
+
+
-
+
+.fileitem1 {
+ width: 100%;
+ height: 20px;
+ display: flex;
+ align-items: center;
+
+ &>img {
+ width: 18px;
+ height: 18px;
+ margin-right: 5px;
+ }
+}
+
+.fileitem2 {
+ width: 100%;
+ height: 18px;
+ display: flex;
+ align-items: center;
+
+ &>img {
+ margin-right: 5px;
+
+ width: 13px;
+ height: 13px;
+ }
+}
+
+.fileitem:nth-child(2) {
+ width: 13px;
+ height: 13px;
+}
+
+.GuiLeftSider {
+ padding: 17px 24px;
+}
+
+.GuiLeftSider p {
+ font-size: 18px;
+ color: #434959;
+ text-align: left;
+ font-weight: 600;
+}
+
+.defaultList button {
+ width: 100%;
+ height: 40px;
+ border-radius: 4px;
+ border: 1.4px solid #4271EE;
+ box-shadow: none;
+ font-size: 16px;
+ color: #4271EE;
+}
+
\ No newline at end of file
diff --git a/src/DataView/vuecomponents/MapContainer.vue b/src/DataView/vuecomponents/MapContainer.vue
index 472b043..0902666 100644
--- a/src/DataView/vuecomponents/MapContainer.vue
+++ b/src/DataView/vuecomponents/MapContainer.vue
@@ -1,78 +1,236 @@
-
+
+
+
+
-
-
diff --git a/src/DataView/vuecomponents/PictureDisplayInterface.vue b/src/DataView/vuecomponents/PictureDisplayInterface.vue
new file mode 100644
index 0000000..f1128bc
--- /dev/null
+++ b/src/DataView/vuecomponents/PictureDisplayInterface.vue
@@ -0,0 +1,240 @@
+
+
+
+
+
+

+ {{ currentItem?.name || '暂无文件' }}
+
+
+ 地图
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/DataView/vuecomponents/SaveFileDialog.vue b/src/DataView/vuecomponents/SaveFileDialog.vue
new file mode 100644
index 0000000..462a273
--- /dev/null
+++ b/src/DataView/vuecomponents/SaveFileDialog.vue
@@ -0,0 +1,301 @@
+
+
+
+ 保存文件
+
+
+
+
+
选择要保存的文件
+
+ 全选
+
+
+
+
+
+
+ {{ file.label }}
+
+
+
+
+
+
+
+
+ 保存
+ 取消
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main.js b/src/main.js
index 086a3be..c0bf67c 100644
--- a/src/main.js
+++ b/src/main.js
@@ -2,54 +2,64 @@ import { createApp } from "vue";
import "./styles.css";
//import App from "./AppHyperSpectral.vue";
import App from "./App.vue";
-import { appWindow } from '@tauri-apps/api/window';
-import { LogicalSize } from '@tauri-apps/api/window';
-import ElementPlus from 'element-plus';
-import 'element-plus/dist/index.css'
-import {createBootstrap} from 'bootstrap-vue-next'
+import { appWindow } from "@tauri-apps/api/window";
+import { LogicalSize } from "@tauri-apps/api/window";
+import ElementPlus from "element-plus";
+import "element-plus/dist/index.css";
+import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
+import { createBootstrap } from "bootstrap-vue-next";
//
// // Add the necessary CSS
-import 'bootstrap/dist/css/bootstrap.css'
-import 'bootstrap-vue-next/dist/bootstrap-vue-next.css'
-import ArcoVue from '@arco-design/web-vue';
+import "bootstrap/dist/css/bootstrap.css";
+import "bootstrap-vue-next/dist/bootstrap-vue-next.css";
+import ArcoVue from "@arco-design/web-vue";
-import '@arco-design/web-vue/dist/arco.css';
-import { Draggable,DraggablePlugin, DraggableDirective } from '@braks/revue-draggable';
-import KonamiCode from 'vue3-konami-code';
+import "@arco-design/web-vue/dist/arco.css";
+import {
+ Draggable,
+ DraggablePlugin,
+ DraggableDirective,
+} from "@braks/revue-draggable";
+import KonamiCode from "vue3-konami-code";
import EventBus from "./eventBus.js";
+import tauriApi from "./utils/tauriApi.js";
async function setWindowSize() {
- // const primaryMonitor = await screen.primaryMonitor();
- // const screenSize = primaryMonitor.size;
+ // const primaryMonitor = await screen.primaryMonitor();
+ // const screenSize = primaryMonitor.size;
- const newSize = new LogicalSize(800, 600);
- await appWindow.setSize(newSize);
- // appWindow.setSize(new Size(1000, 1000));
+ const newSize = new LogicalSize(800, 600);
+ await appWindow.setSize(newSize);
+ // appWindow.setSize(new Size(1000, 1000));
}
var app = createApp(App);
-app.use(ElementPlus);
-app.use(createBootstrap( {components: true, directives: true,plugins:true,icons: true,}));
+app.use(ElementPlus, {
+ locale: zhCn,
+});
+app.use(
+ createBootstrap({
+ components: true,
+ directives: true,
+ plugins: true,
+ icons: true,
+ })
+);
app.use(ArcoVue);
app.use(DraggablePlugin);
app.use(KonamiCode, {
- onKonamiCodeEntered: () => {
- // 用户输入Konami Code后执行的代码
- console.log('Konami Code 已输入!');
- EventBus.emit('konamiactive');
- }
+ onKonamiCodeEntered: () => {
+ // 用户输入Konami Code后执行的代码
+ console.log("Konami Code 已输入!");
+ EventBus.emit("konamiactive");
+ },
});
// or
-app.directive('draggable', DraggableDirective)
-app.component('Draggable', Draggable);
-
-
-
+app.directive("draggable", DraggableDirective);
+app.component("Draggable", Draggable);
+// 注册全局 API
+app.config.globalProperties.$tauriApi = tauriApi;
// app.use(BootstrapVueIcons);
app.mount("#app");
-
-
-
-
diff --git a/src/utils/hyperspectralParser.js b/src/utils/hyperspectralParser.js
new file mode 100644
index 0000000..683b2dc
--- /dev/null
+++ b/src/utils/hyperspectralParser.js
@@ -0,0 +1,112 @@
+import { ref } from 'vue';
+
+export function useHyperspectralDataParser() {
+ const parsedData = ref(null);
+ const error = ref(null);
+
+ // 解析时间结构
+ const parseTimeStruct = (timeData) => {
+ if (!timeData) return null;
+ return {
+ timezone: timeData.time_zone || 0,
+ year: timeData.year || 0,
+ month: timeData.month || 0,
+ day: timeData.day || 0,
+ hour: timeData.hour || 0,
+ minute: timeData.minute || 0,
+ second: timeData.second || 0,
+ millisecond: timeData.millisecond || 0
+ };
+ };
+
+ // 解析设备元数据
+ const parseDeviceInfo = (metaData) => {
+ if (!metaData || metaData.info_type !== "devinfo") {
+ return null;
+ }
+ return {
+ infoType: metaData.info_type,
+ sensorId: metaData.sensor_id || '',
+ bandNum: metaData.bandnum || 0,
+ waveCoeff: {
+ a1: metaData.wave_coeff?.a1 || 0,
+ a2: metaData.wave_coeff?.a2 || 0,
+ a3: metaData.wave_coeff?.a3 || 0,
+ a4: metaData.wave_coeff?.a4 || 0
+ }
+ };
+ };
+
+ // 解析光谱数据
+ const parseSpectralData = (uint8Array, bands, dataType) => {
+ try {
+ switch (dataType) {
+ case 0x20: // float32
+ return new Float32Array(uint8Array.buffer, 0, bands);
+ case 0x21: // float64
+ return new Float64Array(uint8Array.buffer, 0, bands);
+ case 0x10: // uint8
+ return new Uint8Array(uint8Array.buffer, 0, bands);
+ case 0x11: // int16
+ return new Int16Array(uint8Array.buffer, 0, bands);
+ case 0x12: // uint16
+ return new Uint16Array(uint8Array.buffer, 0, bands);
+ case 0x13: // int32
+ return new Int32Array(uint8Array.buffer, 0, bands);
+ case 0x14: // uint32
+ return new Uint32Array(uint8Array.buffer, 0, bands);
+ default:
+ throw new Error(`Unsupported data type: 0x${dataType.toString(16)}`);
+ }
+ } catch (e) {
+ error.value = `Failed to parse spectral data: ${e.message}`;
+ return null;
+ }
+ };
+
+ // 主解析函数
+ const parseHyperspectralData = (rawData, metaData) => {
+ try {
+ if (!rawData || !rawData.spectral_data || !rawData.bands) {
+ throw new Error('Invalid data format: missing required fields');
+ }
+ const uint8Array = new Uint8Array(rawData.spectral_data);
+ const deviceInfo = metaData ? parseDeviceInfo(metaData) : null;
+ const result = {
+ deviceInfo,
+ dataInfo: {
+ name: rawData.name || '',
+ sensorId: rawData.sensor_id || '',
+ fiberId: rawData.fiber_id || 0,
+ collectionTime: rawData.collection_time ? parseTimeStruct(rawData.collection_time) : null,
+ exposure: rawData.exposure || 0,
+ gain: rawData.gain || 0,
+ dataType: rawData.data_type || 0,
+ pixelSize: rawData.pixel_size || 0,
+ groundType: rawData.ground_type || 0,
+ validFlag: rawData.valid_flag || 0,
+ bands: rawData.bands || 0
+ },
+ spectralData: parseSpectralData(uint8Array, rawData.bands, rawData.data_type)
+ };
+ parsedData.value = result;
+ return result;
+ } catch (e) {
+ error.value = `Data parsing error: ${e.message}`;
+ return null;
+ }
+ };
+
+ // 重置状态
+ const reset = () => {
+ parsedData.value = null;
+ error.value = null;
+ };
+
+ return {
+ parsedData,
+ error,
+ parseHyperspectralData,
+ reset
+ };
+}
\ No newline at end of file
diff --git a/src/utils/irisDataDispose.js b/src/utils/irisDataDispose.js
new file mode 100644
index 0000000..0a47ece
--- /dev/null
+++ b/src/utils/irisDataDispose.js
@@ -0,0 +1,455 @@
+class getIrisDataDispose {
+ spectralName;
+ irisData;
+ spectralInfoData;
+ spectral_data;
+ image_info;
+ devinfoData;
+ environmentData;
+
+ constructor(irisData, spectralName) {
+ this.irisData = irisData;
+ this.spectralName = spectralName;
+ this.spectral_data = irisData.spectral_data_section;
+ this.image_info = irisData.image_info_section;
+
+ for (const element of irisData.spectral_info_section) {
+ if (element.info_type == "devinfo") {
+ this.devinfoData = element;
+ } else if (element.info_type == "environment") {
+ this.environmentData = element;
+ }
+ }
+ }
+
+ initData() {
+ const basicTypes = ["ground_dn", "flat_dn", "dark_dn", "gain"];
+ const specialTypes = [
+ "flat_ref",
+ "radiance_ground",
+ "radiance_flat",
+ "refrad",
+ ];
+
+ if (basicTypes.includes(this.spectralName)) {
+ return this.getFileSpectralData();
+ } else if (specialTypes.includes(this.spectralName)) {
+ return this.getSpecialFileSpectralData();
+ }
+ }
+
+ //获取一般后端直接返回的类型
+ getFileSpectralData() {
+ for (const element of this.spectral_data) {
+ const typedArray = manageSpectralData(element, this.devinfoData);
+ const normalArray = Array.from(typedArray);
+ if (element.name.toLowerCase().includes(this.spectralName)) {
+ return { ...element, normalArray };
+ }
+ }
+ }
+
+ //获取需要计算的类型
+ getSpecialFileSpectralData() {
+ let spectralDataMap = new Map([
+ ["ground_dn", null],
+ ["flat_dn", null],
+ ["dark_dn", null],
+ ["flat_ref", null],
+ ["gain", null],
+ ["radiance_ground", null],
+ ["radiance_flat", null],
+ ["refrad", null],
+ ]);
+ for (const element of this.spectral_data) {
+ const typedArray = manageSpectralData(element, this.devinfoData);
+ const normalArray = Array.from(typedArray);
+ if (element.name.toLowerCase().includes("ground_dn")) {
+ spectralDataMap.set("ground_dn", { ...element, normalArray });
+ } else if (element.name.toLowerCase().includes("flat_dn")) {
+ spectralDataMap.set("flat_dn", { ...element, normalArray });
+ } else if (element.name.toLowerCase().includes("dark_dn")) {
+ spectralDataMap.set("dark_dn", { ...element, normalArray });
+ } else if (element.name.toLowerCase().includes("gain")) {
+ spectralDataMap.set("gain", { ...element, normalArray });
+ }
+ }
+
+ if (
+ spectralDataMap.get("ground_dn") &&
+ spectralDataMap.get("flat_dn") &&
+ spectralDataMap.get("dark_dn") &&
+ spectralDataMap.get("gain")
+ ) {
+ const obj1 = {
+ ground_dn: spectralDataMap.get("ground_dn").normalArray,
+ flat_dn: spectralDataMap.get("flat_dn").normalArray,
+ dark_dn: spectralDataMap.get("dark_dn").normalArray,
+ gain: spectralDataMap.get("gain").normalArray,
+ };
+
+ const arrAll = mergeObjectArrays(obj1);
+ const name = spectralDataMap.get("ground_dn").name.split("_")[0];
+
+ // 通用的数值验证函数
+ const validateAndPush = (array, value, type, invalidCount) => {
+ if (isFinite(value) && !isNaN(value)) {
+ array.push(value);
+ return true;
+ } else {
+ invalidCount.invalidResult++;
+ return false;
+ }
+ };
+
+ // 通用的除零检查函数
+ const checkDivision = (numerator, denominator, type, invalidCount) => {
+ if (Math.abs(denominator) < 1e-10) {
+ invalidCount.zeroDiv++;
+ return null;
+ }
+ return numerator / denominator;
+ };
+
+ // 通用的结果验证和返回函数
+ const validateResult = (array, name, type) => {
+ if (array.length === 0) {
+ console.error(`${type}计算错误: 没有有效的数据点,无法生成图表`);
+ return { normalArray: [], name: name };
+ }
+ return { normalArray: array, name: name };
+ };
+
+ if (this.spectralName == "radiance_ground") {
+ const radiance_ground = [];
+ const invalidCount = { zeroDiv: 0, invalidResult: 0 };
+
+ for (const element of arrAll) {
+ const gainExposure = spectralDataMap.get("gain").exposure;
+ const groundExposure = spectralDataMap.get("ground_dn").exposure;
+
+ // 检查曝光时间除零 - 改为补充0值
+ if (Math.abs(groundExposure) < 1e-10) {
+ invalidCount.zeroDiv++;
+ radiance_ground.push(0);
+ continue;
+ }
+
+ const exposureRatio = gainExposure / groundExposure;
+ const dnDiff = element.ground_dn - element.dark_dn;
+ const a = exposureRatio * (element.gain * dnDiff);
+
+ // 验证结果,无效时补充0值
+ if (isFinite(a) && !isNaN(a)) {
+ radiance_ground.push(a);
+ } else {
+ invalidCount.invalidResult++;
+ radiance_ground.push(0);
+ }
+ }
+ // 记录统计信息
+ if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
+ console.warn(`radiance_ground计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${radiance_ground.length} 个`);
+ }
+
+ return validateResult(radiance_ground, name + "_radiance_ground", 'radiance_ground');
+
+ } else if (this.spectralName == "radiance_flat") {
+ const radiance_flat = [];
+ const invalidCount = { zeroDiv: 0, invalidResult: 0 };
+
+ for (const element of arrAll) {
+ const gainExposure = spectralDataMap.get("gain").exposure;
+ const flatExposure = spectralDataMap.get("flat_dn").exposure;
+
+ // 检查曝光时间除零 - 改为补充0值
+ if (Math.abs(flatExposure) < 1e-10) {
+ invalidCount.zeroDiv++;
+ radiance_flat.push(0);
+ continue;
+ }
+
+ const exposureRatio = gainExposure / flatExposure;
+ const dnDiff = element.flat_dn - element.dark_dn;
+ const b = exposureRatio * (element.gain * dnDiff);
+
+ // 验证结果,无效时补充0值
+ if (isFinite(b) && !isNaN(b)) {
+ radiance_flat.push(b);
+ } else {
+ invalidCount.invalidResult++;
+ radiance_flat.push(0);
+ }
+ }
+ // 记录统计信息
+ if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
+ console.warn(`radiance_flat计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${radiance_flat.length} 个`);
+ }
+
+ return validateResult(radiance_flat, name + "_radiance_flat", 'radiance_flat');
+
+ } else if (this.spectralName == "refrad") {
+ const refrad = [];
+ const invalidCount = { zeroDiv: 0, invalidResult: 0 };
+
+ for (const element of arrAll) {
+ const gainExposure = spectralDataMap.get("gain").exposure;
+ const groundExposure = spectralDataMap.get("ground_dn").exposure;
+ const flatExposure = spectralDataMap.get("flat_dn").exposure;
+
+ // 检查曝光时间除零 - 改为补充0值
+ if (Math.abs(groundExposure) < 1e-10 || Math.abs(flatExposure) < 1e-10) {
+ invalidCount.zeroDiv++;
+ refrad.push(0);
+ continue;
+ }
+
+ const groundRatio = gainExposure / groundExposure;
+ const flatRatio = gainExposure / flatExposure;
+
+ const groundDnDiff = element.ground_dn - element.dark_dn;
+ const flatDnDiff = element.flat_dn - element.dark_dn;
+
+ const a = groundRatio * (element.gain * groundDnDiff);
+ const b = flatRatio * (element.gain * flatDnDiff);
+
+ // 检查分母b是否为零 - 改为补充0值
+ if (Math.abs(b) < 1e-10) {
+ invalidCount.zeroDiv++;
+ refrad.push(0);
+ } else {
+ const c = a / b;
+ if (isFinite(c) && !isNaN(c)) {
+ refrad.push(c);
+ } else {
+ invalidCount.invalidResult++;
+ refrad.push(0);
+ }
+ }
+ }
+
+ // 记录统计信息
+ if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
+ console.warn(`refrad计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${refrad.length} 个`);
+ }
+
+ return validateResult(refrad, name + "_refrad", 'refrad');
+
+ } else if (this.spectralName == "flat_ref") {
+ const validData = [];
+ const invalidCount = { zeroDiv: 0, invalidResult: 0 };
+
+ for (const element of arrAll) {
+ const denominator = element.flat_dn - element.dark_dn;
+ const numerator = element.ground_dn - element.dark_dn;
+
+ // 检查分母是否为零或接近零 - 改为补充0值
+ if (Math.abs(denominator) < 1e-10) {
+ invalidCount.zeroDiv++;
+ validData.push(0);
+ } else {
+ const b = numerator / denominator;
+ if (isFinite(b) && !isNaN(b)) {
+ validData.push(b);
+ } else {
+ invalidCount.invalidResult++;
+ validData.push(0);
+ }
+ }
+ }
+
+ // 记录统计信息
+ if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
+ console.warn(`flat_ref计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${validData.length} 个`);
+ }
+ return validateResult(validData, name + "_flat_ref", 'flat_ref');
+ }
+ }
+ }
+
+ getSpectralInfoData() {
+ let spectralInfoData = [];
+ for (let i = 0; i < this.devinfoData.bandnum; i++) {
+ const a =
+ this.devinfoData.wave_coeff.a1 * i ** 3 +
+ this.devinfoData.wave_coeff.a2 * i * i +
+ this.devinfoData.wave_coeff.a3 * i +
+ this.devinfoData.wave_coeff.a4;
+ spectralInfoData.push(a);
+ }
+ return spectralInfoData;
+ }
+
+ parseImageData(image_info) {
+ if (!image_info || image_info.length === 0) {
+ console.log("No image data found");
+ return [];
+ }
+ const imageInfos = image_info;
+ const images = [];
+ for (const imageInfo of imageInfos) {
+ // 获取图像类型
+ const imageType = imageInfo.info_type;
+ let mimeType;
+ switch (imageType) {
+ case 0:
+ mimeType = "image/jpeg";
+ break;
+ case 1:
+ mimeType = "image/png";
+ break;
+ case 2:
+ mimeType = "image/tiff";
+ break;
+ case 3:
+ mimeType = "application/octet-stream"; // 原始数据
+ break;
+ default:
+ mimeType = "application/octet-stream";
+ }
+ // 创建Blob对象
+ const imageBlob = new Blob([new Uint8Array(imageInfo.image_data)], {
+ type: mimeType,
+ });
+ // 创建URL
+ const imageUrl = URL.createObjectURL(imageBlob);
+ images.push({
+ name: imageInfo.name,
+ type: imageType,
+ url: imageUrl,
+ time: imageInfo.collection_time,
+ });
+ }
+
+ return images;
+ }
+}
+
+function mergeObjectArrays(obj) {
+ const keys = Object.keys(obj);
+ const length = obj[keys[0]].length;
+
+ const result = [];
+
+ for (let i = 0; i < length; i++) {
+ const item = {};
+ for (const key of keys) {
+ item[key] = obj[key][i];
+ }
+ result.push(item);
+ }
+
+ return result;
+}
+
+const manageSpectralData = (rawData, devinfoData) => {
+ const bands = devinfoData.bandnum;
+ const uint8Array = new Uint8Array(rawData.spectral_data);
+ try {
+ switch (rawData.data_type) {
+ case 0x20: // float32
+ return new Float32Array(uint8Array.buffer, 0, bands);
+ case 0x21: // float64
+ return new Float64Array(uint8Array.buffer, 0, bands);
+ case 0x10: // uint8
+ return new Uint8Array(uint8Array.buffer, 0, bands);
+ case 0x11: // int16
+ return new Int16Array(uint8Array.buffer, 0, bands);
+ case 0x12: // uint16
+ return new Uint16Array(uint8Array.buffer, 0, bands);
+ case 0x13: // int32
+ return new Int32Array(uint8Array.buffer, 0, bands);
+ case 0x14: // uint32
+ return new Uint32Array(uint8Array.buffer, 0, bands);
+ default:
+ throw new Error(`Unsupported data type: 0x${dataType.toString(16)}`);
+ }
+ } catch (e) {
+ error.value = `Failed to parse spectral data: ${e.message}`;
+ return null;
+ }
+};
+
+const spectralTypeList = [
+ {
+ value: "ground_dn",
+ label: "地物DN",
+ },
+ {
+ value: "flat_dn",
+ label: "参考DN",
+ },
+ {
+ value: "dark_dn",
+ label: "暗噪DN",
+ },
+ {
+ value: "flat_ref",
+ label: "反射率",
+ },
+ {
+ value: "gain",
+ label: "能量校准文件",
+ },
+ {
+ value: "radiance_ground",
+ label: "地物辐射亮度",
+ },
+ {
+ value: "radiance_flat",
+ label: "参考辐射亮度",
+ },
+ {
+ value: "refrad",
+ label: "反射率能量",
+ },
+ {
+ value: "jdfs",
+ label: "绝对反射率",
+ },
+ {
+ value: "ckbzwj",
+ label: "参考校准文件",
+ },
+ {
+ value: "fszd",
+ label: "辐射照度",
+ },
+];
+
+const spectralProcessTypeList = [
+ {
+ value: "D1",
+ label: "一阶导数",
+ },
+ {
+ value: "D2",
+ label: "二阶导数",
+ },
+ {
+ value: "MA",
+ label: "移动平均平滑",
+ },
+];
+
+function D1(arr) {
+ const result = [];
+ for (let i = 1; i < arr.length; i++) {
+ result.push(arr[i] - arr[i - 1]);
+ }
+ result.push(arr[arr.length - 1]);
+ return result;
+}
+
+function D2(arr) {
+ const arr2 = D1(arr);
+ return D1(arr2);
+}
+
+export {
+ spectralTypeList,
+ getIrisDataDispose,
+ spectralProcessTypeList,
+ D1,
+ D2,
+};
diff --git a/src/utils/spectralDataService.js b/src/utils/spectralDataService.js
new file mode 100644
index 0000000..a0c2b92
--- /dev/null
+++ b/src/utils/spectralDataService.js
@@ -0,0 +1,106 @@
+import { getIrisDataDispose, D1, D2 } from '../utils/irisDataDispose';
+import { invoke } from "@tauri-apps/api/tauri";
+
+/**
+ * 光谱数据处理服务
+ */
+export class SpectralDataService {
+ /**
+ * 提取文件名
+ */
+ static extractFileName(filePath) {
+ const match = filePath.match(/[^\\\/]+$/);
+ return match ? match[0] : '';
+ }
+
+ /**
+ * 加载文件数据
+ */
+ static async loadFileData(filePaths) {
+ const fileData = [];
+ for (const path of filePaths) {
+ try {
+ const src = await invoke("getoneirisfile", { path });
+ const fileName = this.extractFileName(path);
+ fileData.push({ data: src, name: fileName });
+ } catch (error) {
+ console.error(`加载文件失败: ${path}`, error);
+ }
+ }
+ return fileData;
+ }
+
+ /**
+ * 处理光谱数据
+ */
+ static processSpectralData(fileData, spectralType, processType = '') {
+ const spectralDataList = [];
+ const imageList = [];
+
+ for (const element of fileData) {
+ if (!element.data) continue;
+
+ try {
+ const dispose = new getIrisDataDispose(element.data, spectralType);
+ const datay = dispose.initData();
+ const datax = dispose.getSpectralInfoData();
+ const environmentData = dispose.environmentData;
+ const img = dispose.parseImageData(element.data.image_info_section);
+
+ if (datay?.normalArray && datax) {
+ spectralDataList.push({
+ name: datay?.name || '',
+ datax: datax,
+ datay: datay.normalArray,
+ environmentData: { ...environmentData, fileName: element.name }
+ });
+ imageList.push(img);
+ }
+ } catch (error) {
+ console.error(`处理光谱数据失败: ${element.name}`, error);
+ }
+ }
+
+ return {
+ spectralDataList,
+ imageList,
+ processedData: this.applyProcessing(spectralDataList, processType)
+ };
+ }
+
+ /**
+ * 应用数据处理(D1/D2等)
+ */
+ static applyProcessing(spectralDataList, processType) {
+ if (!processType) return spectralDataList;
+
+ switch (processType) {
+ case 'D1':
+ return spectralDataList.map(item => ({
+ name: item.name + '_D1',
+ datax: item.datax,
+ datay: D1(item.datay),
+ environmentData: item.environmentData
+ }));
+ case 'D2':
+ return spectralDataList.map(item => ({
+ name: item.name + '_D2',
+ datax: item.datax,
+ datay: D2(item.datay),
+ environmentData: item.environmentData
+ }));
+ default:
+ return spectralDataList;
+ }
+ }
+
+ /**
+ * 批量处理选定文件的光谱数据
+ */
+ static processSelectedFiles(fileData, selectedFileNames, spectralType, processType = '') {
+ const filteredData = fileData.filter(file =>
+ selectedFileNames.includes(file.name)
+ );
+ return this.processSpectralData(filteredData, spectralType, processType);
+ }
+}
\ No newline at end of file
diff --git a/src/utils/tauriApi.js b/src/utils/tauriApi.js
new file mode 100644
index 0000000..d14dea1
--- /dev/null
+++ b/src/utils/tauriApi.js
@@ -0,0 +1,118 @@
+import { invoke } from "@tauri-apps/api/tauri";
+import { dialog, fs } from "@tauri-apps/api";
+
+export default {
+ /**
+ * 打开文件夹选择对话框并获取文件夹内容
+ * @param {string} defaultPath 默认路径
+ * @returns {Promise