there repository

This commit is contained in:
IDONTSUDO 2023-12-10 21:44:41 +03:00
parent 71cd1061cb
commit 5d0e5f7f1c
10 changed files with 257 additions and 2 deletions

View file

@ -74,6 +74,7 @@ export class App {
this.app.use("/", route.router);
});
}
async loadAppDependencies() {
await new DataBaseConnectUseCase().call();
await new CheckAndCreateStaticFilesFolderUseCase().call();

View file

@ -26,6 +26,7 @@
"react-scripts": "5.0.1",
"sass": "^1.66.1",
"socket.io-client": "^4.7.2",
"three": "^0.159.0",
"typescript": "^4.9.5",
"uuid": "^9.0.0",
"web-vitals": "^2.1.4"

View file

@ -45,4 +45,10 @@ export const ArrayExtensions = () => {
return this.length !== 0;
};
}
if ([].hasIncludeElement === undefined) {
// eslint-disable-next-line no-extend-native
Array.prototype.hasIncludeElement = function (element) {
return this.indexOf(element) !== -1;
};
}
};

View file

@ -1,19 +1,27 @@
import { ArrayExtensions } from "./array";
import { MapExtensions } from "./map";
import { StringExtensions } from "./string";
export type CallBackFunction = <T>(value: T) => void;
declare global {
interface Array<T> {
// @strict: The parameter is determined whether the arrays must be exactly the same in content and order of this relationship or simply follow the same requirements.
equals(array: Array<T>, strict: boolean): boolean;
lastElement(): T | undefined;
isEmpty(): boolean;
isNotEmpty():boolean;
isNotEmpty(): boolean;
hasIncludeElement(element: T): boolean;
}
interface String {
isEmpty(): boolean;
}
interface Map<K, V> {
addValueOrMakeCallback(key: K, value: V, callBack: CallBackFunction): void;
}
}
export const extensions = () => {
ArrayExtensions();
StringExtensions();
MapExtensions();
};

View file

@ -0,0 +1,15 @@
export const MapExtensions = () => {
if (Map.prototype.addValueOrMakeCallback === undefined) {
// eslint-disable-next-line no-extend-native
Map.prototype.addValueOrMakeCallback = function (key, value, fn) {
if (this.has(key)) {
this.set(key, value);
fn(this);
return;
} else {
this.set(key, value);
}
};
}
};
Object();

View file

@ -0,0 +1,26 @@
import React from "react";
export const useKeyLister = (fn: Function) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
const pressed = new Map();
const registerKeyPress = React.useCallback(
(event: KeyboardEvent, codes: string[], callBack: Function) => {
if (codes.hasIncludeElement(event.code)) {
pressed.addValueOrMakeCallback(event.code, event.type, (e) => {
if (Array.from(pressed.values()).equals(["keydown", "keydown"], false)) {
callBack();
}
});
}
},
[pressed]
);
React.useEffect(() => {
window.addEventListener("keyup", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => fn));
window.addEventListener("keydown", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => {}));
}, [fn, registerKeyPress]);
return [];
};

View file

