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

76
.vscode/launch.json vendored
View file

@ -1,40 +1,40 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
{
"type": "node",
"request": "launch",
"name": "server-dev",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run-script", "dev"
],
"cwd": "${workspaceRoot}/server/",
},
{
"type": "node",
"request": "launch",
"name": "server-test-watch",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run-script", "test:watch"
],
"cwd": "${workspaceRoot}/server/",
},
{
"type": "node",
"request": "launch",
"name": "ui-dev",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run-script", "dev"
],
"cwd": "${workspaceRoot}/ui/",
}
]
}
"configurations": [
{
"type": "node",
"request": "launch",
"name": "server-dev",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "dev"],
"cwd": "${workspaceRoot}/server/"
},
{
"type": "node",
"request": "launch",
"name": "server-test-watch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "test:watch"],
"cwd": "${workspaceRoot}/server/"
},
{
"type": "node",
"request": "launch",
"name": "ui-dev",
"runtimeExecutable": "npm",
"runtimeArgs": ["run-script", "dev"],
"cwd": "${workspaceRoot}/ui/"
},
{
"type": "chrome",
"request": "launch",
"name": "Launch debug chrome",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
}
]
}

View file

@ -16,6 +16,7 @@ export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery {
return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
await DatasetDBModel.findById(id).updateOne({ processStatus: "RUN" });
model.local_path = `${model.local_path}/${FolderStructure.datasets}/`;
return new ExecProcessUseCase().call(
`${model.project.rootDir}/`,
`blenderproc run $PYTHON_BLENDER_PROC --cfg '${JSON.stringify(model)}'`,

View file

@ -12,6 +12,9 @@ export interface Parts {
stlUrl: string;
image: string;
glUrl: string;
daeUrl: string;
objUrl: string;
solidType: string;
}
export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWithEmpty {
@ -35,7 +38,10 @@ export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWit
el.stlUrl = `${assetAddress}${el.part_path}`;
el.glUrl = `${assetLibsAddress}.glb`;
el.daeUrl = `${assetLibsAddress}.dae`;
el.objUrl = `${assetLibsAddress}.obj`;
el.image = `${assetLibsAddress}.png`;
el.solidType = 'active'
return el;
});
return Result.ok(model);

View file

@ -13,6 +13,7 @@ export enum FolderStructure {
weights = "weights",
datasets = "datasets",
behaviorTrees = "behavior_trees",
robots = "robots",
}
export class UploadCadFileToProjectScenario extends CallbackStrategyWithFileUpload {
@ -20,24 +21,23 @@ export class UploadCadFileToProjectScenario extends CallbackStrategyWithFileUplo
idValidationExpression = new MongoIdValidation();
async call(file: IFile, id: string): ResponseBase {
return (await new ReadByIdDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(id)).map(
async (databaseModel) =>
(await new CreateFileUseCase().call(`${databaseModel.rootDir}/${file.name}`, file.data)).map(async () =>
(
await new ExecProcessUseCase().call(
`${databaseModel.rootDir}/`,
`python3 $PYTHON_BLENDER --path '${databaseModel.rootDir}/assets/'`,
""
)
).map(async () =>
(
await new CreateManyFolderScenario().call(
databaseModel.rootDir,
Object.keys(FolderStructure).map((el) => `/${el}`)
)
).map(() => Result.ok("file upload and save"))
return (await new ReadByIdDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(id)).map(async (databaseModel) =>
(await new CreateFileUseCase().call(`${databaseModel.rootDir}/${file.name}`, file.data)).map(async () =>
(
await new ExecProcessUseCase().call(
`${databaseModel.rootDir}/`,
`python3 $PYTHON_BLENDER --path '${databaseModel.rootDir}/assets/'`,
""
)
).map(async () =>
(
await new CreateManyFolderScenario().call(
databaseModel.rootDir,
Object.keys(FolderStructure).map((el) => `/${el}`)
)
).map(() => Result.ok("file upload and save"))
)
)
);
}
}

1035
ui/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,22 +7,9 @@
"@foxglove/rosmsg": "^5.0.4",
"@foxglove/rosmsg2-serialization": "^2.0.3",
"@foxglove/ws-protocol": "^0.7.3",
"@monaco-editor/react": "^4.6.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.46",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/socket.io-client": "^3.0.0",
"@types/uuid": "^9.0.2",
"babylonjs": "^7.11.2",
"babylonjs-loaders": "^7.11.2",
"babylonjs-serializers": "^7.11.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"formik-antd": "^2.0.4",
"antd": "^4.24.15",
"i18next": "^23.6.0",
"just-clone": "^6.2.0",
"mobx": "^6.10.0",
@ -31,8 +18,6 @@
"pattern-matching-ts": "^2.0.0",
"react": "^18.2.0",
"react-accessible-treeview": "^2.8.3",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-i18next": "^13.3.1",
"react-infinite-scroll-component": "^6.1.0",
@ -42,23 +27,21 @@
"rete-connection-plugin": "^2.0.0",
"rete-react-plugin": "^2.0.4",
"rete-render-utils": "^2.0.1",
"sass": "^1.66.1",
"serve": "^14.2.1",
"socket.io-client": "^4.7.2",
"source-map-loader": "^5.0.0",
"styled-components": "^6.1.8",
"three": "^0.165.0",
"three-stdlib": "^2.28.9",
"three-transform-controls": "^1.0.4",
"ts-pattern": "^5.1.1",
"typescript": "^5.4",
"typescript-mixin": "^1.0.3",
"typescript": "^5.0.2",
"urdf-loader": "^0.12.1",
"uuid": "^9.0.1",
"web-vitals": "^2.1.4",
"ws": "^8.17.0",
"xml-formatter": "^3.6.2"
},
"overrides": {
"typescript": "^5.0.2"
},
"scripts": {
"dev": "react-scripts start",
"build": "react-scripts build",
@ -68,7 +51,8 @@
},
"eslintConfig": {
"extends": [
"react-app" ]
"react-app"
]
},
"browserslist": {
"production": [
@ -83,6 +67,12 @@
]
},
"devDependencies": {
"@types/three": "^0.158.3"
"@types/three": "^0.158.3",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.46",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/socket.io-client": "^3.0.0",
"@types/uuid": "^9.0.2"
}
}
}

View file

@ -1,7 +1,9 @@
# Установка зависимостей
# Установка зависимостей
```
brew install mason
```
### Инициализация
В корне проекта вызовите команду `init`, которая создаст папку `.mason/`
@ -39,9 +41,14 @@ mason new my_brick_name
Для большей информации [читайте и смотрите примеры](https://github.com/felangel/mason/blob/master/packages/mason_cli/README.md)
# Добавить новую форму в деревья поведения
mason make form -o ./src/features/behavior_tree_builder/presentation/ui/forms
# Добавить новую форму в Scene Manager
mason make form -o ./src/features/scene_manager/presentation/forms
# Добавить новую форму
mason make form -o ./src/features/behavior_tree_builder/presentation/ui/forms
# Добавить новый экран
mason make base_feature -o ./src/features/
mason make base_feature -o ./src/features/

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));
}
};
}

View file

@ -18,7 +18,8 @@
"useDefineForClassFields": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictPropertyInitialization": false
"strictPropertyInitialization": false,
"sourceMap": true
},
"types": ["babylonjs", "babylonjs-loaders"],
"include": ["src"]

View file

