This commit is contained in:
IDONTSUDO 2024-07-03 15:25:51 +03:00
parent 559262db34
commit 50822a031d
65 changed files with 7738 additions and 1412 deletions

View file

@ -3,10 +3,10 @@
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="12" "strokeWidth="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>strokeWidth
<g id="SVGRepo_bgCarrier" strokeWidth="0"/>strokeWidth
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"/>
<g id="SVGRepo_iconCarrier"> <g id="Interface / Check"> <path id="Vector" d="M6 12L10.2426 16.2426L18.727 7.75732" stroke="#f8f9fa" stroke-width="2" strokeLinecap="round" strokeLinejoin="round"/> </g> </g>
<g id="SVGRepo_iconCarrier"> <g id="Interface / Check"> <path id="Vector" d="M6 12L10.2426 16.2426L18.727 7.75732" stroke="#f8f9fa" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> </g> </g>
</svg>

Before

Width:  |  Height:  |  Size: 638 B

After

Width:  |  Height:  |  Size: 636 B

Before After
Before After

View file

@ -3,7 +3,7 @@
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="6strokeWidth="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_bgCarrier" strokeWidth="0"/>
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"/>

Before

Width:  |  Height:  |  Size: 661 B

After

Width:  |  Height:  |  Size: 660 B

Before After
Before After

View file