@ -0,0 +1,144 @@
import {
DirectionalLight,
Object3D,
PerspectiveCamera,
Scene,
WebGLRenderer,
AmbientLight,
Vector3,
MeshBasicMaterial,
Mesh,
BoxGeometry,
Object3DEventMap,
Box3,
Sphere,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
export class CoreThereRepository {
scene = new Scene();
camera: PerspectiveCamera;
webGlRender: WebGLRenderer;
htmlCanvasRef: HTMLCanvasElement;
constructor(htmlCanvasRef: HTMLCanvasElement) {
const renderer = new WebGLRenderer({
canvas: htmlCanvasRef as HTMLCanvasElement,
antialias: true,
alpha: true,
});
const aspectCamera = window.outerWidth / window.outerHeight;
this.camera = new PerspectiveCamera(800, aspectCamera, 0.1, 10000);
this.webGlRender = renderer;
this.htmlCanvasRef = htmlCanvasRef;
this.init();
}
addCube(num: number, translateTo: string = "X") {
const geometry = new BoxGeometry(1, 1, 1);
const material = new MeshBasicMaterial({ color: 0x00ff00 });
const cube = new Mesh(geometry, material);
cube.name = "Cube" + String(num);
// cube.translateX(position.x);
// cube.translateY(position.y);
// cube.translateZ(position.z);
eval(`cube.translate${translateTo}(${num * 10})`);
this.scene.add(cube);
}
init() {
const directionalLight = new DirectionalLight(0xffffff, 0.2);
directionalLight.castShadow = true;
directionalLight.position.set(-1, 2, 4);
this.scene.add(directionalLight);
const ambientLight = new AmbientLight(0xffffff, 0.7);
this.scene.add(ambientLight);
this.addCube(1);
this.addCube(2);
this.addCube(3);
this.addCube(4);
const onResize = () => {
this.camera.aspect = window.outerWidth / window.outerHeight;
this.camera.updateProjectionMatrix();
this.webGlRender.setSize(window.outerWidth, window.outerHeight);
};
window.addEventListener("resize", onResize, false);
new OrbitControls(this.camera, this.htmlCanvasRef);
}
render() {
this.webGlRender.setSize(window.outerWidth, window.outerHeight);
this.webGlRender.setAnimationLoop(() => {
this.webGlRender.render(this.scene, this.camera);
});
}
getAllSceneNameModels(): string[] {
return this.scene.children.filter((el) => el.name !== "").map((el) => el.name);
}
getObjectsAtName(name: string): Object3D<Object3DEventMap> {
return this.scene.children.filter((el) => el.name === name)[0];
}
fitCameraToCenteredObject(objects: string[], offset = 4) {
// https://wejn.org/2020/12/cracking-the-threejs-object-fitting-nut/
const boundingBox = new Box3().setFromPoints(
objects.map((el) => this.getObjectsAtName(el)).map((el) => el.position)
);
var size = new Vector3();
boundingBox.getSize(size);
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 cameraZ = Math.max(dx, dy);
if (offset !== undefined && offset !== 0) cameraZ *= offset;
this.camera.position.set(0, 0, cameraZ);
const minZ = boundingBox.min.z;
const cameraToFarEdge = minZ < 0 ? -minZ + cameraZ : cameraZ - minZ;
this.camera.far = cameraToFarEdge * 3;
this.camera.updateProjectionMatrix();
let orbitControls = new OrbitControls(this.camera, this.htmlCanvasRef);
orbitControls.maxDistance = cameraToFarEdge * 2;
new OrbitControls(this.camera, this.htmlCanvasRef);
}
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 vFoV = this.camera.getEffectiveFOV();
let hFoV = this.camera.fov * this.camera.aspect;
let FoV = Math.min(vFoV, hFoV);
let FoV2 = FoV / 2;
let dir = new Vector3();
this.camera.getWorldDirection(dir);
let bsWorld = boundSphere.center.clone();
let th = (FoV2 * Math.PI) / 180.0;
let sina = Math.sin(th);
let R = boundSphere.radius;
let FL = R / sina;
let cameraDir = new Vector3();
let cameraOffs = cameraDir.clone();
console.log(cameraOffs);
cameraOffs.multiplyScalar(-FL);
console.log(-FL);
let newCameraPos = bsWorld.clone().add(cameraOffs);
console.log(newCameraPos);
this.camera.translateX(newCameraPos.x);
this.camera.translateY(newCameraPos.y);
this.camera.translateZ(newCameraPos.z);
this.camera.lookAt(bsWorld);
new OrbitControls(this.camera, this.htmlCanvasRef);
}
}

View file

@ -0,0 +1,43 @@
import * as React from "react";
import { CoreThereRepository } from "../../core/repository/core_there_repository";
const useKeyLister = (fn: Function) => {
const pressed = new Map();
const registerKeyPress = React.useCallback(
(event: KeyboardEvent, codes: string[], callBack: Function) => {
if (codes.hasIncludeElement(event.code)) {
pressed.addValueOrMakeCallback(event.code, event.type, (e) => {
if (Array.from(pressed.values()).equals(["keydown", "keydown"], false)) {
callBack();
}
});
}
},
[pressed]
);
React.useEffect(() => {
window.addEventListener("keyup", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => fn));
window.addEventListener("keydown", (e) => registerKeyPress(e, ["KeyQ", "KeyW"], () => {}));
}, [fn, registerKeyPress]);
return [];
};
export function SceneManger() {
const canvasRef = React.useRef<HTMLCanvasElement>(null);
let thereRepository: null | CoreThereRepository = null;
React.useEffect(() => {
// eslint-disable-next-line react-hooks/exhaustive-deps
thereRepository = new CoreThereRepository(canvasRef.current as HTMLCanvasElement);
thereRepository.render();
// thereRepository.fitSelectedObjectToScreen(thereRepository.getAllSceneNameModels());
thereRepository.fitCameraToCenteredObject(thereRepository.getAllSceneNameModels());
});
return (
<div>
<canvas ref={canvasRef} />
</div>
);
}

9
ui/src/index.test.tsx Normal file
View file

@ -0,0 +1,9 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { SceneManger } from "./features/scene_manager/scene_manager";
test("Content contains var image", () => {
render(<SceneManger />);
const car = screen;
expect(car).toBeInTheDocument();
});

View file

@ -7,6 +7,7 @@ import { RouterProvider } from "react-router-dom";
import { router } from "./core/routers/routers";
import { SocketLister } from "./features/socket_lister/socket_lister";
import { extensions } from "./core/extensions/extensions";
import { SceneManger } from "./features/scene_manager/scene_manager";
extensions();
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
@ -14,7 +15,8 @@ const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
root.render(
<>
<SocketLister>
<RouterProvider router={router} />
{/* <RouterProvider router={router} /> */}
<SceneManger />
</SocketLister>
</>
);