@ -1,21 +1,27 @@
{
"eslintConfig": {
"extends": ["react-app", "shared-config"],
"extends": [
"react-app",
"shared-config"
],
"rules": {
"additional-rule": "warn",
"no-extend-native":"off",
"react-hooks/exhaustive-deps":"off"
"no-extend-native": "off",
"react-hooks/exhaustive-deps": "off",
"array-callback-return": "off"
},
"overrides": [
{
"files": ["**/*.ts?(x)"],
"files": [
"**/*.ts?(x)"
],
"rules": {
"additional-typescript-only-rule": "warn",
"array-callback-return": "off",
"react-hooks/exhaustive-deps": "off",
"no-extend-native":"off"
"no-extend-native": "off"
}
}
]
}
}
}

BIN
web_p/blender/.DS_Store vendored Normal file

Binary file not shown.

BIN
web_p/blender/assets/.DS_Store vendored Normal file

Binary file not shown.

BIN
web_p/blender/libs/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ import blenderproc as bproc
Используется модуль blenderproc
02.05.2024 @shalenikol release 0.1
02.07.2024 @shalenikol release 0.2
"""
import numpy as np
import argparse
@ -13,25 +14,37 @@ import random
import os
import shutil
import json
from pathlib import Path
import bpy
VHACD_PATH = "blenderproc_resources/vhacd"
DIR_MODELS = "models"
DIR_MESH = "assets/libs/objects/" #"assets/mesh/"
FILE_LOG_SCENE = "res.txt"
FILE_RBS_INFO = "rbs_info.json"
FILE_GT_COCO = "scene_gt_coco.json"
EXT_MODELS = ".fbx"
TEXTURE_TMPL = "*.jpg"
Not_Categories_Name = True # наименование категории в COCO-аннотации отсутствует
def _get_list_texture(rel_path: str) -> list:
# local_path/texture/
loc = os.path.dirname(os.path.dirname(rnd_par.output_dir))
path = os.path.join(loc, rel_path)
return list(Path(path).absolute().rglob(TEXTURE_TMPL))
def _get_path_model(name_model: str) -> str:
# TODO on name_model find path for mesh (model.fbx)
# local_path/assets/mesh/
# local_path/assets/libs/objects # assets/mesh/
loc = os.path.dirname(os.path.dirname(rnd_par.output_dir))
return os.path.join(loc, "assets/mesh/"+name_model+".fbx")
return os.path.join(loc, DIR_MESH + name_model + EXT_MODELS)
def _get_path_object(name_obj: str) -> str:
# TODO on name_obj find path for scene object (object.fbx)
loc = os.path.dirname(os.path.dirname(rnd_par.output_dir))
return os.path.join(loc, "assets/mesh/"+name_obj+".fbx")
return os.path.join(loc, DIR_MESH + name_obj + EXT_MODELS)
def convert2relative(height, width, bbox):
"""
@ -43,11 +56,14 @@ def convert2relative(height, width, bbox):
return x/width, y/height, w/width, h/height
def render() -> int:
i = 0
for obj in all_meshs:
# Make the object actively participate in the physics simulation
obj.enable_rigidbody(active=True, collision_shape="COMPOUND")
# Also use convex decomposition as collision shapes
obj.build_convex_decomposition_collision_shape(VHACD_PATH)
i += 1
# print(f"{i} : {obj.get_name()}")
objs = all_meshs + rnd_par.scene.objs
@ -85,13 +101,26 @@ def render() -> int:
# Цикл рендеринга
# Do multiple times: Position the shapenet objects using the physics simulator and render X images with random camera poses
for r in range(rnd_par.n_series):
print(f"********** Series : {r+1}")
is_texture = True if "texture_path" in rnd_par.models_randomization else False
if is_texture:
val = rnd_par.models_randomization["texture_path"]
l_texture = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(l_texture[r % len(l_texture)]))
# один случайный объект в кадре / все заданные объекты
random_obj = random.choice(range(rnd_par.scene.n_obj))
random_obj = random.choice(range(rnd_par.models.n_item))
meshs = []
for i,o in enumerate(all_meshs): #objs
for i,o in enumerate(all_meshs): # активные модели
if rnd_par.single_object and i != random_obj:
continue
meshs += [o]
if is_texture:
mats = o.get_materials()
for mat in mats:
# image = bpy.data.images.load(filepath=str(random.choice(l_texture)))
mat.set_principled_shader_value("Base Color", image)
for i,o in enumerate(rnd_par.scene.objs): # объекты сцены
rnd_mat = rnd_par.scene.obj_data[i]["material_randomization"]
mats = o.get_materials() #[0]
for mat in mats:
@ -99,10 +128,17 @@ def render() -> int:
mat.set_principled_shader_value("Specular", random.uniform(val[0], val[1]))
val = rnd_mat["roughness"]
mat.set_principled_shader_value("Roughness", random.uniform(val[0], val[1]))
val = rnd_mat["base_color"]
mat.set_principled_shader_value("Base Color", np.random.uniform(val[0], val[1]))
val = rnd_mat["metallic"]
mat.set_principled_shader_value("Metallic", random.uniform(val[0], val[1]))
if "texture_path" in rnd_mat: # путь к текстурам (*.jpg)
val = rnd_mat["texture_path"]
val = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(random.choice(val)))
mat.set_principled_shader_value("Base Color", image)
else:
val = rnd_mat["base_color"]
mat.set_principled_shader_value("Base Color", np.random.uniform(val[0], val[1]))
# mat.set_principled_shader_value("Base Color", image)
# Randomly set the color and energy
for i,l in enumerate(ls):
@ -225,7 +261,7 @@ def render() -> int:
cat["name"] = rnd_par.models.names[i] #obj_names[i]
with open(coco_file, "w") as fh:
json.dump(data, fh, indent=0)
json.dump(data, fh, indent=1)
def explore(path: str):
if not os.path.isdir(path):
@ -331,7 +367,7 @@ if __name__ == "__main__":
models_randomization = ds_cfg["models_randomization"]
rnd_par = lambda: None
rnd_par.single_object = True
rnd_par.single_object = False # True
rnd_par.ds_name = cfg["name"]
rnd_par.output_dir = cfg["local_path"]
rnd_par.dataset_objs = cfg["dataSetObjects"]
@ -343,6 +379,7 @@ if __name__ == "__main__":
rnd_par.center_shell = cam_pos["center_shell"]
rnd_par.radius_range = cam_pos["radius_range"]
rnd_par.elevation_range = cam_pos["elevation_range"]
rnd_par.models_randomization = models_randomization
rnd_par.loc_range_low = models_randomization["loc_range_low"]
rnd_par.loc_range_high = models_randomization["loc_range_high"]
@ -353,8 +390,7 @@ if __name__ == "__main__":
bproc.init()
all_meshs = []
ret = _get_models(rnd_par, rnd_par.dataset_objs)
if ret <= 0:
if _get_models(rnd_par, rnd_par.dataset_objs) <= 0:
print("Error: no models in config")
exit(-4)
if _get_scene(rnd_par, ds_cfg["scene"]) == 0:

View file

@ -0,0 +1 @@
/home/idontsudo/robossembler_ws/src/rbs_gripper/meshes/visual/base.dae

View file

@ -0,0 +1 @@
/home/idontsudo/robossembler_ws/src/rbs_arm/meshes/visual/ee_link.dae

View file

@ -0,0 +1 @@
/home/idontsudo/robossembler_ws/src/rbs_gripper/meshes/visual/finger.dae

View file

@ -0,0 +1 @@
/home/idontsudo/robossembler_ws/src/rbs_arm/meshes/visual/fork_link.dae

View file