@ -34,6 +34,7 @@ declare global {
isNegative(): boolean;
isEven(): boolean;
isOdd(): boolean;
isEqualR(num: number): Result<void, void>;
}
interface String {
@ -45,6 +46,7 @@ declare global {
hasPattern(pattern: string): boolean;
hasNoPattern(pattern: string): boolean;
divideByIndex(index: number): string[];
isEqualR(str: string): Result<void, string>;
}
interface Map<K, V> {

View file

@ -1,3 +1,5 @@
import { Result } from "../helper/result";
export const NumberExtensions = () => {
if (Number().fromArray === undefined) {
Number.prototype.fromArray = function () {
@ -15,6 +17,14 @@ export const NumberExtensions = () => {
return `${date.getUTCFullYear()}.${date.getMonth()}.${date.getDay()} ${date.getHours()}:${date.getMinutes()}`;
};
}
if (Number().isEqualR === undefined) {
Number.prototype.isEqualR = function (num) {
if(this === num) {
return Result.ok(undefined)
}
return Result.error(undefined)
};
}
if (Number().isValid === undefined) {
Number.prototype.isValid = function (str: string) {
return !isNaN(Number(str));

View file

@ -1,3 +1,5 @@
import { Result } from "../helper/result";
/* eslint-disable no-extend-native */
export const StringExtensions = () => {
if ("".isEmpty === undefined) {
@ -10,6 +12,14 @@ export const StringExtensions = () => {
return this.length !== 0;
};
}
if ("".isEqualR === undefined) {
String.prototype.isEqualR = function (str) {
if (this === str) {
return Result.ok(String(this));
}
return Result.error(undefined);
};
}
if ("".replaceMany === undefined) {
String.prototype.replaceMany = function (searchValues: string[], replaceValue: string) {
let result = this as string;
@ -44,13 +54,13 @@ export const StringExtensions = () => {
return !this.hasPattern(pattern);
};
}
if (''.divideByIndex === undefined) {
if ("".divideByIndex === undefined) {
String.prototype.divideByIndex = function (index) {
if (this.at(index) === undefined) {
return []
return [];
}
return [this.slice(0, index), this.slice(index+1, this.length)]
}
return [this.slice(0, index), this.slice(index + 1, this.length)];
};
}
};

View file

@ -0,0 +1,3 @@
export enum SpawnPositionTypes {
BoundBox = "BoundBox",
}

View file

@ -1,36 +1,36 @@
import { Scene, Engine, MeshBuilder, FreeCamera, HemisphericLight, Vector3, SceneLoader } from 'babylonjs';
import { GLTFFileLoader } from 'babylonjs-loaders';
// import { Scene, Engine, MeshBuilder, FreeCamera, HemisphericLight, Vector3, SceneLoader } from 'babylonjs';
// import { GLTFFileLoader } from 'babylonjs-loaders';
export class BabylonRepository {
engine: Engine;
canvas: HTMLCanvasElement;
scene: Scene;
sceneLoader: SceneLoader
constructor(canvas: HTMLCanvasElement) {
this.sceneLoader = new SceneLoader();
this.engine = new Engine(canvas, true);
this.scene = new Scene(this.engine);
this.engine.runRenderLoop(() => {
this.scene.render();
});
this.scene.createDefaultCameraOrLight(true, true, true);
new HemisphericLight("hemiLight", new Vector3(0, 1, 0));
SceneLoader.RegisterPlugin(new GLTFFileLoader())
SceneLoader.ImportMeshAsync("",
"http://localhost:4001/1dfc4e1a-9c1a-4fa2-96b2-19c86acb6ea4/assets/libs/objects/",
"sol_gear.glb", this.scene)
// export class BabylonRepository {
// engine: Engine;
// canvas: HTMLCanvasElement;
// scene: Scene;
// sceneLoader: SceneLoader
// constructor(canvas: HTMLCanvasElement) {
// this.sceneLoader = new SceneLoader();
// this.engine = new Engine(canvas, true);
// this.scene = new Scene(this.engine);
// this.engine.runRenderLoop(() => {
// this.scene.render();
// });
// this.scene.createDefaultCameraOrLight(true, true, true);
// new HemisphericLight("hemiLight", new Vector3(0, 1, 0));
// SceneLoader.RegisterPlugin(new GLTFFileLoader())
// SceneLoader.ImportMeshAsync("",
// "http://localhost:4001/1dfc4e1a-9c1a-4fa2-96b2-19c86acb6ea4/assets/libs/objects/",
// "sol_gear.glb", this.scene)
}
deleteAllObjectsScene = () => this.scene.meshes.forEach((el) => this.scene.removeMesh(el, true))
// }
// deleteAllObjectsScene = () => this.scene.meshes.forEach((el) => this.scene.removeMesh(el, true))
loadHttp = (url: string) => {
const divide = url.divideByIndex(url.lastIndexOf('/'))
// loadHttp = (url: string) => {
// const divide = url.divideByIndex(url.lastIndexOf('/'))
SceneLoader.ImportMeshAsync("",
`${divide.at(0)}/`,
`${divide.at(1)}`, this.scene).then((frame) => {
});
// SceneLoader.ImportMeshAsync("",
// `${divide.at(0)}/`,
// `${divide.at(1)}`, this.scene).then((frame) => {
// });
}
}
// }
// }

View file

@ -21,23 +21,26 @@ import {
Quaternion,
MeshBasicMaterial,
BoxGeometry,
MeshStandardMaterial
MeshStandardMaterial,
} from "three";
import { TypedEvent } from "../helper/typed_event";
import { Result } from "../helper/result";
import { GLTFLoader, OrbitControls, TransformControls, OBJLoader, STLLoader, ColladaLoader } from "three-stdlib";
import { ColladaLoader } from "three/examples/jsm/loaders/ColladaLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import { STLLoader } from "three/examples/jsm/loaders/STLLoader";
import { OrbitControls, TransformControls } from "three/examples/jsm/Addons";
import {
BaseSceneItemModel,
CameraViewModel,
StaticAssetItemModel,
} from "../../features/scene_manager/model/scene_assets";
import { SceneMode } from "../../features/scene_manager/model/scene_view";
import { throttle } from "../helper/throttle";
import { Asset, InstanceRgbCamera, RobossemblerAssets, SceneSimpleObject } from "../model/robossembler_assets";
import { LoadingManager } from 'three';
import { UrdfTransforms, coordsToQuaternion } from "../../features/simulations/tranforms_model";
import URDFLoader, { URDFLink } from 'urdf-loader';
import { LoadingManager } from "three";
import { SceneMode } from "../../features/scene_manager/model/scene_view";
import { UrdfTransforms, coordsToQuaternion } from "../../features/simulations/tranforms_model";
import URDFLoader, { URDFLink } from "urdf-loader";
import { ISolidSpawnHelper } from "../../features/scene_manager/presentation/scene_manager_store";
Object3D.DEFAULT_UP = new Vector3(0, 0, 1);
@ -45,7 +48,7 @@ export enum UserData {
selectedObject = "selected_object",
cameraInitialization = "camera_initialization",
objectForMagnetism = "object_for_magnetism",
loadObject = 'load_object'
loadObject = "load_object",
}
interface IEventDraggingChange {
@ -58,10 +61,7 @@ interface IEmissiveCache {
status: boolean;
object3d: Object3D<Object3DEventMap>;
}
type SceneFrames = { [K in string]: URDFLink; }
type SceneFrames = { [K in string]: URDFLink };
export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
scene = new Scene();
@ -110,19 +110,22 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
}
deleteAllObjectsScene = () => {
this.getAllSceneNameModels().forEach((el) => this.scene.remove(this.scene.getObjectByName(el) as Object3D<Object3DEventMap>))
}
this.getAllSceneNameModels().forEach((el) =>
this.scene.remove(this.scene.getObjectByName(el) as Object3D<Object3DEventMap>)
);
};
raiseAnObjectAboveZeroVector = (name: string) => {
const mesh = this.scene.getObjectByName(name) as Object3D;
mesh.position.sub(new Box3().setFromObject(mesh).min);
};
drawPoint(point: Vector3): Mesh<BoxGeometry, MeshBasicMaterial, Object3DEventMap> {
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;
}
getCenterPoint = (object: Object3D<Object3DEventMap>) => object.getWorldPosition(new Box3().setFromObject(object).getCenter(object.position));
getCenterPoint = (object: Object3D<Object3DEventMap>) =>
object.getWorldPosition(new Box3().setFromObject(object).getCenter(object.position));
makeCube(inc: number, vector?: Vector3, color?: string, size?: number) {
const cube = new Mesh(
@ -151,55 +154,34 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
cube.position.copy(vector);
}
this.scene.add(cube);
}
deleteSceneItem = (item: string) =>
this.scene.children.forEach((el) => el.name.isEqualR(item).map(() => this.scene.remove(el)));
}
deleteSceneItem(item: BaseSceneItemModel) {
const updateScene = this.scene;
updateScene.children = item.deleteToScene(updateScene);
}
loadUrdf = (urlPath: string) => {
this.urdfLoader.load(
urlPath,
robot => {
this.scene.add(robot)
// @ts-expect-error
this.sceneFrame = robot.frames
}
);
}
loadInstances(robossemblerAssets: RobossemblerAssets) {
robossemblerAssets.instances.forEach(async (el) => {
if (el instanceof InstanceRgbCamera) {
const cameraModel = CameraViewModel.fromInstanceRgbCamera(el);
cameraModel.mapPerspectiveCamera(this.htmlSceneWidth, this.htmlSceneHeight).forEach((el) => this.scene.add(el));
this.emit(cameraModel);
}
if (el instanceof SceneSimpleObject) {
const asset = robossemblerAssets.getAssetAtInstance(el.instanceAt as string);
this.loader(
asset.meshPath,
() => { },
asset.name,
new Vector3(el.position.x, el.position.y, el.position.z),
new Quaternion(el.quaternion[0], el.quaternion[1], el.quaternion[2], el.quaternion[3])
);
}
this.urdfLoader.load(urlPath, (robot) => {
this.scene.add(robot);
// @ts-expect-error
this.sceneFrame = robot.frames;
});
}
loadInstance(asset: Asset, loadCallback?: Function) {
};
solidSpawn(
solidSpawn: ISolidSpawnHelper,
loadCallback?: (obj: Object3D<Object3DEventMap> | undefined) => void,
vector3?: Vector3
) {
this.loader(
asset.meshPath,
loadCallback ? loadCallback : () => { },
asset.name,
new Vector3(Number(asset.posX), Number(asset.posY), Number(asset.posZ)),
new Quaternion(0, 0, 0, 0)
solidSpawn.url,
() => {
this.raiseAnObjectAboveZeroVector(solidSpawn.name);
if (loadCallback) loadCallback(this.scene.getObjectByName(solidSpawn.name));
},
solidSpawn.name,
vector3
);
}
loadHttpAndPreview(path: string, name: string, loadCallback?: Function) {
this.loader(
path,
() => {
@ -209,7 +191,6 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
name,
new Vector3(0, 0, 0)
);
}
setTransformMode(mode?: SceneMode) {
@ -218,10 +199,10 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.transformControls.detach();
this.transformControls.dispose();
break;
case SceneMode.MOVING:
case SceneMode.Move:
this.transformControls.setMode("translate");
break;
case SceneMode.ROTATE:
case SceneMode.Rotate:
this.transformControls.setMode("rotate");
break;
}
@ -275,7 +256,7 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
}
}
setRayCast(vector: Vector2): Result<void, Intersection<Object3D<Object3DEventMap>>[]> {
setRayCast = (vector: Vector2): Result<void, Intersection<Object3D<Object3DEventMap>>[]> => {
const raycaster = new Raycaster();
raycaster.setFromCamera(vector, this.camera);
const intersects = raycaster.intersectObjects(this.scene.children);
@ -284,16 +265,17 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
}
return Result.error(undefined);
}
};
setRayCastAndGetFirstObjectAndPointToObject(vector: Vector2): Result<void, Vector3> {
this.setRayCast(vector).map((intersects) => {
if (intersects.length > 0) {
return Result.ok(intersects[0].point);
}
});
return Result.error(undefined);
}
setRayCastAndGetFirstObjectAndPointToObject = (vector: Vector2): Result<void, Vector3> =>
this.setRayCast(vector).fold(
(intersects) => {
if (intersects.isNotEmpty()) {
return Result.ok(intersects[0].point);
}
},
() => Result.error(undefined)
) as Result<void, Vector3>;
light() {
const ambientLight = new AmbientLight(0xffffff, 0.7);
@ -321,12 +303,7 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.orbitControls.enabled = !e.value;
});
this.transformControls.addEventListener("objectChange", (event) => {
//@ts-expect-error
const sceneObject = event.target.object;
//TODO:(IDONTSUDO) Trotting doesn't work, need to figure out why
const fn = () => this.watcherSceneEditorObject(sceneObject);
const [throttleFn] = throttle(fn, 1000);
throttleFn();
this.watcherSceneEditorObject(event.target.object);
});
}
@ -334,10 +311,10 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.light();
this.addListeners();
const floor = new GridHelper(1000, 100, 0x888888, 0x444444);
floor.geometry.rotateX(Math.PI * 0.5)
floor.geometry.rotateX(Math.PI * 0.5);
floor.userData = {};
floor.userData[UserData.cameraInitialization] = true;
floor.up.copy(new Vector3(0, 0, 1))
floor.up.copy(new Vector3(0, 0, 1));
this.scene.add(floor);
}
@ -372,10 +349,10 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.glbLoader.load(
url,
(result) => {
this.scene.add(result.scene)
callBack()
this.scene.add(result.scene);
callBack();
},
(err) => { }
(err) => {}
);
break;
case "obj":
@ -392,51 +369,47 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.emit(new StaticAssetItemModel(el.name, el.position, el.quaternion));
this.scene.add(el);
callBack()
callBack();
});
},
(err) => { }
(err) => {}
);
break;
case "dae":
this.daeLoader.load(
url,
(result) => {
this.scene.add(result.scene.children[0])
this.scene.add(result.scene);
},
(err) => { }
(err) => console.log(err)
);
break;
case "stl":
this.stlLoader.load(
url,
(result) => {
const material = new MeshStandardMaterial({
color: 'red',
metalness: 0.35,
roughness: 1,
opacity: 1.0,
transparent: false,
});
const mesh = new Mesh(result, material);
const mesh = new Mesh(
result,
new MeshStandardMaterial({
color: "red",
metalness: 0.35,
roughness: 1,
opacity: 1.0,
transparent: false,
})
);
mesh.name = name;
// var geometry = mesh.geometry;
// geometry.computeBoundingBox(); // Вычисляем ограничивающий параллелепипед для геометрии
if (position) mesh.position.copy(position)
if (position) mesh.position.copy(position);
this.scene.add(mesh);
callBack()
callBack();
},
(err) => { }
(err) => {}
);
break;
}
@ -526,11 +499,10 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
urdfTransforms = (urdfTransforms: UrdfTransforms) => {
urdfTransforms.transforms.forEach((transform) => {
if (this.sceneFrame) {
const currentLink = this.sceneFrame[transform?.child_frame_id ?? ""]
const currentLink = this.sceneFrame[transform?.child_frame_id ?? ""];
currentLink.quaternion.copy(coordsToQuaternion(transform.transform.rotation))
currentLink.quaternion.copy(coordsToQuaternion(transform.transform.rotation));
}
})
}
});
};
}

