diff --git a/frontend/farm_designer/__tests__/three_d_garden_map_test.tsx b/frontend/farm_designer/__tests__/three_d_garden_map_test.tsx
index 5a5b0dc7f..0e95cadd6 100644
--- a/frontend/farm_designer/__tests__/three_d_garden_map_test.tsx
+++ b/frontend/farm_designer/__tests__/three_d_garden_map_test.tsx
@@ -1,9 +1,14 @@
import React from "react";
import { mount } from "enzyme";
import { ThreeDGardenMapProps, ThreeDGardenMap } from "../three_d_garden_map";
+import { fakeMapTransformProps } from "../../__test_support__/map_transform_props";
+import { fakeBotSize } from "../../__test_support__/fake_bot_data";
describe("", () => {
const fakeProps = (): ThreeDGardenMapProps => ({
+ mapTransformProps: fakeMapTransformProps(),
+ botSize: fakeBotSize(),
+ gridOffset: { x: 10, y: 10 },
});
it("renders", () => {
diff --git a/frontend/farm_designer/index.tsx b/frontend/farm_designer/index.tsx
index d43c37574..1fa5ae206 100755
--- a/frontend/farm_designer/index.tsx
+++ b/frontend/farm_designer/index.tsx
@@ -194,7 +194,10 @@ export class RawFarmDesigner
{this.props.getConfigValue(BooleanSetting.three_d_garden)
- ?
+ ?
:
{
- props;
- return
;
+ const config = clone(INITIAL);
+ const { gridSize } = props.mapTransformProps;
+ config.botSizeX = gridSize.x;
+ config.botSizeY = gridSize.y;
+ config.bedWidthOuter = gridSize.y + 160;
+ config.bedLengthOuter = gridSize.x + 160;
+
+ return
;
};
diff --git a/frontend/promo/__tests__/promo_test.tsx b/frontend/promo/__tests__/promo_test.tsx
index 39728c29b..8b1bdd3f8 100644
--- a/frontend/promo/__tests__/promo_test.tsx
+++ b/frontend/promo/__tests__/promo_test.tsx
@@ -1,11 +1,11 @@
import React from "react";
-import { shallow } from "enzyme";
+import { mount } from "enzyme";
import { Promo } from "../promo";
describe("
", () => {
it("renders", () => {
console.error = jest.fn();
- const wrapper = shallow(
);
+ const wrapper = mount(
);
expect(wrapper.html()).toContain("three-d-garden");
});
});
diff --git a/frontend/promo/promo.tsx b/frontend/promo/promo.tsx
index 71c89815d..70c179f57 100644
--- a/frontend/promo/promo.tsx
+++ b/frontend/promo/promo.tsx
@@ -1,5 +1,17 @@
import React from "react";
import { ThreeDGarden } from "../three_d_garden";
+import {
+ Config, INITIAL, modifyConfigsFromUrlParams,
-export const Promo = () =>
-
;
+} from "../three_d_garden/config";
+
+export const Promo = () => {
+ const [config, setConfig] = React.useState
(INITIAL);
+
+ React.useEffect(() => {
+ setConfig(modifyConfigsFromUrlParams(config));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []); // intentionally empty dependency array
+
+ return ;
+};
diff --git a/frontend/three_d_garden/__tests__/bed_test.tsx b/frontend/three_d_garden/__tests__/bed_test.tsx
new file mode 100644
index 000000000..24a178696
--- /dev/null
+++ b/frontend/three_d_garden/__tests__/bed_test.tsx
@@ -0,0 +1,27 @@
+import React from "react";
+import { mount } from "enzyme";
+import { INITIAL } from "../config";
+import { Bed, BedProps } from "../bed";
+import { clone } from "lodash";
+
+describe("", () => {
+ const fakeProps = (): BedProps => ({
+ config: clone(INITIAL),
+ });
+
+ it("renders bed", () => {
+ const p = fakeProps();
+ p.config.extraLegsX = 0;
+ const wrapper = mount();
+ expect(wrapper.html()).toContain("args=\"1500,50,50\"");
+ });
+
+ it("renders bed with extra legs", () => {
+ const p = fakeProps();
+ p.config.extraLegsX = 2;
+ p.config.extraLegsY = 2;
+ p.config.legsFlush = false;
+ const wrapper = mount();
+ expect(wrapper.html()).toContain("args=\"1500,50,50\"");
+ });
+});
diff --git a/frontend/three_d_garden/__tests__/components_test.tsx b/frontend/three_d_garden/__tests__/components_test.tsx
new file mode 100644
index 000000000..8aba8c89d
--- /dev/null
+++ b/frontend/three_d_garden/__tests__/components_test.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+import { mount } from "enzyme";
+import { AmbientLight, Mesh, PointLight } from "../components";
+import { AmbientLightProps, MeshProps, PointLightProps } from "@react-three/fiber";
+
+describe("", () => {
+ const fakeProps = (): AmbientLightProps => ({
+ intensity: 0.5,
+ });
+
+ it("adds props", () => {
+ const wrapper = mount();
+ expect(wrapper.props().intensity).toEqual(0.5);
+ });
+});
+
+describe("", () => {
+ const fakeProps = (): PointLightProps => ({
+ intensity: 0.5,
+ });
+
+ it("adds props", () => {
+ const wrapper = mount();
+ expect(wrapper.props().intensity).toEqual(0.5);
+ });
+});
+
+describe("", () => {
+ const fakeProps = (): MeshProps => ({
+ name: "mesh",
+ });
+
+ it("adds props", () => {
+ const wrapper = mount();
+ expect(wrapper.props().name).toEqual("mesh");
+ });
+});
diff --git a/frontend/three_d_garden/__tests__/config_test.ts b/frontend/three_d_garden/__tests__/config_test.ts
new file mode 100644
index 000000000..3ec339aaf
--- /dev/null
+++ b/frontend/three_d_garden/__tests__/config_test.ts
@@ -0,0 +1,76 @@
+import { clone } from "lodash";
+import { INITIAL, modifyConfig, modifyConfigsFromUrlParams } from "../config";
+
+describe("modifyConfig()", () => {
+ it("modifies config: lab", () => {
+ const initial = clone(INITIAL);
+ const result = modifyConfig(initial, { scene: "Lab" });
+ expect(initial.lab).toEqual(false);
+ expect(result.lab).toEqual(true);
+ expect(initial.clouds).toEqual(true);
+ expect(result.clouds).toEqual(false);
+ expect(initial.bedType).toEqual("Standard");
+ expect(result.bedType).toEqual("Mobile");
+ });
+
+ it("modifies config: lab XL", () => {
+ const initial = clone(INITIAL);
+ const result = modifyConfig(initial, {
+ scene: "Lab",
+ sizePreset: "Genesis XL",
+ });
+ expect(initial.bedType).toEqual("Standard");
+ expect(result.bedType).toEqual("Standard");
+ });
+
+ it("modifies config: Jr", () => {
+ const initial = clone(INITIAL);
+ const result = modifyConfig(initial, { sizePreset: "Jr" });
+ expect(initial.x).toEqual(300);
+ expect(result.x).toEqual(100);
+ });
+
+ it("modifies config: bedType", () => {
+ const initial = clone(INITIAL);
+ initial.bedZOffset = 100;
+ initial.bedType = "Mobile";
+ const result = modifyConfig(initial, { bedType: "Standard" });
+ expect(result.bedZOffset).toEqual(0);
+ });
+
+ it("resets config", () => {
+ const initial = clone(INITIAL);
+ initial.bedLengthOuter = 1;
+ const result = modifyConfig(initial, { otherPreset: "Reset all" });
+ expect(result.bedLengthOuter).toEqual(3000);
+ });
+
+ it("modifies config: preset", () => {
+ const initial = clone(INITIAL);
+ initial.bedHeight = 1;
+ const result = modifyConfig(initial, { otherPreset: "Initial" });
+ expect(result.bedHeight).toEqual(300);
+ });
+});
+
+describe("modifyConfigsFromUrlParams()", () => {
+ it("sets config scene", () => {
+ window.location.search = "?scene=Lab";
+ const initial = clone(INITIAL);
+ initial.lab = false;
+ const result = modifyConfigsFromUrlParams(initial);
+ expect(result.lab).toEqual(true);
+ });
+
+ it("sets other config", () => {
+ window.location.search = "?kit=JR&x=1&ground=true";
+ const initial = clone(INITIAL);
+ initial.sizePreset = "Genesis XL";
+ initial.x = 100;
+ initial.ground = false;
+ const result = modifyConfigsFromUrlParams(initial);
+ expect(result.sizePreset).toEqual("Jr");
+ expect(result.x).toEqual(1);
+ expect(result.ground).toEqual(true);
+ });
+});
diff --git a/frontend/three_d_garden/__tests__/index_test.tsx b/frontend/three_d_garden/__tests__/index_test.tsx
index 5304f2c66..7e65291e1 100644
--- a/frontend/three_d_garden/__tests__/index_test.tsx
+++ b/frontend/three_d_garden/__tests__/index_test.tsx
@@ -19,9 +19,12 @@ import {
} from "..";
import React from "react";
+import { INITIAL } from "../config";
+import { clone } from "lodash";
describe("", () => {
const fakeProps = (): ThreeDGardenProps => ({
+ config: clone(INITIAL),
});
it("renders", () => {
@@ -32,6 +35,7 @@ describe("", () => {
describe("", () => {
const fakeProps = (): ThreeDGardenModelProps => ({
+ config: clone(INITIAL),
});
it("renders model", () => {
diff --git a/frontend/three_d_garden/bed.tsx b/frontend/three_d_garden/bed.tsx
new file mode 100644
index 000000000..d9448783c
--- /dev/null
+++ b/frontend/three_d_garden/bed.tsx
@@ -0,0 +1,161 @@
+import React from "react";
+import { Box, Extrude } from "@react-three/drei";
+import { DoubleSide, Path, Shape } from "three";
+import { range } from "lodash";
+import { Config } from "./config";
+import { Group, MeshPhongMaterial } from "./components";
+
+const soil = (
+ Type: typeof Path | typeof Shape,
+ botSize: Record<"x" | "y" | "z" | "thickness", number>,
+): Path | Shape => {
+ const { x, y, thickness } = botSize;
+
+ const hole = new Type();
+ hole.moveTo(thickness, thickness);
+ hole.lineTo(thickness, y - thickness);
+ hole.lineTo(x - thickness, y - thickness);
+ hole.lineTo(x - thickness, thickness);
+ hole.lineTo(thickness, thickness);
+ return hole;
+};
+
+const bedStructure2D = (
+ botSize: Record<"x" | "y" | "z" | "thickness", number>,
+) => {
+ const { x, y } = botSize;
+ const shape = new Shape();
+
+ // outer edge
+ shape.moveTo(0, 0);
+ shape.lineTo(0, y);
+ shape.lineTo(x, y);
+ shape.lineTo(x, 0);
+ shape.lineTo(0, 0);
+
+ // inner edge
+ shape.holes.push(soil(Path, botSize));
+
+ return shape;
+};
+
+export interface BedProps {
+ config: Config;
+}
+
+export const Bed = (props: BedProps) => {
+ const {
+ bedWidthOuter, bedLengthOuter, botSizeZ, bedHeight, bedZOffset,
+ legSize, legsFlush, extraLegsX, extraLegsY,
+ soilHeight, ccSupportSize,
+ } = props.config;
+ const thickness = props.config.bedWallThickness;
+ const botSize = { x: bedLengthOuter, y: bedWidthOuter, z: botSizeZ, thickness };
+ const bedStartZ = 0;
+ const legXPositions = [
+ 0 + legSize / 2 + thickness,
+ ...(extraLegsX
+ ? range(0, bedLengthOuter, bedLengthOuter / (extraLegsX + 1)).slice(1)
+ : []),
+ bedLengthOuter - legSize / 2 - thickness,
+ ];
+ const legYPositions = (index: number) =>
+ [
+ 0 + legSize / 2 + thickness,
+ ...(extraLegsY && (index == 0 || index == (legXPositions.length - 1))
+ ? range(0, bedWidthOuter, bedWidthOuter / (extraLegsY + 1)).slice(1)
+ : []),
+ bedWidthOuter - legSize / 2 - thickness,
+ ];
+ const casterHeight = legSize * 1.375;
+
+ const Bed = ({ children }: { children: React.ReactElement }) =>
+
+ {children}
+ ;
+
+ const Soil = ({ children }: { children: React.ReactElement }) => {
+ const soilDepth = bedHeight + (soilHeight - 50) - soilHeight;
+ return
+ {children}
+ ;
+ };
+
+ const bedColor = "#ad7039";
+ return
+
+
+
+
+
+
+
+
+
+
+
+
+ {legXPositions.map((x, index) =>
+
+ {legYPositions(index).map(y => {
+ const legTopOffset = legsFlush ? bedHeight / 2 : bedHeight;
+ return
+
+
+
+ ;
+ })}
+ )}
+ ;
+};
diff --git a/frontend/three_d_garden/components.tsx b/frontend/three_d_garden/components.tsx
index 18cc9e443..954c54e5a 100644
--- a/frontend/three_d_garden/components.tsx
+++ b/frontend/three_d_garden/components.tsx
@@ -3,6 +3,7 @@ import {
AmbientLightProps,
DirectionalLightProps,
GroupProps,
+ MeshPhongMaterialProps,
MeshProps,
PointLightProps,
} from "@react-three/fiber";
@@ -24,3 +25,6 @@ export const Mesh = (props: MeshProps) =>
export const PointLight = (props: PointLightProps) =>
;
+
+export const MeshPhongMaterial = (props: MeshPhongMaterialProps) =>
+ ;
diff --git a/frontend/three_d_garden/config.ts b/frontend/three_d_garden/config.ts
new file mode 100644
index 000000000..e809ad295
--- /dev/null
+++ b/frontend/three_d_garden/config.ts
@@ -0,0 +1,410 @@
+export interface Config {
+ sizePreset: string;
+ bedType: string;
+ otherPreset: string;
+ label: string;
+ botSizeX: number;
+ botSizeY: number;
+ botSizeZ: number;
+ bedWallThickness: number;
+ bedHeight: number;
+ ccSupportSize: number;
+ x: number;
+ y: number;
+ z: number;
+ beamLength: number;
+ columnLength: number;
+ zAxisLength: number;
+ bedXOffset: number;
+ bedYOffset: number;
+ bedZOffset: number;
+ zGantryOffset: number;
+ bedWidthOuter: number;
+ bedLengthOuter: number;
+ legSize: number;
+ legsFlush: boolean;
+ extraLegsX: number;
+ extraLegsY: number;
+ bedBrightness: number;
+ soilBrightness: number;
+ soilHeight: number;
+ plants: string;
+ labels: boolean;
+ labelsOnHover: boolean;
+ ground: boolean;
+ grid: boolean;
+ axes: boolean;
+ trail: boolean;
+ tracks: boolean;
+ clouds: boolean;
+ sunInclination: number;
+ sunAzimuth: number;
+ perspective: boolean;
+ bot: boolean;
+ laser: boolean;
+ tool: string;
+ cableCarriers: boolean;
+ viewCube: boolean;
+ stats: boolean;
+ config: boolean;
+ zoom: boolean;
+ pan: boolean;
+ bounds: boolean;
+ threeAxes: boolean;
+ xyDimensions: boolean;
+ zDimension: boolean;
+ promoInfo: boolean;
+ solar: boolean;
+ utilitiesPost: boolean;
+ packaging: boolean;
+ lab: boolean;
+ people: boolean;
+ scene: string;
+ lowDetail: boolean;
+}
+
+export const INITIAL: Config = {
+ sizePreset: "Genesis",
+ bedType: "Standard",
+ otherPreset: "Initial",
+ label: "FarmBot Genesis v1.7",
+ botSizeX: 2720,
+ botSizeY: 1230,
+ botSizeZ: 500,
+ bedWallThickness: 40,
+ bedHeight: 300,
+ ccSupportSize: 50,
+ x: 300,
+ y: 700,
+ z: 200,
+ beamLength: 1500,
+ columnLength: 500,
+ zAxisLength: 1000,
+ bedXOffset: 140,
+ bedYOffset: 60,
+ bedZOffset: 0,
+ zGantryOffset: 140,
+ bedWidthOuter: 1360,
+ bedLengthOuter: 3000,
+ legSize: 100,
+ legsFlush: true,
+ extraLegsX: 1,
+ extraLegsY: 0,
+ bedBrightness: 8,
+ soilBrightness: 6,
+ soilHeight: 500,
+ plants: "Spring",
+ labels: false,
+ labelsOnHover: true,
+ ground: true,
+ grid: false,
+ axes: false,
+ trail: false,
+ tracks: true,
+ clouds: true,
+ sunInclination: 140,
+ sunAzimuth: 230,
+ perspective: true,
+ bot: true,
+ laser: false,
+ tool: "rotaryTool",
+ cableCarriers: true,
+ viewCube: false,
+ stats: false,
+ config: false,
+ zoom: false,
+ pan: false,
+ bounds: false,
+ threeAxes: false,
+ xyDimensions: false,
+ zDimension: false,
+ promoInfo: true,
+ solar: false,
+ utilitiesPost: true,
+ packaging: false,
+ lab: false,
+ people: false,
+ scene: "Outdoor",
+ lowDetail: false,
+};
+
+export const STRING_KEYS = [
+ "sizePreset", "bedType", "otherPreset", "label", "plants", "tool", "scene",
+];
+
+export const NUMBER_KEYS = [
+ "botSizeX", "botSizeY", "botSizeZ", "bedWallThickness", "bedHeight",
+ "ccSupportSize", "x", "y", "z", "beamLength", "columnLength", "zAxisLength",
+ "bedXOffset", "bedYOffset", "bedZOffset", "zGantryOffset", "bedWidthOuter",
+ "bedLengthOuter", "legSize", "extraLegsX", "extraLegsY", "bedBrightness",
+ "soilBrightness", "soilHeight", "sunInclination", "sunAzimuth",
+];
+
+export const BOOLEAN_KEYS = [
+ "legsFlush", "labels", "labelsOnHover", "ground", "grid", "axes", "trail",
+ "tracks", "clouds", "perspective", "bot", "laser", "cableCarriers",
+ "viewCube", "stats", "config", "zoom", "pan", "bounds", "threeAxes",
+ "xyDimensions", "zDimension", "promoInfo", "solar", "utilitiesPost",
+ "packaging", "lab", "people", "lowDetail",
+];
+
+export const PRESETS: Record = {
+ "Jr": {
+ ...INITIAL,
+ sizePreset: "Jr",
+ bedType: "Standard",
+ label: "FarmBot Jr",
+ botSizeX: 620,
+ botSizeY: 220,
+ botSizeZ: 250,
+ beamLength: 550,
+ columnLength: 300,
+ zAxisLength: 750,
+ bedXOffset: 140,
+ bedYOffset: 80,
+ zGantryOffset: 140,
+ bedWidthOuter: 400,
+ bedLengthOuter: 900,
+ extraLegsX: 0,
+ extraLegsY: 0,
+ soilHeight: 280,
+ tracks: true,
+ },
+ "Genesis": {
+ ...INITIAL,
+ sizePreset: "Genesis",
+ bedType: "Standard",
+ label: "FarmBot Genesis v1.7",
+ botSizeX: 2720,
+ botSizeY: 1230,
+ botSizeZ: 500,
+ beamLength: 1500,
+ columnLength: 500,
+ zAxisLength: 1000,
+ bedXOffset: 140,
+ bedYOffset: 60,
+ zGantryOffset: 140,
+ bedWidthOuter: 1360,
+ bedLengthOuter: 3000,
+ extraLegsX: 1,
+ extraLegsY: 0,
+ soilHeight: 500,
+ tracks: true,
+ },
+ "Genesis XL": {
+ ...INITIAL,
+ sizePreset: "Genesis XL",
+ bedType: "Standard",
+ label: "FarmBot Genesis XL v1.7",
+ botSizeX: 5720,
+ botSizeY: 2730,
+ botSizeZ: 500,
+ beamLength: 3000,
+ columnLength: 500,
+ zAxisLength: 1000,
+ bedXOffset: 140,
+ bedYOffset: 60,
+ zGantryOffset: 140,
+ bedWidthOuter: 2860,
+ bedLengthOuter: 6000,
+ extraLegsX: 3,
+ extraLegsY: 1,
+ soilHeight: 500,
+ tracks: true,
+ },
+ "Initial": INITIAL,
+ "Minimal": {
+ ...INITIAL,
+ bedWallThickness: 40,
+ bedHeight: 300,
+ x: 300,
+ y: 200,
+ z: 200,
+ ccSupportSize: 50,
+ legSize: 100,
+ legsFlush: false,
+ bedBrightness: 8,
+ soilBrightness: 6,
+ plants: "",
+ labels: false,
+ labelsOnHover: false,
+ ground: true,
+ grid: false,
+ axes: false,
+ trail: false,
+ clouds: false,
+ sunInclination: 90,
+ sunAzimuth: 0,
+ perspective: true,
+ bot: true,
+ laser: false,
+ tool: "",
+ cableCarriers: true,
+ viewCube: false,
+ stats: false,
+ config: false,
+ zoom: true,
+ pan: true,
+ bounds: false,
+ threeAxes: false,
+ xyDimensions: false,
+ zDimension: false,
+ promoInfo: false,
+ solar: false,
+ utilitiesPost: false,
+ packaging: false,
+ lab: false,
+ people: false,
+ scene: "Outdoor",
+ lowDetail: false,
+ },
+ "Maximal": {
+ ...INITIAL,
+ bedWallThickness: 40,
+ bedHeight: 300,
+ x: 300,
+ y: 200,
+ z: 200,
+ ccSupportSize: 50,
+ legSize: 100,
+ legsFlush: true,
+ bedBrightness: 8,
+ soilBrightness: 6,
+ plants: "Spring",
+ labels: true,
+ labelsOnHover: false,
+ ground: true,
+ grid: true,
+ axes: true,
+ trail: true,
+ clouds: true,
+ sunInclination: 30,
+ sunAzimuth: 45,
+ perspective: true,
+ bot: true,
+ laser: true,
+ tool: "",
+ cableCarriers: true,
+ viewCube: true,
+ stats: true,
+ config: true,
+ zoom: true,
+ pan: true,
+ bounds: true,
+ threeAxes: true,
+ xyDimensions: true,
+ zDimension: true,
+ promoInfo: true,
+ solar: true,
+ utilitiesPost: true,
+ packaging: true,
+ lab: true,
+ people: true,
+ scene: "outdoor",
+ lowDetail: false,
+ },
+};
+
+const SIZE_CONFIG_KEYS: (keyof Config)[] = [
+ "sizePreset", "label", "bedType",
+ "botSizeX", "botSizeY", "botSizeZ", "beamLength", "columnLength", "zAxisLength",
+ "bedXOffset", "bedYOffset", "zGantryOffset", "bedWidthOuter", "bedLengthOuter",
+ "extraLegsX", "extraLegsY", "soilHeight", "tracks",
+];
+
+const OTHER_CONFIG_KEYS: (keyof Config)[] = [
+ "bedWallThickness", "bedHeight", "x", "y", "z",
+ "ccSupportSize", "legSize", "legsFlush",
+ "bedBrightness", "soilBrightness", "plants", "labels", "ground", "grid", "axes",
+ "trail", "clouds", "sunInclination", "sunAzimuth", "perspective", "bot", "laser",
+ "tool", "cableCarriers", "viewCube", "stats", "config", "zoom", "bounds",
+ "threeAxes", "xyDimensions", "zDimension", "labelsOnHover", "promoInfo", "pan",
+ "solar", "utilitiesPost", "packaging", "lab", "people", "scene", "lowDetail",
+];
+
+export const modifyConfig = (config: Config, update: Partial) => {
+ const newConfig: Config = { ...config, ...update };
+ if (update.sizePreset) {
+ const presetConfig = PRESETS[update.sizePreset];
+ SIZE_CONFIG_KEYS.map(key => newConfig[key] = presetConfig[key] as never);
+ if (update.sizePreset == "Jr") {
+ newConfig.x = 100;
+ newConfig.y = 100;
+ newConfig.z = 50;
+ }
+ }
+ if (update.scene) {
+ newConfig.lab = update.scene == "Lab";
+ newConfig.clouds = update.scene != "Lab";
+ newConfig.people = update.scene == "Lab";
+ newConfig.bedType =
+ (update.scene == "Lab" && newConfig.sizePreset != "Genesis XL")
+ ? "Mobile"
+ : "Standard";
+ }
+ if (update.bedType || (newConfig.bedType != config.bedType)) {
+ newConfig.bedZOffset = newConfig.bedType == "Mobile" ? 500 : 0;
+ newConfig.legsFlush = newConfig.bedType != "Mobile";
+ }
+ if (update.otherPreset) {
+ if (update.otherPreset == "Reset all") {
+ Object.keys(config).map(key => {
+ const configKey = key as keyof Config;
+ newConfig[configKey] = INITIAL[configKey] as never;
+ });
+ } else {
+ const presetConfig = PRESETS[update.otherPreset];
+ OTHER_CONFIG_KEYS.map(key => newConfig[key] = presetConfig[key] as never);
+ }
+ }
+ return newConfig;
+};
+
+export const KIT_LOOKUP: { [x: string]: string } = {
+ "genesis": "Genesis",
+ "genesis_xl": "Genesis XL",
+ "jr": "Jr",
+};
+
+export const modifyConfigsFromUrlParams = (config: Config) => {
+ let newConfig: Config = { ...config };
+ const urlParams = new URLSearchParams(window.location.search);
+ const kit = urlParams.get("kit")?.toLowerCase();
+ if (kit) {
+ const sizePreset = KIT_LOOKUP[kit];
+ if (sizePreset && sizePreset != config.sizePreset) {
+ newConfig = modifyConfig(newConfig, { sizePreset });
+ }
+ }
+ STRING_KEYS.map(key => {
+ const value = urlParams.get(key);
+ if (value) {
+ newConfig = modifyConfig(newConfig, { [key]: value });
+ }
+ });
+ NUMBER_KEYS.map(key => {
+ const value = urlParams.get(key);
+ if (value) {
+ newConfig = modifyConfig(newConfig, { [key]: parseInt(value) });
+ }
+ });
+ BOOLEAN_KEYS.map(key => {
+ const value = urlParams.get(key);
+ if (value) {
+ newConfig = modifyConfig(newConfig, { [key]: value == "true" });
+ }
+ });
+ return newConfig;
+};
+
+type SeasonProperties = {
+ sunIntensity: number;
+ sunColor: string;
+ cloudOpacity: number;
+};
+export const seasonProperties: Record = {
+ Winter: { sunIntensity: 4 / 4, sunColor: "#A0C4FF", cloudOpacity: 0.85 },
+ Spring: { sunIntensity: 7 / 4, sunColor: "#BDE0FE", cloudOpacity: 0.2 },
+ Summer: { sunIntensity: 9 / 4, sunColor: "#FFFFFF", cloudOpacity: 0 },
+ Fall: { sunIntensity: 5.5 / 4, sunColor: "#FFD6BC", cloudOpacity: 0.3 },
+};
diff --git a/frontend/three_d_garden/index.tsx b/frontend/three_d_garden/index.tsx
index c05144943..9421354f5 100644
--- a/frontend/three_d_garden/index.tsx
+++ b/frontend/three_d_garden/index.tsx
@@ -1,25 +1,32 @@
-import { Circle, PerspectiveCamera, OrbitControls, Box } from "@react-three/drei";
+import { Circle, PerspectiveCamera, OrbitControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import React from "react";
import { AmbientLight, DirectionalLight } from "./components";
+import { Config } from "./config";
+import { Bed } from "./bed";
export interface ThreeDGardenProps {
+ config: Config;
}
export const ThreeDGarden = (props: ThreeDGardenProps) => {
- props;
return
;
};
export interface ThreeDGardenModelProps {
+ config: Config;
}
export const ThreeDGardenModel = (props: ThreeDGardenModelProps) => {
- props;
+ const mid = {
+ x: props.config.bedLengthOuter / 2,
+ y: props.config.bedWidthOuter / 2,
+ z: props.config.bedHeight,
+ };
return
{
rotation={[0, 0, 0]}
up={[0, 0, 1]} />
@@ -36,12 +43,7 @@ export const ThreeDGardenModel = (props: ThreeDGardenModelProps) => {
args={[30000, 16]}
position={[0, 0, -10]}>
-
-
-
+
;
};