@ -0,0 +1 @@
/home/idontsudo/robossembler_ws/src/rbs_arm/meshes/visual/main_link.dae

View file

@ -0,0 +1,346 @@
<robot name="rbs_arm">n <link name="world" />n <joint name="base_link_joint" type="fixed">n <origin
rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0" />n <parent
link="world" />n <child link="base_link" />n </joint>n <link name="base_link">n <collision
name="base_link_collision">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 0.00000 0.00000" />n <geometry>n <mesh
filename="start_link.stl"
scale="1.00000 1.00000 1.00000" />n </geometry>n </collision> n <inertial>n <inertia
ixx="0.00503302470272442" ixy="0.000343817346410954" ixz="-4.74990755448368E-06"
iyy="0.00337962410057753" iyz="-2.3099255620051E-05" izz="0.00405858207282473" />n <origin
rpy="0.00000 0.00000 0.00000"
xyz="-0.000297002857922682 0.0964721185617698 -0.000361033370053684" /> n <mass
value="1.88031044620482" />n </inertial>n <visual name="base_link_visual">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 0.00000 0.00000" />n <geometry> n <mesh
filename="start_link.dae"
scale="1.00000 1.00000 1.00000" />n </geometry>n </visual>n </link>n <gazebo
reference="base_link">n <visual>n <material>n <diffuse>0.8 0.8 0.8 1</diffuse>n <specular>0.6
0.6
0.6 1</specular>n <ambient>1.0 1.0 1.0</ambient>n <lighting>true</lighting>n <emissive>0
0 0
1</emissive>n <pbr>n <metal>n <albedo_map>
/base_link_d.png</albedo_map> n <normal_map>
/base_link_n.png</normal_map>
n <ambient_occlusion_map>
/base_link_ao.png</ambient_occlusion_map>
n <roughness_map>
/base_link_r.png</roughness_map>
n </metal>n </pbr>n </material>n </visual>n </gazebo>n <joint name="fork0_link_joint"
type="revolute">n <limit
effort="78" lower="-6.14159" upper="6.14159" velocity="0.52" />n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 0.00000 0.17833" />n <parent link="base_link" />
n <child link="fork0_link" />n <axis xyz="0 0 1" />n </joint>n <link name="fork0_link">n <collision
name="fork0_link_collision">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry>n <mesh
filename="fork_link.stl"
scale="1.00000 1.00000 1.00000" />n </geometry>n </collision> n <inertial>n <inertia
ixx="0.00367804533572758" ixy="1.04277925521833E-05" ixz="-0.00149971410403071"
iyy="0.00415208849477534" iyz="-0.00122" izz="0.00329" />n <origin
rpy="0.00000 0.00000 0.00000"
xyz="0.0472051139085306 0.00208890925682996 0.0557265410642575" /> n <mass
value="1.12472202892859" />n </inertial>n <visual name="fork0_link_visual">n <origin
rpy="0.00000 -0.00000 -0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry> n <mesh
filename="fork_link.dae"
scale="1.00000 1.00000 1.00000" />n </geometry>n </visual>n </link>n <ros2_control
name="fork0_link_joint_hardware_interface" type="actuator">n <hardware>n <plugin>
ign_ros2_control/IgnitionSystem</plugin>n </hardware> n <joint name="fork0_link_joint">n <command_interface
name="position">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <command_interface
name="velocity">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <!-- WARN When this active a robot falls
down -->n <!-- <command_interface
name="effort"/> -->n <!-- <param name="p">${p}</param> -->n <!-- <param name="d">${d}</param> -->n <!-- <command_interface
name="effort"/> -->n <state_interface
name="position" />n <state_interface
name="velocity" />n <state_interface name="effort" />n </joint>n </ros2_control>n <gazebo
reference="fork0_link">n <visual>n <material>n <diffuse>0.8 0.8 0.8 1</diffuse>n <specular>0.6
0.6
0.6 1</specular>n <ambient>1.0 1.0 1.0</ambient>n <lighting>true</lighting>n <emissive>0
0 0
1</emissive>n <pbr>n <metal>n <albedo_map>
/fork_d.png</albedo_map>
n <normal_map>
/fork_n.png</normal_map>
n <ambient_occlusion_map>
/fork_ao.png</ambient_occlusion_map>
n <roughness_map>
/fork_r.png</roughness_map>
n </metal>n </pbr>n </material>n </visual>n </gazebo>n <joint name="main0_link_joint"
type="revolute">n <limit
effort="78" lower="-1.5708" upper="3.14159" velocity="0.52" />n <origin
rpy="-0.00000 0.00000 0.00000" xyz="0.10000 0.00000 0.09400" />n <parent
link="fork0_link" /> n <child link="main0_link" />n <axis xyz="0 1 0" />n </joint>n <link
name="main0_link">n <collision name="main0_link_collision">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 0.00000 0.00000" />n <geometry>n <mesh
filename="main_link.stl"
scale="1.00000 1.00000 1.00000" />n </geometry>n </collision> n <inertial>n <inertia
ixx="0.00315699373090845" ixy="2.84713820858537E-05" ixz="-7.01601261191721E-05"
iyy="0.00343729241263707" iyz="-0.000101485203138902" izz="0.00125534890134052" />n <origin
rpy="0.00000 0.00000 0.00000"
xyz="0.00186712264682627 -0.000412152188777604 0.0516389446895805" /> n <mass
value="1.58688811563124" />n </inertial>n <visual name="main0_link_visual">n <origin
rpy="0.00000 -0.00000 -0.00000" xyz="0.00000 0.00000 0.00000" />n <geometry> n <mesh
filename="main_link.dae"
scale="1.00000 1.00000 1.00000" />n </geometry>n </visual>n </link>n <ros2_control
name="main0_link_joint_hardware_interface" type="actuator">n <hardware>n <plugin>
ign_ros2_control/IgnitionSystem</plugin>n </hardware> n <joint name="main0_link_joint">n <command_interface
name="position">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <command_interface
name="velocity">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <!-- WARN When this active a robot falls
down -->n <!-- <command_interface
name="effort"/> -->n <!-- <param name="p">${p}</param> -->n <!-- <param name="d">${d}</param> -->n <!-- <command_interface
name="effort"/> -->n <state_interface
name="position" />n <state_interface
name="velocity" />n <state_interface name="effort" />n </joint>n </ros2_control>n <gazebo
reference="main0_link">n <visual>n <material>n <diffuse>0.8 0.8 0.8 1</diffuse>n <specular>0.6
0.6
0.6 1</specular>n <ambient>1.0 1.0 1.0</ambient>n <lighting>true</lighting>n <emissive>0
0 0
1</emissive>n <pbr>n <metal>n <albedo_map>
/main_link_d.png</albedo_map>
n <normal_map>
/main_link_n.png</normal_map>
n <ambient_occlusion_map>
/main_link_ao.png</ambient_occlusion_map>
n <roughness_map>
/main_link_r.png</roughness_map>
n </metal>n </pbr>n </material>n </visual>n </gazebo>n <joint name="fork1_link_joint"
type="revolute">n <limit
effort="78" lower="-6.14159" upper="6.14159" velocity="0.52" />n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 0.00000 0.13300" />n <parent
link="main0_link" /> n <child link="fork1_link" />n <axis xyz="0 0 1" />n </joint>n <link
name="fork1_link">n <collision name="fork1_link_collision">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry>n <mesh
filename="fork_link.stl"
scale="1.00000 1.00000 1.00000" />n </geometry>n </collision> n <inertial>n <inertia
ixx="0.00367804533572758" ixy="1.04277925521833E-05" ixz="-0.00149971410403071"
iyy="0.00415208849477534" iyz="-0.00122" izz="0.00329" />n <origin
rpy="0.00000 0.00000 0.00000"
xyz="0.0472051139085306 0.00208890925682996 0.0557265410642575" /> n <mass
value="1.12472202892859" />n </inertial>n <visual name="fork1_link_visual">n <origin
rpy="0.00000 -0.00000 -0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry> n <mesh
filename="fork_link.dae"
scale="1.00000 1.00000 1.00000" />n </geometry>n </visual>n </link>n <ros2_control
name="fork1_link_joint_hardware_interface" type="actuator">n <hardware>n <plugin>
ign_ros2_control/IgnitionSystem</plugin>n </hardware> n <joint name="fork1_link_joint">n <command_interface
name="position">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <command_interface
name="velocity">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <!-- WARN When this active a robot falls
down -->n <!-- <command_interface
name="effort"/> -->n <!-- <param name="p">${p}</param> -->n <!-- <param name="d">${d}</param> -->n <!-- <command_interface
name="effort"/> -->n <state_interface
name="position" />n <state_interface
name="velocity" />n <state_interface name="effort" />n </joint>n </ros2_control>n <gazebo
reference="fork1_link">n <visual>n <material>n <diffuse>0.8 0.8 0.8 1</diffuse>n <specular>0.6
0.6
0.6 1</specular>n <ambient>1.0 1.0 1.0</ambient>n <lighting>true</lighting>n <emissive>0
0 0
1</emissive>n <pbr>n <metal>n <albedo_map>
/fork_d.png</albedo_map>
n <normal_map>
/fork_n.png</normal_map>
n <ambient_occlusion_map>
/fork_ao.png</ambient_occlusion_map>
n <roughness_map>
/fork_r.png</roughness_map>
n </metal>n </pbr>n </material>n </visual>n </gazebo>n <joint name="main1_link_joint"
type="revolute">n <limit
effort="78" lower="-1.5708" upper="3.14159" velocity="0.52" />n <origin
rpy="-0.00000 0.00000 0.00000" xyz="0.10000 0.00000 0.09400" />n <parent
link="fork1_link" /> n <child link="main1_link" />n <axis xyz="0 1 0" />n </joint>n <link
name="main1_link">n <collision name="main1_link_collision">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 0.00000 0.00000" />n <geometry>n <mesh
filename="main_link.stl"
scale="1.00000 1.00000 1.00000" />n </geometry>n </collision> n <inertial>n <inertia
ixx="0.00315699373090845" ixy="2.84713820858537E-05" ixz="-7.01601261191721E-05"
iyy="0.00343729241263707" iyz="-0.000101485203138902" izz="0.00125534890134052" />n <origin
rpy="0.00000 0.00000 0.00000"
xyz="0.00186712264682627 -0.000412152188777604 0.0516389446895805" /> n <mass
value="1.58688811563124" />n </inertial>n <visual name="main1_link_visual">n <origin
rpy="0.00000 -0.00000 -0.00000" xyz="0.00000 0.00000 0.00000" />n <geometry> n <mesh
filename="main_link.dae"
scale="1.00000 1.00000 1.00000" />n </geometry>n </visual>n </link>n <ros2_control
name="main1_link_joint_hardware_interface" type="actuator">n <hardware>n <plugin>
ign_ros2_control/IgnitionSystem</plugin>n </hardware> n <joint name="main1_link_joint">n <command_interface
name="position">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <command_interface
name="velocity">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <!-- WARN When this active a robot falls
down -->n <!-- <command_interface
name="effort"/> -->n <!-- <param name="p">${p}</param> -->n <!-- <param name="d">${d}</param> -->n <!-- <command_interface
name="effort"/> -->n <state_interface
name="position" />n <state_interface
name="velocity" />n <state_interface name="effort" />n </joint>n </ros2_control>n <gazebo
reference="main1_link">n <visual>n <material>n <diffuse>0.8 0.8 0.8 1</diffuse>n <specular>0.6
0.6
0.6 1</specular>n <ambient>1.0 1.0 1.0</ambient>n <lighting>true</lighting>n <emissive>0
0 0
1</emissive>n <pbr>n <metal>n <albedo_map>
/main_link_d.png</albedo_map>
n <normal_map>
/main_link_n.png</normal_map>
n <ambient_occlusion_map>
/main_link_ao.png</ambient_occlusion_map>
n <roughness_map>
/main_link_r.png</roughness_map>
n </metal>n </pbr>n </material>n </visual>n </gazebo>n <joint name="fork2_link_joint"
type="revolute">n <limit
effort="78" lower="-6.14159" upper="6.14159" velocity="0.52" />n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 0.00000 0.13300" />n <parent
link="main1_link" /> n <child link="fork2_link" />n <axis xyz="0 0 1" />n </joint>n <link
name="fork2_link">n <collision name="fork2_link_collision">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry>n <mesh
filename="fork_link.stl"
scale="1.00000 1.00000 1.00000" />n </geometry>n </collision> n <inertial>n <inertia
ixx="0.00367804533572758" ixy="1.04277925521833E-05" ixz="-0.00149971410403071"
iyy="0.00415208849477534" iyz="-0.00122" izz="0.00329" />n <origin
rpy="0.00000 0.00000 0.00000"
xyz="0.0472051139085306 0.00208890925682996 0.0557265410642575" /> n <mass
value="1.12472202892859" />n </inertial>n <visual name="fork2_link_visual">n <origin
rpy="0.00000 -0.00000 -0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry> n <mesh
filename="fork_link.dae"
scale="1.00000 1.00000 1.00000" />n </geometry>n </visual>n </link>n <ros2_control
name="fork2_link_joint_hardware_interface" type="actuator">n <hardware>n <plugin>
ign_ros2_control/IgnitionSystem</plugin>n </hardware> n <joint name="fork2_link_joint">n <command_interface
name="position">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <command_interface
name="velocity">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <!-- WARN When this active a robot falls
down -->n <!-- <command_interface
name="effort"/> -->n <!-- <param name="p">${p}</param> -->n <!-- <param name="d">${d}</param> -->n <!-- <command_interface
name="effort"/> -->n <state_interface
name="position" />n <state_interface
name="velocity" />n <state_interface name="effort" />n </joint>n </ros2_control>n <gazebo
reference="fork2_link">n <visual>n <material>n <diffuse>0.8 0.8 0.8 1</diffuse>n <specular>0.6
0.6
0.6 1</specular>n <ambient>1.0 1.0 1.0</ambient>n <lighting>true</lighting>n <emissive>0
0 0
1</emissive>n <pbr>n <metal>n <albedo_map>
/fork_d.png</albedo_map>
n <normal_map>
/fork_n.png</normal_map>
n <ambient_occlusion_map>
/fork_ao.png</ambient_occlusion_map>
n <roughness_map>
/fork_r.png</roughness_map>
n </metal>n </pbr>n </material>n </visual>n </gazebo>n <joint name="ee_link_joint"
type="revolute">n <limit
effort="78" lower="-1.5708" upper="3.14159" velocity="0.52" />n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.10000 0.00000 0.09473" />n <parent
link="fork2_link" /> n <child link="ee_link" />n <axis xyz="0 1 0" />n </joint>n <joint
name="tool0_joint" type="fixed">n <origin rpy="0.00000 0.00000 0.00000"
xyz="0.00000 0.00000 0.11000" />n <parent link="ee_link" />n <child link="tool0" />n </joint>
n <link name="tool0" />n <link
name="ee_link">n <collision name="ee_link_collision">n <origin
rpy="-0.00000 0.00000 -0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry>n <mesh
filename="ee_link.stl"
scale="1.00000 1.00000 1.00000" />n </geometry>n </collision>n <inertial>n <inertia
ixx="0.00147695259043549" ixy="-2.66894744420299E-05"
ixz="-4.40871314563273E-05" iyy="0.00135500487881796" iyz="-3.19001462979333E-05"
izz="0.00087582892706912" />n <origin rpy="0.00000 0.00000 0.00000"
xyz="-9.7531539777207E-06 -0.000888494418875867 0.0342332199538358" />n <mass
value="1.88031044620482" />n </inertial> n <visual name="ee_link_visual">n <origin
rpy="0.00000 0.00000 0.00000" xyz="0.00000 -0.00000 0.00000" />n <geometry>n <mesh
filename="ee_link.dae"
scale="1.00000 1.00000 1.00000" />n </geometry> n </visual>n </link>n <ros2_control
name="ee_link_joint_hardware_interface" type="actuator">n <hardware>n <plugin>
ign_ros2_control/IgnitionSystem</plugin>n </hardware>n <joint name="ee_link_joint">n <command_interface
name="position">n <!-- <param name="min">-1</param> -->n <!-- <param name="max">1</param> -->n </command_interface>n <command_interface name="velocity">n <!--
<param
name="min">-1</param> -->n <!--
<param
name="max">1</param> -->n </command_interface>
n <!-- WARN When this active a robot falls down -->n <!-- <command_interface name="effort"/> -->n <!-- <param name="p">${p}</param> -->n <!-- <param name="d">${d}</param> -->n <!-- <command_interface name="effort"/> -->n <state_interface name="position" />n <state_interface name="velocity" />n <state_interface
name="effort" />n </joint>n </ros2_control>n <gazebo reference="ee_link">n <visual>n <material>
n <diffuse>0.8 0.8 0.8 1</diffuse>n <specular>0.6 0.6 0.6 1</specular>n <ambient>1.0
1.0 1.0</ambient>n <lighting>true</lighting>n <emissive>0 0 0 1</emissive>n <pbr>
n <metal>n <albedo_map>
/ee_link_d.png</albedo_map>
n <normal_map>
/ee_link_n.png</normal_map>
n <ambient_occlusion_map>
/ee_link_ao.png</ambient_occlusion_map>
n <roughness_map>
/ee_link_r.png</roughness_map>
n </metal>n </pbr>n </material>n </visual>n </gazebo>n <!-- END robot description -->n <ros2_control name="rbs_gripper_gazebo"
type="system">n <!-- Plugins -->n <hardware>n <plugin>ign_ros2_control/IgnitionSystem</plugin>n </hardware>n <!--
Joint interfaces -->
n <joint name="rbs_gripper_rot_base_joint">n <state_interface name="position">n <param
name="initial_value">0.000</param>n </state_interface> n <command_interface
name="position" />n <command_interface name="velocity" />n <command_interface
name="effort" />n <state_interface name="velocity" />n <state_interface
name="effort" />n </joint>n <joint
name="rbs_gripper_r_finger_joint">n <state_interface name="position">n <param
name="initial_value">0.000</param>n </state_interface> n <command_interface
name="position" />n <command_interface name="velocity" />n <command_interface
name="effort" />n <state_interface name="velocity" />n <state_interface
name="effort" />n </joint>n <joint
name="rbs_gripper_l_finger_joint">n <param name="mimic">rbs_gripper_r_finger_joint</param>
n <param name="multiplier">1</param> n </joint>n </ros2_control>n <joint
name="rbs_gripper_gripper_base_joint" type="fixed">n <origin rpy="0 0 0" xyz="0 0 0" />n <parent
link="tool0" />n <child link="rbs_gripper_gripper_base_link" />n </joint>n <link
name="rbs_gripper_gripper_base_link">n <inertial>n <origin rpy="0 0 0"
xyz="0.000364704367134063 0.0336387482840125 0.0593891203954369" />n <mass
value="1.13983632906086" />n <inertia ixx="0.00107738806534129"
ixy="-1.09841172461737E-05" ixz="2.62750043451545E-06" iyy="0.000717388573992299"
iyz="-2.95426438182787E-05" izz="0.00115777179755934" /> n </inertial>n <visual>n <origin
rpy="0 0 0" xyz="0 0 0" />n <geometry>n <mesh
filename="base.dae" /> n </geometry> n <material name="rbs_gripper_material">n <color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />n </material>n </visual>
n <collision>n <origin
rpy="0 0 0" xyz="0 0 0" />n <geometry>n <mesh
filename="base.stl" /> n </geometry>n </collision>n </link> n <link
name="rbs_gripper_rot_base_link">n <inertial>n <origin
rpy="0 0 0" xyz="6.79110135283868E-11 -3.80956832067611E-10 0.00775394473595793" />n <mass
value="0.161003401535982" />n <inertia ixx="0.00011089089949771"
ixy="5.01335040610636E-06" ixz="1.74608448389267E-14" iyy="0.000105515893695012"
iyz="-2.03282362854432E-14" izz="0.000206912001661452" />n </inertial>n <visual>n <origin
rpy="0 0 0"
xyz="0 0 0" />n <geometry>n <mesh
filename="rotor.dae" /> n </geometry>n <material name="rbs_gripper_material">n <color
rgba="0.250980392156863 0.250980392156863 0.250980392156863 1" />n </material>n </visual>
n <collision>n <origin rpy="0 0 0" xyz="0 0 0" />n <geometry> n <mesh
filename="rotor.stl" /> n </geometry>n </collision>n </link>n <joint
name="rbs_gripper_rot_base_joint" type="revolute"> n <origin
rpy="0 0 0" xyz="0 0 0.10861" />n <parent link="rbs_gripper_gripper_base_link" />n <child
link="rbs_gripper_rot_base_link" />n <axis xyz="0 0 1" />n <limit
effort="78" lower="-3.14159" upper="3.14159" velocity="0.52" />n </joint>n <link
name="rbs_gripper_l_finger_link">n <inertial>n <origin
rpy="0 0 0" xyz="0.00399878118534129 0.0187296413885176 -0.0777776233934166" />n <mass
value="0.0601996441483964" />n <inertia ixx="4.18533281165612E-05"
ixy="-7.11657995951147E-06" ixz="1.81029223490065E-05" iyy="7.89886367868258E-05"
iyz="1.20542845942065E-05"
izz="5.16740841307935E-05" />n </inertial>n <visual>n <origin rpy="0 0 0"
xyz="0 0 0" />n <geometry>n <mesh
filename="finger.dae" /> n </geometry>n <material name="rbs_gripper_material">n <color
rgba="0.752941176470588 0 0 1" />n </material> n </visual>n <collision>n <origin
rpy="0 0 0" xyz="0 0 0" />n <geometry>n <mesh
filename="finger.stl" /> n </geometry> n </collision>n </link>n <joint
name="rbs_gripper_l_finger_joint" type="prismatic"> n <origin rpy="0 0 1.5708"
xyz="0 0 0.1071" />n <parent
link="rbs_gripper_rot_base_link" />n <child link="rbs_gripper_l_finger_link" />n <axis
xyz="-1 0 0" />n <limit effort="10" lower="0" upper="0.064"
velocity="0.53" />n <mimic joint="rbs_gripper_r_finger_joint" multiplier="1" />n </joint>
n <link name="rbs_gripper_r_finger_link">n <inertial> n <origin rpy="0 0 0"
xyz="0.0039988 -0.077778 -0.01873" />n <mass value="0.0602" />n <inertia
ixx="4.1853E-05" ixy="1.8103E-05" ixz="7.1166E-06" iyy="5.1674E-05"
iyz="-1.2054E-05" izz="7.8989E-05" />n </inertial>n <visual>n <origin rpy="0 0 0"
xyz="0 0 0" />n <geometry>n <mesh
filename="finger.dae" /> n </geometry>n <material name="rbs_gripper_material">n <color
rgba="0.75294 0 0 1" />n </material> n </visual>n <collision>n <origin
rpy="0 0 0" xyz="0 0 0" />n <geometry>n <mesh
filename="finger.stl" /> n </geometry> n </collision>n </link>n <joint
name="rbs_gripper_r_finger_joint" type="prismatic"> n <origin rpy="0 0 -1.5708"
xyz="0 0 0.1071" />n <parent
link="rbs_gripper_rot_base_link" />n <child link="rbs_gripper_r_finger_link" />n <axis
xyz="-1 0 0" />n <limit effort="10" lower="0" upper="0.064"
velocity="0.53" />n </joint>n <link name="gripper_grasp_point" />n <joint
name="rbs_gripper_gripper_tool0_joint" type="fixed">n <origin rpy="0 0 0"
xyz="0 0 0.09139" />n <parent link="rbs_gripper_rot_base_link" />n <child
link="gripper_grasp_point" />n </joint>n <ros2_control name="fts_sensor"
type="sensor">n <hardware>n <plugin>ign_ros2_control/IgnitionFts</plugin>n </hardware>n <sensor
name="fts_sensor">n <state_interface name="force.x" />n <state_interface name="force.y" />
n <state_interface
name="force.z" />n <state_interface name="torque.x" />n <state_interface
name="torque.y" />n <state_interface
name="torque.z" />n </sensor>n </ros2_control>n <gazebo reference="tool0_joint">n <preserveFixedJoint>
true</preserveFixedJoint>n <sensor name="fts_sensor" type="force_torque">n <always_on>true</always_on>
n <update_rate>
50</update_rate>n <visualize>true</visualize>n <topic>ft_data</topic>n <force_torque>
n <frame>
sensor</frame>n <measure_direction>child_to_parent</measure_direction>n </force_torque>
n </sensor> n </gazebo>n <gazebo>n <plugin filename="libign_ros2_control-system.so"
name="ign_ros2_control::IgnitionROS2ControlPlugin">n <parameters>
/home/idontsudo/robossembler_ws/install/rbs_arm/share/rbs_arm/config/rbs_arm0_controllers.yaml</parameters>
n <ros>n <namespace></namespace>n </ros>n </plugin>n </gazebo>n</robot>

