This commit is contained in:
IDONTSUDO 2024-07-13 18:18:14 +03:00
parent 50822a031d
commit d8b5018cb2
69 changed files with 3302 additions and 3652 deletions

4
.vscode/launch.json vendored
View file

@ -1,9 +1,5 @@
{
// 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": [
{
"type": "node",

View file

@ -41,8 +41,9 @@ git clone https://gitlab.com/robossembler/webservice
export PYTHON_BLENDER="/путь_к_директории_сайлами_из/rcg_pipeline"
export PYTHON_BLENDER_PROC="/путь_к_генераторуатасетов_/renderBOPdataset.py"
export PYTHON_EDUCATION="absolute_path/webp/education.py"
```
export PYTHON_ROBOT_BUILDER="/путь_к_генераторуатасетов_/robot_builder.py"
```
## Запуск сервера
Из директории `server` в корне репозитория

2478
server/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -24,24 +24,18 @@
"eslint": "^8.47.0",
"mocha": "latest",
"node-watch": "^0.7.4",
"nodemon": "^3.0.1",
"nyc": "latest",
"source-map-support": "latest",
"ts-node": "^10.9.1",
"tslint": "latest",
"typescript": "^5.1.6"
},
"dependencies": {
"@grpc/grpc-js": "^1.9.0",
"axios": "^1.6.2",
"babel-register": "^6.26.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"cors": "^2.8.5",
"express": "^4.18.2",
"express-fileupload": "^1.4.2",
"first-di": "^1.0.11",
"md5": "^2.3.0",
"mongoose": "^7.6.2",
"mongoose-autopopulate": "^1.1.0",
"pattern-matching-ts": "^2.0.0",
@ -50,8 +44,6 @@
"rimraf": "^5.0.5",
"socket.io": "^4.7.2",
"socket.io-client": "^4.7.2",
"spark-md5": "^3.0.2",
"ts-md5": "^1.3.1",
"ts-pattern": "^5.1.1",
"tsc-watch": "^6.0.4",
"uuid": "^9.0.1"

View file

@ -1,5 +1,6 @@
export enum StaticFiles {
robossembler_assets = "robossembler_assets.json",
assets = "/assets/assets.json",
parts = '/assets/parts.json'
parts = '/assets/parts.json',
robots = '/robots/'
}

View file

@ -0,0 +1,39 @@
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../core/controllers/http_controller";
import { Result } from "../../core/helpers/result";
import { RobotModel } from "./robot_model";
import { StaticFiles } from "../../core/models/static_files";
import { GetServerAddressUseCase } from "../../core/usecases/get_server_address_usecase";
import { SearchManyDataBaseModelUseCase } from "../../core/usecases/search_many_database_model_usecase";
import { IProjectModel, ProjectDBModel } from "../projects/models/project_model_database_model";
import { ExecProcessUseCase } from "../../core/usecases/exec_process_usecase";
export class CreateRobotScenario extends CallbackStrategyWithValidationModel<RobotModel> {
validationModel: RobotModel = new RobotModel();
call = async (model: RobotModel): ResponseBase =>
(
await new SearchManyDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(
{ isActive: true },
"is dont active projects"
)
).map((projectModel) => {
const { rootDir } = projectModel[0];
return new GetServerAddressUseCase().call().map(async (serverAddress) =>
(
await new ExecProcessUseCase().call(
rootDir,
`python3 $PYTHON_ROBOT_BUILDER --path ${projectModel[0].rootDir + StaticFiles.robots} --name ${
model.name
} --nDOF ${model.nDof} --toolType ${model.toolType}`,
""
)
).map(() =>
Result.ok({
robotUrl: `${serverAddress}/${
rootDir.match(new RegExp(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gm))[0]
}${StaticFiles.robots}${model.name}/robot.xml`,
})
)
);
});
}

View file

@ -0,0 +1,12 @@
import { IsNotEmpty, IsNumber, IsString } from "class-validator";
export class RobotModel {
@IsNotEmpty()
@IsString()
name: string;
@IsNumber()
nDof: number;
@IsNotEmpty()
@IsString()
toolType: string;
}

View file

@ -1,7 +1,8 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { CreateRobotScenario } from "./create_robot_scenario";
import { SceneDBModel } from "./scene_database_model";
import { SceneValidationModel } from "./scene_validation_model";
export class ScenePresentation extends CrudController<SceneValidationModel, typeof SceneDBModel> {
constructor() {
super({
@ -9,5 +10,10 @@ export class ScenePresentation extends CrudController<SceneValidationModel, type
validationModel: SceneValidationModel,
databaseModel: SceneDBModel,
});
this.subRoutes.push({
method: "POST",
subUrl: "create/robot",
fn: new CreateRobotScenario(),
});
}
}

30
ui/package-lock.json generated
View file

@ -28,6 +28,7 @@
"react-infinite-scroll-component": "^6.1.0",
"react-router-dom": "^6.18.0",
"react-scripts": "5.0.1",
"react-slider": "^2.0.6",
"reflect-metadata": "^0.1.13",
"rete-connection-plugin": "^2.0.0",
"rete-react-plugin": "^2.0.4",
@ -35,7 +36,7 @@
"socket.io-client": "^4.7.2",
"source-map-loader": "^5.0.0",
"styled-components": "^6.1.8",
"three": "^0.165.0",
"three": "^0.152.2",
"ts-pattern": "^5.1.1",
"typescript": "^5.0.2",
"urdf-loader": "^0.12.1",
@ -49,6 +50,7 @@
"@types/node": "^16.18.46",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/react-slider": "^1.3.6",
"@types/socket.io-client": "^3.0.0",
"@types/three": "^0.158.3",
"@types/uuid": "^9.0.2"
@ -3902,6 +3904,15 @@
"@types/react": "*"
}
},
"node_modules/@types/react-slider": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/@types/react-slider/-/react-slider-1.3.6.tgz",
"integrity": "sha512-RS8XN5O159YQ6tu3tGZIQz1/9StMLTg/FCIPxwqh2gwVixJnlfIodtVx+fpXVMZHe7A58lAX1Q4XTgAGOQaCQg==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@ -14156,6 +14167,17 @@
"webpack": "^5.0.0"
}
},
"node_modules/react-slider": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/react-slider/-/react-slider-2.0.6.tgz",
"integrity": "sha512-gJxG1HwmuMTJ+oWIRCmVWvgwotNCbByTwRkFZC6U4MBsHqJBmxwbYRJUmxy4Tke1ef8r9jfXjgkmY/uHOCEvbA==",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"react": "^16 || ^17 || ^18"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@ -16121,9 +16143,9 @@
}
},
"node_modules/three": {
"version": "0.165.0",
"resolved": "https://registry.npmjs.org/three/-/three-0.165.0.tgz",
"integrity": "sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA=="
"version": "0.152.2",
"resolved": "https://registry.npmjs.org/three/-/three-0.152.2.tgz",
"integrity": "sha512-Ff9zIpSfkkqcBcpdiFo2f35vA9ZucO+N8TNacJOqaEE6DrB0eufItVMib8bK8Pcju/ZNT6a7blE1GhTpkdsILw=="
},
"node_modules/throat": {
"version": "6.0.2",

View file

@ -7,9 +7,9 @@
"@foxglove/rosmsg": "^5.0.4",
"@foxglove/rosmsg2-serialization": "^2.0.3",
"@foxglove/ws-protocol": "^0.7.3",
"antd": "^4.24.15",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"antd": "^4.24.15",
"i18next": "^23.6.0",
"just-clone": "^6.2.0",
"mobx": "^6.10.0",
@ -30,7 +30,7 @@
"socket.io-client": "^4.7.2",
"source-map-loader": "^5.0.0",
"styled-components": "^6.1.8",
"three": "^0.165.0",
"three": "^0.152.2",
"ts-pattern": "^5.1.1",
"typescript": "^5.0.2",
"urdf-loader": "^0.12.1",
@ -67,12 +67,12 @@
]
},
"devDependencies": {
"@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/three": "^0.158.3",
"@types/uuid": "^9.0.2"
}
}
}

View file

@ -41,7 +41,7 @@ mason new my_brick_name
Для большей информации [читайте и смотрите примеры](https://github.com/felangel/mason/blob/master/packages/mason_cli/README.md)
# Добавить новую форму в деревья поведения
# Добавить новую форму в Behavior tree builder
mason make form -o ./src/features/behavior_tree_builder/presentation/ui/forms

View file

@ -71,4 +71,10 @@ export const ArrayExtensions = () => {
}
};
}
if ([].add === undefined) {
Array.prototype.add = function (element) {
this.push(element);
return this;
};
}
};

View file

