diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 0f756bf..798c659 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -23,6 +23,8 @@ module.exports = {
"warn",
{ allowConstantExport: true },
],
+ "no-throw-literal": "off",
+ "@typescript-eslint/no-throw-literal": "error",
},
settings: {
react: {
diff --git a/package-lock.json b/package-lock.json
index a373c13..8ad77ba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,16 +14,21 @@
"@mui/icons-material": "^5.14.3",
"@mui/material": "^5.14.5",
"@react-three/fiber": "^8.13.7",
+ "@reduxjs/toolkit": "^1.9.5",
"d3-scale": "^4.0.2",
"framer-motion": "^10.15.2",
"normalize.css": "^8.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-redux": "^8.1.2",
+ "redux": "^4.2.1",
"three": "^0.155.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
+ "@types/react-redux": "^7.1.26",
+ "@types/redux": "^3.6.0",
"@types/three": "^0.155.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
@@ -1279,6 +1284,29 @@
}
}
},
+ "node_modules/@reduxjs/toolkit": {
+ "version": "1.9.5",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz",
+ "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==",
+ "dependencies": {
+ "immer": "^9.0.21",
+ "redux": "^4.2.1",
+ "redux-thunk": "^2.4.2",
+ "reselect": "^4.1.8"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18",
+ "react-redux": "^7.2.1 || ^8.0.2"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -1539,6 +1567,15 @@
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz",
"integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg=="
},
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"node_modules/@types/json-schema": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
@@ -1600,6 +1637,18 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-redux": {
+ "version": "7.1.26",
+ "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.26.tgz",
+ "integrity": "sha512-UKPo7Cm7rswYU6PH6CmTNCRv5NYF3HrgKuHEYTK8g/3czYLrUux50gQ2pkxc9c7ZpQZi+PNhgmI8oNIRoiVIxg==",
+ "dev": true,
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.3.0",
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0",
+ "redux": "^4.0.0"
+ }
+ },
"node_modules/@types/react-transition-group": {
"version": "4.4.6",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
@@ -1608,6 +1657,16 @@
"@types/react": "*"
}
},
+ "node_modules/@types/redux": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@types/redux/-/redux-3.6.0.tgz",
+ "integrity": "sha512-ic+60DXHW5seNyqFvfr7Sk5cnXs+HsF9tIeIaxjOuSP5kzgDXC+AzKTYmjAfuLx4Sccm/0vjwBQj3OOkUkwOqg==",
+ "deprecated": "This is a stub types definition for Redux (https://github.com/reactjs/redux). Redux provides its own type definitions, so you don't need @types/redux installed!",
+ "dev": true,
+ "dependencies": {
+ "redux": "*"
+ }
+ },
"node_modules/@types/scheduler": {
"version": "0.16.3",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
@@ -1639,6 +1698,11 @@
"meshoptimizer": "~0.18.1"
}
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+ },
"node_modules/@types/webxr": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.3.tgz",
@@ -3569,6 +3633,15 @@
"node": ">= 4"
}
},
+ "node_modules/immer": {
+ "version": "9.0.21",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+ "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -4649,6 +4722,49 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/react-redux": {
+ "version": "8.1.2",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz",
+ "integrity": "sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.1",
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "@types/use-sync-external-store": "^0.0.3",
+ "hoist-non-react-statics": "^3.3.2",
+ "react-is": "^18.0.0",
+ "use-sync-external-store": "^1.0.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8 || ^17.0 || ^18.0",
+ "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0",
+ "react-native": ">=0.59",
+ "redux": "^4 || ^5.0.0-beta.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-redux/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
"node_modules/react-slider": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/react-slider/-/react-slider-2.0.4.tgz",
@@ -4726,6 +4842,22 @@
"balanced-match": "^1.0.0"
}
},
+ "node_modules/redux": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+ "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+ "dependencies": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "node_modules/redux-thunk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+ "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+ "peerDependencies": {
+ "redux": "^4"
+ }
+ },
"node_modules/regenerator-runtime": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
@@ -4748,6 +4880,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/reselect": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz",
+ "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="
+ },
"node_modules/resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
@@ -6367,6 +6504,17 @@
}
}
},
+ "@reduxjs/toolkit": {
+ "version": "1.9.5",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz",
+ "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==",
+ "requires": {
+ "immer": "^9.0.21",
+ "redux": "^4.2.1",
+ "redux-thunk": "^2.4.2",
+ "reselect": "^4.1.8"
+ }
+ },
"@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -6521,6 +6669,15 @@
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz",
"integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg=="
},
+ "@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "requires": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"@types/json-schema": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
@@ -6582,6 +6739,18 @@
"@types/react": "*"
}
},
+ "@types/react-redux": {
+ "version": "7.1.26",
+ "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.26.tgz",
+ "integrity": "sha512-UKPo7Cm7rswYU6PH6CmTNCRv5NYF3HrgKuHEYTK8g/3czYLrUux50gQ2pkxc9c7ZpQZi+PNhgmI8oNIRoiVIxg==",
+ "dev": true,
+ "requires": {
+ "@types/hoist-non-react-statics": "^3.3.0",
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0",
+ "redux": "^4.0.0"
+ }
+ },
"@types/react-transition-group": {
"version": "4.4.6",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
@@ -6590,6 +6759,15 @@
"@types/react": "*"
}
},
+ "@types/redux": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@types/redux/-/redux-3.6.0.tgz",
+ "integrity": "sha512-ic+60DXHW5seNyqFvfr7Sk5cnXs+HsF9tIeIaxjOuSP5kzgDXC+AzKTYmjAfuLx4Sccm/0vjwBQj3OOkUkwOqg==",
+ "dev": true,
+ "requires": {
+ "redux": "*"
+ }
+ },
"@types/scheduler": {
"version": "0.16.3",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
@@ -6621,6 +6799,11 @@
"meshoptimizer": "~0.18.1"
}
},
+ "@types/use-sync-external-store": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+ },
"@types/webxr": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.3.tgz",
@@ -8050,6 +8233,11 @@
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
"dev": true
},
+ "immer": {
+ "version": "9.0.21",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+ "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA=="
+ },
"import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -8841,6 +9029,26 @@
}
}
},
+ "react-redux": {
+ "version": "8.1.2",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz",
+ "integrity": "sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==",
+ "requires": {
+ "@babel/runtime": "^7.12.1",
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "@types/use-sync-external-store": "^0.0.3",
+ "hoist-non-react-statics": "^3.3.2",
+ "react-is": "^18.0.0",
+ "use-sync-external-store": "^1.0.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ }
+ }
+ },
"react-slider": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/react-slider/-/react-slider-2.0.4.tgz",
@@ -8902,6 +9110,20 @@
"balanced-match": "^1.0.0"
}
},
+ "redux": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+ "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "redux-thunk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+ "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+ "requires": {}
+ },
"regenerator-runtime": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
@@ -8918,6 +9140,11 @@
"functions-have-names": "^1.2.3"
}
},
+ "reselect": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz",
+ "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="
+ },
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
diff --git a/package.json b/package.json
index 75e5bb0..f813464 100644
--- a/package.json
+++ b/package.json
@@ -17,16 +17,21 @@
"@mui/icons-material": "^5.14.3",
"@mui/material": "^5.14.5",
"@react-three/fiber": "^8.13.7",
+ "@reduxjs/toolkit": "^1.9.5",
"d3-scale": "^4.0.2",
"framer-motion": "^10.15.2",
"normalize.css": "^8.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-redux": "^8.1.2",
+ "redux": "^4.2.1",
"three": "^0.155.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
+ "@types/react-redux": "^7.1.26",
+ "@types/redux": "^3.6.0",
"@types/three": "^0.155.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
diff --git a/src/app.tsx b/src/app.tsx
index 0df7c49..7eb89a1 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -1,14 +1,16 @@
import { Box, Stack } from "@mui/material";
-import DataSideBar from "./components/dataSideBar";
-import ResultsBar from "./components/resultsBar";
-import CentrePlot from "./components/centrePlot";
-import LegendBar from "./components/legendBar";
+import DataSideBar from "./data-entry/dataSideBar";
+import ResultsBar from "./results/resultsBar";
+import CentrePlot from "./plot/centrePlot";
+import LegendBar from "./legend/legendBar";
+import BasicAppBar from "./basicAppBar";
export default function App(): JSX.Element {
return (
-
-
-
+
+
+
+
@@ -20,7 +22,7 @@ export default function App(): JSX.Element {
-
-
+
+
);
}
diff --git a/src/components/basicAppBar.tsx b/src/basicAppBar.tsx
similarity index 99%
rename from src/components/basicAppBar.tsx
rename to src/basicAppBar.tsx
index 129722f..bfa71ce 100644
--- a/src/components/basicAppBar.tsx
+++ b/src/basicAppBar.tsx
@@ -8,7 +8,6 @@ import MenuIcon from "@mui/icons-material/Menu";
import { Drawer } from "@mui/material";
import SideMenu from "./sideMenu";
-
export default function BasicAppBar(): JSX.Element {
const [state, setState] = React.useState({ menuOpen: false });
const toggleDrawer = (open: boolean) => () => {
diff --git a/src/calculations/ray.test.ts b/src/calculations/ray.test.ts
index c086a32..22f6806 100644
--- a/src/calculations/ray.test.ts
+++ b/src/calculations/ray.test.ts
@@ -6,5 +6,11 @@ test("Getting a point from a ray", () => {
const ray1 = new Ray(new Vector2(1, 1), new Vector2(1, 1));
const vector1 = ray1.getPoint(5);
const vector2 = new Vector2(6, 6);
- expect(vector1?.equals(vector2));
+ expect(vector1.equals(vector2));
+});
+
+test("Getting point at distance", () => {
+ const ray1 = new Ray(new Vector2(1, 1), new Vector2(0, 0));
+ const point = ray1.getPointAtDistance(4);
+ console.log(point);
});
diff --git a/src/calculations/ray.ts b/src/calculations/ray.ts
index 8811b40..586987f 100644
--- a/src/calculations/ray.ts
+++ b/src/calculations/ray.ts
@@ -18,21 +18,18 @@ export class Ray {
* @param scalar
* @returns
*/
- getPoint(scalar: number): Vector2 | null {
- if (scalar < 0) return null;
+ getPoint(scalar: number): Vector2 {
const result = new Vector2(this.direction.x, this.direction.y);
result.multiplyScalar(scalar);
result.add(this.initial_point);
return result;
}
- getPointAtDistance(distance: number): Vector2 | null {
+ getPointAtDistance(distance: number): Vector2 {
return this.getPoint(distance / this.direction.length());
}
- getParameterRange(t1: number, t2: number): NumericRange | null {
- if (t1 < 0 && t2 < 0) return null;
-
+ getParameterRange(t1: number, t2: number): NumericRange {
let tMin = Math.min(t1, t2);
const tMax = Math.max(t1, t2);
diff --git a/src/components/dataSideBar.tsx b/src/components/dataSideBar.tsx
deleted file mode 100644
index f88e137..0000000
--- a/src/components/dataSideBar.tsx
+++ /dev/null
@@ -1,300 +0,0 @@
-import {
- Card,
- CardContent,
- Stack,
- Typography,
- Divider,
- Autocomplete,
- TextField,
- Button,
- FormControl,
- Select,
- MenuItem,
- InputLabel,
- SelectChangeEvent,
- ButtonGroup,
- Input,
-} from "@mui/material";
-import { Detector, BeamlineConfig } from "../utils/types";
-import React from "react";
-import RemoveIcon from "@mui/icons-material/Remove";
-import AddIcon from "@mui/icons-material/Add";
-import { DistanceUnits, EnergyUnits, WavelengthUnits, AngleUnits } from "../utils/units";
-
-
-export default function DataSideBar(): JSX.Element {
- const [cameraDiameterUnits, setCameraDiameterUnits] =
- React.useState(DistanceUnits.millimetre);
-
- const handleCameraDiameterUnits = (event: SelectChangeEvent) => {
- setCameraDiameterUnits(event.target.value as DistanceUnits);
- };
-
- const [clearanceDiameterUnits, setClearnaceDiameterUnits] =
- React.useState(DistanceUnits.millimetre);
-
- const handleClearanceDiameterUnits = (event: SelectChangeEvent) => {
- setClearnaceDiameterUnits(event.target.value as DistanceUnits);
- };
-
- const [beamstopDiameterUnits, setBeamstopDiameterUnits] =
- React.useState(DistanceUnits.millimetre);
-
- const handleBeamstopDiameterUnits = (event: SelectChangeEvent) => {
- setBeamstopDiameterUnits(event.target.value as DistanceUnits);
- };
- const [pixelSizeUnits, setPixelSizeUnits] = React.useState(
- DistanceUnits.millimetre,
- );
-
- const handlePixelSizeUnits = (event: SelectChangeEvent) => {
- setPixelSizeUnits(event.target.value as DistanceUnits);
- };
- const [beamEnergyUnits, setBeamEnergyUnits] = React.useState(
- EnergyUnits.electronVolts,
- );
-
- const handleBeamEnergyUnits = (event: SelectChangeEvent) => {
- setBeamEnergyUnits(event.target.value as EnergyUnits);
- };
-
- const [wavelengthUnits, setWavelengthUnits] = React.useState(
- WavelengthUnits.nanmometres,
- );
-
- const handleWavelengthUnits = (event: SelectChangeEvent) => {
- setWavelengthUnits(event.target.value as WavelengthUnits);
- };
-
- const [cameraLength, setCameraLength] = React.useState(1.9);
-
- const handleCameraLength = (event: React.ChangeEvent) => {
- setCameraLength(parseFloat(event.target.value));
- };
- const [angleUnits, setAngleUnits] = React.useState(
- AngleUnits.radians,
- );
-
- const handleAngleUnits = (event: SelectChangeEvent) => {
- setAngleUnits(event.target.value as AngleUnits);
- };
-
- const [angle, setAngle] = React.useState(90);
-
- const handleAngleChange = (event: React.ChangeEvent) => {
- setAngle(parseFloat(event.target.value));
- };
-
- return (
-
-
-
- Configuration
-
- Predefined Configuration Templates
-
- (
-
- )}
- />
-
-
- Detector
- (
-
- )}
- />
- Resolution: 150x160
-
- Pixel size
-
- units
-
-
-
-
-
- Beamstop
-
- Diameter: {4}
-
- units
-
-
-
-
-
- Position
-
- x:
- px
-
-
-
- y:
- px
-
-
-
- Clearance
-
- Diameter: {4}
-
- units
-
-
-
-
- Camera Tube
-
- Diameter: {4}
-
- units
-
-
-
- Position
-
- x:
- px
-
-
- y:
- px
-
-
- Beam properties
-
- Energy
-
- units
-
-
-
-
- WaveLength
-
- units
-
-
-
- Minimum allowed wavelength: {4}
- Maximum allowed wavelength: {4}
-
-
- Camera Length:
-
-
-
-
-
- m
-
-
-
- Angle:
-
-
- units
-
-
-
-
-
-
- );
-}
diff --git a/src/components/legendBar.tsx b/src/components/legendBar.tsx
deleted file mode 100644
index c8f3618..0000000
--- a/src/components/legendBar.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import {
- Card,
- CardContent,
- Checkbox,
- FormControlLabel,
- FormGroup,
- Stack,
- Typography,
-} from "@mui/material";
-
-export default function LegendBar(): JSX.Element {
- return (
-
-
-
- Legend
- Add something to do with colors here
-
- } label="Detector" />
- } label="Beamstop" />
- } label="Camera tube" />
- } label="Q range" />
- } label="Mask" />
- } label="Calibrant" />
-
- Currently selected Calibrant is: {5}
-
-
-
- );
-}
diff --git a/src/components/resultsBar.tsx b/src/components/resultsBar.tsx
deleted file mode 100644
index 600ef48..0000000
--- a/src/components/resultsBar.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { Box, Card, CardContent, Divider, FormControl, InputLabel, MenuItem, Select, SelectChangeEvent, Stack, Typography } from "@mui/material";
-import { AngleUnits } from "../utils/units";
-import React from "react";
-const theta = "\u03B8"
-
-enum ScatteringQuantity {
- q = "q",
- d = "d",
- s = "s",
- twoTheta = "2" + theta,
-}
-
-
-
-export default function ResultsBar(): JSX.Element {
- const [angleUnits, setAngleUnits] = React.useState(
- AngleUnits.radians,
- );
-
- const handleAngleUnits = (event: SelectChangeEvent) => {
- setAngleUnits(event.target.value as AngleUnits);
- };
- const [quantity, setQuantity] = React.useState(
- ScatteringQuantity.q
- );
-
- const handleQuantity = (event: SelectChangeEvent) => {
- setQuantity(event.target.value as ScatteringQuantity);
- };
-
- return (
-
-
-
-
- Results bottom bar
-
-
- Scattering quantity:
-
- quantity
-
-
-
- units
-
-
-
- Min {quantity} value:
- Max {quantity} value:
- Requested min {quantity} value:
- Requested max {quantity} value:
-
-
-
-
- );
-}
diff --git a/src/components/sideMenu.tsx b/src/components/sideMenu.tsx
deleted file mode 100644
index 36a2f69..0000000
--- a/src/components/sideMenu.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import Box from "@mui/material/Box";
-import List from "@mui/material/List";
-import Divider from "@mui/material/Divider";
-import ListItem from "@mui/material/ListItem";
-import { Button, Stack, Typography } from "@mui/material";
-
-export default function SideMenu() {
- return (
-
-
-
-
- Reset to default
-
-
-
-
-
-
- );
-}
diff --git a/src/data-entry/configSlice.ts b/src/data-entry/configSlice.ts
new file mode 100644
index 0000000..1e0024e
--- /dev/null
+++ b/src/data-entry/configSlice.ts
@@ -0,0 +1,19 @@
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+import testBeamlineConfig from "../presets/presetConfigs.json";
+import { BeamlineConfig } from "../utils/types";
+import { RootState } from "../store";
+
+const beamlineConfigSlice = createSlice({
+ name: "config",
+ initialState: (testBeamlineConfig as Record).test,
+ reducers: {
+ editConfig: (state, action: PayloadAction>) => {
+ return { ...state, ...action.payload };
+ },
+ },
+});
+
+export const beamlineConfigReducer = beamlineConfigSlice.reducer;
+
+export const { editConfig } = beamlineConfigSlice.actions;
+export const configSelector = (state: RootState) => state.config;
diff --git a/src/data-entry/dataSideBar.tsx b/src/data-entry/dataSideBar.tsx
new file mode 100644
index 0000000..b017672
--- /dev/null
+++ b/src/data-entry/dataSideBar.tsx
@@ -0,0 +1,345 @@
+import {
+ Card,
+ CardContent,
+ Stack,
+ Typography,
+ Divider,
+ Autocomplete,
+ TextField,
+ Button,
+ FormControl,
+ Select,
+ MenuItem,
+ InputLabel,
+ SelectChangeEvent,
+ ButtonGroup,
+ Input,
+} from "@mui/material";
+import RemoveIcon from "@mui/icons-material/Remove";
+import AddIcon from "@mui/icons-material/Add";
+import {
+ DistanceUnits,
+ EnergyUnits,
+ WavelengthUnits,
+ AngleUnits,
+} from "../utils/units";
+import { useDispatch, useSelector } from "react-redux";
+import { configSelector, editConfig } from "./configSlice";
+import { editUnits, unitSelector } from "./unitSlice";
+import detectorData from "../presets/detectors.json";
+import presetData from "../presets/presetConfigs.json";
+import { BeamlineConfig, Detector } from "../utils/types";
+import { useState } from "react";
+
+
+const detectorList = detectorData as Record;
+const presetList = presetData as Record;
+
+export default function DataSideBar(): JSX.Element {
+ const config = useSelector(configSelector);
+ const units = useSelector(unitSelector);
+ const dispatch = useDispatch();
+ const [preset, setPreset] = useState("test");
+
+ const handlePresetChange = (preset: string): void => {
+ setPreset(preset);
+ dispatch(editConfig(presetList[preset]));
+ };
+
+ const handleDetectorChange = (detector: string): void => {
+ dispatch(editConfig({ detector: detector }));
+ };
+
+ return (
+
+
+
+ Configuration
+
+ Predefined Configuration Templates
+
+ (
+
+ )}
+ onChange={(_, value) => {
+ value ? handlePresetChange(value) : {};
+ }}
+ />
+
+
+ Detector
+ (
+
+ )}
+ onChange={(_, value) => {
+ value ? handleDetectorChange(value) : {};
+ }}
+ />
+
+ Resolution: {detectorList[config.detector].resolution.height} x{" "}
+ {detectorList[config.detector].resolution.width}
+
+
+
+ Pixel size: {detectorList[config.detector].pixel_size} x{" "}
+ {detectorList[config.detector].pixel_size}{" "}
+
+
+ units
+
+
+
+
+
+ Beamstop
+
+
+ Diameter: {config.beamstop.diameter}
+
+
+ units
+
+
+
+
+
+ Position
+
+
+ x: {config.beamstop.centre.x} px
+
+
+
+
+
+ y: {config.beamstop.centre.y} px
+
+
+
+
+ Clearance
+
+ Diameter: {config.clearance}
+
+ units
+
+
+
+
+ Camera Tube
+
+
+ Diameter: {config.cameraTube.diameter}
+
+
+ units
+
+
+
+ Position
+
+
+ x: {config.cameraTube.centre.x} px
+
+
+
+
+ y: {config.cameraTube.centre.y} px
+
+
+
+ Beam properties
+
+ Energy:
+
+ units
+
+
+
+
+ WaveLength
+
+ units
+
+
+
+
+ Minimum allowed wavelength: {config.minWavelength}{" "}
+
+
+ Maximum allowed wavelength: {config.maxWavelength}
+
+
+
+ Camera Length:
+
+
+
+
+
+ m
+
+
+
+ Angle:
+
+ dispatch(editConfig({ angle: parseFloat(event.target.value) }))
+ }
+ />
+
+ units
+
+
+
+
+
+
+ );
+}
diff --git a/src/data-entry/unitSlice.ts b/src/data-entry/unitSlice.ts
new file mode 100644
index 0000000..9c0efff
--- /dev/null
+++ b/src/data-entry/unitSlice.ts
@@ -0,0 +1,33 @@
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+import { RootState } from "../store";
+import {
+ AngleUnits,
+ DistanceUnits,
+ EnergyUnits,
+ UnitConfig,
+ WavelengthUnits,
+} from "../utils/units";
+
+const defaultUnits: UnitConfig = {
+ cameraDiameterUnits: DistanceUnits.millimetre,
+ clearanceDiameterUnits: DistanceUnits.micrometre,
+ beamEnergyUnits: EnergyUnits.electronVolts,
+ pixelSizeUnits: DistanceUnits.millimetre,
+ angleUnits: AngleUnits.radians,
+ wavelengthUnits: WavelengthUnits.angstroms,
+ beamstopDiameterUnits: DistanceUnits.millimetre,
+};
+
+const unitConfigSlice = createSlice({
+ name: "unit-config",
+ initialState: defaultUnits,
+ reducers: {
+ editUnits: (state, action: PayloadAction>) => {
+ return { ...state, ...action.payload };
+ },
+ },
+});
+
+export const { editUnits } = unitConfigSlice.actions;
+export const unitConfigReducer = unitConfigSlice.reducer;
+export const unitSelector = (state: RootState) => state.units;
diff --git a/src/index.css b/src/index.css
index 929290a..399400d 100644
--- a/src/index.css
+++ b/src/index.css
@@ -2,17 +2,17 @@
@import "@h5web/lib/styles.css";
body {
- margin: 0;
- height: 100vh;
- width: 100vw;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
- "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
- sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
+ margin: 0;
+ height: 100vh;
+ width: 100vw;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
- monospace;
-}
\ No newline at end of file
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
+ monospace;
+}
diff --git a/src/legend/legendBar.tsx b/src/legend/legendBar.tsx
new file mode 100644
index 0000000..6679638
--- /dev/null
+++ b/src/legend/legendBar.tsx
@@ -0,0 +1,31 @@
+import {
+ Card,
+ CardContent,
+ Checkbox,
+ FormControlLabel,
+ FormGroup,
+ Stack,
+ Typography,
+} from "@mui/material";
+
+export default function LegendBar(): JSX.Element {
+ return (
+
+
+
+ Legend
+ Add something to do with colors here
+
+ } label="Detector" />
+ } label="Beamstop" />
+ } label="Camera tube" />
+ } label="Q range" />
+ } label="Mask" />
+ } label="Calibrant" />
+
+ Currently selected Calibrant is: {5}
+
+
+
+ );
+}
diff --git a/src/main.tsx b/src/main.tsx
index 5ce9948..3569e45 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,17 +1,14 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./app.tsx";
-import BasicAppBar from "./components/basicAppBar.tsx";
import "./index.css";
-import { Box } from "@mui/material";
-
-
+import { Provider } from "react-redux";
+import store from "./store.ts";
ReactDOM.createRoot(document.getElementById("root")!).render(
-
-
+
-
+
,
);
diff --git a/src/components/centrePlot.tsx b/src/plot/centrePlot.tsx
similarity index 100%
rename from src/components/centrePlot.tsx
rename to src/plot/centrePlot.tsx
diff --git a/src/presets/detectors.json b/src/presets/detectors.json
index 95cefe2..e0f08f2 100644
--- a/src/presets/detectors.json
+++ b/src/presets/detectors.json
@@ -1,8 +1,16 @@
{
- "name": "Pilatus P3-2M",
+ "Pilatus P3-2M": {
"resolution": {
- "width": "1475",
- "height": "1679"
+ "width": 1475,
+ "height": 1679
},
"pixel_size": 0.172
-}
\ No newline at end of file
+ },
+ "test": {
+ "resolution": {
+ "width": 1,
+ "height": 1
+ },
+ "pixel_size": 1
+ }
+}
diff --git a/src/presets/presetConfigs.json b/src/presets/presetConfigs.json
index 9e26dfe..8050da2 100644
--- a/src/presets/presetConfigs.json
+++ b/src/presets/presetConfigs.json
@@ -1 +1,50 @@
-{}
\ No newline at end of file
+{
+ "test": {
+ "detector": "test",
+ "beamstop": {
+ "centre": {
+ "x": 1,
+ "y": 2
+ },
+ "diameter": 1
+ },
+ "cameraTube": {
+ "centre": {
+ "x": 1,
+ "y": 2
+ },
+ "diameter": 1
+ },
+ "angle": 1,
+ "cameraLength": 1,
+ "clearance": 1,
+ "minWavelength": 1,
+ "maxWavelength": 3,
+ "minCameraLength": 2,
+ "maxCameraLength": 4
+ },
+ "second": {
+ "detector": "Pilatus P3-2M",
+ "beamstop": {
+ "centre": {
+ "x": 1,
+ "y": 2
+ },
+ "diameter": 4
+ },
+ "cameraTube": {
+ "centre": {
+ "x": 1,
+ "y": 2
+ },
+ "diameter": 1
+ },
+ "angle": 1,
+ "cameraLength": 1,
+ "clearance": 1,
+ "minWavelength": 1,
+ "maxWavelength": 1,
+ "minCameraLength": 1,
+ "maxCameraLength": 1
+ }
+}
\ No newline at end of file
diff --git a/src/results/resultsBar.tsx b/src/results/resultsBar.tsx
new file mode 100644
index 0000000..2929e3b
--- /dev/null
+++ b/src/results/resultsBar.tsx
@@ -0,0 +1,94 @@
+import {
+ Box,
+ Card,
+ CardContent,
+ Divider,
+ FormControl,
+ InputLabel,
+ MenuItem,
+ Select,
+ SelectChangeEvent,
+ Stack,
+ Typography,
+} from "@mui/material";
+import { AngleUnits } from "../utils/units";
+import React from "react";
+const theta = "\u03B8";
+
+enum ScatteringQuantity {
+ q = "q",
+ d = "d",
+ s = "s",
+ twoTheta = "2" + theta,
+}
+
+export default function ResultsBar(): JSX.Element {
+ const [angleUnits, setAngleUnits] = React.useState(
+ AngleUnits.radians,
+ );
+
+ const handleAngleUnits = (event: SelectChangeEvent) => {
+ setAngleUnits(event.target.value as AngleUnits);
+ };
+ const [quantity, setQuantity] = React.useState(
+ ScatteringQuantity.q,
+ );
+
+ const handleQuantity = (event: SelectChangeEvent) => {
+ setQuantity(event.target.value as ScatteringQuantity);
+ };
+
+ return (
+
+
+
+
+ Results bottom bar
+
+
+ Scattering quantity:
+
+ quantity
+
+
+
+ units
+
+
+
+ Min {quantity} value:
+ Max {quantity} value:
+ Requested min {quantity} value:
+ Requested max {quantity} value:
+
+
+
+
+ );
+}
diff --git a/src/sideMenu.tsx b/src/sideMenu.tsx
new file mode 100644
index 0000000..846b534
--- /dev/null
+++ b/src/sideMenu.tsx
@@ -0,0 +1,21 @@
+import Box from "@mui/material/Box";
+import List from "@mui/material/List";
+import Divider from "@mui/material/Divider";
+import ListItem from "@mui/material/ListItem";
+import { Button, Stack, Typography } from "@mui/material";
+
+export default function SideMenu() {
+ return (
+
+
+
+
+ Reset to default
+
+
+
+
+
+
+ );
+}
diff --git a/src/store.ts b/src/store.ts
new file mode 100644
index 0000000..c42d4a5
--- /dev/null
+++ b/src/store.ts
@@ -0,0 +1,15 @@
+import { configureStore } from "@reduxjs/toolkit";
+import { beamlineConfigReducer } from "./data-entry/configSlice";
+import { unitConfigReducer } from "./data-entry/unitSlice";
+
+const store = configureStore({
+ reducer: {
+ config: beamlineConfigReducer,
+ units: unitConfigReducer,
+ },
+});
+
+export default store;
+
+export type RootState = ReturnType;
+export type AppDispatch = typeof store.dispatch;
diff --git a/src/utils/types.ts b/src/utils/types.ts
index b90f0f8..f20dce0 100644
--- a/src/utils/types.ts
+++ b/src/utils/types.ts
@@ -1,9 +1,8 @@
import { Vector2 } from "three";
export interface Detector {
- name: string;
resolution: { height: number; width: number };
- pixel_size: { height: number; width: number };
+ pixel_size: number;
}
export interface CircularDevice {
@@ -12,11 +11,10 @@ export interface CircularDevice {
}
export interface BeamlineConfig {
- name: string | null
- detector: Detector;
- Beamstop: CircularDevice;
- CameraTube: CircularDevice;
- angle: number;
+ detector: string;
+ beamstop: CircularDevice;
+ cameraTube: CircularDevice;
+ angle: number | null;
cameraLength: number;
clearance: number; // remember to do int checks on this value
minWavelength: number;
diff --git a/src/utils/units.ts b/src/utils/units.ts
index 50aabfd..defbd61 100644
--- a/src/utils/units.ts
+++ b/src/utils/units.ts
@@ -1,22 +1,32 @@
-const mu = "\u03bc"
-const angstrum = "\u212B"
+const mu = "\u03bc";
+const angstrum = "\u212B";
export enum DistanceUnits {
- millimetre = "mm",
- micrometre = mu + "m",
+ millimetre = "mm",
+ micrometre = mu + "m",
}
export enum EnergyUnits {
- electronVolts = "eV",
- kiloElectronVolts = "keV",
+ electronVolts = "eV",
+ kiloElectronVolts = "keV",
}
export enum WavelengthUnits {
- nanmometres = "nm",
- angstroms = angstrum
+ nanmometres = "nm",
+ angstroms = angstrum,
}
export enum AngleUnits {
- radians = "rad",
- degrees = "deg",
-}
\ No newline at end of file
+ radians = "rad",
+ degrees = "deg",
+}
+
+export interface UnitConfig {
+ pixelSizeUnits: DistanceUnits;
+ beamEnergyUnits: EnergyUnits;
+ beamstopDiameterUnits: DistanceUnits;
+ clearanceDiameterUnits: DistanceUnits;
+ cameraDiameterUnits: DistanceUnits;
+ wavelengthUnits: WavelengthUnits;
+ angleUnits: AngleUnits;
+}