View file

@ -0,0 +1 @@
/home/idontsudo/robossembler_ws/src/rbs_gripper/meshes/visual/rotor.dae

View file

@ -0,0 +1 @@
/home/idontsudo/robossembler_ws/src/rbs_arm/meshes/visual/start_link.dae

View file

@ -1,20 +1,531 @@
"""
train_Dope
train_Dope
Общая задача: оценка позиции объекта (Pose estimation)
Реализуемая функция: обучение нейросетевой модели DOPE по заданному BOP-датасету
python3 $PYTHON_EDUCATION --path /Users/idontsudo/webservice/server/build/public/7065d6b6-c8a3-48c5-9679-bb8f3a690296 \
python3 $PYTHON_EDUCATION --path /Users/user/webservice/server/build/public/7065d6b6-c8a3-48c5-9679-bb8f3a690296 \
--name test1234 --datasetName 32123213
25.04.2024 @shalenikol release 0.1
08.05.2024 @shalenikol release 0.1
"""
import os
import json
import shutil
import numpy as np
import transforms3d as t3d
def train_Dope_i(path:str, wname:str, dname:str, outpath:str, epochs:int):
results = f"torchrun --nproc_per_node=1 train.py --local_rank 0 --data {os.path.join(path,dname)} --object fork" \
+ f" -e {epochs} --batchsize 16 --exts jpg --imagesize 640 --pretrained" \
+ " --net_path /home/shalenikol/fork_work/dope_training/output/weights_2996/net_epoch_47.pth"
print(results)
FILE_RBS_INFO = "rbs_info.json"
FILE_CAMERA = "camera.json"
FILE_GT = "scene_gt.json"
FILE_GT_COCO = "scene_gt_coco.json"
FILE_GT_INFO = "scene_gt_info.json"
FILE_MODEL = "epoch"
EXT_MODEL = ".pth"
EXT_RGB = "jpg"
DIR_ROOT_DS = "dataset_dope"
DIR_TRAIN_OUT = "out_weights"
MODEL_SCALE = 1000 # исходная модель в метрах, преобразуем в мм (для DOPE)
# Own_Numbering_Files = True # наименование image-файлов: собственная нумерация
nn_image = 0
K_intrinsic = []
model_info = []
camera_data = {}
im_width = 0
nb_update_network = 0
# [
# [min(x), min(y), min(z)],
# [min(x), max(y), min(z)],
# [min(x), max(y), max(z)],
# [min(x), min(y), max(z)],
# [max(x), min(y), max(z)],
# [max(x), max(y), min(z)],
# [max(x), max(y), max(z)],
# [max(x), min(y), max(z)],
# [xc, yc, zc] # min + (max - min) / 2
# ]
def trans_3Dto2D_point_in_camera(xyz, K_m, R_m2c, t_m2c):
"""
xyz : 3D-координаты точки
K_m : внутренняя матрица камеры 3х3
R_m2c : матрица поворота 3х3
t_m2c : вектор перемещения 3х1
return [u,v]
"""
K = np.array(K_m)
r = np.array(R_m2c)
r.shape = (3, 3)
t = np.array(t_m2c)
t.shape = (3, 1)
T = np.concatenate((r, t), axis=1)
P_m = np.array(xyz)
P_m.resize(4)
P_m[-1] = 1.0
P_m.shape = (4, 1)
# Project (X, Y, Z, 1) into cameras coordinate system
P_c = T @ P_m # 4x1
# Apply camera intrinsics to map (Xc, Yc, Zc) to p=(x, y, z)
p = K @ P_c
# Normalize by z to get (u,v,1)
uv = (p / p[2][0])[:-1]
return uv.flatten().tolist()
def gt_parse(path: str, out_dir: str):
global nn_image
with open(os.path.join(path, FILE_GT_COCO), "r") as fh:
coco_data = json.load(fh)
with open(os.path.join(path, FILE_GT), "r") as fh:
gt_data = json.load(fh)
with open(os.path.join(path, FILE_GT_INFO), "r") as fh:
gt_info = json.load(fh)
for img in coco_data["images"]:
rgb_file = os.path.join(path, img["file_name"])
if os.path.isfile(rgb_file):
# if Own_Numbering_Files:
ext = os.path.splitext(rgb_file)[1] # only ext
f = f"{nn_image:06}"
out_img = os.path.join(out_dir, f + ext)
# else:
# f = os.path.split(rgb_file)[1] # filename with extension
# f = os.path.splitext(f)[0] # only filename
# out_img = out_dir
shutil.copy2(rgb_file, out_img)
out_file = os.path.join(out_dir,f+".json")
nn_image += 1
# full annotation of the one image
all_data = camera_data.copy()
cat_names = {obj["id"]: obj["name"] for obj in coco_data["categories"]}
id_img = img["id"] # 0, 1, 2 ...
sid_img = str(id_img) # "0", "1", "2" ...
img_info = gt_info[sid_img]
img_gt = gt_data[sid_img]
img_idx = 0 # object index on the image
objs = []
for ann in coco_data["annotations"]:
if ann["image_id"] == id_img:
item = ann["category_id"]
obj_data = {}
obj_data["class"] = cat_names[item]
x, y, width, height = ann["bbox"]
obj_data["bounding_box"] = {"top_left":[x,y], "bottom_right":[x+width,y+height]}
# visibility from FILE_GT_INFO
item_info = img_info[img_idx]
obj_data["visibility"] = item_info["visib_fract"]
# location from FILE_GT
item_gt = img_gt[img_idx]
obj_id = item_gt["obj_id"] - 1 # index with 0
cam_R_m2c = item_gt["cam_R_m2c"]
cam_t_m2c = item_gt["cam_t_m2c"]
obj_data["location"] = cam_t_m2c
q = t3d.quaternions.mat2quat(np.array(cam_R_m2c))
obj_data["quaternion_xyzw"] = [q[1], q[2], q[3], q[0]]
cuboid_xyz = model_info[obj_id]
obj_data["projected_cuboid"] = [
trans_3Dto2D_point_in_camera(cub, K_intrinsic, cam_R_m2c, cam_t_m2c)
for cub in cuboid_xyz
]
objs.append(obj_data)
img_idx += 1
all_data["objects"] = objs
with open(out_file, "w") as fh:
json.dump(all_data, fh, indent=2)
def explore(path: str, res_dir: str):
if not os.path.isdir(path):
return
folders = [
os.path.join(path, o)
for o in os.listdir(path)
if os.path.isdir(os.path.join(path, o))
]
for path_entry in folders:
if os.path.isfile(os.path.join(path_entry,FILE_GT_COCO)) and \
os.path.isfile(os.path.join(path_entry,FILE_GT_INFO)) and \
os.path.isfile(os.path.join(path_entry,FILE_GT)):
gt_parse(path_entry, res_dir)
else:
explore(path_entry, res_dir)
def BOP2DOPE_dataset(dpath: str, out_dir: str) -> str:
""" Convert BOP-dataset to YOLO format for train """
res_dir = os.path.join(out_dir, DIR_ROOT_DS)
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
os.mkdir(res_dir)
explore(dpath, res_dir)
return out_dir
def train(dopepath:str, wname:str, epochs:int, pretrain: bool, lname: list):
import random
# try:
import configparser as configparser
# except ImportError:
# import ConfigParser as configparser
import torch
# import torch.nn.parallel
import torch.optim as optim
import torch.utils.data
import torchvision.transforms as transforms
from torch.autograd import Variable
import datetime
from tensorboardX import SummaryWriter
from models_dope import DopeNetwork
from utils_dope import CleanVisiiDopeLoader #, VisualizeBeliefMap, save_image
import warnings
warnings.filterwarnings("ignore")
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
torch.autograd.set_detect_anomaly(False)
torch.autograd.profiler.profile(False)
torch.autograd.gradcheck = False
torch.backends.cudnn.benchmark = True
start_time = datetime.datetime.now()
print("start:", start_time.strftime("%m/%d/%Y, %H:%M:%S"))
res_model = os.path.join(dopepath, wname + EXT_MODEL)
local_rank = 0
opt = lambda: None
opt.use_s3 = False
opt.train_buckets = []
opt.endpoint = None
opt.lr=0.0001
opt.loginterval=100
opt.sigma=0.5 # 4
opt.nbupdates=None
# opt.save=False
# opt.option="default"
# opt.gpuids=[0]
opt.namefile=FILE_MODEL
opt.workers=8
opt.batchsize=16
opt.data = [os.path.join(dopepath, DIR_ROOT_DS)]
opt.outf = os.path.join(dopepath, DIR_TRAIN_OUT)
opt.object = lname #["fork"]
opt.exts = [EXT_RGB]
# opt.imagesize = im_width
opt.epochs = epochs
opt.pretrained = pretrain
opt.net_path = res_model if pretrain else None
opt.manualseed = random.randint(1, 10000)
# # Validate Arguments
# if opt.use_s3 and (opt.train_buckets is None or opt.endpoint is None):
# raise ValueError(
# "--train_buckets and --endpoint must be specified if training with data from s3 bucket."
# )
# if not opt.use_s3 and opt.data is None:
# raise ValueError("--data field must be specified.")
os.makedirs(opt.outf, exist_ok=True)
# if local_rank == 0:
# writer = SummaryWriter(opt.outf + "/runs/")
random.seed(opt.manualseed)
torch.cuda.set_device(local_rank)
# torch.distributed.init_process_group(backend="nccl", init_method="env://")
torch.manual_seed(opt.manualseed)
torch.cuda.manual_seed_all(opt.manualseed)
# # Data Augmentation
# if not opt.save:
# contrast = 0.2
# brightness = 0.2
# noise = 0.1
# normal_imgs = [0.59, 0.25]
# transform = transforms.Compose(
# [
# AddRandomContrast(0.2),
# AddRandomBrightness(0.2),
# transforms.Resize(opt.imagesize),
# ]
# )
# else:
# contrast = 0.00001
# brightness = 0.00001
# noise = 0.00001
# normal_imgs = None
# transform = transforms.Compose(
# [transforms.Resize(opt.imagesize), transforms.ToTensor()]
# )
# Load Model
net = DopeNetwork()
output_size = 50
# opt.sigma = 0.5
train_dataset = CleanVisiiDopeLoader(
opt.data,
sigma=opt.sigma,
output_size=output_size,
extensions=opt.exts,
objects=opt.object,
use_s3=opt.use_s3,
buckets=opt.train_buckets,
endpoint_url=opt.endpoint,
)
trainingdata = torch.utils.data.DataLoader(
train_dataset,
batch_size=opt.batchsize,
shuffle=True,
num_workers=opt.workers,
pin_memory=True,
)
if not trainingdata is None:
print(f"training data: {len(trainingdata)} batches")
print("Loading Model...")
net = net.cuda()
# net = torch.nn.parallel.DistributedDataParallel(
# net.cuda(), device_ids=[local_rank], output_device=local_rank
# )
if opt.pretrained:
if opt.net_path is not None:
net.load_state_dict(torch.load(opt.net_path))
else:
print("Error: Did not specify path to pretrained weights.")
quit()
parameters = filter(lambda p: p.requires_grad, net.parameters())
optimizer = optim.Adam(parameters, lr=opt.lr)
print("ready to train!")
global nb_update_network
nb_update_network = 0
# best_results = {"epoch": None, "passed": None, "add_mean": None, "add_std": None}
scaler = torch.cuda.amp.GradScaler()
def _runnetwork(epoch, train_loader): #, syn=False
global nb_update_network
# net
net.train()
loss_avg_to_log = {}
loss_avg_to_log["loss"] = []
loss_avg_to_log["loss_affinities"] = []
loss_avg_to_log["loss_belief"] = []
loss_avg_to_log["loss_class"] = []
for batch_idx, targets in enumerate(train_loader):
optimizer.zero_grad()
data = Variable(targets["img"].cuda())
target_belief = Variable(targets["beliefs"].cuda())
target_affinities = Variable(targets["affinities"].cuda())
output_belief, output_aff = net(data)
loss = None
loss_belief = torch.tensor(0).float().cuda()
loss_affinities = torch.tensor(0).float().cuda()
loss_class = torch.tensor(0).float().cuda()
for stage in range(len(output_aff)): # output, each belief map layers.
loss_affinities += (
(output_aff[stage] - target_affinities)
* (output_aff[stage] - target_affinities)
).mean()
loss_belief += (
(output_belief[stage] - target_belief)
* (output_belief[stage] - target_belief)
).mean()
loss = loss_affinities + loss_belief
# if batch_idx == 0:
# post = "train"
# if local_rank == 0:
# for i_output in range(1):
# # input images
# writer.add_image(
# f"{post}_input_{i_output}",
# targets["img_original"][i_output],
# epoch,
# dataformats="CWH",
# )
# # belief maps gt
# imgs = VisualizeBeliefMap(target_belief[i_output])
# img, grid = save_image(
# imgs, "some_img.png", mean=0, std=1, nrow=3, save=False
# )
# writer.add_image(
# f"{post}_belief_ground_truth_{i_output}",
# grid,
# epoch,
# dataformats="CWH",
# )
# # belief maps guess
# imgs = VisualizeBeliefMap(output_belief[-1][i_output])
# img, grid = save_image(
# imgs, "some_img.png", mean=0, std=1, nrow=3, save=False
# )
# writer.add_image(
# f"{post}_belief_guess_{i_output}",
# grid,
# epoch,
# dataformats="CWH",
# )
loss.backward()
optimizer.step()
nb_update_network += 1
# log the loss
loss_avg_to_log["loss"].append(loss.item())
loss_avg_to_log["loss_class"].append(loss_class.item())
loss_avg_to_log["loss_affinities"].append(loss_affinities.item())
loss_avg_to_log["loss_belief"].append(loss_belief.item())
if batch_idx % opt.loginterval == 0:
print(
"Train Epoch: {} [{}/{} ({:.0f}%)] \tLoss: {:.15f} \tLocal Rank: {}".format(
epoch,
batch_idx * len(data),
len(train_loader.dataset),
100.0 * batch_idx / len(train_loader),
loss.item(),
local_rank,
)
)
# # log the loss values
# if local_rank == 0:
# writer.add_scalar("loss/train_loss", np.mean(loss_avg_to_log["loss"]), epoch)
# writer.add_scalar("loss/train_cls", np.mean(loss_avg_to_log["loss_class"]), epoch)
# writer.add_scalar("loss/train_aff", np.mean(loss_avg_to_log["loss_affinities"]), epoch)
# writer.add_scalar("loss/train_bel", np.mean(loss_avg_to_log["loss_belief"]), epoch)
for epoch in range(1, opt.epochs + 1):
_runnetwork(epoch, trainingdata)
try:
if local_rank == 0:
torch.save(
net.state_dict(),
f"{opt.outf}/{opt.namefile}_{str(epoch).zfill(3)}.pth",
)
except Exception as e:
print(f"Encountered Exception: {e}")
if not opt.nbupdates is None and nb_update_network > int(opt.nbupdates):
break
# if local_rank == 0:
# save result model
torch.save(net.state_dict(), res_model) #os.path.join(dopepath, wname + EXT_MODEL))
# else:
# torch.save(
# net.state_dict(),
# f"{opt.outf}/{opt.namefile}_{str(epoch).zfill(3)}_rank_{local_rank}.pth",
# )
print("end:", datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
print("Total time taken: ", str(datetime.datetime.now() - start_time).split(".")[0])
def train_Dope_i(path:str, wname:str, dname:str, outpath:str, epochs:int, pretrain: bool):
""" Main procedure for train DOPE model """
global K_intrinsic, model_info, camera_data, im_width
if not os.path.isdir(outpath):
print(f"Invalid output path '{outpath}'")
exit(-1)
out_dir = os.path.join(outpath, wname)
ds_path = os.path.join(path, dname)
if not os.path.isdir(ds_path):
print(f"{ds_path} : no BOP directory")
return ""
camera_json = os.path.join(ds_path, FILE_CAMERA)
if not os.path.isfile(camera_json):
print(f"{camera_json} : no intrinsic camera file")
return ""
rbs_info = os.path.join(ds_path, FILE_RBS_INFO)
if not os.path.isfile(rbs_info):
print(f"{rbs_info} : no dataset info file")
return ""
camera_data = {}
with open(camera_json, "r") as fh:
data = json.load(fh)
keys = ["cx","cy","fx","fy"]
intrinsic = {k: data[k] for k in keys}
im_height = data["height"]
im_width = data["width"]
camera_data["camera_data"] = dict(intrinsic=intrinsic, height=im_height, width=im_width)
K_intrinsic = [
[data["fx"], 0.0, data["cx"]],
[0.0, data["fy"], data["cy"]],
[0.0, 0.0, 1.0]
]
# calc cuboid + center
with open(rbs_info, "r") as fh:
info = json.load(fh)
# список имён объектов
list_name = list(map(lambda x: x["name"], info))
# in FILE_RBS_INFO model numbering from smallest to largest
model_info = []
for m_info in info:
cub = np.array(m_info["cuboid"]) * MODEL_SCALE
xyz_min = cub.min(axis=0)
xyz_max = cub.max(axis=0)
# [xc, yc, zc] # min + (max - min) / 2
center = []
for i in range(3):
center.append(xyz_min[i] + (xyz_max[i]- xyz_min[i]) / 2)
c = np.array(center, ndmin=2)
model_info.append(np.append(cub, c, axis=0))
if pretrain:
# продолжить обучение
if not os.path.isdir(out_dir):
print(f"No dir '{out_dir}'")
exit(-2)
dpath = out_dir
# model_path = os.path.join(dpath, wname + ".pt")
else:
# обучение сначала
if not os.path.isdir(out_dir):
os.mkdir(out_dir)
dpath = BOP2DOPE_dataset(ds_path, out_dir)
if len(dpath) == 0:
print(f"Error in convert dataset '{ds_path}' to '{outpath}'")
exit(-4)
# model_path = os.path.join(dpath, FILE_BASEMODEL)
# results = f"python train.py --local_rank 0 --data {dpath} --object fork" \
# + f" -e {epochs} --batchsize 16 --exts jpg --imagesize 640 --pretrained" \
# + " --net_path /home/shalenikol/fork_work/dope_training/output/weights_2996/net_epoch_47.pth"
# print(results)
train(dpath, wname, epochs, pretrain, list_name)
import argparse
@ -25,6 +536,7 @@ if __name__ == "__main__":
parser.add_argument("--datasetName", required=True, help="String with dataset name")
parser.add_argument("--outpath", default="weights", help="Output path for weights")
parser.add_argument("--epoch", default=3, help="How many training epochs")
parser.add_argument('--pretrain', action="store_true", help="Use pretraining")
args = parser.parse_args()
train_Dope_i(args.path, args.name, args.datasetName, args.outpath, args.epoch)
train_Dope_i(args.path, args.name, args.datasetName, args.outpath, args.epoch, args.pretrain)

View file

@ -28,7 +28,7 @@ DIR_COCO_DS = "rbs_coco"
DIR_RGB_DS = "images"
DIR_LABELS_DS = "labels"
SZ_SERIES = 5 # number of train images per validation images
SZ_SERIES = 15 # number of train images per validation images
nn_image = 0
f1 = f2 = None
@ -166,7 +166,6 @@ def train_YoloV8(path:str, wname:str, dname:str, outpath:str, epochs:int, pretra
shutil.copy2(wf, os.path.join(dpath, wname + ".pt"))
shutil.rmtree(results.save_dir)
# print(f"\n ********\n{wf}")
if __name__ == "__main__":
import argparse