View file

@ -5,11 +5,12 @@ import { IStyle } from "../../model/style";
export interface IIconsProps extends IStyle {
type: string;
onClick?: Function;
height?: number;
width?: number;
}
export function Icon(props: IIconsProps) {
const icon = getIconSvg(props.type);
return icon.fold(
return getIconSvg(props.type, props.height, props.width).fold(
(node) => {
return (
<div
@ -41,7 +42,11 @@ export function Icon(props: IIconsProps) {
)
);
}
const getIconSvg = (type: string): Result<undefined, React.JSX.Element> => {
const getIconSvg = (
type: string,
height: number | undefined,
width: number | undefined
): Result<undefined, React.JSX.Element> => {
switch (type) {
case "":
return Result.ok();
@ -51,9 +56,9 @@ const getIconSvg = (type: string): Result<undefined, React.JSX.Element> => {
<path
d="M5 12H19M19 12L13 6M19 12L13 18"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
@ -64,65 +69,65 @@ const getIconSvg = (type: string): Result<undefined, React.JSX.Element> => {
<path
d="M17 18C17 18.5523 17.4477 19 18 19C18.5523 19 19 18.5523 19 18C19 17.4477 18.5523 17 18 17C17.4477 17 17 17.4477 17 18Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11 18C11 18.5523 11.4477 19 12 19C12.5523 19 13 18.5523 13 18C13 17.4477 12.5523 17 12 17C11.4477 17 11 17.4477 11 18Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5 18C5 18.5523 5.44772 19 6 19C6.55228 19 7 18.5523 7 18C7 17.4477 6.55228 17 6 17C5.44772 17 5 17.4477 5 18Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17 12C17 12.5523 17.4477 13 18 13C18.5523 13 19 12.5523 19 12C19 11.4477 18.5523 11 18 11C17.4477 11 17 11.4477 17 12Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11 12C11 12.5523 11.4477 13 12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5 12C5 12.5523 5.44772 13 6 13C6.55228 13 7 12.5523 7 12C7 11.4477 6.55228 11 6 11C5.44772 11 5 11.4477 5 12Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17 6C17 6.55228 17.4477 7 18 7C18.5523 7 19 6.55228 19 6C19 5.44772 18.5523 5 18 5C17.4477 5 17 5.44772 17 6Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11 6C11 6.55228 11.4477 7 12 7C12.5523 7 13 6.55228 13 6C13 5.44772 12.5523 5 12 5C11.4477 5 11 5.44772 11 6Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5 6C5 6.55228 5.44772 7 6 7C6.55228 7 7 6.55228 7 6C7 5.44772 6.55228 5 6 5C5.44772 5 5 5.44772 5 6Z"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
@ -132,9 +137,9 @@ const getIconSvg = (type: string): Result<undefined, React.JSX.Element> => {
<path
d="M21 21L12 12M12 12L3 3M12 12L21.0001 3M12 12L3 21.0001"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
@ -367,7 +372,13 @@ const getIconSvg = (type: string): Result<undefined, React.JSX.Element> => {
);
case "DeleteCircle":
return Result.ok(
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width={width ? width : "20"}
height={height ? height : "20"}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
@ -451,6 +462,24 @@ const getIconSvg = (type: string): Result<undefined, React.JSX.Element> => {
</g>
</svg>
);
case "Solid":
return Result.ok(
<svg
xmlns="http://www.w3.org/2000/svg"
width={width ? width : "20"}
height={height ? height : "20"}
viewBox="0 0 24 24"
fill="none"
>
<path
d="M12 10.2308L3.08495 7.02346M12 10.2308L20.9178 7.03406M12 10.2308V20.8791M5.13498 18.5771L10.935 20.6242C11.3297 20.7635 11.527 20.8331 11.7294 20.8608C11.909 20.8853 12.091 20.8853 12.2706 20.8608C12.473 20.8331 12.6703 20.7635 13.065 20.6242L18.865 18.5771C19.6337 18.3058 20.018 18.1702 20.3018 17.9269C20.5523 17.7121 20.7459 17.4386 20.8651 17.1308C21 16.7823 21 16.3747 21 15.5595V8.44058C21 7.62542 21 7.21785 20.8651 6.86935C20.7459 6.56155 20.5523 6.28804 20.3018 6.0732C20.018 5.82996 19.6337 5.69431 18.865 5.42301L13.065 3.37595C12.6703 3.23665 12.473 3.167 12.2706 3.13936C12.091 3.11484 11.909 3.11484 11.7294 3.13936C11.527 3.167 11.3297 3.23665 10.935 3.37595L5.13498 5.42301C4.36629 5.69431 3.98195 5.82996 3.69824 6.0732C3.44766 6.28804 3.25414 6.56155 3.13495 6.86935C3 7.21785 3 7.62542 3 8.44058V15.5595C3 16.3747 3 16.7823 3.13495 17.1308C3.25414 17.4386 3.44766 17.7121 3.69824 17.9269C3.98195 18.1702 4.36629 18.3058 5.13498 18.5771Z"
stroke="#000000"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
case "Camera":
return Result.ok(
<svg width="18" height="14" viewBox="0 0 18 14" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -460,6 +489,42 @@ const getIconSvg = (type: string): Result<undefined, React.JSX.Element> => {
/>
</svg>
);
case "Move":
return Result.ok(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" xmlSpace="preserve">
<g fill="#ffffff">
<path
fill="#ffffff"
d="M178.492 368a.5.5 0 0 0-.346.146l-2 2a.5.5 0 1 0 .708.708l1.146-1.147v7.586l-3 3V378.5a.5.5 0 0 0-.508-.508.5.5 0 0 0-.492.508v3a.5.5 0 0 0 .5.5h3a.5.5 0 1 0 0-1h-1.793l3-3h7.586l-1.147 1.146a.5.5 0 1 0 .708.708l2-2a.5.5 0 0 0 0-.708l-2-2a.5.5 0 0 0-.36-.152.5.5 0 0 0-.348.86l1.147 1.146H179v-7.293l1.146 1.147a.5.5 0 1 0 .708-.708l-2-2a.5.5 0 0 0-.362-.146z"
transform="translate(-171 -365)"
/>
</g>
</svg>
);
case "Save":
return Result.ok(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18.1716 1C18.702 1 19.2107 1.21071 19.5858 1.58579L22.4142 4.41421C22.7893 4.78929 23 5.29799 23 5.82843V20C23 21.6569 21.6569 23 20 23H4C2.34315 23 1 21.6569 1 20V4C1 2.34315 2.34315 1 4 1H18.1716ZM4 3C3.44772 3 3 3.44772 3 4V20C3 20.5523 3.44772 21 4 21L5 21L5 15C5 13.3431 6.34315 12 8 12L16 12C17.6569 12 19 13.3431 19 15V21H20C20.5523 21 21 20.5523 21 20V6.82843C21 6.29799 20.7893 5.78929 20.4142 5.41421L18.5858 3.58579C18.2107 3.21071 17.702 3 17.1716 3H17V5C17 6.65685 15.6569 8 14 8H10C8.34315 8 7 6.65685 7 5V3H4ZM17 21V15C17 14.4477 16.5523 14 16 14L8 14C7.44772 14 7 14.4477 7 15L7 21L17 21ZM9 3H15V5C15 5.55228 14.5523 6 14 6H10C9.44772 6 9 5.55228 9 5V3Z"
fill="white"
/>
</svg>
);
case "Select":
return Result.ok(
<svg xmlns="http://www.w3.org/2000/svg" fill="white" viewBox="0 0 24 24">
<path d="M6 3v18l5-7h9zm4.485 10L7 17.88V5.058L17.108 13z" fillRule="evenodd" />
<path fill="none" d="M0 0h24v24H0z" />
</svg>
);
case "Rotate":
return Result.ok(
<svg xmlns="http://www.w3.org/2000/svg" fill="white" viewBox="0 0 24 24">
<path d="M11.2797426,15.9868494 L10.1464466,14.8535534 C9.95118446,14.6582912 9.95118446,14.3417088 10.1464466,14.1464466 C10.3417088,13.9511845 10.6582912,13.9511845 10.8535534,14.1464466 L12.8535534,16.1464466 C13.0488155,16.3417088 13.0488155,16.6582912 12.8535534,16.8535534 L10.8535534,18.8535534 C10.6582912,19.0488155 10.3417088,19.0488155 10.1464466,18.8535534 C9.95118446,18.6582912 9.95118446,18.3417088 10.1464466,18.1464466 L11.3044061,16.9884871 C10.3667147,16.9573314 9.46306739,16.8635462 8.61196501,16.7145167 C9.33747501,19.2936084 10.6229353,21 12,21 C14.0051086,21 15.8160018,17.3821896 15.9868494,12.7202574 L14.8535534,13.8535534 C14.6582912,14.0488155 14.3417088,14.0488155 14.1464466,13.8535534 C13.9511845,13.6582912 13.9511845,13.3417088 14.1464466,13.1464466 L16.1464466,11.1464466 C16.3417088,10.9511845 16.6582912,10.9511845 16.8535534,11.1464466 L18.8535534,13.1464466 C19.0488155,13.3417088 19.0488155,13.6582912 18.8535534,13.8535534 C18.6582912,14.0488155 18.3417088,14.0488155 18.1464466,13.8535534 L16.9884871,12.6955939 C16.8167229,17.8651676 14.7413901,22 12,22 C9.97580598,22 8.3147521,19.7456544 7.515026,16.484974 C4.2543456,15.6852479 2,14.024194 2,12 C2,9.97580598 4.2543456,8.3147521 7.515026,7.515026 C8.3147521,4.2543456 9.97580598,2 12,2 C13.5021775,2 14.8263891,3.23888365 15.7433738,5.30744582 C15.8552836,5.55989543 15.7413536,5.8552671 15.4889039,5.96717692 C15.2364543,6.07908673 14.9410827,5.96515672 14.8291729,5.71270711 C14.0550111,3.96632921 13.0221261,3 12,3 C10.6229353,3 9.33747501,4.70639159 8.61196501,7.28548333 C9.67174589,7.09991387 10.812997,7 12,7 C17.4892085,7 22,9.13669069 22,12 C22,13.5021775 20.7611164,14.8263891 18.6925542,15.7433738 C18.4401046,15.8552836 18.1447329,15.7413536 18.0328231,15.4889039 C17.9209133,15.2364543 18.0348433,14.9410827 18.2872929,14.8291729 C20.0336708,14.0550111 21,13.0221261 21,12 C21,9.89274656 17.0042017,8 12,8 C10.6991081,8 9.46636321,8.12791023 8.35424759,8.35424759 C8.12791023,9.46636321 8,10.6991081 8,12 C8,13.3008919 8.12791023,14.5336368 8.35424759,15.6457524 C9.25899447,15.8298862 10.2435788,15.9488767 11.2797426,15.9868494 Z M7.28548333,8.61196501 C4.70639159,9.33747501 3,10.6229353 3,12 C3,13.3770647 4.70639159,14.662525 7.28548333,15.388035 C7.09991387,14.3282541 7,13.187003 7,12 C7,10.812997 7.09991387,9.67174589 7.28548333,8.61196501 L7.28548333,8.61196501 Z" />
</svg>
);
case "Settings":
return Result.ok(
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">

View file

@ -55,7 +55,7 @@ export class AllProjectStore extends ModalStore {
}
if (this.file === undefined) {
message.error("загрузите файл");
return;
return
}
this.isLoading = true;

View file

@ -1,5 +1,4 @@
import { extensions } from "../../../core/extensions/extensions";
import { Form } from "../presentation/ui/forms/forms";
import { ISkillView } from "../presentation/ui/skill_tree/skill_tree";
extensions();

View file

@ -6,6 +6,10 @@ export interface Parts {
material_path: string;
stlUrl: string;
image: string;
glUrl: string;
solidType: string;
daeUrl: string;
objUrl: string;
}
export class DetailsHttpRepository extends CoreHttpRepository {

View file

@ -29,6 +29,9 @@ export class DetailsStore extends UiDrawerFormState<EnvelopmentViewModel, CoreEr
errorHandingStrategy = (error: CoreError) => {};
init = async (navigate?: NavigateFunction | undefined): Promise<void> => {
await this.mapOk("parts", this.detailsHttpRepository.getAssetsActiveProject());
this.detailsViewModel = this.parts.map((el) => {
return {
label: el.name,

View file

@ -2,20 +2,14 @@ import { Box3, GridHelper, Mesh, Object3D, Vector3 } from "three";
import { CoreThreeRepository } from "../../core/repository/core_three_repository";
export class DetailsThreeRepository extends CoreThreeRepository {
raiseAnObjectAboveZeroVector = (name: string) => {
const mesh = this.scene.getObjectByName(name) as Object3D;
mesh.position.sub(new Box3().setFromObject(mesh).min)
}
matchTwoPlacesInTheCenter = () => {
}
loadHttpAndPreview = (path: string, name: string, loadCallback?: Function) => {
this.loader(
path,
() => {
this.raiseAnObjectAboveZeroVector(name)
console.log(this.getCenterPoint(this.scene.children.filter((el) => el instanceof GridHelper).at(0) as Object3D))
this.getCenterPoint(this.scene.children.filter((el) => el instanceof GridHelper).at(0) as Object3D)
},
name,
new Vector3(0, 0, 0)

View file

@ -0,0 +1,30 @@
import { Quaternion, Vector3 } from "three";
import { SceneModelsTypes } from "./solid_body_model";
import { Result } from "../../../core/helper/result";
export enum CameraTypes {
RGB = "RGB",
}
export class CameraModel {
type = SceneModelsTypes.CAMERA;
constructor(
public quaternion: Quaternion,
public vector3: Vector3,
public name: string,
public cameraType: CameraTypes,
public width: number,
public updateRate: number,
public fov: number,
public near: number,
public far: number,
public height: number,
public topic: string,
public parent?: string,
public fixed?: string
) {}
validate = (): Result<string, CameraModel> => {
return Result.ok(this);
};
static empty = () =>
new CameraModel(new Quaternion(0, 0, 0, 0), new Vector3(0, 0, 0), "", CameraTypes.RGB, 0, 0, 0, 0, 0, 0, "");
}

View file

@ -20,9 +20,8 @@ export interface SceneManagerView {
}
export enum SceneMode {
ROTATE = "Rotate",
MOVING = "Moving",
EMPTY = "Empty",
ADD_CAMERA = "Add camera",
MAGNETISM_MARKING = "magnetism_marking",
Rotate = "Rotate",
Move = "Move",
Select = "Select",
Save = 'Save',
}

View file

@ -0,0 +1,30 @@
import { Quaternion, Vector3 } from "three";
export enum SceneModelsTypes {
SOLID = "SOLID",
ROBOT = "ROBOT",
LIGHT = "LIGHT",
CAMERA = 'CAMERA'
}
export enum SolidBodyTypes {
ACTIVE = "ACTIVE",
STATIC = "STATIC",
}
interface ISpawnTypes {
type: "POINT";
name: "123";
}
export class SolidBodyModel {
type = SceneModelsTypes.SOLID;
spawn?: ISpawnTypes;
constructor(
public quaternion: Quaternion,
public vector3: Vector3,
public name: string,
public solidType: SolidBodyTypes | string,
public mesh: string,
public collisionMesh: string,
public inertia?: number,
public mass?: number
) {}
}

View file

@ -0,0 +1,14 @@
import { SpawnPositionTypes } from "../../../../core/model/spawn_position_types";
import { CoreButton } from "../../../../core/ui/button/button";
import { CoreText, CoreTextType } from "../../../../core/ui/text/text";
export const SpawnPositionTypesForm = ({ onClick: onClick }: { onClick: Function }) => {
return (
<>
<CoreText text={"Тип размещения"} type={CoreTextType.header} />
{Object.entries(SpawnPositionTypes).map(([_, value], i) => (
<CoreButton key={i} text={value} onClick={() => onClick(value)} />
))}
</>
);
};

View file

@ -1,31 +1,60 @@
import { NavigateFunction } from "react-router-dom";
import { CoreError, FormState, UiDrawerFormState } from "../../../../../core/store/base_store";
import { CoreError, FormState } from "../../../../../core/store/base_store";
import { CoreButton } from "../../../../../core/ui/button/button";
import { CameraViewModel } from "../../../model/scene_assets";
import { IDefaultSceneManagerProps } from "../scene_manager_forms";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
import React from "react";
import { CoreInput } from "../../../../../core/ui/input/input";
import { CoreText, CoreTextType } from "../../../../../core/ui/text/text";
import { message } from "antd";
import { CameraModel, CameraTypes } from "../../../model/camera_view_model";
import { CoreSelect } from "../../../../../core/ui/select/select";
class CameraFormStore extends FormState<CameraViewModel, CoreError> {
class CameraFormStore extends FormState<CameraModel, CoreError> {
errorHandingStrategy = (error: CoreError) => {};
init = async (navigate?: NavigateFunction | undefined) => {};
viewModel: CameraViewModel = CameraViewModel.empty();
viewModel: CameraModel = CameraModel.empty();
constructor() {
super();
}
}
export const CameraForm = (props: IDefaultSceneManagerProps) => {
export const CameraForm = (props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new CameraFormStore());
React.useEffect(() => {
store.init();
}, []);
return (
<div style={{ margin: 10, padding: 10 }}>
<div style={{ margin: 10, padding: 10, overflowY: "auto", height: "100%" }}>
<CoreText text="Камера" type={CoreTextType.header} />
<CoreInput label={"Камера линк"} onChange={(text) => store.updateForm({ cameraLink: text })} />
<CoreInput value={store.viewModel.topic} label={"Топик"} onChange={(text) => store.updateForm({ topic: text })} />
<CoreInput value={store.viewModel.name} label={"Имя"} onChange={(text) => store.updateForm({ name: text })} />
<CoreInput
value={String(store.viewModel.updateRate)}
validation={(text) => Number().isValid(text)}
label={"Update Rate"}
onChange={(text) => store.updateForm({ updateRate: Number(text) })}
/>
<CoreInput
value={String(store.viewModel.height)}
validation={(text) => Number().isValid(text)}
label={"Height"}
onChange={(text) => store.updateForm({ height: Number(text) })}
/>
<CoreInput
value={String(store.viewModel.width)}
validation={(text) => Number().isValid(text)}
label={"Width"}
onChange={(text) => store.updateForm({ width: Number(text) })}
/>
<CoreSelect
items={Object.entries(CameraTypes).map(([_, v]) => v)}
value={store.viewModel.cameraType}
label={"Типы камер"}
onChange={(text) => store.updateForm({ cameraType: text as CameraTypes })}
/>
<div style={{ height: 10 }} />
<CoreButton
text="Создать"
@ -33,7 +62,7 @@ export const CameraForm = (props: IDefaultSceneManagerProps) => {
onClick={() =>
store.viewModel.validate().fold(
(model) => {
props.store.addNewCamera(model);
// props.store.addNewCamera(model);
},
(error) => message.error(error)
)

View file

@ -0,0 +1,6 @@
import { observer } from "mobx-react-lite";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
export const LightForm = observer((props: IDefaultSceneManagerFormProps) => {
return <></>;
});

View file

@ -0,0 +1,14 @@
import { NavigateFunction } from "react-router-dom";
import { FormState, CoreError } from "../../../../../core/store/base_store";
import { LightViewModel } from "./light_view_model";
export class LightStore extends FormState<LightViewModel, CoreError> {
viewModel: LightViewModel = LightViewModel.empty();
constructor() {
super();
}
errorHandingStrategy = (error: CoreError) => {};
init(navigate?: NavigateFunction | undefined): Promise<any> {
throw new Error("Method not implemented.");
}
}

View file

@ -0,0 +1,9 @@
import { Result } from "../../../../../core/helper/result";
export class LightViewModel {
constructor() {}
isValid = (): Result<void, LightViewModel> => {
return Result.ok(this);
};
static empty = () => new LightViewModel();
}

View file

@ -0,0 +1,40 @@
import React from "react";
import { observer } from "mobx-react-lite";
import { PointStore, PointStoreType } from "./point_store";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
import { CoreText, CoreTextType } from "../../../../../core/ui/text/text";
import { CoreInput } from "../../../../../core/ui/input/input";
import { CoreButton } from "../../../../../core/ui/button/button";
import { match } from "ts-pattern";
import { SpawnPositionTypesForm } from "../../components/spawn_position_types";
export const PointForm = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new PointStore());
React.useEffect(() => {
store.init();
}, [store]);
return (
<div>
{match(store.storeType)
.with(PointStoreType.initNewPoint, () => (
<>
<CoreText text="Точка" type={CoreTextType.header} />
<CoreInput label="Имя" onChange={(text) => store.updateForm({ name: text })} />
<CoreButton
text="Следующий этап"
onClick={() => store.onClickNext(PointStoreType.makeSceneSolidAndEditPosition)}
/>
</>
))
.with(PointStoreType.makeSceneSolidAndEditPosition, () => (
<>
<SpawnPositionTypesForm onClick={store.selectSpawnType} />
</>
))
.otherwise(() => (
<></>
))}
</div>
);
});

View file

@ -0,0 +1,6 @@
import { HttpRepository } from "../../../../../core/repository/http_repository";
export class PointHttpRepository extends HttpRepository {
}

View file

@ -0,0 +1,26 @@
import makeAutoObservable from "mobx-store-inheritance";
import { NavigateFunction } from "react-router-dom";
import { PointViewModel } from "./point_view_model";
import { PointHttpRepository } from "./point_http_repository";
import { FormState, CoreError } from "../../../../../core/store/base_store";
import { SpawnPositionTypes } from "../../../../../core/model/spawn_position_types";
export enum PointStoreType {
makeSceneSolidAndEditPosition = "makeSceneSolidAndEditPosition",
initNewPoint = "initNewPoint",
}
export class PointStore extends FormState<PointViewModel, CoreError> {
onClickNext = (pointStoreType: PointStoreType) => (this.storeType = pointStoreType);
viewModel: PointViewModel = PointViewModel.empty();
cameraDeviceHttpRepository: PointHttpRepository = new PointHttpRepository();
storeType: PointStoreType = PointStoreType.initNewPoint;
spawnPositionTypes: SpawnPositionTypes;
constructor() {
super();
makeAutoObservable(this);
}
selectSpawnType = (type: SpawnPositionTypes) => {
this.spawnPositionTypes = type;
};
errorHandingStrategy = (error: CoreError) => {};
init = async (navigate?: NavigateFunction | undefined) => {};
}

View file

@ -0,0 +1,16 @@
import { Quaternion, Vector3 } from "three";
import { Result } from "../../../../../core/helper/result";
export class PointViewModel {
type = "POINT";
name: string;
vector3: Vector3;
quaternion: Quaternion;
constructor() {}
isValid(): Result<string, PointViewModel> {
return Result.ok();
}
static empty() {
return new PointViewModel();
}
}

View file

@ -1,6 +1,6 @@
import { IDefaultSceneManagerProps } from "../scene_manager_forms";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
export const RobotForm = (props: IDefaultSceneManagerProps) => {
export const RobotForm = (props: IDefaultSceneManagerFormProps) => {
return <div>ROBOT</div>;
};

View file

@ -1,23 +1,37 @@
import { SceneMangerStore } from "../scene_manager_store";
import { CameraForm } from "./camera/camera_form";
import { LightForm } from "./light/light_form";
import { PointForm } from "./point/point_form";
import { RobotForm } from "./robot/robot_form";
import { SolidBodyForm } from "./solid_body/solid_body_form";
import { Trajectory } from "./trajectory/trajectory_form";
import { ZoneForm } from "./zone/zone_form";
export enum SceneManagerForms {
robot = "robot",
camera = "camera",
solidBody = "solidBody",
solidBody = "SolidBody",
previewSolidBody = "previewSolidBody",
light = "Light",
point = "point",
trajectory = "trajectory",
zone = "zone",
}
interface IForms {
name: string;
component: JSX.Element;
}
export interface IDefaultSceneManagerProps {
export interface IDefaultSceneManagerFormProps {
dependency: Object;
store: SceneMangerStore;
}
export const sceneManagerForms = (props: Object, store: SceneMangerStore): IForms[] => [
{ name: SceneManagerForms.camera, component: <CameraForm dependency={props} store={store} /> },
{ name: SceneManagerForms.robot, component: <RobotForm dependency={props} store={store} /> },
{ name: SceneManagerForms.solidBody, component: <SolidBodyForm dependency={props} store={store} /> },
{ name: SceneManagerForms.point, component: <PointForm dependency={props} store={store} /> },
{ name: SceneManagerForms.light, component: <LightForm dependency={props} store={store} /> },
{ name: SceneManagerForms.zone, component: <ZoneForm dependency={props} store={store} /> },
{ name: SceneManagerForms.trajectory, component: <Trajectory dependency={props} store={store} /> },
];

View file

@ -1,5 +1,62 @@
import { IDefaultSceneManagerProps } from "../scene_manager_forms";
import React from "react";
import { CoreText, CoreTextType } from "../../../../../core/ui/text/text";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
import { SolidBodyStore, SolidBodyStoreType } from "./solid_body_store";
import { observer } from "mobx-react-lite";
import { CoreButton } from "../../../../../core/ui/button/button";
import { match } from "ts-pattern";
import { SpawnPositionTypesForm } from "../../components/spawn_position_types";
export const SolidBodyForm = (props:IDefaultSceneManagerProps) => {
return <></>;
};
export const SolidBodyForm = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new SolidBodyStore(props.store));
React.useEffect(() => {
store.init();
}, []);
return (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
{Object.hasOwn(props.dependency, "type") && Object.hasOwn(props.dependency, "name") ? (
<>
x:{props.store.scene.find((el) => el.name.isEqual(props.store.selectedItemName ?? ""))?.vector3.x}
y:{props.store.scene.find((el) => el.name.isEqual(props.store.selectedItemName ?? ""))?.vector3.y}
y:{props.store.scene.find((el) => el.name.isEqual(props.store.selectedItemName ?? ""))?.vector3.z}
solidType:{props.store.scene.find((el) => el.name.isEqual(props.store.selectedItemName ?? ""))?.solidType}
</>
) : (
<>
{match(store.solidBodyStoreType)
.with(SolidBodyStoreType.selectBody, () => (
<>
<CoreText text={"Твердое тело"} type={CoreTextType.header} />
{store.parts.map((el, i) => (
<div key={i} style={{ padding: 10, margin: 10 }}>
<CoreText text={el.name} type={CoreTextType.medium} />
<img src={el.image} />
<CoreButton text="Выбрать" onClick={() => store.clickSelectBody(el)} />
</div>
))}
</>
))
.with(SolidBodyStoreType.selectSpawnPositionType, () => (
<>
<SpawnPositionTypesForm onClick={store.selectSpawnType} />
</>
))
.with(SolidBodyStoreType.spawn2DVector, () => (
<>
{props.store.mousePosition ? (
""
) : (
<CoreText text={"Выберите точку размещения"} type={CoreTextType.header} />
)}
</>
))
.otherwise(() => (
<></>
))}
</>
)}
</div>
);
});

View file

@ -4,14 +4,14 @@ import { FormState, CoreError } from "../../../../../core/store/base_store";
import { CoreHttpRepository } from "../../../../../core/repository/http_repository";
import { Parts } from "../../../../details/details_http_repository";
import { Vector2 } from "three";
import { SceneMangerStore } from "../../scene_manager_store";
import { SpawnPositionTypes } from "../../../../../core/model/spawn_position_types";
export enum SolidBodyStoreType {
selectBody = "selectBody",
selectSpawnPositionType = "selectSpawnPositionType",
spawn2DVector = "spawn2DVector",
}
export enum SpawnPositionTypes {
BoundBox = "BoundBox",
}
export class SolidBodyStore extends FormState<SolidBodyViewModel, CoreError> {
viewModel: SolidBodyViewModel = SolidBodyViewModel.empty();
parts: Parts[] = [];
@ -20,20 +20,33 @@ export class SolidBodyStore extends FormState<SolidBodyViewModel, CoreError> {
solidBodyStoreType: SolidBodyStoreType = SolidBodyStoreType.selectBody;
selectBody: Parts;
spawnType: string;
errorHandingStrategy = (error: CoreError) => {};
constructor() {
sceneManagerStore: SceneMangerStore;
vector2d?: Vector2;
constructor(sceneManagerStore: SceneMangerStore) {
super();
this.sceneManagerStore = sceneManagerStore;
makeAutoObservable(this);
}
vector2d?: Vector2;
init = async () => {
this.mapOk("parts", this.coreHttpRepository.getAssetsActiveProject());
};
errorHandingStrategy = (error: CoreError) => {};
dispose = () => {};
selectSpawnType = (type: string) => {
this.spawnType = type;
this.solidBodyStoreType = SolidBodyStoreType.spawn2DVector;
this.sceneManagerStore.mousePositionAwait = true;
this.sceneManagerStore.solidSpawnHelper = {
url: this.selectBody.objUrl,
name: this.selectBody.name,
isFinished: false,
solidType: this.selectBody.solidType,
type: this.spawnType,
};
this.sceneManagerStore.activeFormType = undefined;
};
selectVector = () => {};
clickSelectBody = (el: Parts) => {
this.selectBody = el;
this.solidBodyStoreType = SolidBodyStoreType.selectSpawnPositionType;

View file

@ -0,0 +1,13 @@
import React from "react";
import { observer } from "mobx-react-lite";
import { TrajectoryStore } from "./trajectory_store";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
export const Trajectory = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new TrajectoryStore());
React.useEffect(() => {
store.init();
}, [store]);
return <>Trajectory</>;
});

View file

@ -0,0 +1,3 @@
import { HttpRepository } from "../../../../../core/repository/http_repository";
export class TrajectoryHttpRepository extends HttpRepository {}

View file

@ -0,0 +1,20 @@
import makeAutoObservable from "mobx-store-inheritance";
import { NavigateFunction } from "react-router-dom";
import { TrajectoryViewModel } from "./trajectory_view_model";
import { TrajectoryHttpRepository } from "./trajectory_http_repository";
import { FormState, CoreError } from "../../../../../core/store/base_store";
export class TrajectoryStore extends FormState<TrajectoryViewModel, CoreError> {
constructor() {
super();
makeAutoObservable(this);
}
viewModel: TrajectoryViewModel = TrajectoryViewModel.empty();
cameraDeviceHttpRepository: TrajectoryHttpRepository = new TrajectoryHttpRepository();
errorHandingStrategy = (error: CoreError) => { }
init = async (navigate?: NavigateFunction | undefined) => {
}
}

View file

@ -0,0 +1,12 @@
import { Result } from "../../../../../core/helper/result";
export class TrajectoryViewModel {
constructor() {}
isValid(): Result<string, TrajectoryViewModel> {
return Result.ok();
}
static empty() {
return new TrajectoryViewModel();
}
}

View file

@ -0,0 +1,15 @@
import React from "react";
import { observer } from "mobx-react-lite";
import { ZoneStore } from "./zone_store";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
export const ZoneForm = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new ZoneStore());
React.useEffect(() => {
store.init();
}, [store]);
return <>zone</>;
});

View file

@ -0,0 +1,3 @@
import { HttpRepository } from "../../../../../core/repository/http_repository";
export class ZoneHttpRepository extends HttpRepository {}

View file

@ -0,0 +1,19 @@
import makeAutoObservable from "mobx-store-inheritance";
import { NavigateFunction } from "react-router-dom";
import { ZoneViewModel } from "./zone_view_model";
import { ZoneHttpRepository } from "./zone_http_repository";
import { FormState, CoreError } from "../../../../../core/store/base_store";
export class ZoneStore extends FormState<ZoneViewModel, CoreError> {
constructor() {
super();
makeAutoObservable(this);
}
viewModel: ZoneViewModel = ZoneViewModel.empty();
cameraDeviceHttpRepository: ZoneHttpRepository = new ZoneHttpRepository();
errorHandingStrategy = (error: CoreError) => { }
init = async (navigate?: NavigateFunction | undefined) => {
}
}

View file

@ -0,0 +1,14 @@
import { Result } from "../../../../../core/helper/result";
export class ZoneViewModel {
name: string;
constructor(name: string) {
this.name = name;
}
isValid(): Result<string, ZoneViewModel> {
return Result.ok();
}
static empty() {
return new ZoneViewModel("");
}
}

View file

@ -1,14 +1,13 @@
import * as React from "react";
import { DrawersSceneManager, SceneMangerStore, StoreMode } from "./scene_manager_store";
import { observer } from "mobx-react-lite";
import { Drawer, Popover } from "antd";
import { useNavigate, useParams } from "react-router-dom";
import { MainPage } from "../../../core/ui/pages/main_page";
import { CoreText, CoreTextType } from "../../../core/ui/text/text";
import { Drawer } from "antd";
import { CoreButton } from "../../../core/ui/button/button";
import { CoreInput } from "../../../core/ui/input/input";
import { DrawersDataset } from "../../dataset/dataset_store";
import { Popover } from "antd";
import { Icon } from "../../../core/ui/icons/icons";
import { sceneManagerForms } from "./forms/scene_manager_forms";
@ -34,6 +33,7 @@ export const SceneManger = observer(() => {
return (
<MainPage
page={"Сцена"}
panelStyle={{ display: store.storeMode.isEqual(StoreMode.sceneInstance) ? "" : "none" }}
panelChildren={
<div style={{ width: "100%", height: "100%" }}>
<div style={{ height: 260, width: "100%", padding: 10 }}>
@ -45,8 +45,8 @@ export const SceneManger = observer(() => {
content={
<div>
{store.popoverItems.map((el, i) => (
<div onClick={() => el.fn()}>
<CoreText key={i} text={el.name} type={CoreTextType.medium} color="white" />
<div key={i} onClick={() => el.fn()}>
<CoreText text={el.name} type={CoreTextType.medium} color="white" />
</div>
))}
</div>
@ -56,11 +56,33 @@ export const SceneManger = observer(() => {
<CoreButton text="Добавить" filled={true} />
</span>
</Popover>
<div style={{ position: "relative" }}>
<div style={{ position: "absolute" }}>
<div style={{ position: "relative", left: 20 }}>
{store.sceneHelperInstruments.map((el, i) => (
<div
key={i}
onClick={() => el.onClick()}
style={{
marginTop: 4,
width: 50,
height: 50,
backgroundColor: el.isSelected ? "rgba(160, 132, 255, 1)" : "rgba(99, 81, 159, 1)",
border: "1px solid",
borderRadius: 5,
}}
>
<Icon type={el.icon} />
</div>
))}
</div>
</div>
</div>
</div>
<div style={{ height: 10 }} />
<div
style={{
borderRadius: 22,
borderRadius: 7,
height: 200,
width: "-webkit-fill-available",
backgroundColor: "white",
@ -71,15 +93,29 @@ export const SceneManger = observer(() => {
<div
key={index}
style={{
paddingLeft: 20,
display: "flex",
backgroundColor: index.isEven() ? "rgba(217, 217, 217, 0.27)" : "",
backgroundColor: el.isSelected
? "rgba(104, 80, 164, 0.47)"
: index.isEven()
? "rgba(217, 217, 217, 0.27)"
: "",
alignItems: "center",
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
}}
onClick={() => store.selectSceneItems(el.name, index, !el.isSelected)}
>
<Icon type={el.icon} />
<Icon width={13} height={13} type={el.icon} style={{ marginLeft: 10 }} />
<div style={{ width: 10 }} />
<CoreText text={el.name} type={CoreTextType.small} />
<Icon
type="DeleteCircle"
width={13}
height={13}
onClick={() => store.deleteSceneItem(el)}
style={{ marginRight: 10 }}
/>
</div>
))}
</div>
@ -92,12 +128,12 @@ export const SceneManger = observer(() => {
borderRadius: 7,
backgroundColor: "white",
margin: 10,
overflow: "auto",
}}
>
{sceneManagerForms(store.activeFormDependency ?? {}, store).map((el) => {
{sceneManagerForms(store.activeFormDependency ?? {}, store).map((el, i) => {
if (el.name.isEqual(store.activeFormType ?? "")) {
return <>{el.component}</>;
return <span key={i}>{el.component}</span>;
}
return <></>;
})}

View file

@ -1,17 +1,19 @@
import makeAutoObservable from "mobx-store-inheritance";
import { Object3D, Object3DEventMap, Vector2 } from "three";
import { message } from "antd";
import { CoreThreeRepository } from "../../../core/repository/core_three_repository";
import { Object3D, Vector2 } from "three";
import { HttpError } from "../../../core/repository/http_repository";
import { UiDrawerFormState } from "../../../core/store/base_store";
import { UiBaseError } from "../../../core/model/ui_base_error";
import { SceneMenu, SceneMode } from "../model/scene_view";
import { BaseSceneItemModel, CameraViewModel, RobossemblerFiles, StaticAssetItemModel } from "../model/scene_assets";
import { SceneHttpRepository } from "../data/scene_http_repository";
import { message } from "antd";
import { RobossemblerAssets } from "../../../core/model/robossembler_assets";
import { SceneViewModel } from "../model/scene_view_model";
import { SceneModel } from "../model/scene_model";
import { SceneManagerForms } from "./forms/scene_manager_forms";
import { SolidBodyViewModel } from "./forms/solid_body/solid_body_view_model";
import { SolidBodyModel } from "../model/solid_body_model";
export enum DrawersSceneManager {
NewScene = "Новая сцена",
@ -20,6 +22,13 @@ export enum StoreMode {
sceneInstance = "sceneInstance",
allScenes = "allScenes",
}
export interface ISolidSpawnHelper {
url: string;
solidType: string;
name: string;
isFinished: boolean;
type: string;
}
interface IPopoverItem {
name: string;
fn: Function;
@ -27,18 +36,12 @@ interface IPopoverItem {
interface SceneItems {
fn: Function;
name: string;
isSelected: boolean;
icon: string;
}
export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpError> {
popoverItems: IPopoverItem[] = [
{ name: "Камера", fn: () => this.createNewForm(SceneManagerForms.camera, { store: this }) },
{ name: "Твердое тело", fn: () => this.createNewForm(SceneManagerForms.solidBody, { store: this }) },
{ name: "Робот", fn: () => this.createNewForm(SceneManagerForms.robot, { store: this }) },
{ name: "Точка", fn: () => {} },
{ name: "Траектория", fn: () => {} },
{ name: "Зона", fn: () => {} },
];
activeFormType?: string;
selectedItemName?: string;
activeFormDependency?: Object;
viewModel: SceneViewModel = SceneViewModel.empty();
sceneMode: SceneMode;
@ -55,19 +58,79 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
scenes: SceneModel[] = [];
storeMode: StoreMode;
canvasRef?: HTMLCanvasElement;
mousePositionAwait: boolean = false;
mousePosition?: Vector2;
solidSpawnHelper?: ISolidSpawnHelper;
selectSceneObject?: Object;
isLoadingForm: boolean = false;
scene: SolidBodyModel[] = [];
sceneHelperInstruments: { icon: string; onClick: Function; isSelected: boolean }[] = [
{ icon: SceneMode.Select, onClick: () => this.setMode(SceneMode.Select), isSelected: false },
{ icon: SceneMode.Move, onClick: () => this.setMode(SceneMode.Move), isSelected: false },
{ icon: SceneMode.Rotate, onClick: () => this.setMode(SceneMode.Rotate), isSelected: false },
{
icon: SceneMode.Save,
onClick: () => {
this.setMode(SceneMode.Rotate);
this.sceneSave();
},
isSelected: false,
},
];
popoverItems: IPopoverItem[] = [
{ name: "Камера", fn: () => this.createNewForm(SceneManagerForms.camera) },
{ name: "Твердое тело", fn: () => this.createNewForm(SceneManagerForms.solidBody) },
{ name: "Источник света", fn: () => this.createNewForm(SceneManagerForms.light) },
{ name: "Робот", fn: () => this.createNewForm(SceneManagerForms.robot) },
{ name: "Точка", fn: () => this.createNewForm(SceneManagerForms.point) },
{ name: "Траектория", fn: () => this.createNewForm(SceneManagerForms.trajectory) },
{ name: "Зона", fn: () => this.createNewForm(SceneManagerForms.zone) },
];
constructor() {
super(DrawersSceneManager);
makeAutoObservable(this);
this.sceneItems = [];
this.sceneHttpRepository = new SceneHttpRepository();
this.sceneMode = SceneMode.EMPTY;
this.sceneMode = SceneMode.Select;
this.sceneMenu = SceneMenu.empty();
}
createNewForm = (formType: SceneManagerForms, dependency: Object) => {
this.activeFormDependency = dependency;
sceneSave = () => {};
selectSceneItems = (name: string, index: number, selected: boolean) => {
this.sceneItems.map((el, i) => i.isEqualR(index).map(() => (el.isSelected = selected)));
if (selected) {
this.createNewForm(SceneManagerForms.solidBody);
this.selectedItemName = name;
}
if (!selected) {
this.createNewForm(undefined);
this.selectedItemName = undefined;
}
this.activeFormDependency = {
type: "Preview",
name: name,
};
};
setMode = (mode: SceneMode) => {
this.sceneHelperInstruments.map((el) => {
el.isSelected = false;
if (el.icon.isEqual(mode)) {
el.isSelected = true;
}
});
this.sceneMode = mode;
this.coreThreeRepository?.setTransformMode(this.sceneMode);
this.sceneModeWatcher();
};
createNewForm = (formType: SceneManagerForms | undefined) => {
this.activeFormDependency = {
store: this,
};
this.activeFormType = formType;
};
makeSolid = () => {};
createNewScene = () =>
this.viewModel.valid().fold(
async (s) => {
@ -78,12 +141,11 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
async (e) => message.error(e)
);
deleteSceneItem(item: BaseSceneItemModel) {
const itm = this.sceneModels.filter((el) => el.id === item.id);
this.coreThreeRepository!.deleteSceneItem(itm[0]);
this.sceneModels = this.sceneModels.filter((el) => el.name !== item.name);
deleteSceneItem = (item: SceneItems) => {
this.sceneItems = this.sceneItems.filter((el) => !el.name.isEqual(item.name));
this.coreThreeRepository?.deleteSceneItem(item.name);
this.visibleSaveButton();
}
};
visibleSaveButton = () => {
this.isVisibleSaveButton = true;
@ -92,7 +154,8 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
addNewCamera = (model: CameraViewModel) => {
model.position = this.coreThreeRepository!.camera.position;
model.quaternion = this.coreThreeRepository!.camera.quaternion;
this.sceneItems.push({ name: model.cameraLink, icon: "Camera", fn: () => {} });
this.sceneItems.push({ name: model.cameraLink, icon: "Camera", fn: () => {}, isSelected: false });
this.coreThreeRepository?.addSceneCamera(model);
this.visibleSaveButton();
};
@ -117,7 +180,7 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
} catch (error) {
message.error(String(error));
}
}
};
isRenderedAsset(name: string): boolean {
return this.sceneModels
@ -130,19 +193,7 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
.isNotEmpty();
}
hiddenMenu() {
this.isSceneMenuShow = false;
}
setSceneMode = (mode: SceneMode) => {
if (this.sceneMode === undefined || this.sceneMode !== mode) {
this.sceneMode = mode;
} else if (this.sceneMode === mode) {
this.sceneMode = SceneMode.EMPTY;
}
this.coreThreeRepository?.setTransformMode(this.sceneMode);
this.sceneModeWatcher();
};
hiddenMenu = () => (this.isSceneMenuShow = false);
sceneModeWatcher() {}
@ -155,20 +206,19 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
this.mapOk("scenes", this.sceneHttpRepository.getAllScenes());
}
};
errorHandingStrategy = (error: HttpError) => {
if (error.status === 404) {
this.errors.push(new UiBaseError(`${RobossemblerFiles.robossemblerAssets} not found to project`));
}
};
errorHandingStrategy = (error: HttpError) =>
error.status
.isEqualR(404)
.map(() => this.errors.push(new UiBaseError(`${RobossemblerFiles.robossemblerAssets} not found to project`)));
async loadScene(canvasRef: HTMLCanvasElement) {
loadScene = (canvasRef: HTMLCanvasElement) => {
this.canvasRef = canvasRef;
if (this.storeMode.isEqual(StoreMode.sceneInstance)) this.loadWebGl(canvasRef);
this.storeMode.isEqualR(StoreMode.sceneInstance).map(() => this.loadWebGl(canvasRef));
// await this.mapOk<RobossemblerAssets>("robossemblerAssets", this.sceneHttpRepository.getRobossemblerAssets());
// if (this.robossemblerAssets) {
// this.coreThreeRepository?.loadInstances(this.robossemblerAssets);
// }
}
};
loadWebGl(canvasRef: HTMLCanvasElement): void {
this.coreThreeRepository = new CoreThreeRepository(canvasRef as HTMLCanvasElement, this.watcherSceneEditorObject);
@ -176,56 +226,80 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
this.coreThreeRepository.render();
this.sceneModels = this.coreThreeRepository.getAllSceneModels();
window.addEventListener("click", (event) => this.clickLister(event));
window.addEventListener("mousedown", (e) => this.sceneContextMenu(e));
canvasRef.addEventListener("click", (event) => this.clickLister(event, canvasRef.getBoundingClientRect().x));
canvasRef.addEventListener("mousedown", (e) => this.sceneContextMenu(e));
}
clickLister(event: MouseEvent) {
clickLister = (event: MouseEvent, offset: number = 0) => {
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) {
const boundingRect = this.canvasRef!.getBoundingClientRect();
vector.x = ((event.clientX - offset) / boundingRect.width) * 2 - 1;
vector.y = -(event.clientY / boundingRect.height) * 2 + 1;
if (this.mousePositionAwait && this.solidSpawnHelper) {
this.mousePositionAwait = false;
this.mousePosition = vector;
this.coreThreeRepository?.setRayCastAndGetFirstObjectAndPointToObject(vector).map((v3) => {
this.coreThreeRepository?.solidSpawn(
this.solidSpawnHelper as ISolidSpawnHelper,
(obj: Object3D<Object3DEventMap> | undefined) => {
const { solidType, name, url } = this.solidSpawnHelper as ISolidSpawnHelper;
this.scene.push(new SolidBodyModel(obj!.quaternion, obj!.position, name, solidType, url, url));
this.sceneItems.push({
name: String(this.solidSpawnHelper?.name),
icon: "Solid",
isSelected: false,
fn: () => this.createNewForm(SceneManagerForms.solidBody),
});
},
v3
);
});
}
if (this.sceneMode.isEqual(SceneMode.Select)) {
return;
}
if (this.sceneMode === SceneMode.MOVING || this.sceneMode === SceneMode.ROTATE) {
if (this.sceneMode === SceneMode.Move || this.sceneMode === SceneMode.Rotate) {
this.transformContollsCall(vector);
}
}
};
sceneContextMenu(e: MouseEvent): void {
if (e.button === 2) {
sceneContextMenu = (e: MouseEvent) =>
e.button.isEqualR(2).map(() => {
this.isSceneMenuShow = true;
this.sceneMenu.x = e.clientX;
this.sceneMenu.y = e.clientY;
}
}
});
watcherThereObjects = (sceneItemModel: BaseSceneItemModel): void => {
this.sceneModels.push(sceneItemModel);
watcherThereObjects = (sceneItemModel: BaseSceneItemModel) => {
// this.sceneModels.push(sceneItemModel);
console.log(sceneItemModel);
};
watcherSceneEditorObject = (mesh: Object3D) => {
this.sceneModels = this.sceneModels.map((el) => {
if (el.name === mesh.name) {
el.position = mesh.position;
el.quaternion = mesh.quaternion;
return el;
}
return el;
});
this.scene = this.scene.map((el) =>
el.name.isEqualR(mesh.name).fold(
() => {
el.vector3 = mesh.position;
el.quaternion = mesh.quaternion;
return el;
},
() => el
)
);
this.visibleSaveButton();
};
transformContollsCall = (vector: Vector2) => {
transformContollsCall = (vector: Vector2) =>
this.coreThreeRepository?.setRayCastAndGetFirstObject(vector).fold(
(success) => this.coreThreeRepository?.setTransformControlsAttach(success),
(_error) => this.coreThreeRepository?.disposeTransformControlsMode()
(object) => this.coreThreeRepository?.setTransformControlsAttach(object),
(_) => this.coreThreeRepository?.disposeTransformControlsMode()
);
};
dispose() {
dispose = () => {
window.removeEventListener("click", this.clickLister);
window.removeEventListener("mousedown", (e) => this.sceneContextMenu(e));
}
};
}