@ -23,6 +23,7 @@ declare global {
repeat(quantity: number): Array<T>;
rFind<T>(predicate: (value: T, index: number, obj: never[]) => boolean, thisArg?: any): Result<void, T>;
maxLength(length: number): Array<T>;
add(element: T): Array<T>;
}
interface Number {
fromArray(): number[];
@ -34,12 +35,13 @@ declare global {
isNegative(): boolean;
isEven(): boolean;
isOdd(): boolean;
isEqualR(num: number): Result<void, void>;
isEqualR(number: number): Result<void, void>;
}
interface String {
isEmpty(): boolean;
isNotEmpty(): boolean;
isNotEmptyR(): Result<void, string>;
replaceMany(searchValues: string[], replaceValue: string): string;
isEqual(str: string): boolean;
isEqualMany(str: string[]): boolean;
@ -58,6 +60,9 @@ declare global {
getPredicateValue(callBack: (value: V) => boolean): K[];
incrementValue(key: K): void;
}
interface Boolean {
r(): Result<void, void>;
}
}
export const extensions = () => {
StringExtensions();

View file

@ -12,6 +12,14 @@ export const StringExtensions = () => {
return this.length !== 0;
};
}
if ("".isNotEmptyR === undefined) {
String.prototype.isNotEmptyR = function () {
if (this.isEmpty()) {
return Result.error(undefined);
}
return Result.ok(String(this));
};
}
if ("".isEqualR === undefined) {
String.prototype.isEqualR = function (str) {
if (this === str) {

View file

@ -0,0 +1,52 @@
import { Quaternion, Vector3, PerspectiveCamera, CameraHelper } from "three";
import { CoreThreeRepository, UserData } from "../repository/core_three_repository";
import { Result } from "../helper/result";
import { SceneModelsTypes } from "./scene_models_type";
import { Instance } from "./scene_asset";
export enum CameraTypes {
RGB = "RGB",
}
export class CameraModel implements Instance {
type = SceneModelsTypes.CAMERA;
constructor(
public quaternion: number[],
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 aspect: number,
public parent?: string,
public fixed?: string
) {}
update = (coreThreeRepository: CoreThreeRepository) => this.toWebGl(coreThreeRepository);
icon: string = "Camera";
toWebGl = (coreThreeRepository: CoreThreeRepository) => {
const camera = coreThreeRepository.scene.getObjectByName(this.name);
if (camera) {
coreThreeRepository.scene.remove(coreThreeRepository.scene.getObjectByName(this.name + "camera_helper")!);
coreThreeRepository.scene.remove(camera);
}
const perspectiveCamera = new PerspectiveCamera(this.fov, this.aspect, this.near, this.far);
perspectiveCamera.name = this.name;
perspectiveCamera.position.copy(this.vector3);
perspectiveCamera.quaternion.copy(new Quaternion().fromArray(this.quaternion));
const cameraHelper = new CameraHelper(perspectiveCamera);
cameraHelper.name = this.name + "camera_helper";
perspectiveCamera.userData[UserData.selectedObject] = true;
cameraHelper.userData[UserData.selectedObject] = true;
coreThreeRepository.scene.add(...[perspectiveCamera, cameraHelper]);
};
validate = (): Result<string, CameraModel> => {
return Result.ok(this);
};
static empty = () => new CameraModel([], new Vector3(0, 0, 0), "", CameraTypes.RGB, 0, 0, 50, 0.1, 2000, 0, "", 0);
}

View file

@ -0,0 +1,57 @@
import { DirectionalLight, Object3D, PointLight, Quaternion, SpotLight, Vector3 } from "three";
import { Result } from "../helper/result";
import { SceneModelsTypes } from "./scene_models_type";
import { CoreThreeRepository } from "../repository/core_three_repository";
import { Instance } from "./scene_asset";
import { Type } from "class-transformer";
export enum TypeLight {
POINT = "POINT",
DIRECTIONAL = "DIRECTIONAL",
SPOT = "SPOT",
}
export class LightModel implements Instance {
type = SceneModelsTypes.LIGHT;
color: string;
typeLight: TypeLight;
intensity: number;
width: number;
height: number;
distance: number;
angle: number;
penumbra: number;
decay: number;
@Type(() => Vector3)
vector3: Vector3;
quaternion: number[];
constructor() {}
update = (coreThreeRepository: CoreThreeRepository) => this.toWebGl(coreThreeRepository);
icon: string = "Light";
name: string;
isValid = (): Result<void, LightModel> => {
// SDF -> point, directional, spot.
// THREE -> PointLight,DirectionalLight,SpotLight
return Result.ok(this);
};
toWebGl = (coreThreeRepository: CoreThreeRepository) => {
// TODO: maybe change mapper
let light: Object3D;
this.typeLight
.isEqualR(TypeLight.DIRECTIONAL)
.map(() => (light = new DirectionalLight(this.color, this.intensity)));
this.typeLight
.isEqualR(TypeLight.POINT)
.map(() => (light = new PointLight(this.color, this.intensity, this.distance, this.decay)));
this.typeLight
.isEqualR(TypeLight.SPOT)
.map(
() => (light = new SpotLight(this.color, this.intensity, this.distance, this.angle, this.penumbra, this.decay))
);
light!.castShadow = true;
light!.position.copy(this.vector3);
light!.quaternion.copy(new Quaternion().fromArray(this.quaternion));
coreThreeRepository.scene.add(light!);
};
static empty = () => new LightModel();
}

View file

@ -0,0 +1,35 @@
import { Quaternion, Vector3 } from "three";
import { Result } from "../helper/result";
import { SceneModelsTypes } from "./scene_models_type";
import { Instance } from "./scene_asset";
import { CoreThreeRepository } from "../repository/core_three_repository";
import { Type } from "class-transformer";
export class PointModel implements Instance {
type = SceneModelsTypes.POINT;
name: string;
@Type(() => Vector3)
vector3: Vector3;
color: string = "#E91E63";
size: number = 0.5;
quaternion: number[];
icon: string = "Point";
constructor() {}
update = (coreThreeRepository: CoreThreeRepository) => this.toWebGl(coreThreeRepository);
toWebGl = (coreThreeRepository: CoreThreeRepository) =>
coreThreeRepository.makePoint(
this.name,
this.vector3,
new Quaternion().fromArray(this.quaternion),
this.color,
this.size
);
isValid(): Result<string, PointModel> {
return Result.ok();
}
static empty() {
return new PointModel();
}
}

View file

@ -1,172 +0,0 @@
import { IsArray, IsEnum, IsNumber, IsOptional, IsString, ValidateNested } from "class-validator";
import { Type } from "class-transformer";
export class Gravity {
@IsNumber()
x: number;
@IsNumber()
y: number;
@IsNumber()
z: number;
}
export class Pose {
@IsNumber()
x: number;
@IsNumber()
y: number;
@IsNumber()
z: number;
@IsNumber()
roll: number;
@IsNumber()
pitch: number;
@IsNumber()
yaw: number;
}
export class Position {
@IsNumber()
x: number;
@IsNumber()
y: number;
@IsNumber()
z: number;
}
export enum InstanceType {
RGB_CAMERA = "rgb_camera",
SCENE_SIMPLE_OBJECT = "scene_simple_object",
}
abstract class CoreInstances {}
export class Instance extends CoreInstances {
@IsEnum(InstanceType)
instanceType: InstanceType;
@Type(() => Position)
position: Position;
@IsArray()
quaternion: number[];
@IsOptional()
@IsString()
instanceAt: null | string = null;
}
export class SceneSimpleObject extends Instance {}
export class InstanceRgbCamera extends Instance {
@IsString()
cameraLink: string;
@IsString()
topicCameraInfo: string;
@IsOptional()
@IsString()
topicDepth: string | null;
@IsString()
topicImage: string;
}
export class Asset {
@IsString()
name: string;
@IsString()
ixx: string;
@IsString()
ixy: string;
@IsString()
ixz: string;
@IsString()
iyy: string;
@IsString()
izz: string;
@IsString()
mass: string;
@IsString()
posX: string;
@IsString()
posY: string;
@IsString()
posZ: string;
@IsString()
eulerX: string;
@IsString()
eulerY: string;
@IsString()
eulerZ: string;
@IsString()
iyz: string;
@IsString()
meshPath: string;
@IsString()
friction: string;
@IsString()
centerMassX: string;
@IsString()
centerMassY: string;
@IsString()
centerMassZ: string;
@IsArray()
@IsOptional()
actions: string[];
}
export class Physics {
@IsString()
engine_name: string;
@Type(() => Gravity)
gravity: Gravity;
}
export class RobossemblerAssets {
@ValidateNested()
@Type(() => Asset, {
discriminator: {
property: "type",
subTypes: [
{ value: InstanceRgbCamera, name: InstanceType.RGB_CAMERA },
{ value: SceneSimpleObject, name: InstanceType.SCENE_SIMPLE_OBJECT },
],
},
keepDiscriminatorProperty: true,
})
assets: Asset[];
@IsArray()
@Type(() => Instance, {
discriminator: {
property: "type",
subTypes: [
{ value: InstanceRgbCamera, name: InstanceType.RGB_CAMERA },
{ value: SceneSimpleObject, name: InstanceType.SCENE_SIMPLE_OBJECT },
],
},
keepDiscriminatorProperty: true,
})
instances: Instance[];
@IsOptional()
@ValidateNested()
@Type(() => Physics)
physics: Physics;
convertLocalPathsToServerPaths(server_address: string): RobossemblerAssets {
this.assets = this.assets.map((el) => {
el.meshPath = server_address + el.meshPath;
return el;
});
return this;
}
getAssetPath(assetName: string): string {
const findElement = this.assets.find((el) => el.name === assetName);
if (findElement === undefined) {
throw new Error("RobossemblerAssets.getAssetPath not found asset by name:" + assetName);
}
return findElement.meshPath;
}
getAssetAtInstance(instanceAt: string): Asset {
return this.assets.filter((el) => el.name === instanceAt)[0];
}
}

View file

@ -0,0 +1,75 @@
import { Quaternion, Vector3 } from "three";
import { SceneModelsTypes } from "./scene_models_type";
import { Result } from "../helper/result";
import { Instance } from "./scene_asset";
import { CoreThreeRepository } from "../repository/core_three_repository";
import { Type } from "class-transformer";
import { URDFRobot } from "urdf-loader";
import { SceneItems, SceneMangerStore } from "../../features/scene_manager/presentation/scene_manager_store";
export enum ToolTypes {
RBS_GRIPPER = "RBS_GRIPPER",
}
interface RobotJoint {
limit: {
lower: Number;
upper: Number;
};
angel: Number;
name: string;
}
export class RobotModel implements Instance {
type = SceneModelsTypes.ROBOT;
@Type(() => Vector3)
vector3: Vector3;
jointPosition: RobotJoint[];
quaternion: number[];
name: string;
httpUrl: string;
nDof: number;
toolType: string;
constructor(
vector3: Vector3,
quaternion: number[],
name: string,
httpUrl: string,
nDof: number,
toolType: string,
jointPosition: RobotJoint[]
) {
this.quaternion = quaternion;
this.vector3 = vector3;
this.name = name;
this.httpUrl = httpUrl;
this.nDof = nDof;
this.toolType = toolType;
this.jointPosition = jointPosition;
}
icon: string = "Robot";
toSceneItems = (sceneMangerStore: SceneMangerStore): SceneItems => {
return {
fn: () => { },
name: this.name,
isSelected: false,
icon: "Robot",
};
};
toWebGl = (coreThreeRepository: CoreThreeRepository) => {
console.log(JSON.stringify(this));
coreThreeRepository.loadUrdfRobot(this);
};
update(coreThreeRepository: CoreThreeRepository): any {
const robot = coreThreeRepository.scene.getObjectByName(this.name) as URDFRobot;
robot.position.copy(this.vector3);
robot.quaternion.copy(new Quaternion().fromArray(this.quaternion));
this.jointPosition.forEach((el) => {
robot.setJointValue(el.name, el.angel);
});
}
isValid(): Result<string, RobotModel> {
return Result.ok(this);
}
static empty = () => new RobotModel(new Vector3(0, 0, 0), [0, 0, 0, 1], "", "", 1, ToolTypes.RBS_GRIPPER, []);
}

View file

@ -0,0 +1,40 @@
import { IsArray, IsEnum, IsNumber, IsOptional, IsString, ValidateNested } from "class-validator";
import { Type } from "class-transformer";
import { CameraModel } from "./camera_model";
import { SceneModelsTypes } from "./scene_models_type";
import { RobotModel } from "./robot_model";
import { SolidModel } from "./solid_model";
import { PointModel } from "./point_model";
import { ZoneModel } from "./zone_model";
import { CoreThreeRepository } from "../repository/core_three_repository";
import { LightModel } from "./light_model";
import { Vector3 } from "three";
export abstract class Instance {
abstract icon: string;
@Type(() => Vector3)
vector3: Vector3;
quaternion: number[];
name: string;
toWebGl = (coreThreeRepository: CoreThreeRepository) => {};
update = (coreThreeRepository: CoreThreeRepository) => {};
}
export class SceneAsset {
@IsArray()
@Type(() => Instance, {
discriminator: {
property: "type",
subTypes: [
{ value: SolidModel, name: SceneModelsTypes.SOLID },
{ value: CameraModel, name: SceneModelsTypes.CAMERA },
{ value: RobotModel, name: SceneModelsTypes.ROBOT },
{ value: PointModel, name: SceneModelsTypes.POINT },
{ value: LightModel, name: SceneModelsTypes.LIGHT },
{ value: ZoneModel, name: SceneModelsTypes.ZONE },
],
},
keepDiscriminatorProperty: true,
})
scene: (Instance | SolidModel | CameraModel | RobotModel | PointModel | ZoneModel)[];
}

View file

@ -0,0 +1,8 @@
export enum SceneModelsTypes {
SOLID = "SOLID",
ROBOT = "ROBOT",
LIGHT = "LIGHT",
CAMERA = "CAMERA",
POINT = "POINT",
ZONE = "ZONE",
}

View file

@ -0,0 +1,26 @@
import { Quaternion, Scene, Vector3 } from "three";
import { SceneModelsTypes } from "./scene_models_type";
import { Instance } from "./scene_asset";
import { CoreThreeRepository } from "../repository/core_three_repository";
import { Type } from "class-transformer";
export class SolidModel implements Instance {
type = SceneModelsTypes.SOLID;
@Type(() => Vector3)
public vector3: Vector3;
constructor(
vector3:Vector3,
public quaternion: number[],
public name: string,
public solidType: string,
public mesh: string,
public collisionMesh: string
) {
this.vector3 = vector3
}
update = (coreThreeRepository: CoreThreeRepository) => this.toWebGl(coreThreeRepository)
icon: string = "Solid";
toWebGl = (coreThreeRepository: CoreThreeRepository) => coreThreeRepository.loader(this.mesh, () => {}, this.name);
static empty = () => new SolidModel(new Vector3(0, 0, 0), [], "", "", "", "");
}

View file

@ -0,0 +1,33 @@
import { Vector3 } from "three";
import { Result } from "../helper/result";
import { SceneModelsTypes } from "./scene_models_type";
import { Instance } from "./scene_asset";
import { CoreThreeRepository } from "../repository/core_three_repository";
import { Type } from "class-transformer";
export class ZoneModel implements Instance {
type = SceneModelsTypes.ZONE;
color: string = "#E91E63";
@Type(() => Vector3)
vector3: Vector3;
constructor(
vector3: Vector3,
public quaternion: number[],
public name: string,
public width: number,
public height: number,
public length: number
) {
this.vector3 = vector3;
}
update = (coreThreeRepository: CoreThreeRepository) => this.toWebGl(coreThreeRepository)
icon: string = "Zone";
toWebGl = (coreThreeRepository: CoreThreeRepository) => coreThreeRepository.makeZone(this);
isValid(): Result<string, ZoneModel> {
return Result.ok();
}
static empty() {
return new ZoneModel(new Vector3(0, 0, 0), [0, 0, 0, 0], "", 0, 0, 0);
}
}

View file

@ -22,25 +22,25 @@ import {
MeshBasicMaterial,
BoxGeometry,
MeshStandardMaterial,
LoadingManager,
} from "three";
import { TypedEvent } from "../helper/typed_event";
import { Result } from "../helper/result";
import URDFLoader, { URDFLink } from "urdf-loader";
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 { LoadingManager } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { TransformControls } from "three/examples/jsm/controls/TransformControls";
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";
import { ISpawnHelper, SceneItems } from "../../features/scene_manager/presentation/scene_manager_store";
import { CameraModel } from "../model/camera_model";
import { SolidModel } from "../model/solid_model";
import { Instance, SceneAsset } from "../model/scene_asset";
import { ZoneModel } from "../model/zone_model";
import { TypedEvent } from "../helper/typed_event";
import { Result } from "../helper/result";
import { RobotModel } from "../model/robot_model";
Object3D.DEFAULT_UP = new Vector3(0, 0, 1);
@ -63,7 +63,8 @@ interface IEmissiveCache {
}
type SceneFrames = { [K in string]: URDFLink };
export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
export class CoreThreeRepository extends TypedEvent<any> {
scene = new Scene();
camera: PerspectiveCamera;
webGlRender: WebGLRenderer;
@ -95,7 +96,7 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
});
const aspectCamera = this.htmlSceneWidth / this.htmlSceneHeight;
this.camera = new PerspectiveCamera(100, aspectCamera, 0.1, 2000);
this.camera.position.set(60, 20, 10);
this.camera.position.set(1, 1, 1);
this.webGlRender = renderer;
this.htmlCanvasRef = htmlCanvasRef;
@ -108,6 +109,9 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.init();
}
updateInstance = (viewModel: Instance) => (
this.scene.remove(this.scene.getObjectByName(viewModel.name)!), viewModel.toWebGl(this)
);
deleteAllObjectsScene = () => {
this.getAllSceneNameModels().forEach((el) =>
@ -124,25 +128,40 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.scene.add(cube);
return cube;
}
loadScene = (sceneAssets: SceneAsset) => sceneAssets.scene.forEach((el) => el.toWebGl(this));
getCenterPoint = (object: Object3D<Object3DEventMap>) =>
object.getWorldPosition(new Box3().setFromObject(object).getCenter(object.position));
makeZone = (zoneModel: ZoneModel) => {
const mesh = new Mesh(
new BoxGeometry(zoneModel.width, zoneModel.height, zoneModel.length),
new MeshBasicMaterial({
color: zoneModel.color,
transparent: true,
})
);
mesh.name = zoneModel.name;
mesh.userData[UserData.selectedObject] = "";
mesh.position.copy(zoneModel.vector3);
mesh.quaternion.copy(new Quaternion().fromArray(zoneModel.quaternion));
this.scene.add(mesh);
};
makeCube(inc: number, vector?: Vector3, color?: string, size?: number) {
const cube = new Mesh(
const mesh = new Mesh(
new BoxGeometry(size ?? 10, size ?? 10, size ?? 10),
new MeshBasicMaterial({ color: color ?? 0x0095dd, transparent: true, opacity: 0.5 })
);
cube.userData[UserData.objectForMagnetism] = true;
cube.userData[UserData.selectedObject] = true;
cube.name = "cube" + String(inc);
mesh.userData[UserData.objectForMagnetism] = true;
mesh.userData[UserData.selectedObject] = true;
mesh.name = "cube" + String(inc);
if (vector) {
cube.position.copy(vector);
mesh.position.copy(vector);
}
this.scene.add(cube);
this.scene.add(mesh);
}
makePoint(vector?: Vector3, color?: string, size?: number) {
makePoint(name: string, vector?: Vector3, quaternion?: Quaternion, color?: string, size?: number) {
const cube = new Mesh(
new BoxGeometry(size ?? 10, size ?? 10, size ?? 10),
new MeshBasicMaterial({ color: color ?? 0x0095dd, transparent: true, opacity: 0.5 })
@ -153,24 +172,68 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
if (vector) {
cube.position.copy(vector);
}
if (quaternion) {
cube.quaternion.copy(quaternion);
}
cube.name = name;
this.scene.add(cube);
}
deleteSceneItem = (item: string) =>
this.scene.children.forEach((el) => el.name.isEqualR(item).map(() => this.scene.remove(el)));
deleteSceneItemByName = (name: string) =>
this.scene.children.forEach((el) => el.name.isEqualR(name).map(() => this.scene.remove(el)));
deleteSceneItem = (item: SceneItems) =>
item.icon.isEqualR("Camera").fold(
() => this.deleteSceneItemByName(item.name + "camera_helper"),
() => this.deleteSceneItemByName(item.name)
);
loadUrdfRobot = (robotModel: RobotModel) =>
this.urdfLoader.load(robotModel.httpUrl, (robot) => {
robot.userData[UserData.selectedObject] = true;
robot.name = robotModel.name;
if (robotModel.vector3) robot.position.copy(new Vector3(0, 0, 0));
if (robotModel.quaternion) robot.quaternion.copy(new Quaternion().fromArray(robotModel.quaternion));
// robot.setJointValue("ee_link_joint", 4);
if (robotModel.jointPosition.isEmpty()) {
Object.entries(robot.joints).forEach(([name, uRDFJoint]) => {
if (uRDFJoint.jointType !== "fixed") {
robotModel.jointPosition.push({
angel: uRDFJoint.angle,
limit: {
lower: uRDFJoint.limit.lower,
upper: uRDFJoint.limit.upper,
},
name: name,
});
}
});
}
// Object.entries(robot.joints).forEach(([k, v]) => robot.setJointValue(k, 1));
loadUrdf = (urlPath: string) => {
this.urdfLoader.load(urlPath, (robot) => {
this.scene.add(robot);
// @ts-expect-error
this.sceneFrame = robot.frames;
});
};
loadUrdf = (urlPath: string, vector3?: Vector3, quaternion?: Quaternion) =>
this.urdfLoader.load(urlPath, (robot) => {
robot.userData[UserData.selectedObject] = true;
solidSpawn(
solidSpawn: ISolidSpawnHelper,
if (vector3) robot.position.copy(new Vector3(0, 0, 0));
if (quaternion) robot.quaternion.copy(quaternion);
Object.entries(robot.joints).forEach(([k, v]) => robot.setJointValue(k, 1));
this.scene.add(robot);
// @ts-expect-error
this.sceneFrame = robot.frames;
});
solidSpawn = (
solidSpawn: ISpawnHelper,
loadCallback?: (obj: Object3D<Object3DEventMap> | undefined) => void,
vector3?: Vector3
) {
) =>
this.loader(
solidSpawn.url,
() => {
@ -180,7 +243,7 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
solidSpawn.name,
vector3
);
}
loadHttpAndPreview(path: string, name: string, loadCallback?: Function) {
this.loader(
path,
@ -208,13 +271,15 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
}
}
addSceneCamera(cameraModel: CameraViewModel) {
cameraModel.mapPerspectiveCamera(this.htmlSceneWidth, this.htmlSceneHeight).forEach((el) => this.scene.add(el));
}
addSceneCamera = (cameraModel: CameraModel) => cameraModel.toWebGl(this);
disposeTransformControlsMode() {
this.transformControls.detach();
}
updateSolidBody = (solidBodyModel: SolidModel) => {
const mesh = this.scene.getObjectByName(solidBodyModel.name);
mesh?.position.copy(solidBodyModel.vector3);
mesh?.quaternion.copy(new Quaternion().fromArray(solidBodyModel.quaternion));
};
disposeTransformControlsMode = () => this.transformControls.detach();
setRayCastAndGetFirstObjectName(vector: Vector2): Result<void, string> {
this.scene.add(this.transformControls);
@ -310,13 +375,13 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
init() {
this.light();
this.addListeners();
const floor = new GridHelper(1000, 100, 0x888888, 0x444444);
floor.geometry.rotateX(Math.PI * 0.5);
floor.userData = {};
floor.userData[UserData.cameraInitialization] = true;
floor.up.copy(new Vector3(0, 0, 1));
const gridHelper = new GridHelper(1000, 100, 0x888888, 0x444444);
gridHelper.geometry.rotateX(Math.PI * 0.5);
gridHelper.userData = {};
gridHelper.userData[UserData.cameraInitialization] = true;
gridHelper.up.copy(new Vector3(0, 0, 1));
this.scene.add(floor);
this.scene.add(gridHelper);
}
render() {
@ -326,13 +391,6 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
});
}
getAllSceneModels(): BaseSceneItemModel[] {
return this.getAllSceneNameModels().map(
(name) =>
new StaticAssetItemModel(name, this.getObjectsAtName(name).position, this.getObjectsAtName(name).quaternion)
);
}
getAllSceneNameModels(): string[] {
return this.scene.children.filter((el) => el.name !== "").map((el) => el.name);
}
@ -367,7 +425,7 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
if (position) el.position.copy(position);
if (quaternion) el.quaternion.copy(quaternion);
this.emit(new StaticAssetItemModel(el.name, el.position, el.quaternion));
// this.emit(new StaticAssetItemModel(el.name, el.position, el.quaternion));
this.scene.add(el);
callBack();
});
@ -379,6 +437,13 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
this.daeLoader.load(
url,
(result) => {
result.scene.children.forEach((el) => {
el.userData[UserData.selectedObject] = true;
el.name = name;
});
result.scene.name = name;
if (position) result.scene.position.copy(position);
if (quaternion) result.scene.quaternion.copy(quaternion);
this.scene.add(result.scene);
},
(err) => console.log(err)
@ -420,13 +485,13 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
objects.map((el) => this.getObjectsAtName(el)).map((el) => el.position)
);
var size = new Vector3();
boundingBox.getSize(size);
var vector3 = new Vector3();
boundingBox.getSize(vector3);
const fov = this.camera.fov * (Math.PI / 180);
const fovh = 2 * Math.atan(Math.tan(fov / 2) * this.camera.aspect);
let dx = size.z / 2 + Math.abs(size.x / 2 / Math.tan(fovh / 2));
let dy = size.z / 2 + Math.abs(size.y / 2 / Math.tan(fov / 2));
let dx = vector3.z / 2 + Math.abs(vector3.x / 2 / Math.tan(fovh / 2));
let dy = vector3.z / 2 + Math.abs(vector3.y / 2 / Math.tan(fov / 2));
let cameraZ = Math.max(dx, dy);
if (offset !== undefined && offset !== 0) cameraZ *= offset;
@ -473,8 +538,9 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
fitSelectedObjectToScreen(objects: string[]) {
//https://stackoverflow.com/questions/14614252/how-to-fit-camera-to-object
let boundBox = new Box3().setFromPoints(objects.map((el) => this.getObjectsAtName(el)).map((el) => el.position));
let boundSphere = boundBox.getBoundingSphere(new Sphere());
let boundSphere = new Box3()
.setFromPoints(objects.map((el) => this.getObjectsAtName(el)).map((el) => el.position))
.getBoundingSphere(new Sphere());
let vFoV = this.camera.getEffectiveFOV();
let hFoV = this.camera.fov * this.camera.aspect;
let FoV = Math.min(vFoV, hFoV);

View file

@ -62,21 +62,21 @@ export class SimpleErrorState extends UiLoader {
export class ModalStore extends SimpleErrorState {
isModalOpen: boolean = false;
showModal = () => {
this.isModalOpen = true
this.isModalOpen = true;
};
handleOk = () => {
this.isModalOpen = false
this.isModalOpen = false;
};
handleCancel = () => {
this.isModalOpen = false
this.isModalOpen = false;
};
}
export abstract class UiErrorState<T> extends UiLoader {
abstract errorHandingStrategy: (error: T) => void;
abstract init(navigate?: NavigateFunction): Promise<any>;
dispose() { }
dispose() {}
errors: UiBaseError[] = [];
}
@ -108,6 +108,9 @@ export abstract class UiDrawerFormState<V, E> extends DrawerState<E> {
//@ts-ignore
this.viewModel = Object.assign(this.viewModel, value);
}
loadDependency = (viewModel: V) => {
this.viewModel = viewModel;
};
}
export abstract class FormState<V, E> extends UiErrorState<E> {
abstract viewModel: V;
@ -115,4 +118,7 @@ export abstract class FormState<V, E> extends UiErrorState<E> {
//@ts-ignore
this.viewModel = Object.assign(this.viewModel, value);
}
loadDependency = (viewModel: V) => {
this.viewModel = viewModel;
};
}

View file

@ -7,6 +7,7 @@ export interface IIconsProps extends IStyle {
onClick?: Function;
height?: number;
width?: number;
isNeedStopPropagation?: boolean;
}
export function Icon(props: IIconsProps) {
@ -14,8 +15,9 @@ export function Icon(props: IIconsProps) {
(node) => {
return (
<div
onClick={() => {
onClick={(e) => {
if (props.onClick) props.onClick();
if (props.isNeedStopPropagation) e.stopPropagation();
}}
style={props.style}
>
@ -480,6 +482,150 @@ const getIconSvg = (
/>
</svg>
);
case "Plus":
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="M4 12H20M12 4V20" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
case "Minus":
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="M6 12L18 12" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
case "Zone":
return Result.ok(
<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
fill="#000000"
width={width ? width : "20"}
height={height ? height : "20"}
version="1.1"
id="Layer_1"
viewBox="0 0 512 512"
xmlSpace="preserve"
>
<g>
<g>
<path d="M256,168.306c-4.513,0-8.17,3.658-8.17,8.17v23.421c0,4.512,3.657,8.17,8.17,8.17c4.513,0,8.17-3.658,8.17-8.17v-23.421 C264.17,171.963,260.513,168.306,256,168.306z" />
</g>
</g>
<g>
<g>
<path d="M256,112.204c-4.513,0-8.17,3.658-8.17,8.17v23.421c0,4.512,3.657,8.17,8.17,8.17c4.513,0,8.17-3.658,8.17-8.17v-23.421 C264.17,115.862,260.513,112.204,256,112.204z" />
</g>
</g>
<g>
<g>
<path d="M256,56.102c-4.513,0-8.17,3.658-8.17,8.17v23.421c0,4.512,3.657,8.17,8.17,8.17c4.513,0,8.17-3.658,8.17-8.17V64.272 C264.17,59.76,260.513,56.102,256,56.102z" />
</g>
</g>
<g>
<g>
<path d="M328.956,288.686l-20.284-11.711c-3.91-2.257-8.906-0.918-11.161,2.99c-2.256,3.908-0.917,8.904,2.99,11.161 l20.284,11.711c1.288,0.743,2.692,1.096,4.077,1.096c2.824,0,5.57-1.466,7.083-4.086 C334.202,295.939,332.863,290.942,328.956,288.686z" />
</g>
</g>
<g>
<g>
<path d="M377.54,316.737l-20.283-11.711c-3.906-2.257-8.906-0.918-11.16,2.99c-2.256,3.908-0.917,8.904,2.99,11.161l20.283,11.711 c1.287,0.743,2.692,1.096,4.078,1.096c2.824,0,5.57-1.465,7.083-4.086C382.788,323.991,381.448,318.995,377.54,316.737z" />
</g>
</g>
<g>
<g>
<path d="M426.127,344.788l-20.283-11.711c-3.906-2.258-8.906-0.918-11.16,2.99c-2.256,3.908-0.917,8.904,2.99,11.16l20.283,11.711 c1.287,0.743,2.692,1.096,4.078,1.096c2.824,0,5.57-1.465,7.083-4.086C431.373,352.042,430.034,347.046,426.127,344.788z" />
</g>
</g>
<g>
<g>
<path d="M214.489,279.967c-2.255-3.909-7.254-5.246-11.161-2.99l-20.284,11.711c-3.908,2.256-5.246,7.253-2.99,11.161 c1.513,2.621,4.259,4.086,7.083,4.086c1.386,0,2.792-0.353,4.078-1.096l20.284-11.711 C215.406,288.871,216.745,283.875,214.489,279.967z" />
</g>
</g>
<g>
<g>
<path d="M165.903,308.018c-2.257-3.909-7.254-5.246-11.161-2.99l-20.283,11.711c-3.908,2.256-5.246,7.253-2.99,11.161 c1.513,2.621,4.259,4.086,7.083,4.086c1.386,0,2.792-0.353,4.077-1.096l20.283-11.711 C166.82,316.923,168.159,311.926,165.903,308.018z" />
</g>
</g>
<g>
<g>
<path d="M117.317,336.069c-2.257-3.908-7.254-5.247-11.161-2.99L85.873,344.79c-3.908,2.256-5.246,7.253-2.99,11.16 c1.514,2.621,4.259,4.086,7.083,4.086c1.386,0,2.792-0.353,4.077-1.096l20.283-11.711 C118.234,344.974,119.573,339.977,117.317,336.069z" />
</g>
</g>
<g>
<g>
<path d="M474.712,125.01L260.085,1.095c-2.527-1.46-5.643-1.46-8.17,0L37.288,125.01c-2.527,1.46-4.085,4.156-4.085,7.075v247.83 c0,2.919,1.558,5.616,4.085,7.075l214.627,123.915c1.264,0.73,2.674,1.095,4.085,1.095c1.411,0,2.821-0.365,4.085-1.095 L474.712,386.99c2.527-1.46,4.085-4.156,4.085-7.075v-247.83C478.797,129.166,477.24,126.469,474.712,125.01z M247.83,489.679 L57.713,379.915l8.027-4.634c3.909-2.256,5.247-7.253,2.991-11.162c-2.255-3.908-7.254-5.246-11.16-2.99l-8.028,4.634V146.236 L239.66,256l-8.029,4.635c-3.908,2.256-5.246,7.253-2.99,11.161c1.514,2.621,4.259,4.086,7.083,4.086 c1.386,0,2.792-0.353,4.077-1.096l8.029-4.635V489.679z M256,224.408c-4.513,0-8.17,3.658-8.17,8.17v9.27L57.713,132.085 L247.83,22.321v9.27c0,4.512,3.657,8.17,8.17,8.17c4.513,0,8.17-3.658,8.17-8.17v-9.27l190.116,109.764L264.17,241.849v-9.27 C264.17,228.067,260.513,224.408,256,224.408z M462.457,365.764l-8.029-4.635c-3.91-2.257-8.907-0.917-11.161,2.99 c-2.256,3.908-0.917,8.904,2.99,11.161l8.027,4.634L264.17,489.679V270.151l8.029,4.635c1.288,0.743,2.692,1.096,4.078,1.096 c2.824,0,5.57-1.465,7.083-4.086c2.256-3.908,0.917-8.904-2.99-11.161L272.34,256l190.116-109.764V365.764z" />
</g>
</g>
</svg>
);
case "Point":
return Result.ok(
<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
width={width ? width : "20"}
height={height ? height : "20"}
viewBox="0 0 24 24"
version="1.1"
>
<g id="🔍-Product-Icons" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="ic_fluent_point_scan_24_regular" fill="#212121" fillRule="nonzero">
<path
d="M10.2502491,2 C10.6299449,2 10.9437401,2.28215388 10.9934025,2.64822944 L11.0002491,2.75 L11.0006909,7.54409036 C13.8530802,7.88540535 16.1151657,10.1477856 16.4560297,13.0003134 L21.25,13.0000501 C21.6642136,13.0000501 22,13.3358365 22,13.7500501 C22,14.1297458 21.7178461,14.443541 21.3517706,14.4932034 L21.25,14.5000501 L16.4558272,14.5008817 C16.1142704,17.3526115 13.8525157,19.614164 11.0006909,19.9554115 L11.0002491,21.25 C11.0002491,21.6642136 10.6644627,22 10.2502491,22 C9.87055333,22 9.55675813,21.7178461 9.50709571,21.3517706 L9.50024909,21.25 L9.50011804,19.9554486 C6.64814674,19.6143283 4.38624018,17.3527151 4.04467102,14.5008817 L2.75,14.5000501 C2.33578644,14.5000501 2,14.1642636 2,13.7500501 C2,13.3703543 2.28215388,13.0565591 2.64822944,13.0068967 L2.75,13.0000501 L4.04446845,13.0003134 C4.3853449,10.147682 6.64758231,7.88524105 9.50011804,7.54405318 L9.50024909,2.75 C9.50024909,2.33578644 9.83603553,2 10.2502491,2 Z M9.5,14.5 L5.55904782,14.5008541 C5.88028911,16.5231258 7.47773525,18.1202911 9.50014726,18.4411111 L9.5,14.5 Z M14.9414504,14.5008541 L11,14.5 L11.0008468,18.4410324 C13.0230241,18.12003 14.6202353,16.5229605 14.9414504,14.5008541 Z M9.50014726,9.05839069 C7.47723457,9.37929011 5.87949819,10.9771669 5.55880947,13.0001498 L9.5,13 L9.50014726,9.05839069 Z M11.0008468,9.05846938 L11,13 L14.9416887,13.0001498 C14.6324784,11.0495757 13.1360034,9.49422061 11.2158966,9.09771754 L11.0008468,9.05846938 Z"
id="🎨-Color"
></path>
</g>
</g>
</svg>
);
case "Light":
return Result.ok(
<svg
width={width ? width : "20"}
height={height ? height : "20"}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
xmlSpace="preserve"
>
<g fill="black">
<path
fill="black"
d="M1028 1556c-3.283 0-6 2.441-6 5.5 0 1.706.905 3.146 2.152 4.36l.994.994a.5.5 0 0 0 .303.148.5.5 0 0 0 .051.998h5a.5.5 0 0 0 .045-.998.5.5 0 0 0 .309-.148l.998-.999c1.212-1.198 2.146-2.651 2.146-4.353 0-3.059-2.716-5.5-6-5.5zm0 1c2.792 0 5 2.036 5 4.5 0 1.334-.743 2.549-1.852 3.644l-1 1a.5.5 0 0 0 .28.854h-4.86a.5.5 0 0 0 .287-.854l-1-1a.5.5 0 0 0-.01-.01c-1.14-1.108-1.847-2.286-1.847-3.64 0-2.464 2.208-4.5 5-4.5zm-2.5 12a.5.5 0 1 0 0 1h1.5v.5a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-.5h1.5a.5.5 0 1 0 0-1z"
transform="translate(-1018 -1553.5)"
/>
<path
fill="black"
d="M1025.49 1561.006a.5.5 0 0 0-.344.848l.854.853v1.543a.5.5 0 1 0 1 0V1563h2v1.25a.5.5 0 1 0 1 0v-1.543l.854-.854a.5.5 0 0 0-.708-.706l-.853.853h-2.586l-.854-.854a.5.5 0 0 0-.363-.14z"
transform="translate(-1018 -1553.5)"
/>
</g>
</svg>
);
case "Robot":
return Result.ok(
<svg
xmlns="http://www.w3.org/2000/svg"
fill="#000000"
width={width ? width : "20"}
height={height ? height : "20"}
viewBox="0 0 50 50"
>
<path d="M39 2.03125C38.738281 2.0625 38.503906 2.199219 38.34375 2.40625L35.40625 6.09375C34.835938 5.378906 33.972656 4.90625 33 4.90625L29 4.90625C27.6875 4.90625 26.566406 5.765625 26.125 6.9375L16.4375 6.9375C14.8125 4.5625 12.082031 3 9 3C4.042969 3 0 7.042969 0 12C0 15.082031 1.5625 17.8125 3.9375 19.4375C3.949219 19.445313 3.957031 19.460938 3.96875 19.46875C3.96875 19.480469 3.96875 19.488281 3.96875 19.5L14.75 39.9375L6.875 39.9375C5.226563 39.9375 3.9375 41.359375 3.9375 43L3.9375 49C3.933594 49.28125 4.046875 49.554688 4.246094 49.753906C4.445313 49.953125 4.71875 50.066406 5 50.0625L39 50.0625C39.28125 50.066406 39.554688 49.953125 39.753906 49.753906C39.953125 49.554688 40.066406 49.28125 40.0625 49L40.0625 43C40.0625 41.359375 38.773438 39.9375 37.125 39.9375L29.90625 39.9375L16.96875 17.0625L26.125 17.0625C26.566406 18.234375 27.6875 19.09375 29 19.09375L33 19.09375C33.972656 19.09375 34.835938 18.621094 35.40625 17.90625L38.34375 21.59375C38.636719 21.960938 39.148438 22.066406 39.5625 21.84375L49.46875 16.4375C49.882813 16.214844 50.074219 15.730469 49.929688 15.285156C49.78125 14.835938 49.339844 14.5625 48.875 14.625C48.753906 14.644531 48.636719 14.6875 48.53125 14.75L39.375 19.78125L36.09375 15.625L36.09375 8.40625L39.375 4.25L48.53125 9.25C48.835938 9.457031 49.230469 9.472656 49.550781 9.292969C49.871094 9.113281 50.0625 8.769531 50.042969 8.402344C50.027344 8.035156 49.804688 7.710938 49.46875 7.5625L39.5625 2.15625C39.390625 2.058594 39.195313 2.015625 39 2.03125 Z M 9 5C11.480469 5 13.664063 6.28125 14.90625 8.21875C14.917969 8.238281 14.925781 8.261719 14.9375 8.28125C14.957031 8.324219 14.976563 8.367188 15 8.40625C15.023438 8.472656 15.054688 8.535156 15.09375 8.59375C15.109375 8.621094 15.140625 8.628906 15.15625 8.65625C15.175781 8.6875 15.195313 8.71875 15.21875 8.75C15.722656 9.71875 16 10.828125 16 12C16 13.160156 15.714844 14.257813 15.21875 15.21875C15.210938 15.230469 15.195313 15.238281 15.1875 15.25C15.175781 15.269531 15.164063 15.292969 15.15625 15.3125C15.152344 15.320313 15.160156 15.335938 15.15625 15.34375C15.132813 15.363281 15.113281 15.382813 15.09375 15.40625C15.027344 15.492188 14.976563 15.585938 14.9375 15.6875C14.925781 15.71875 14.914063 15.75 14.90625 15.78125C13.664063 17.71875 11.480469 19 9 19C5.125 19 2 15.875 2 12C2 8.125 5.125 5 9 5 Z M 9 6.34375C8.933594 6.34375 8.878906 6.371094 8.8125 6.375C8.75 6.390625 8.683594 6.410156 8.625 6.4375C5.707031 6.644531 3.34375 9.03125 3.34375 12C3.34375 15.101563 5.898438 17.65625 9 17.65625C12.101563 17.65625 14.65625 15.101563 14.65625 12C14.65625 9.042969 12.308594 6.660156 9.40625 6.4375C9.394531 6.4375 9.386719 6.40625 9.375 6.40625C9.304688 6.386719 9.230469 6.378906 9.15625 6.375C9.101563 6.375 9.054688 6.34375 9 6.34375 Z M 29 7.09375L33 7.09375C33.511719 7.09375 33.90625 7.488281 33.90625 8L33.90625 16C33.90625 16.511719 33.511719 16.90625 33 16.90625L29 16.90625C28.488281 16.90625 28.09375 16.511719 28.09375 16L28.09375 8C28.09375 7.488281 28.488281 7.09375 29 7.09375 Z M 8.9375 8.34375C8.957031 8.34375 8.980469 8.34375 9 8.34375C11.015625 8.34375 12.65625 9.984375 12.65625 12C12.65625 14.015625 11.015625 15.65625 9 15.65625C6.984375 15.65625 5.34375 14.015625 5.34375 12C5.34375 10.003906 6.949219 8.378906 8.9375 8.34375 Z M 17.5 9.0625L25.90625 9.0625L25.90625 14.9375L17.5 14.9375C17.820313 14.011719 18 13.03125 18 12C18 10.96875 17.820313 9.988281 17.5 9.0625 Z M 15.375 18.3125L27.59375 39.9375L16.96875 39.9375L6.84375 20.71875C7.539063 20.890625 8.253906 21 9 21C11.496094 21 13.742188 19.960938 15.375 18.3125 Z M 6.875 42.0625L16.09375 42.0625C16.34375 42.167969 16.625 42.167969 16.875 42.0625L37.125 42.0625C37.558594 42.0625 37.9375 42.4375 37.9375 43L37.9375 47.9375L6.0625 47.9375L6.0625 43C6.0625 42.4375 6.441406 42.0625 6.875 42.0625Z" />
</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">

View file

@ -1,7 +1,10 @@
import * as React from "react";
import { CoreText, CoreTextType } from "../text/text";
import { IStyle } from "../../model/style";
export enum CoreInputType {
small = "small",
default = "default",
}
interface IInputProps extends IStyle {
label: string;
value?: string;
@ -9,6 +12,7 @@ interface IInputProps extends IStyle {
onChange?: (value: string) => void;
validation?: (value: string) => boolean;
error?: string;
type?: CoreInputType;
}
export const CoreInput = (props: IInputProps) => {
@ -21,34 +25,38 @@ export const CoreInput = (props: IInputProps) => {
setAppendInnerText(false);
}
}, [ref, value, isAppendInnerText, setAppendInnerText, props]);
const isSmall = props.type !== undefined && props.type.isEqual(CoreInputType.small);
return (
<div
style={Object.assign(
{
backgroundColor: "rgba(230, 224, 233, 1)",
height: 58,
height: isSmall ? 40 : 58,
borderRadius: "4px 4px 0px 0px",
borderBottom: "solid 1px black",
padding: "10px 10px 10px 10px",
},
props.style
)}
>
<CoreText type={CoreTextType.small} text={props.label} />
<CoreText type={CoreTextType.small} style={isSmall ? { fontSize: 8, position:'relative',top:-8 } : {}} text={props.label} />
<input
defaultValue={props.value}
style={{
backgroundColor: "#00008000",
border: 1,
fontSize: 16,
fontSize: isSmall ? 12 : 16,
fontFamily: "Roboto",
color: "#1D1B20",
height: 24,
width: "100%",
userSelect: "none",
outline: "none",
position: isSmall ? "relative" : undefined,
top: isSmall ? -8 : undefined,
}}
onChange={(e) => {
const val = e.target.value;

View file

@ -0,0 +1,109 @@
import * as React from "react";
import { CoreText, CoreTextType } from "../text/text";
import { IStyle } from "../../model/style";
import { Icon } from "../icons/icons";
interface IInputProps extends IStyle {
label: string;
value?: number;
step: number;
max: number;
min: number;
subLabel?: React.ReactNode;
onChange?: (value: number) => void;
validation?: (value: number) => boolean;
error?: string;
}
export const CoreInputNumber = (props: IInputProps) => {
const [value, setValue] = React.useState<number>(() => props.value ?? 0);
const ref = React.useRef<HTMLDivElement>(null);
const [isAppendInnerText, setAppendInnerText] = React.useState(true);
React.useEffect(() => {
if (ref.current && isAppendInnerText) {
ref.current.innerText = String(value);
setAppendInnerText(false);
}
}, [ref, value, isAppendInnerText, setAppendInnerText, props]);
return (
<>
{/* <div style={{ position: "absolute" }}>
<div style={{ width: width, display: "flex", justifyContent: "flex-end" }}>
<Icon type="Plus" />
<Icon type="Minus" />
</div>
</div> */}
<div
style={Object.assign(
{
backgroundColor: "rgba(230, 224, 233, 1)",
height: 58,
borderRadius: "4px 4px 0px 0px",
borderBottom: "solid 1px black",
padding: "10px 10px 10px 10px",
},
props.style
)}
>
<div>
<CoreText type={CoreTextType.small} text={props.label} />
</div>
<div style={{ width: "100%", display: "flex", justifyContent: "flex-end" }}>
<input
style={{
backgroundColor: "#00008000",
border: 1,
fontSize: 16,
fontFamily: "Roboto",
color: "#1D1B20",
height: 24,
width: "100%",
userSelect: "none",
outline: "none",
}}
value={value}
onChange={(e) => {
const val = e.target.value;
setValue(Number(val));
if (val) {
if (props.validation !== undefined && props.validation(Number(val)) && props.onChange) {
props.onChange(Number(val));
return;
}
if (props.onChange && props.validation === undefined) {
props.onChange(Number(val));
return;
}
}
}}
/>
{value ? (
props.validation ? (
props.validation(value) ? null : (
<div style={{ color: "#ff1d0c" }}>{props.error ? props.error : "error"}</div>
)
) : null
) : null}
<Icon
type="Plus"
onClick={() => {
setValue(value + props.step);
if (props.onChange) props.onChange(value);
}}
/>
<Icon
type="Minus"
onClick={() => {
setValue(value - props.step);
if (props.onChange) props.onChange(value);
}}
/>
</div>
</div>
</>
);
};

View file

@ -43,8 +43,9 @@ export const CoreSelect = (props: ICoreSelectProps) => {
}}
>
{cursorIsCorses
? props.items.map((el) => (
? props.items.map((el, i) => (
<div
key={i}
onClick={() => {
setValue(el);
props.onChange(el);

View file

@ -0,0 +1,43 @@
import React, { useRef, useState } from "react";
// TODO: need
export const CoreSlider = ({
max,
min,
step,
initialValue,
onChange,
}: {
max: number;
min: number;
step: number;
initialValue: number;
onChange: (value: number) => void;
}) => {
const refSlider = useRef<HTMLDivElement>(null);
const refWheel = useRef<HTMLDivElement>(null);
const [value, setValue] = useState<number>(initialValue);
React.useEffect(() => {
if (refSlider.current && refWheel.current) {
console.log((max - min) / step);
console.log(refSlider.current.clientWidth / ((max - min) / step));
const oneStep = refSlider.current.clientWidth / ((max - min) / step);
refWheel.current.style.left = ((value - min) / step) * oneStep + "px";
}
}, []);
return (
<div
ref={refSlider}
onClick={(event) => {
console.log(event)
}}
style={{ width: "100%", height: 11, backgroundColor: "rgba(104, 80, 164, 1)" }}
>
<div
style={{ position: "relative", width: 21, height: 18, background: "#D9D9D9", borderRadius: "20px", bottom: 3 }}
ref={refWheel}
></div>
</div>
);
};

View file

@ -48,7 +48,6 @@ const getStyle = (type: CoreTextType, color: string | undefined) => {
fontFamily: "Roboto",
fontWeight: 500,
textOverflow: "ellipsis",
fontSizeAdjust: 16,
}
if (type.isEqual(CoreTextType.big)) return {
@ -84,4 +83,4 @@ export function CoreText(props: ITextProps) {
</div>
);
}
// CREATE COMPONENT , HTML WRITE , JSX->JS TSX -> TS, PROPS , LIFE CYCLE , REACT HOOK, STATE MANAGMENT -> PUBSUB -> Конечный автомат -> ROUTER

View file

@ -1,10 +1,103 @@
import { plainToInstance } from "class-transformer";
import { Result } from "../../../core/helper/result";
import { HttpMethod, CoreHttpRepository } from "../../../core/repository/http_repository";
import { CoreError } from "../../../core/store/base_store";
import { SceneModel } from "../model/scene_model";
import { SceneViewModel } from "../model/scene_view_model";
import { SceneAsset } from "../../../core/model/scene_asset";
export class SceneHttpRepository extends CoreHttpRepository {
getScene = () => {
return plainToInstance(SceneAsset, {
scene: [
// {
// quaternion: [0, 0, 0, 1],
// vector3: { x: 1, y: 1, z: 1 },
// name: "body_down",
// solidType: "active",
// mesh: "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.dae",
// collisionMesh: "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.dae",
// type: "SOLID",
// },
// {
// quaternion: [0.3797976276673656, 0.5269410603416079, 0.6168038601812418, 0.44456706919183975],
// vector3: { x: 60, y: 20.000000000000004, z: 9.999999999999993 },
// name: "231",
// cameraType: "RGB",
// width: 0,
// updateRate: 0,
// fov: 50,
// near: 0.1,
// far: 2000,
// height: 0,
// topic: "231",
// type: "CAMERA",
// aspect: 0.48721804511278194,
// },
// {
// type: "POINT",
// name: "POINT 1",
// quaternion: [0, 0, 0, 1],
// vector3: { x: 0.504300334422403, y: 0.66062343475878, z: 1 },
// },
// {
// type: "ZONE",
// name: "ZONE 1",
// quaternion: [0, 0, 0, 1],
// vector3: { x: 0, y: 0, z: 0 },
// width: 100,
// height: 100,
// length: 10,
// },
{
quaternion: [0, 0, 0, 1],
vector3: { x: 0, y: 10, z: 0 },
name: "ARM0",
nDof: 6,
httpUrl: "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/robots/124/robot.xml",
toolType: "",
jointPosition: [],
type: "ROBOT",
},
// {
// type: "LIGHT",
// name:"light1S",
// typeLight: "SPOT",
// color: "0xffffff",
// intensity: 100,
// distance: 100,
// angle: 100,
// penumbra: 100,
// decay: 100,
// quaternion: [0, 0, 0, 1],
// vector3: { x: 0, y: 0, z: 0 },
// },
// {
// type: "LIGHT",
// name:"light1P",
// typeLight: "POINT",
// color: "0xffffff",
// intensity: 100,
// distance: 100,
// decay: 100,
// quaternion: [0, 0, 0, 1],
// vector3: { x: 0, y: 0, z: 0 },
// },
// {
// name:"light1D",
// type: "LIGHT",
// typeLight: "DIRECTIONAL",
// color: "0xffffff",
// intensity: 100,
// quaternion: [0, 0, 0, 1],
// vector3: { x: 0, y: 0, z: 0 },
// },
],
});
};
getAllScenes = () => this._jsonRequest<SceneModel[]>(HttpMethod.GET, "/scenes");
newScene = (sceneViewModel: SceneViewModel) =>

View file

@ -1,30 +0,0 @@
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

@ -1,163 +0,0 @@
import { CameraHelper, Object3D, PerspectiveCamera, Quaternion, Scene, Vector3 } from "three";
import { v4 as uuidv4 } from "uuid";
import { UserData } from "../../../core/repository/core_three_repository";
import {
Asset,
Instance,
InstanceRgbCamera,
InstanceType,
SceneSimpleObject,
} from "../../../core/model/robossembler_assets";
import { Result } from "../../../core/helper/result";
export enum RobossemblerFiles {
robossemblerAssets = "robossembler_assets.json",
}
export enum SceneModelsType {
ASSET,
}
export abstract class BaseSceneItemModel {
id: string;
name: string;
position: Vector3;
quaternion: Quaternion;
constructor(name: string) {
this.id = uuidv4();
this.name = name;
}
abstract toInstance(): Instance;
abstract deleteToScene(scene: Scene): Object3D[];
toQuaternionArray() {
return [this.quaternion.x, this.quaternion.y, this.quaternion.z, this.quaternion.w];
}
}
export class StaticAssetItemModel extends BaseSceneItemModel {
name: string;
type = SceneModelsType.ASSET;
constructor(name: string, position: Vector3, quaternion: Quaternion) {
super(name);
this.name = name;
this.position = position;
this.quaternion = quaternion;
}
static fromSceneSimpleObjectAndAsset(sceneSimpleObject: SceneSimpleObject, asset: Asset) {
const { x, y, z } = sceneSimpleObject.position;
const quaternion = sceneSimpleObject.quaternion;
return new StaticAssetItemModel(
asset.name,
new Vector3(x, y, z),
new Quaternion(quaternion[0], quaternion[1], quaternion[2], quaternion[3])
);
}
toInstance(): Instance {
const instance = new Instance();
instance.instanceType = InstanceType.SCENE_SIMPLE_OBJECT;
instance.position = this.position;
instance.instanceAt = this.name;
instance.quaternion = this.toQuaternionArray();
return instance;
}
deleteToScene(scene: Scene): Object3D[] {
return scene.children.filter((el) => el.name !== this.name);
}
}
export interface ICoreInstance {
instanceAt: null | string;
type: string;
position: Vector3;
quaternion: Quaternion;
}
export interface ICameraInstance extends ICoreInstance {
cameraLink: string;
topicImage: string;
topicCameraInfo: string;
topicDepth: string | null;
}
export class CameraViewModel extends BaseSceneItemModel {
cameraLink: string;
topicImage: string;
topicCameraInfo: string;
topicDepth: null | string;
constructor(cameraLink: string, topicImage: string, topicCameraInfo: string, topicDepth: string | null) {
super(cameraLink);
this.cameraLink = cameraLink;
this.topicImage = topicImage;
this.topicCameraInfo = topicCameraInfo;
this.topicDepth = topicDepth;
}
static fromInstanceRgbCamera(instanceRgbCamera: InstanceRgbCamera) {
const { cameraLink, topicImage, topicCameraInfo, topicDepth, position, quaternion } = instanceRgbCamera;
const instance = new CameraViewModel(cameraLink, topicImage, topicCameraInfo, topicDepth);
const { x, y, z } = position;
instance.position = new Vector3(x, y, z);
instance.quaternion = new Quaternion(quaternion[0], quaternion[1], quaternion[2], quaternion[3]);
return instance;
}
deleteToScene(scene: Scene): Object3D[] {
return scene.children.filter((el) => {
if (el.name === this.name) {
return false;
}
if (el.name === this.cameraLink + "camera_helper") {
return false;
}
return true;
});
}
toInstance(): InstanceRgbCamera {
return {
instanceType: InstanceType.RGB_CAMERA,
position: this.position,
quaternion: this.toQuaternionArray(),
instanceAt: null,
cameraLink: this.cameraLink,
topicCameraInfo: this.topicCameraInfo,
topicDepth: this.topicDepth,
topicImage: this.topicImage,
};
}
validate(): Result<string, CameraViewModel> {
if (this.cameraLink.isEmpty()) {
return Result.error("cameraLink is empty");
}
return Result.ok(this);
}
mapPerspectiveCamera(htmlSceneWidth: number, htmlSceneHeight: number) {
const perspectiveCamera = new PerspectiveCamera(48, htmlSceneWidth / htmlSceneHeight, 7.1, 28.5);
perspectiveCamera.position.copy(this.position);
perspectiveCamera.quaternion.copy(this.quaternion);
perspectiveCamera.name = this.cameraLink;
const cameraHelper = new CameraHelper(perspectiveCamera);
perspectiveCamera.userData[UserData.selectedObject] = true;
cameraHelper.userData[UserData.selectedObject] = true;
cameraHelper.name = this.cameraLink + "camera_helper";
return [cameraHelper, perspectiveCamera];
}
static empty() {
return new CameraViewModel("", "", "", "");
}
}

View file

@ -1,18 +1,3 @@
export class SceneMenu {
x?: number;
y?: number;
isShow?: boolean;
constructor(x: number | undefined, y: number | undefined, isShow: boolean | undefined) {
this.x = x;
this.y = y;
this.isShow = isShow;
}
static empty() {
return new SceneMenu(undefined, undefined, false);
}
}
export interface SceneManagerView {
name: string;

View file

@ -1,30 +0,0 @@
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,60 @@
import { FormState } from "../../../../core/store/base_store";
import { CoreInput } from "../../../../core/ui/input/input";
import { CoreText, CoreTextType } from "../../../../core/ui/text/text";
export const CoordsForm = ({ store, update }: { store: FormState<any, any>; update: Function }) => {
return (
<>
<CoreText text="Координаты" type={CoreTextType.header} />
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор X"
onChange={(text) => {
store.updateForm({ vector3: store.viewModel.vector3.setX(Number(text)) });
update();
}}
/>
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор Y"
onChange={(text) => {
store.updateForm({ vector3: store.viewModel.vector3.setY(Number(text)) });
update();
}}
/>
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор Z"
onChange={(text) => {
store.updateForm({ vector3: store.viewModel.vector3.setZ(Number(text)) });
update();
}}
/>
<CoreText text="Координаты" type={CoreTextType.header} />
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор X"
onChange={(text) => {
store.updateForm({ vector3: store.viewModel.vector3.setX(Number(text)) });
update();
}}
/>
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор Y"
onChange={(text) => {
store.updateForm({ vector3: store.viewModel.vector3.setY(Number(text)) });
update();
}}
/>
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор Z"
onChange={(text) => {
store.updateForm({ vector3: store.viewModel.vector3.setZ(Number(text)) });
update();
}}
/>
</>
);
};

View file

@ -1,43 +0,0 @@
import * as React from "react";
import { BaseSceneItemModel, CameraViewModel, StaticAssetItemModel } from "../../model/scene_assets";
import { Button } from "antd";
export interface IStaticAssetModelViewProps {
model: BaseSceneItemModel;
onTap: Function;
}
export function StaticAssetModelView(props: IStaticAssetModelViewProps) {
if (props.model instanceof CameraViewModel) {
return (
<div
style={{
backgroundColor: "ActiveBorder",
padding: "10px",
color: "white",
textAlignLast: "center",
}}
>
{props.model.cameraLink}
<Button onClick={() => props.onTap()}>delete</Button>
</div>
);
}
if (props.model instanceof StaticAssetItemModel) {
return (
<div
style={{
backgroundColor: "brown",
padding: "10px",
color: "white",
textAlignLast: "center",
}}
>
{props.model.name}
<Button onClick={() => props.onTap()}>delete</Button>
</div>
);
}
return <></>;
}

View file

@ -1,25 +1,19 @@
import { NavigateFunction } from "react-router-dom";
import { CoreError, FormState } from "../../../../../core/store/base_store";
import { CoreButton } from "../../../../../core/ui/button/button";
import { CameraViewModel } from "../../../model/scene_assets";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
import React from "react";
import { message } from "antd";
import { CoreButton } from "../../../../../core/ui/button/button";
import { IDefaultSceneManagerFormProps, isPreviewMode } from "../scene_manager_forms";
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";
import { CameraFormStore } from "./camera_store";
import { Loader } from "../../../../../core/ui/loader/loader";
import { observer } from "mobx-react-lite";
import { CameraTypes } from "../../../../../core/model/camera_model";
class CameraFormStore extends FormState<CameraModel, CoreError> {
errorHandingStrategy = (error: CoreError) => {};
init = async (navigate?: NavigateFunction | undefined) => {};
viewModel: CameraModel = CameraModel.empty();
constructor() {
super();
}
}
export const CameraForm = (props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new CameraFormStore());
export const CameraForm = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new CameraFormStore(props.store));
React.useEffect(() => {
store.init();
@ -27,7 +21,6 @@ export const CameraForm = (props: IDefaultSceneManagerFormProps) => {
return (
<div style={{ margin: 10, padding: 10, overflowY: "auto", height: "100%" }}>
<CoreText text="Камера" type={CoreTextType.header} />
<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
@ -43,33 +36,50 @@ export const CameraForm = (props: IDefaultSceneManagerFormProps) => {
onChange={(text) => store.updateForm({ height: Number(text) })}
/>
<CoreInput
value={String(store.viewModel.width)}
value={String(store.viewModel.width)}
validation={(text) => Number().isValid(text)}
label={"Width"}
onChange={(text) => store.updateForm({ width: Number(text) })}
/>
<CoreInput
value={String(store.viewModel.fov)}
label={"Fov"}
validation={(text) => Number().isValid(text)}
onChange={(text) => (store.updateForm({ fov: Number(text) }), store.updateCameraScene())}
/>
<CoreInput
value={String(store.viewModel.far)}
label={"Far"}
validation={(text) => Number().isValid(text)}
onChange={(text) => (store.updateForm({ far: Number(text) }), store.updateCameraScene())}
/>
<CoreInput
value={String(store.viewModel.near)}
label={"Far"}
validation={(text) => Number().isValid(text)}
onChange={(text) => (store.updateForm({ near: Number(text) }), store.updateCameraScene())}
/>
<CoreSelect
items={Object.entries(CameraTypes).map(([_, v]) => v)}
value={store.viewModel.cameraType}
label={"Типы камер"}
label={"Тип камеры"}
onChange={(text) => store.updateForm({ cameraType: text as CameraTypes })}
/>
<div style={{ height: 10 }} />
<CoreButton
text="Создать"
style={{ width: 96 }}
onClick={() =>
onClick={() => {
store.viewModel.validate().fold(
(model) => {
// props.store.addNewCamera(model);
props.store.addNewCamera(model);
},
(error) => message.error(error)
)
}
);
}}
/>
<div style={{ height: 50 }} />
</div>
);
};
// onClick={props.store.addNewCamera()}
});

View file

@ -0,0 +1,35 @@
import makeAutoObservable from "mobx-store-inheritance";
import { NavigateFunction } from "react-router-dom";
import { FormState, CoreError } from "../../../../../core/store/base_store";
import { SceneMangerStore } from "../../scene_manager_store";
import { isPreviewMode } from "../scene_manager_forms";
import { CameraModel } from "../../../../../core/model/camera_model";
export class CameraFormStore extends FormState<CameraModel, CoreError> {
viewModel: CameraModel = CameraModel.empty();
sceneMangerStore: SceneMangerStore;
type?: string;
constructor(sceneMangerStore: SceneMangerStore) {
super();
makeAutoObservable(this);
this.sceneMangerStore = sceneMangerStore;
}
errorHandingStrategy = (error: CoreError) => {};
updateCameraScene = () =>
this.type?.isNotEmptyR().map(() => this.viewModel.toWebGl(this.sceneMangerStore.coreThreeRepository!));
init = async (navigate?: NavigateFunction | undefined) => {
isPreviewMode(this.sceneMangerStore.activeFormDependency).map(() =>
this.sceneMangerStore.scene
.rFind<CameraModel>((el) => el.name.isEqual(this.sceneMangerStore.selectedItemName ?? ""))
.fold(
(cameraModel) => {
this.loadDependency(cameraModel);
this.type = "preview";
},
() => console.log(`Unknown FormType`)
)
);
};
}

View file

@ -1,9 +1,9 @@
import { NavigateFunction } from "react-router-dom";
import { FormState, CoreError } from "../../../../../core/store/base_store";
import { LightViewModel } from "./light_view_model";
import { LightModel } from "../../../../../core/model/light_model";
export class LightStore extends FormState<LightViewModel, CoreError> {
viewModel: LightViewModel = LightViewModel.empty();
export class LightStore extends FormState<LightModel, CoreError> {
viewModel: LightModel = LightModel.empty();
constructor() {
super();
}

View file

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

View file

@ -9,7 +9,7 @@ import { match } from "ts-pattern";
import { SpawnPositionTypesForm } from "../../components/spawn_position_types";
export const PointForm = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new PointStore());
const [store] = React.useState(() => new PointStore(props.store));
React.useEffect(() => {
store.init();
}, [store]);
@ -17,6 +17,28 @@ export const PointForm = observer((props: IDefaultSceneManagerFormProps) => {
return (
<div>
{match(store.storeType)
.with(PointStoreType.previewPoint, () => (
<>
<CoreText text="Точка" type={CoreTextType.header} />
<CoreText text={store.viewModel.name} type={CoreTextType.medium} />
<CoreText text="Позиция" type={CoreTextType.header} />
<CoreInput
label="X"
value={String(store.viewModel.vector3.x)}
onChange={(text) => (store.updateForm({ vector3: store.viewModel.vector3.setX(Number(text)) }), store.updateWebGl())}
/>
<CoreInput
label="Y"
value={String(store.viewModel.vector3.y)}
onChange={(text) => (store.updateForm({ vector3: store.viewModel.vector3.setY(Number(text)) }),store.updateWebGl())}
/>
<CoreInput
label="Z"
value={String(store.viewModel.vector3.z)}
onChange={(text) => (store.updateForm({ vector3: store.viewModel.vector3.setZ(Number(text)) }), store.updateWebGl())}
/>
</>
))
.with(PointStoreType.initNewPoint, () => (
<>
<CoreText text="Точка" type={CoreTextType.header} />

View file

@ -1,26 +1,54 @@
import makeAutoObservable from "mobx-store-inheritance";
import { NavigateFunction } from "react-router-dom";
import { PointViewModel } from "./point_view_model";
import { PointModel } from "../../../../../core/model/point_model";
import { PointHttpRepository } from "./point_http_repository";
import { FormState, CoreError } from "../../../../../core/store/base_store";
import { SpawnPositionTypes } from "../../../../../core/model/spawn_position_types";
import { isPreviewMode } from "../scene_manager_forms";
import { SceneMangerStore } from "../../scene_manager_store";
export enum PointStoreType {
makeSceneSolidAndEditPosition = "makeSceneSolidAndEditPosition",
initNewPoint = "initNewPoint",
previewPoint = "previewPoint",
}
export class PointStore extends FormState<PointViewModel, CoreError> {
onClickNext = (pointStoreType: PointStoreType) => (this.storeType = pointStoreType);
viewModel: PointViewModel = PointViewModel.empty();
export class PointStore extends FormState<PointModel, CoreError> {
viewModel: PointModel = PointModel.empty();
cameraDeviceHttpRepository: PointHttpRepository = new PointHttpRepository();
storeType: PointStoreType = PointStoreType.initNewPoint;
spawnPositionTypes: SpawnPositionTypes;
constructor() {
sceneMangerStore: SceneMangerStore;
constructor(sceneMangerStore: SceneMangerStore) {
super();
makeAutoObservable(this);
this.sceneMangerStore = sceneMangerStore;
}
selectSpawnType = (type: SpawnPositionTypes) => {
this.spawnPositionTypes = type;
};
updateWebGl = () =>
this.storeType
.isEqualR(PointStoreType.previewPoint)
.map(() => this.sceneMangerStore.coreThreeRepository!.updateInstance(this.viewModel));
onClickNext = (pointStoreType: PointStoreType) => (this.storeType = pointStoreType);
errorHandingStrategy = (error: CoreError) => {};
init = async (navigate?: NavigateFunction | undefined) => {};
init = async (navigate?: NavigateFunction | undefined) =>
isPreviewMode(this.sceneMangerStore.activeFormDependency).map(() =>
this.sceneMangerStore.scene
.rFind<PointModel>((el) => el.name.isEqual(this.sceneMangerStore.selectedItemName ?? ""))
.fold(
(solidBodyModel) => {
this.loadDependency(solidBodyModel);
this.storeType = PointStoreType.previewPoint;
},
() =>
console.log(
`Unknown FormType ${this.sceneMangerStore.selectedItemName} : ${JSON.stringify(
this.sceneMangerStore.scene
)}`
)
)
);
}

View file

@ -1,16 +0,0 @@
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 +0,0 @@
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
export const RobotForm = (props: IDefaultSceneManagerFormProps) => {
return <div>ROBOT</div>;
};

View file

@ -0,0 +1,97 @@
import React from "react";
import { observer } from "mobx-react-lite";
import { RobotFormStore, RobotStoreType } from "./robot_form_store";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
import { CoreText, CoreTextType } from "../../../../../core/ui/text/text";
import { CoreInputNumber } from "../../../../../core/ui/inputNumber/input_number";
import { CoreInput, CoreInputType } from "../../../../../core/ui/input/input";
import { match } from "ts-pattern";
import { CoreSelect } from "../../../../../core/ui/select/select";
import { ToolTypes } from "../../../../../core/model/robot_model";
import { CoreButton } from "../../../../../core/ui/button/button";
import { SpawnPositionTypesForm } from "../../components/spawn_position_types";
import { CoordsForm } from "../../components/coords_form";
export const RobotForm = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new RobotFormStore(props.store));
React.useEffect(() => {
store.init();
}, []);
return (
<div style={{ overflowY: "scroll", height: "100%" }}>
{match(store.storeType)
.with(RobotStoreType.awaitMouseClick, () => (
<>
<CoreText type={CoreTextType.medium} text="Ожидание клика мыши" />
</>
))
.with(RobotStoreType.selectSpawnPosition, () => (
<>
<SpawnPositionTypesForm onClick={store.selectSpawnType} />
</>
))
.with(RobotStoreType.initNewRobot, () => (
<>
<CoreText text="Новый робот" type={CoreTextType.header} />
<CoreInput
type={CoreInputType.small}
value={store.viewModel.nDof.toString()}
label="Имя"
onChange={(text) => store.updateForm({ name: text })}
/>
<CoreInput
type={CoreInputType.small}
value={store.viewModel.nDof.toString()}
label="Ndof"
onChange={(text) => store.updateForm({ nDof: Number(text) })}
/>
<CoreSelect
items={Object.keys(ToolTypes)}
value={store.viewModel.toolType}
label={"ToolType"}
onChange={(text) => store.updateForm({ toolType: text })}
/>
<CoreButton onClick={() => store.createNewRobot()} text="Создать" />
</>
))
.with(RobotStoreType.previewRobot, () => (
<>
<CoordsForm store={store} update={() => store.updateScene()} />
<div style={{ height: 40 }} />
<CoreText text="Управление соединениями" type={CoreTextType.header} />
{store.viewModel.jointPosition.map((el, i) => (
<div>
<CoreInputNumber
key={i}
step={0.1}
max={Number(el.limit.upper)}
min={Number(el.limit.lower)}
value={0}
onChange={(value) => (
store.updateForm({
jointPosition: store.viewModel.jointPosition.map((element, index) =>
index.isEqualR(i).fold(
() => {
element.angel = value;
return element;
},
() => element
)
),
}),
store.updateScene()
)}
label={el.name}
/>
</div>
))}
<div style={{ height: 40 }} />
</>
))
.otherwise(() => (
<></>
))}
</div>
);
});

View file

@ -0,0 +1,10 @@
import { RobotModel } from "../../../../../core/model/robot_model";
import { HttpMethod, HttpRepository } from "../../../../../core/repository/http_repository";
export interface RobotURL {
robotUrl: string;
}
export class RobotFormHttpRepository extends HttpRepository {
createNewRobot = (robotModel: RobotModel) =>
this._jsonRequest<RobotURL>(HttpMethod.POST, "/scenes/create/robot", robotModel);
}

View file

@ -0,0 +1,86 @@
import makeAutoObservable from "mobx-store-inheritance";
import { NavigateFunction } from "react-router-dom";
import { RobotFormHttpRepository } from "./robot_form_http_repository";
import { FormState, CoreError } from "../../../../../core/store/base_store";
import { RobotModel } from "../../../../../core/model/robot_model";
import { SceneMangerStore } from "../../scene_manager_store";
import { isPreviewMode } from "../scene_manager_forms";
import { message } from "antd";
import { SceneModelsTypes } from "../../../../../core/model/scene_models_type";
import { Vector3 } from "three";
export enum RobotStoreType {
previewRobot = "previewRobot",
selectSpawnPosition = "selectSpawnPosition",
initNewRobot = "createNewRobot",
awaitMouseClick = "awaitMouseClick",
}
export class RobotFormStore extends FormState<RobotModel, CoreError> {
sceneMangerStore: SceneMangerStore;
storeType: RobotStoreType = RobotStoreType.initNewRobot;
viewModel: RobotModel = RobotModel.empty();
robotFormHttpRepository: RobotFormHttpRepository = new RobotFormHttpRepository();
spawnType: string;
listener: Function;
clickLister = (event: MouseEvent) =>
this.storeType.isEqualR(RobotStoreType.awaitMouseClick).map(() =>
this.sceneMangerStore!.clickScene(event, this.sceneMangerStore!.canvasOffsetX).map((vector3) => {
this.viewModel.vector3 = vector3;
this.viewModel.toWebGl(this.sceneMangerStore.coreThreeRepository!);
this.sceneMangerStore.activeFormType = undefined;
this.sceneMangerStore.sceneItems.push(this.viewModel.toSceneItems(this.sceneMangerStore))
this.sceneMangerStore.scene.push(this.viewModel)
window.removeEventListener("click", this.clickLister);
})
);
selectSpawnType = (type: string) => {
this.spawnType = type;
setTimeout(() => window.addEventListener("click", this.clickLister), 1000);
this.storeType = RobotStoreType.awaitMouseClick;
};
dispose = (): void => {
window.removeEventListener("click", this.clickLister);
};
constructor(sceneMangerStore: SceneMangerStore) {
super();
makeAutoObservable(this);
this.sceneMangerStore = sceneMangerStore;
}
updateScene = () =>
this.storeType
.isEqualR(RobotStoreType.previewRobot)
.map(() => this.viewModel.update(this.sceneMangerStore.coreThreeRepository!));
createNewRobot = () =>
this.viewModel.isValid().fold(
async (s) =>
(await this.robotFormHttpRepository.createNewRobot(s)).fold(
(s) => {
this.viewModel.httpUrl = s.robotUrl;
this.storeType = RobotStoreType.selectSpawnPosition;
},
(e) => {
message.error(e.error);
}
),
async (e) => message.error(e)
);
errorHandingStrategy = (error: CoreError) => {};
init = async (navigate?: NavigateFunction | undefined) =>
isPreviewMode(this.sceneMangerStore.activeFormDependency).map(() =>
this.sceneMangerStore.scene
.rFind<RobotModel>((el) => el.name.isEqual(this.sceneMangerStore.selectedItemName ?? ""))
.fold(
(solidBodyModel) => {
this.loadDependency(solidBodyModel);
this.storeType = RobotStoreType.previewRobot;
},
() =>
console.log(
`Unknown FormType ${this.sceneMangerStore.selectedItemName} : ${JSON.stringify(
this.sceneMangerStore.scene
)}`
)
)
);
}

View file

@ -1,8 +1,9 @@
import { Result } from "../../../../core/helper/result";
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 { RobotForm } from "./robot_form/robot_form";
import { SolidBodyForm } from "./solid_body/solid_body_form";
import { Trajectory } from "./trajectory/trajectory_form";
import { ZoneForm } from "./zone/zone_form";
@ -16,6 +17,7 @@ export enum SceneManagerForms {
point = "point",
trajectory = "trajectory",
zone = "zone",
capturePoints = "capturePoints",
}
interface IForms {
name: string;
@ -25,7 +27,10 @@ export interface IDefaultSceneManagerFormProps {
dependency: Object;
store: SceneMangerStore;
}
export const isPreviewMode = (dependency: Object): Result<void, void> => {
if (Object.hasOwn(dependency, "type")) return Result.ok();
return Result.error(undefined);
};
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} /> },
@ -34,4 +39,5 @@ export const sceneManagerForms = (props: Object, store: SceneMangerStore): IForm
{ 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} /> },
{ name: SceneManagerForms.capturePoints, component: <CameraForm dependency={props} store={store} /> },
];

View file

@ -6,57 +6,79 @@ 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";
import { CoreInput } from "../../../../../core/ui/input/input";
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} />
<>
{match(store.solidBodyStoreType)
.with(SolidBodyStoreType.previewSolid, () => (
<>
<CoreText text={"Твердое тело"} type={CoreTextType.header} />
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор X"
onChange={(text) => (
store.updateForm({ vector3: store.viewModel.vector3.setX(Number(text)) }),
store.updateBodySimulation()
)}
</>
))
.otherwise(() => (
<></>
))}
</>
)}
/>
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор Y"
onChange={(text) => (
store.updateForm({ vector3: store.viewModel.vector3.setY(Number(text)) }),
store.updateBodySimulation()
)}
/>
<CoreInput
value={String(store.viewModel.vector3.x)}
label="Вектор Z"
onChange={(text) => (
store.updateForm({ vector3: store.viewModel.vector3.setZ(Number(text)) }),
store.updateBodySimulation()
)}
/>
<CoreText text={"Тип твердого тела: " + store.viewModel.solidType} type={CoreTextType.header} />
</>
))
.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

@ -1,34 +1,53 @@
import makeAutoObservable from "mobx-store-inheritance";
import { SolidBodyViewModel } from "./solid_body_view_model";
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";
import { isPreviewMode } from "../scene_manager_forms";
import { SolidModel } from "../../../../../core/model/solid_model";
import { SceneModelsTypes } from "../../../../../core/model/scene_models_type";
export enum SolidBodyStoreType {
selectBody = "selectBody",
selectSpawnPositionType = "selectSpawnPositionType",
spawn2DVector = "spawn2DVector",
previewSolid = "previewSolid",
}
export class SolidBodyStore extends FormState<SolidBodyViewModel, CoreError> {
viewModel: SolidBodyViewModel = SolidBodyViewModel.empty();
export class SolidBodyStore extends FormState<SolidModel, CoreError> {
viewModel: SolidModel = SolidModel.empty();
parts: Parts[] = [];
spawnPositionTypes = Object.keys(SpawnPositionTypes);
coreHttpRepository: CoreHttpRepository = new CoreHttpRepository();
solidBodyStoreType: SolidBodyStoreType = SolidBodyStoreType.selectBody;
selectBody: Parts;
spawnType: string;
sceneManagerStore: SceneMangerStore;
sceneMangerStore: SceneMangerStore;
vector2d?: Vector2;
constructor(sceneManagerStore: SceneMangerStore) {
constructor(sceneMangerStore: SceneMangerStore) {
super();
this.sceneManagerStore = sceneManagerStore;
this.sceneMangerStore = sceneMangerStore;
makeAutoObservable(this);
}
init = async () => {
isPreviewMode(this.sceneMangerStore.activeFormDependency).map(() =>
this.sceneMangerStore.scene
.rFind<SolidModel>((el) => el.name.isEqual(this.sceneMangerStore.selectedItemName ?? ""))
.fold(
(solidBodyModel) => {
this.loadDependency(solidBodyModel);
this.solidBodyStoreType = SolidBodyStoreType.previewSolid;
},
() =>
console.log(
`Unknown FormType ${this.sceneMangerStore.selectedItemName} : ${JSON.stringify(
this.sceneMangerStore.scene
)}`
)
)
);
this.mapOk("parts", this.coreHttpRepository.getAssetsActiveProject());
};
errorHandingStrategy = (error: CoreError) => {};
@ -37,16 +56,20 @@ export class SolidBodyStore extends FormState<SolidBodyViewModel, CoreError> {
selectSpawnType = (type: string) => {
this.spawnType = type;
this.solidBodyStoreType = SolidBodyStoreType.spawn2DVector;
this.sceneManagerStore.mousePositionAwait = true;
this.sceneManagerStore.solidSpawnHelper = {
url: this.selectBody.objUrl,
this.sceneMangerStore.mousePositionAwait = true;
this.sceneMangerStore.spawnHelper = {
url: this.selectBody.daeUrl,
name: this.selectBody.name,
spawn: SceneModelsTypes.SOLID,
isFinished: false,
solidType: this.selectBody.solidType,
type: this.spawnType,
};
this.sceneManagerStore.activeFormType = undefined;
this.sceneMangerStore.activeFormType = undefined;
};
updateBodySimulation = () =>
this.solidBodyStoreType
.isEqualR(SolidBodyStoreType.previewSolid)
.map(() => this.viewModel.update(this.sceneMangerStore.coreThreeRepository!));
clickSelectBody = (el: Parts) => {
this.selectBody = el;
this.solidBodyStoreType = SolidBodyStoreType.selectSpawnPositionType;

View file

@ -1,7 +0,0 @@
export class SolidBodyViewModel {
name: string;
static empty() {
return new SolidBodyViewModel();
}
}

View file

@ -2,14 +2,34 @@ import React from "react";
import { observer } from "mobx-react-lite";
import { ZoneStore } from "./zone_store";
import { IDefaultSceneManagerFormProps } from "../scene_manager_forms";
import { CoreText, CoreTextType } from "../../../../../core/ui/text/text";
import { CoreInput } from "../../../../../core/ui/input/input";
export const ZoneForm = observer((props: IDefaultSceneManagerFormProps) => {
const [store] = React.useState(() => new ZoneStore());
const [store] = React.useState(() => new ZoneStore(props.store));
React.useEffect(() => {
store.init();
}, [store]);
return <>zone</>;
return (
<>
<CoreText text={"Зона"} type={CoreTextType.header} />
<CoreText text={store.viewModel.name} type={CoreTextType.medium} />
<CoreInput
label="Длина"
value={String(store.viewModel.length)}
onChange={(text) => (store.updateForm({ length: Number(text) }), store.updateWebGl())}
/>
<CoreInput
label="Высота"
value={String(store.viewModel.height)}
onChange={(text) => (store.updateForm({ height: Number(text) }), store.updateWebGl())}
/>
<CoreInput
label="Ширина"
value={String(store.viewModel.width)}
onChange={(text) => (store.updateForm({ width: Number(text) }), store.updateWebGl())}
/>
</>
);
});

View file

@ -1,19 +1,42 @@
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 { ZoneModel } from "../../../../../core/model/zone_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) => {
}
import { isPreviewMode } from "../scene_manager_forms";
import { SceneMangerStore } from "../../scene_manager_store";
export enum ZoneStoreType {
preview = "preview",
}
export class ZoneStore extends FormState<ZoneModel, CoreError> {
constructor(sceneMangerStore: SceneMangerStore) {
super();
this.sceneMangerStore = sceneMangerStore;
makeAutoObservable(this);
}
storeType: ZoneStoreType;
sceneMangerStore: SceneMangerStore;
viewModel: ZoneModel = ZoneModel.empty();
cameraDeviceHttpRepository: ZoneHttpRepository = new ZoneHttpRepository();
errorHandingStrategy = (error: CoreError) => {};
init = async (navigate?: NavigateFunction | undefined) => {
isPreviewMode(this.sceneMangerStore.activeFormDependency).map(() =>
this.sceneMangerStore.scene
.rFind<ZoneModel>((el) => el.name.isEqual(this.sceneMangerStore.selectedItemName ?? ""))
.fold(
(zoneModel) => {
this.loadDependency(zoneModel);
this.storeType = ZoneStoreType.preview;
},
() =>
console.log(
`Unknown FormType ${this.sceneMangerStore.selectedItemName} : ${JSON.stringify(
this.sceneMangerStore.scene
)}`
)
)
);
};
updateWebGl = () => this.storeType.isEqualR(ZoneStoreType.preview).map(() => this.sceneMangerStore.coreThreeRepository!.updateInstance(this.viewModel))
}

View file

@ -1,14 +0,0 @@
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

@ -10,6 +10,7 @@ import { CoreInput } from "../../../core/ui/input/input";
import { DrawersDataset } from "../../dataset/dataset_store";
import { Icon } from "../../../core/ui/icons/icons";
import { sceneManagerForms } from "./forms/scene_manager_forms";
import { SceneMode } from "../model/scene_view";
export const SceneManagerPath = "/scene/manager/";
@ -33,7 +34,12 @@ export const SceneManger = observer(() => {
return (
<MainPage
page={"Сцена"}
panelStyle={{ display: store.storeMode.isEqual(StoreMode.sceneInstance) ? "" : "none" }}
panelStyle={{
display: store.storeMode.isEqualR(StoreMode.sceneInstance).fold(
() => "",
() => "none"
),
}}
panelChildren={
<div style={{ width: "100%", height: "100%" }}>
<div style={{ height: 260, width: "100%", padding: 10 }}>
@ -75,6 +81,23 @@ export const SceneManger = observer(() => {
<Icon type={el.icon} />
</div>
))}
{store.isVisibleSaveButton ? (
<>
<div
onClick={() => store.sceneSave()}
style={{
marginTop: 4,
width: 50,
height: 50,
backgroundColor: "rgba(99, 81, 159, 1)",
border: "1px solid",
borderRadius: 5,
}}
>
<Icon type={SceneMode.Save} />
</div>
</>
) : null}
</div>
</div>
</div>
@ -104,7 +127,7 @@ export const SceneManger = observer(() => {
justifyContent: "space-between",
width: "100%",
}}
onClick={() => store.selectSceneItems(el.name, index, !el.isSelected)}
onClick={() => store.selectSceneItems(el.name, index, !el.isSelected, el.icon)}
>
<Icon width={13} height={13} type={el.icon} style={{ marginLeft: 10 }} />
<div style={{ width: 10 }} />
@ -112,6 +135,7 @@ export const SceneManger = observer(() => {
<Icon
type="DeleteCircle"
width={13}
isNeedStopPropagation={true}
height={13}
onClick={() => store.deleteSceneItem(el)}
style={{ marginRight: 10 }}
@ -124,19 +148,18 @@ export const SceneManger = observer(() => {
<div
style={{
width: "-webkit-fill-available",
height: "100%",
height: "60%",
borderRadius: 7,
backgroundColor: "white",
margin: 10,
overflow: "auto",
}}
>
{sceneManagerForms(store.activeFormDependency ?? {}, store).map((el, i) => {
if (el.name.isEqual(store.activeFormType ?? "")) {
return <span key={i}>{el.component}</span>;
}
return <></>;
})}
{sceneManagerForms(store.activeFormDependency ?? {}, store).map((el, i) =>
el.name.isEqualR(store.activeFormType ?? "").fold(
() => <span key={i}>{el.component}</span>,
() => <span key={i}></span>
)
)}
</div>
</div>
}

View file

@ -1,19 +1,23 @@
import makeAutoObservable from "mobx-store-inheritance";
import { Object3D, Object3DEventMap, Vector2 } from "three";
import { Object3D, Object3DEventMap, Vector2, Vector3 } from "three";
import { message } from "antd";
import { CoreThreeRepository } from "../../../core/repository/core_three_repository";
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 { SceneMode } from "../model/scene_view";
import { SceneHttpRepository } from "../data/scene_http_repository";
import { RobossemblerAssets } from "../../../core/model/robossembler_assets";
import { Instance, SceneAsset } from "../../../core/model/scene_asset";
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";
import { CameraModel } from "../../../core/model/camera_model";
import { SolidModel } from "../../../core/model/solid_model";
import { PointModel } from "../../../core/model/point_model";
import { RobotModel } from "../../../core/model/robot_model";
import { ZoneModel } from "../../../core/model/zone_model";
import { SceneModelsTypes } from "../../../core/model/scene_models_type";
import { Result } from "../../../core/helper/result";
export enum DrawersSceneManager {
NewScene = "Новая сцена",
@ -22,9 +26,9 @@ export enum StoreMode {
sceneInstance = "sceneInstance",
allScenes = "allScenes",
}
export interface ISolidSpawnHelper {
export interface ISpawnHelper {
url: string;
solidType: string;
spawn: SceneModelsTypes;
name: string;
isFinished: boolean;
type: string;
@ -33,7 +37,7 @@ interface IPopoverItem {
name: string;
fn: Function;
}
interface SceneItems {
export interface SceneItems {
fn: Function;
name: string;
isSelected: boolean;
@ -42,17 +46,15 @@ interface SceneItems {
export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpError> {
activeFormType?: string;
selectedItemName?: string;
activeFormDependency?: Object;
activeFormDependency: Object = {};
viewModel: SceneViewModel = SceneViewModel.empty();
sceneMode: SceneMode;
sceneMenu: SceneMenu;
sceneItems: SceneItems[];
sceneItems: SceneItems[] = [];
isVisibleSaveButton: boolean = false;
coreThreeRepository: null | CoreThreeRepository = null;
sceneHttpRepository: SceneHttpRepository;
sceneModels: BaseSceneItemModel[] = [];
isSceneMenuShow = false;
robossemblerAssets?: RobossemblerAssets;
robossemblerAssets?: SceneAsset;
objectForMagnetism: string;
objectMagnetism: string;
scenes: SceneModel[] = [];
@ -60,46 +62,80 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
canvasRef?: HTMLCanvasElement;
mousePositionAwait: boolean = false;
mousePosition?: Vector2;
solidSpawnHelper?: ISolidSpawnHelper;
spawnHelper?: ISpawnHelper;
selectSceneObject?: Object;
isLoadingForm: boolean = false;
scene: SolidBodyModel[] = [];
scene: (Instance | SolidModel | CameraModel | RobotModel | PointModel | ZoneModel)[] = [];
sceneHelperInstruments: { icon: string; onClick: Function; isSelected: boolean }[] = [
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) },
{ name: "Камера", fn: () => this.createNewForm(SceneManagerForms.camera, true) },
{ name: "Твердое тело", fn: () => this.createNewForm(SceneManagerForms.solidBody, true) },
{ name: "Источник света", fn: () => this.createNewForm(SceneManagerForms.light, true) },
{ name: "Робот", fn: () => this.createNewForm(SceneManagerForms.robot, true) },
{ name: "Точка", fn: () => this.createNewForm(SceneManagerForms.point, true) },
{ name: "Траектория", fn: () => this.createNewForm(SceneManagerForms.trajectory, true) },
{ name: "Зона", fn: () => this.createNewForm(SceneManagerForms.zone, true) },
{ name: "Точки захвата", fn: () => this.createNewForm(SceneManagerForms.capturePoints, true) },
];
canvasOffsetX?: number;
constructor() {
super(DrawersSceneManager);
makeAutoObservable(this);
this.sceneItems = [];
this.sceneHttpRepository = new SceneHttpRepository();
this.sceneMode = SceneMode.Select;
this.sceneMenu = SceneMenu.empty();
}
sceneSave = () => {};
selectSceneItems = (name: string, index: number, selected: boolean) => {
sceneSave = () => {
console.log(JSON.stringify(this.scene));
};
iconToSceneManagerForm = (icon: string): SceneManagerForms => {
if (icon.isEqual("Camera")) {
this.activeFormDependency = {
type: "Preview",
};
return SceneManagerForms.camera;
}
if (icon.isEqual("Zone")) {
this.activeFormDependency = {
type: "Preview",
};
return SceneManagerForms.zone;
}
if (icon.isEqual("Robot")) {
this.activeFormDependency = {
type: "Preview",
};
return SceneManagerForms.robot;
}
if (icon.isEqual("Point")) {
this.activeFormDependency = {
type: "Preview",
};
return SceneManagerForms.point;
}
this.activeFormDependency = {
type: "Preview",
};
return SceneManagerForms.solidBody;
};
selectSceneItems = (name: string, index: number, selected: boolean, icon: string) => {
this.sceneItems.map((el) => {
el.isSelected = false;
return el;
});
this.sceneItems.map((el, i) => i.isEqualR(index).map(() => (el.isSelected = selected)));
if (selected) {
this.createNewForm(SceneManagerForms.solidBody);
this.createNewForm(this.iconToSceneManagerForm(icon));
this.selectedItemName = name;
}
@ -107,28 +143,21 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
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;
}
el.icon.isEqualR(mode).map(() => (el.isSelected = true));
return el;
});
this.sceneMode = mode;
this.coreThreeRepository?.setTransformMode(this.sceneMode);
this.sceneModeWatcher();
};
createNewForm = (formType: SceneManagerForms | undefined) => {
this.activeFormDependency = {
store: this,
};
createNewForm = (formType: SceneManagerForms | undefined, isNeedClearDependency?: boolean) => {
this.activeFormDependency = Object.assign(this.activeFormDependency, { store: this });
if (isNeedClearDependency) this.activeFormDependency = { store: this };
this.activeFormType = formType;
};
createNewScene = () =>
@ -143,7 +172,8 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
deleteSceneItem = (item: SceneItems) => {
this.sceneItems = this.sceneItems.filter((el) => !el.name.isEqual(item.name));
this.coreThreeRepository?.deleteSceneItem(item.name);
this.coreThreeRepository?.deleteSceneItem(item);
this.visibleSaveButton();
};
@ -151,48 +181,26 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
this.isVisibleSaveButton = true;
};
addNewCamera = (model: CameraViewModel) => {
model.position = this.coreThreeRepository!.camera.position;
model.quaternion = this.coreThreeRepository!.camera.quaternion;
this.sceneItems.push({ name: model.cameraLink, icon: "Camera", fn: () => {}, isSelected: false });
addNewCamera = (model: CameraModel) => {
model.vector3 = this.coreThreeRepository!.camera.position;
// model.quaternion = this.coreThreeRepository!.camera.quaternion;
this.sceneItems.push({ name: model.name, icon: "Camera", fn: () => {}, isSelected: false });
this.scene.push(model);
this.coreThreeRepository?.addSceneCamera(model);
this.visibleSaveButton();
};
getCameraLinkNames = (): string[] => {
return this.sceneModels.map((el) => {
if (el instanceof CameraViewModel) {
return el.cameraLink;
}
return "";
});
};
loaderWatcher = () => {};
loadSceneRobossemblerAsset = (name: string) => {
try {
const assetPath = this.robossemblerAssets?.getAssetPath(name) as string;
this.coreThreeRepository?.loader(assetPath, this.loaderWatcher, name);
this.visibleSaveButton();
// this.coreThreeRepository?.loader(assetPath, this.loaderWatcher, name);
// this.visibleSaveButton();
} catch (error) {
message.error(String(error));
}
};
isRenderedAsset(name: string): boolean {
return this.sceneModels
.filter((el) => {
if (el instanceof StaticAssetItemModel) {
return el.name === name;
}
return false;
})
.isNotEmpty();
}
hiddenMenu = () => (this.isSceneMenuShow = false);
sceneModeWatcher() {}
@ -207,9 +215,7 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
}
};
errorHandingStrategy = (error: HttpError) =>
error.status
.isEqualR(404)
.map(() => this.errors.push(new UiBaseError(`${RobossemblerFiles.robossemblerAssets} not found to project`)));
error.status.isEqualR(404).map(() => this.errors.push(new UiBaseError(`not found to project`)));
loadScene = (canvasRef: HTMLCanvasElement) => {
this.canvasRef = canvasRef;
@ -222,36 +228,52 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
loadWebGl(canvasRef: HTMLCanvasElement): void {
this.coreThreeRepository = new CoreThreeRepository(canvasRef as HTMLCanvasElement, this.watcherSceneEditorObject);
this.coreThreeRepository.on(this.watcherThereObjects);
this.coreThreeRepository.render();
this.sceneModels = this.coreThreeRepository.getAllSceneModels();
this.coreThreeRepository.render();
this.canvasOffsetX = canvasRef.getBoundingClientRect().x;
canvasRef.addEventListener("click", (event) => this.clickLister(event, canvasRef.getBoundingClientRect().x));
canvasRef.addEventListener("mousedown", (e) => this.sceneContextMenu(e));
const sceneAssets = this.sceneHttpRepository.getScene();
this.coreThreeRepository?.loadScene(sceneAssets);
this.sceneItems = sceneAssets.scene.map((el) => {
return {
fn: () => {},
name: el.name,
icon: el.icon,
isSelected: false,
};
});
this.scene = sceneAssets.scene;
}
clickScene = (event: MouseEvent, offset: number = 0): Result<void, Vector3> => {
const vector = new Vector2();
const boundingRect = this.canvasRef!.getBoundingClientRect();
vector.x = ((event.clientX - offset) / boundingRect.width) * 2 - 1;
vector.y = -(event.clientY / boundingRect.height) * 2 + 1;
return this.coreThreeRepository!.setRayCastAndGetFirstObjectAndPointToObject(vector);
};
clickLister = (event: MouseEvent, offset: number = 0) => {
const vector = new Vector2();
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) {
if (this.mousePositionAwait && this.spawnHelper) {
this.mousePositionAwait = false;
this.mousePosition = vector;
this.coreThreeRepository?.setRayCastAndGetFirstObjectAndPointToObject(vector).map((v3) => {
this.coreThreeRepository?.solidSpawn(
this.solidSpawnHelper as ISolidSpawnHelper,
this.spawnHelper as ISpawnHelper,
(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),
name: String(this.spawnHelper?.name),
icon: "Solid",
isSelected: false,
fn: () => this.createNewForm(SceneManagerForms.solidBody),
});
this.visibleSaveButton();
},
v3
);
@ -261,38 +283,27 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
return;
}
if (this.sceneMode === SceneMode.Move || this.sceneMode === SceneMode.Rotate) {
if (this.sceneMode.isEqualMany([SceneMode.Move, SceneMode.Rotate])) {
this.transformContollsCall(vector);
}
};
sceneContextMenu = (e: MouseEvent) =>
e.button.isEqualR(2).map(() => {
this.isSceneMenuShow = true;
this.sceneMenu.x = e.clientX;
this.sceneMenu.y = e.clientY;
});
watcherThereObjects = (sceneItemModel: BaseSceneItemModel) => {
// this.sceneModels.push(sceneItemModel);
console.log(sceneItemModel);
};
watcherSceneEditorObject = (mesh: Object3D) => {
this.scene = this.scene.map((el) =>
watcherSceneEditorObject = (mesh: Object3D) => (
(this.scene = this.scene.map((el) =>
el.name.isEqualR(mesh.name).fold(
() => {
el.vector3 = mesh.position;
el.quaternion = mesh.quaternion;
el.quaternion = mesh.quaternion.toArray();
return el;
},
() => el
)
);
this.visibleSaveButton();
};
)),
this.visibleSaveButton()
);
transformContollsCall = (vector: Vector2) =>
// @ts-ignore
this.coreThreeRepository?.setRayCastAndGetFirstObject(vector).fold(
(object) => this.coreThreeRepository?.setTransformControlsAttach(object),
(_) => this.coreThreeRepository?.disposeTransformControlsMode()
@ -300,6 +311,5 @@ export class SceneMangerStore extends UiDrawerFormState<SceneViewModel, HttpErro
dispose = () => {
window.removeEventListener("click", this.clickLister);
window.removeEventListener("mousedown", (e) => this.sceneContextMenu(e));
};
}

View file

@ -5,11 +5,11 @@ import { extensions } from "./core/extensions/extensions";
import { SocketLister } from "./features/socket_lister/socket_lister";
import { RouterProvider } from "react-router-dom";
import { router } from "./core/routers/routers";
import { configure } from "mobx"
import { configure } from "mobx";
configure({
enforceActions: "never",
})
enforceActions: "never",
});
extensions();
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);

View file

@ -8,6 +8,7 @@
27.04.2024 @shalenikol release 0.1
"""
import argparse
from train_Yolo import train_YoloV8
from train_Dope import train_Dope_i

26
web_p/robot_builder.py Normal file
View file

@ -0,0 +1,26 @@
import shutil
import argparse
import os.path
parser = argparse.ArgumentParser()
parser.add_argument("--path")
parser.add_argument("--nDOF")
parser.add_argument("--toolType")
parser.add_argument("--name")
args = parser.parse_args()
2
def copy_and_move_folder(src, dst):
try:
if os.path.exists(dst):
shutil.rmtree(dst)
shutil.copytree(src, dst)
print(f"Folder {src} successfully copied")
except shutil.Error as e:
print(f"Error: {e}")
source_folder = os.path.dirname(os.path.abspath(__file__)) + "/robot_builder/"
copy_and_move_folder(source_folder, args.path + args.name)

View file

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

File diff suppressed because one or more lines are too long

View file

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

File diff suppressed because one or more lines are too long

View file

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

File diff suppressed because one or more lines are too long

View file

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

File diff suppressed because one or more lines are too long

View file

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

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because one or more lines are too long

View file

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

File diff suppressed because one or more lines are too long