From de5b493c77448bcf72e32be8b13a590b6e9d0a00 Mon Sep 17 00:00:00 2001 From: IDONTSUDO Date: Fri, 16 Feb 2024 14:16:35 +0300 Subject: [PATCH] mark debug --- .vscode/settings.json | 2 +- ui/src/core/extensions/extensions.ts | 6 + ui/src/core/extensions/number.ts | 8 + ui/src/core/extensions/object.ts | 7 + ui/src/core/model/core_vector3.ts | 17 ++ .../core/repository/core_three_repository.ts | 49 +++++- ui/src/core/repository/http_repository.ts | 3 + .../components/static_asset_item_view.tsx | 4 +- .../presentation/scene_manager.tsx | 64 ++++--- .../presentation/scene_manager_store.ts | 14 +- .../stick_objects_marking_screen.tsx | 133 ++++++++++++++ .../stick_objects_marking_store.tsx | 164 ++++++++++++++++++ .../stick_objects_marking_three_repository.ts | 96 ++++++++++ ui/src/index.tsx | 4 +- 14 files changed, 534 insertions(+), 37 deletions(-) create mode 100644 ui/src/core/extensions/number.ts create mode 100644 ui/src/core/extensions/object.ts create mode 100644 ui/src/core/model/core_vector3.ts create mode 100644 ui/src/features/stick_objects_marking/stick_objects_marking_screen.tsx create mode 100644 ui/src/features/stick_objects_marking/stick_objects_marking_store.tsx create mode 100644 ui/src/features/stick_objects_marking/stick_objects_marking_three_repository.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 30e0524..6581d96 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,6 +15,6 @@ "*ui": false, "*ui.*": false }, - "cSpell.words": ["antd", "Collada", "Contolls", "fileupload", "metadatas", "undici", "uuidv"], + "cSpell.words": ["antd", "Collada", "Contolls", "fileupload", "lerp", "metadatas", "undici", "uuidv"], "editor.rulers": [100] } diff --git a/ui/src/core/extensions/extensions.ts b/ui/src/core/extensions/extensions.ts index c21cb5b..2b7998c 100644 --- a/ui/src/core/extensions/extensions.ts +++ b/ui/src/core/extensions/extensions.ts @@ -1,5 +1,6 @@ import { ArrayExtensions } from "./array"; import { MapExtensions } from "./map"; +import { NumberExtensions } from "./number"; import { StringExtensions } from "./string"; export type CallBackVoidFunction = (value: T) => void; @@ -15,6 +16,9 @@ declare global { isNotEmpty(): boolean; hasIncludeElement(element: T): boolean; } + interface Number { + fromArray(): number[]; + } interface String { isEmpty(): boolean; isNotEmpty(): boolean; @@ -22,9 +26,11 @@ declare global { interface Map { addValueOrMakeCallback(key: K, value: V, callBack: CallBackVoidFunction): void; } + interface Vector3 {} } export const extensions = () => { ArrayExtensions(); StringExtensions(); + NumberExtensions(); MapExtensions(); }; diff --git a/ui/src/core/extensions/number.ts b/ui/src/core/extensions/number.ts new file mode 100644 index 0000000..565ced6 --- /dev/null +++ b/ui/src/core/extensions/number.ts @@ -0,0 +1,8 @@ +export const NumberExtensions = () => { + if (Number().fromArray === undefined) { + // eslint-disable-next-line no-extend-native + Number.prototype.fromArray = function () { + return Array.from(this.toString()).map((el) => Number(el)); + }; + } +}; diff --git a/ui/src/core/extensions/object.ts b/ui/src/core/extensions/object.ts new file mode 100644 index 0000000..acca8fd --- /dev/null +++ b/ui/src/core/extensions/object.ts @@ -0,0 +1,7 @@ +/* eslint-disable no-extend-native */ + +export const ObjectExtensionsIsKeyExists = (obj: any, keys: string[]): boolean => { + return true; +}; + +// {"objectThatSticksName":"cube2","objectThatSticksNamePoints":[{"x":25,"y":4.987889622413917,"z":10.504078531217838}],"objectsToWhichItSticksName":"cube1","objectsToWhichItSticksPoints":[{"x":5,"y":3.0783236330074963,"z":1.1333166084347885}]} diff --git a/ui/src/core/model/core_vector3.ts b/ui/src/core/model/core_vector3.ts new file mode 100644 index 0000000..c6e2b08 --- /dev/null +++ b/ui/src/core/model/core_vector3.ts @@ -0,0 +1,17 @@ +import { Vector3 } from "three"; + +export class CoreVector3 { + vector: Vector3; + constructor(vector: Vector3) { + this.vector = vector; + } + + static divideLineIntoEqualSegments(beginPoint: Vector3, endPoint: Vector3, segments: number): Vector3[] { + return Number(segments) + .fromArray() + .map((el) => new Vector3().lerpVectors(beginPoint, endPoint, (el * 1) / segments)); + } + add(vector: Vector3) { + return new CoreVector3(new Vector3(this.vector.x + vector.x, this.vector.y + vector.y, this.vector.z + vector.z)); + } +} diff --git a/ui/src/core/repository/core_three_repository.ts b/ui/src/core/repository/core_three_repository.ts index c240b48..1d82d30 100644 --- a/ui/src/core/repository/core_three_repository.ts +++ b/ui/src/core/repository/core_three_repository.ts @@ -21,6 +21,9 @@ import { Quaternion, MeshBasicMaterial, PlaneGeometry, + BoxGeometry, + BufferGeometry, + Line, } from "three"; import { TypedEvent } from "../helper/typed_event"; import { Result } from "../helper/result"; @@ -37,10 +40,12 @@ import { RobossemblerAssets, SceneSimpleObject, } from "../../features/scene_manager/model/robossembler_assets"; +import { CoreVector3 } from "../model/core_vector3"; export enum UserData { selectedObject = "selected_object", cameraInitialization = "camera_initialization", + objectForMagnetism = "object_for_magnetism", } interface IEventDraggingChange { @@ -95,7 +100,39 @@ export class CoreThreeRepository extends TypedEvent { this.init(); } + drawPoint(point: Vector3): Mesh { + var cube = new Mesh(new BoxGeometry(0.5, 0.5, 0.5), new MeshBasicMaterial({ color: 0x0095dd })); + cube.position.add(point); + this.scene.add(cube); + return cube; + } + makeCube(inc: number, vector?: Vector3, color?: string, size?: number) { + const cube = new Mesh( + new BoxGeometry(size ?? 10, size ?? 10, size ?? 10), + new MeshBasicMaterial({ color: color ?? 0x0095dd, transparent: true, opacity: 0.5 }) + ); + cube.userData[UserData.objectForMagnetism] = true; + cube.userData[UserData.selectedObject] = true; + cube.name = "cube" + String(inc); + if (vector) { + cube.position.copy(vector); + } + this.scene.add(cube); + } + makePoint(vector?: Vector3, color?: string, size?: number) { + const cube = new Mesh( + new BoxGeometry(size ?? 10, size ?? 10, size ?? 10), + new MeshBasicMaterial({ color: color ?? 0x0095dd, transparent: true, opacity: 0.5 }) + ); + cube.userData[UserData.objectForMagnetism] = true; + cube.userData[UserData.selectedObject] = true; + + if (vector) { + cube.position.copy(vector); + } + this.scene.add(cube); + } deleteSceneItem(item: BaseSceneItemModel) { const updateScene = this.scene; updateScene.children = item.deleteToScene(updateScene); @@ -205,12 +242,12 @@ export class CoreThreeRepository extends TypedEvent { } light() { - const directionalLight = new DirectionalLight(0xffffff, 0.2); - directionalLight.castShadow = true; - directionalLight.position.set(-1, 2, 4); - this.scene.add(directionalLight); const ambientLight = new AmbientLight(0xffffff, 0.7); this.scene.add(ambientLight); + + this.scene.add(new AmbientLight(0x222222)); + + this.scene.add(new DirectionalLight(0xffffff, 1)); } addListeners() { @@ -252,7 +289,11 @@ export class CoreThreeRepository extends TypedEvent { new MeshBasicMaterial({ color: 0x808080, wireframe: true }) ); planeMesh.userData[UserData.selectedObject] = true; + planeMesh.userData[UserData.objectForMagnetism] = true; planeMesh.rotation.x = -Math.PI / 2; + this.makeCube(1); + this.makeCube(2, new Vector3(20, 0, 10), "yellow"); + this.scene.add(planeMesh); } diff --git a/ui/src/core/repository/http_repository.ts b/ui/src/core/repository/http_repository.ts index dc6b2ef..bd48284 100644 --- a/ui/src/core/repository/http_repository.ts +++ b/ui/src/core/repository/http_repository.ts @@ -17,6 +17,7 @@ export class HttpError extends Error { export class HttpRepository { private server = "http://localhost:4001"; + public async _formDataRequest(method: HttpMethod, url: string, data?: any): Promise> { let formData = new FormData(); formData.append("file", data); @@ -32,6 +33,7 @@ export class HttpRepository { } return Result.ok(response.text as T); } + public async _jsonRequest(method: HttpMethod, url: string, data?: any): Promise> { try { const reqInit = { @@ -69,6 +71,7 @@ export class HttpRepository { } return Result.ok(response.text as T); } + public async _jsonToClassInstanceRequest( method: HttpMethod, url: string, diff --git a/ui/src/features/scene_manager/presentation/components/static_asset_item_view.tsx b/ui/src/features/scene_manager/presentation/components/static_asset_item_view.tsx index 040faba..80634a3 100644 --- a/ui/src/features/scene_manager/presentation/components/static_asset_item_view.tsx +++ b/ui/src/features/scene_manager/presentation/components/static_asset_item_view.tsx @@ -15,7 +15,7 @@ export function StaticAssetModelView(props: IStaticAssetModelViewProps) { backgroundColor: "ActiveBorder", padding: "10px", color: "white", - width: "100px", + textAlignLast: "center", }} > @@ -32,7 +32,7 @@ export function StaticAssetModelView(props: IStaticAssetModelViewProps) { backgroundColor: "brown", padding: "10px", color: "white", - width: "100px", + textAlignLast: "center", }} > diff --git a/ui/src/features/scene_manager/presentation/scene_manager.tsx b/ui/src/features/scene_manager/presentation/scene_manager.tsx index db927ed..47e2884 100644 --- a/ui/src/features/scene_manager/presentation/scene_manager.tsx +++ b/ui/src/features/scene_manager/presentation/scene_manager.tsx @@ -13,22 +13,24 @@ export const SceneManagerPath = "/scene/manager/"; export const SceneManger = observer(() => { const canvasRef = React.useRef(null); - const [sceneMangerStore] = React.useState(() => new SceneMangerStore()); + const [store] = React.useState(() => new SceneMangerStore()); const id = useParams().id as string; React.useEffect(() => { - sceneMangerStore.init(); - sceneMangerStore.loadScene(id, canvasRef.current!); + store.init(); + store.loadScene(id, canvasRef.current!); document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = "scroll"; - sceneMangerStore.dispose(); + store.dispose(); }; - }, [id, sceneMangerStore]); + }, [id, store]); - const sceneIcons: SceneManagerView[] = Object.values(SceneMode).map((el) => { - return { name: el, clickHandel: () => sceneMangerStore.setSceneMode(el as SceneMode) }; - }); + const sceneIcons: SceneManagerView[] = Object.values(SceneMode) + .filter((el) => el !== SceneMode.EMPTY) + .map((el) => { + return { name: el, clickHandel: () => store.setSceneMode(el as SceneMode) }; + }); return (
@@ -48,8 +50,7 @@ export const SceneManger = observer(() => { return (
{ el.clickHandel(); @@ -70,25 +71,25 @@ export const SceneManger = observer(() => { }} >
Scene manager
- {sceneMangerStore.isVisibleSaveButton ? ( + {store.isVisibleSaveButton ? ( <> - + ) : ( <> )} - {sceneMangerStore.isLoading ? <>Loading... : <>} - {sceneMangerStore.sceneMode === SceneMode.ADD_CAMERA ? ( + {store.isLoading ? <>Loading... : <>} + {store.sceneMode === SceneMode.ADD_CAMERA ? (
{ - sceneMangerStore.addNewCamera(model); + store.addNewCamera(model); actions.setSubmitting(false); actions.resetForm(); }} validate={(model) => { - return model.validate(sceneMangerStore.getCameraLinkNames()); + return model.validate(store.getCameraLinkNames()); }} render={() => (
@@ -115,19 +116,19 @@ export const SceneManger = observer(() => { ) : ( <> )} - {sceneMangerStore.sceneMode === SceneMode.MOVING || SceneMode.ROTATE ? ( + {store.sceneMode === SceneMode.MOVING || SceneMode.ROTATE ? ( <> - {sceneMangerStore.robossemblerAssets?.assets.map((el) => { + {store.robossemblerAssets?.assets.map((el) => { return (
{el.name} - {sceneMangerStore.isRenderedAsset(el.name) ? ( + {store.isRenderedAsset(el.name) ? ( <> ) : (
- {sceneMangerStore.sceneModels.map((el) => { - return sceneMangerStore.deleteSceneItem(el)} model={el} />; + {store.sceneModels.map((el) => { + return store.deleteSceneItem(el)} model={el} />; })}
-
{sceneMangerStore.sceneMode === SceneMode.MAGNETISM_MARKING ? <> : <>}
+ + {store.sceneMode === SceneMode.MAGNETISM_MARKING ? ( + <> +
+
completion of objects
+
+ {store.objectMagnetism ? ( + <>{store.objectMagnetism} + ) : ( + + )} + {store.objectForMagnetism ? <>{store.objectForMagnetism} : } +
+
+ + ) : ( + <> + )}
); diff --git a/ui/src/features/scene_manager/presentation/scene_manager_store.ts b/ui/src/features/scene_manager/presentation/scene_manager_store.ts index 78df48f..2093419 100644 --- a/ui/src/features/scene_manager/presentation/scene_manager_store.ts +++ b/ui/src/features/scene_manager/presentation/scene_manager_store.ts @@ -1,6 +1,6 @@ import makeAutoObservable from "mobx-store-inheritance"; -import { CoreThreeRepository } from "../../../core/repository/core_three_repository"; -import { Object3D, Vector2 } from "three"; +import { CoreThreeRepository, UserData } from "../../../core/repository/core_three_repository"; +import { Object3D, Vector2, Vector3 } from "three"; import { HttpError } from "../../../core/repository/http_repository"; import { UiErrorState } from "../../../core/store/base_store"; import { UiBaseError } from "../../../core/model/ui_base_error"; @@ -19,6 +19,8 @@ export class SceneMangerStore extends UiErrorState { sceneModels: BaseSceneItemModel[] = []; isSceneMenuShow = false; robossemblerAssets?: RobossemblerAssets; + objectForMagnetism: string; + objectMagnetism: string; constructor() { super(); @@ -129,14 +131,14 @@ export class SceneMangerStore extends UiErrorState { } clickLister(event: MouseEvent) { + const vector = new Vector2(); + vector.x = (event.clientX / window.innerWidth) * 2 - 1; + vector.y = -(event.clientY / window.innerHeight) * 2 + 1; if (this.sceneMode === SceneMode.EMPTY) { return; } - if (this.sceneMode === SceneMode.MOVING || this.sceneMode === SceneMode.ROTATE) { - const vector = new Vector2(); - vector.x = (event.clientX / window.innerWidth) * 2 - 1; - vector.y = -(event.clientY / window.innerHeight) * 2 + 1; + if (this.sceneMode === SceneMode.MOVING || this.sceneMode === SceneMode.ROTATE) { this.transformContollsCall(vector); } } diff --git a/ui/src/features/stick_objects_marking/stick_objects_marking_screen.tsx b/ui/src/features/stick_objects_marking/stick_objects_marking_screen.tsx new file mode 100644 index 0000000..74d0056 --- /dev/null +++ b/ui/src/features/stick_objects_marking/stick_objects_marking_screen.tsx @@ -0,0 +1,133 @@ +import * as React from "react"; +import { observer } from "mobx-react-lite"; +import { useParams } from "react-router-dom"; +import { Button } from "antd"; +import { StickObjectsMarkingStore, StickObjectsMarkingStoreMode } from "./stick_objects_marking_store"; +import { Vector3 } from "three"; + +export const StickObjectsMarking = "/stick/objects/marking"; +interface StickButtonsProps { + isVisible: boolean; + name: string; + groupMode: StickObjectsMarkingStoreMode; + storeMode: StickObjectsMarkingStoreMode; + storeModePoints: StickObjectsMarkingStoreMode; + setMode: Function; + setPointMode: Function; + points: Vector3[]; + body: string; +} + +export const StickButtons: React.FunctionComponent = observer((props) => { + return ( + <> + {props.isVisible ? ( + <> + {props.name} + + {props.points.map((el) => { + return ( + <> + {el.x} {el.y} {el.z} + + ); + })} + + ) : ( + + )} + + ); +}); + +export const StickObjectsMarkingScreen = observer(() => { + const canvasRef = React.useRef(null); + const [store] = React.useState(() => new StickObjectsMarkingStore()); + const id = useParams().id as string; + + React.useEffect(() => { + store.init(); + store.loadScene(canvasRef.current!); + document.body.style.overflow = "hidden"; + return () => { + document.body.style.overflow = "scroll"; + store.dispose(); + }; + }, [id, store]); + + return ( +
+ +
+
+ {Object.keys(store.points).map((el) => { + // @ts-expect-error + const v = store.points[el]; + return ( + <> +
+ {el as string}:{v} +
+ + ); + })} +
Marking objects for sticking
+
+ store.setMode(StickObjectsMarkingStoreMode.objectThatSticks)} + groupMode={StickObjectsMarkingStoreMode.objectThatSticks} + name={store.objectThatSticksName} + storeModePoints={StickObjectsMarkingStoreMode.addPointsObjectThatSticks} + isVisible={store.objectThatSticksName !== undefined} + setPointMode={() => store.setMode(StickObjectsMarkingStoreMode.addPointsObjectThatSticks)} + points={store.objectThatSticksNamePoints} + body="objectThatSticksName" + /> + store.setMode(StickObjectsMarkingStoreMode.objectsToWhichItSticks)} + groupMode={StickObjectsMarkingStoreMode.objectsToWhichItSticks} + name={store.objectsToWhichItSticksName} + storeModePoints={StickObjectsMarkingStoreMode.addPointsObjectsToWhichItSticks} + isVisible={store.objectsToWhichItSticksName !== undefined} + setPointMode={() => store.setMode(StickObjectsMarkingStoreMode.addPointsObjectsToWhichItSticks)} + /> + + +
+
+
+
+ ); +}); diff --git a/ui/src/features/stick_objects_marking/stick_objects_marking_store.tsx b/ui/src/features/stick_objects_marking/stick_objects_marking_store.tsx new file mode 100644 index 0000000..644f9f1 --- /dev/null +++ b/ui/src/features/stick_objects_marking/stick_objects_marking_store.tsx @@ -0,0 +1,164 @@ +import makeAutoObservable from "mobx-store-inheritance"; +import { Box3, Vector2, Vector3 } from "three"; +import { UiErrorState } from "../../core/store/base_store"; +import { HttpError } from "../../core/repository/http_repository"; +import { UiBaseError } from "../../core/model/ui_base_error"; +import { RobossemblerFiles } from "../scene_manager/model/scene_assets"; +import { StickObjectsMarkingThreeRepository } from "./stick_objects_marking_three_repository"; +import { UserData } from "../../core/repository/core_three_repository"; +import { ObjectExtensionsIsKeyExists } from "../../core/extensions/object"; + +export enum StickObjectsMarkingStoreMode { + objectsToWhichItSticks = "objectsToWhichItSticks", + objectThatSticks = "objectThatSticks", + addPointsObjectsToWhichItSticks = "addPointsObjectsToWhichItSticks", + addPointsObjectThatSticks = "addPointsObjectThatSticks", + move = "move", +} + +export class StickyHelper { + objectThatSticksName: string; + objectThatSticksNamePoints: Vector3[] = []; + objectsToWhichItSticksName: string; + objectsToWhichItSticksPoints: Vector3[] = []; + + constructor( + objectThatSticksName: string, + objectThatSticksNamePoints: Vector3[], + objectsToWhichItSticksName: string, + objectsToWhichItSticksPoints: Vector3[] + ) { + this.objectThatSticksName = objectThatSticksName; + this.objectThatSticksNamePoints = objectThatSticksNamePoints; + this.objectsToWhichItSticksName = objectsToWhichItSticksName; + this.objectsToWhichItSticksPoints = objectsToWhichItSticksPoints; + } +} + +export class StickObjectsMarkingStore extends UiErrorState { + mode: StickObjectsMarkingStoreMode; + stickObjectsMarkingThreeRepository: null | StickObjectsMarkingThreeRepository = null; + objectThatSticksName: string; + objectThatSticksNamePoints: Vector3[] = []; + objectsToWhichItSticksName: string; + objectsToWhichItSticksPoints: Vector3[] = []; + points = {}; + constructor() { + super(); + makeAutoObservable(this); + this.points = {}; + this.mode = StickObjectsMarkingStoreMode.move; + this.loadStickyJSON( + '{"objectThatSticksName":"cube2","objectThatSticksNamePoints":[{"x":5,"y":-0.5419443937360455,"z":0.041458499858311626}],"objectsToWhichItSticksName":"cube1","objectsToWhichItSticksPoints":[{"x":-5,"y":-2.2134708060033113,"z":1.1937718220731925}]}' + ); + } + updatePoint = (key: string, value: any) => { + // @ts-expect-error + this.points[key] = value; + }; + onSaveSticky(): void { + window.prompt( + "Copy to clipboard: Ctrl+C, Enter", + JSON.stringify( + new StickyHelper( + this.objectThatSticksName, + this.objectThatSticksNamePoints, + this.objectsToWhichItSticksName, + this.objectsToWhichItSticksPoints + ) + ) + ); + } + setMode(stickObjectsMarkingStoreMode: StickObjectsMarkingStoreMode): void { + this.mode = stickObjectsMarkingStoreMode; + } + + loaderWatcher() {} + + async init(): Promise {} + + errorHandingStrategy = (error: HttpError) => { + if (error.status === 404) { + this.errors.push(new UiBaseError(`${RobossemblerFiles.robossemblerAssets} not found to project`)); + } + }; + + async loadScene(canvasRef: HTMLCanvasElement) { + this.loadWebGl(canvasRef); + } + watcherSceneEditorObject() {} + loadWebGl(canvasRef: HTMLCanvasElement): void { + this.stickObjectsMarkingThreeRepository = new StickObjectsMarkingThreeRepository( + canvasRef as HTMLCanvasElement, + this.watcherSceneEditorObject, + this.updatePoint + ); + this.stickObjectsMarkingThreeRepository.stickyHelperLoader([ + new StickyHelper( + this.objectThatSticksName, + this.objectThatSticksNamePoints, + this.objectsToWhichItSticksName, + this.objectsToWhichItSticksPoints + ), + ]); + this.stickObjectsMarkingThreeRepository.render(); + window.addEventListener("click", (event) => this.clickLister(event)); + } + + clickLister(event: MouseEvent) { + const vector = new Vector2(); + vector.x = (event.clientX / window.innerWidth) * 2 - 1; + vector.y = -(event.clientY / window.innerHeight) * 2 + 1; + if (this.mode) { + if (this.mode === StickObjectsMarkingStoreMode.move) { + this.stickObjectsMarkingThreeRepository?.setRayCastAndGetFirstObject(vector).fold( + (success) => this.stickObjectsMarkingThreeRepository?.setTransformControlsAttach(success), + (_error) => this.stickObjectsMarkingThreeRepository?.disposeTransformControlsMode() + ); + } + this.stickObjectsMarkingThreeRepository?.setRayCast(vector).map((touch) => { + const objectMagnetism = touch.filter((el) => el.object.userData[UserData.objectForMagnetism] === true); + const BoundBoxVector = new Box3().setFromObject(objectMagnetism[0].object).getCenter(new Vector3()); + const centerRelativeVector = new Vector3().subVectors(BoundBoxVector, objectMagnetism[0].point); + if (objectMagnetism.isNotEmpty()) { + if (this.mode === StickObjectsMarkingStoreMode.objectsToWhichItSticks) { + this.objectsToWhichItSticksName = objectMagnetism[0].object.name; + } + if (this.mode === StickObjectsMarkingStoreMode.objectThatSticks) { + this.objectThatSticksName = objectMagnetism[0].object.name; + } + if (this.mode === StickObjectsMarkingStoreMode.addPointsObjectThatSticks) { + this.objectThatSticksNamePoints.push(centerRelativeVector); + } + if (this.mode === StickObjectsMarkingStoreMode.addPointsObjectsToWhichItSticks) { + this.objectsToWhichItSticksPoints.push(centerRelativeVector); + } + } + }); + } + } + + dispose() { + window.removeEventListener("click", this.clickLister); + } + loadStickyJSON(value: string): void { + const object = JSON.parse(value) as Object; + if ( + ObjectExtensionsIsKeyExists(object, [ + "objectThatSticksName", + "objectThatSticksNamePoints", + "objectsToWhichItSticksName", + "objectsToWhichItSticksPoints", + ]) + ) { + // @ts-expect-error + this.objectThatSticksName = object["objectThatSticksName"]; + // @ts-expect-error + this.objectThatSticksNamePoints = object["objectThatSticksNamePoints"]; + // @ts-expect-error + this.objectsToWhichItSticksName = object["objectsToWhichItSticksName"]; + // @ts-expect-error + this.objectsToWhichItSticksPoints = object["objectsToWhichItSticksPoints"]; + } + } +} diff --git a/ui/src/features/stick_objects_marking/stick_objects_marking_three_repository.ts b/ui/src/features/stick_objects_marking/stick_objects_marking_three_repository.ts new file mode 100644 index 0000000..58f986a --- /dev/null +++ b/ui/src/features/stick_objects_marking/stick_objects_marking_three_repository.ts @@ -0,0 +1,96 @@ +import { Box3, BoxGeometry, Mesh, MeshBasicMaterial, Object3D, Vector3 } from "three"; +import { CoreThreeRepository } from "../../core/repository/core_three_repository"; +import { StickyHelper } from "./stick_objects_marking_store"; +import { CoreVector3 } from "../../core/model/core_vector3"; + +export class StickObjectsMarkingThreeRepository extends CoreThreeRepository { + stickyObjects: StickyHelper[]; + updatePoint: Function; + constructor(htmlCanvasRef: HTMLCanvasElement, watcherSceneEditorObject: Function, updatePoint: Function) { + super(htmlCanvasRef, watcherSceneEditorObject); + this.updatePoint = updatePoint; + this.sceneWatcher(); + } + + getStickyObject(name: string, pointNameHelper: string, index: number) { + const objectThatSticksNameMesh = this.scene.getObjectByName(name); + const pointName = objectThatSticksNameMesh!.name + ":point:" + index + pointNameHelper; + return this.scene.getObjectByName(pointName); + } + + mapperStickyObject(point: Vector3, index: number, name: string, pointNameHelper: string) { + const objectThatSticksNameMesh = this.scene.getObjectByName(name); + const pointName = objectThatSticksNameMesh!.name + ":point:" + index + pointNameHelper; + const sceneObject = this.scene.getObjectByName(pointName); + let pointMesh: Object3D; + if (sceneObject) { + pointMesh = sceneObject; + } else { + pointMesh = new Mesh(new BoxGeometry(1.1, 1.1, 1.1), new MeshBasicMaterial({ color: "#8BC34A" })); + } + pointMesh.position.copy(new Box3().setFromObject(objectThatSticksNameMesh!).getCenter(new Vector3()).add(point)); + pointMesh.name = pointName; + if (sceneObject === undefined) this.scene.add(pointMesh); + } + + stickyHelperLoader(stickyObjects: StickyHelper[]) { + this.stickyObjects = stickyObjects; + + stickyObjects.forEach((el) => { + el.objectThatSticksNamePoints.forEach((point, index) => + this.mapperStickyObject(point, index, el.objectThatSticksName, "objectThatSticksNamePoints") + ); + el.objectsToWhichItSticksPoints.forEach((point, index) => + this.mapperStickyObject(point, index, el.objectsToWhichItSticksName, "objectsToWhichItSticksPoints") + ); + }); + } + + sceneWatcher() { + this.transformControls.addEventListener("objectChange", (event) => { + //@ts-expect-error + const sceneActiveObject = event.target.object as Mesh; + + this.stickyObjects.forEach((stickyHelper) => { + if (sceneActiveObject.name === stickyHelper.objectThatSticksName) { + //локальные векторы точек + const objectThatSticksName = stickyHelper.objectThatSticksNamePoints[0]; + const objectsToWhichItSticksPoint = stickyHelper.objectsToWhichItSticksPoints[0]; + //глобальные векторы обьектов + const globalVectorObjStickyName = this.scene.getObjectByName(stickyHelper.objectThatSticksName); + const globalVectorObjToWhichSticks = this.scene.getObjectByName( + stickyHelper.objectsToWhichItSticksName + )!.position; + + //глобальные векторы точек + const objectThatSticksNamePosition = new CoreVector3(globalVectorObjStickyName!.position).add( + objectThatSticksName + ).vector; + const objectsToWhichItSticksNamePosition = new CoreVector3(globalVectorObjToWhichSticks).add( + objectsToWhichItSticksPoint + ).vector; + + this.updatePoint("objectThatSticksNamePosition", JSON.stringify(objectThatSticksNamePosition)); + this.updatePoint("objectsToWhichItSticksNamePosition", JSON.stringify(objectsToWhichItSticksNamePosition)); + const distance = objectThatSticksNamePosition.distanceTo(objectsToWhichItSticksNamePosition); + this.updatePoint("distnace", JSON.stringify(distance)); + + const pos = objectThatSticksNamePosition.sub(objectsToWhichItSticksNamePosition); + this.updatePoint("position", pos); + if (distance < 20) { + this.transformControls.detach(); + return; + } + if (distance < 1000) { + this.scene.getObjectByName(stickyHelper.objectsToWhichItSticksName)?.position.copy(pos); + + this.updatePoint( + "update", + JSON.stringify(objectThatSticksNamePosition.sub(objectsToWhichItSticksNamePosition)) + ); + } + } + }); + }); + } +} diff --git a/ui/src/index.tsx b/ui/src/index.tsx index cb9bf12..22ce2c7 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -10,6 +10,7 @@ import { RouterProvider } from "react-router-dom"; import { router } from "./core/routers/routers"; import { SceneManger } from "./features/scene_manager/presentation/scene_manager"; import { BehaviorTreeBuilderScreen } from "./features/behavior_tree_builder/presentation/behavior_tree_builder_screen"; +import { StickObjectsMarkingScreen } from "./features/stick_objects_marking/stick_objects_marking_screen"; extensions(); const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement); @@ -21,7 +22,8 @@ root.render( {/* */} <> - + {/* */} + {/* */}