import { Color3 } from "@babylonjs/core";
import { LayersModel } from "@tensorflow/tfjs-layers";
import { ProgressionExerciseStatement } from "./progression-exercise-statement";
import { CabriIntegration } from "./cabri-integration";
import { CabriDataService } from "../services/cabri-data.service";
import { GlobalService } from "../services/global.service";
import { NgZone, Renderer2 } from "@angular/core";
import { SolidesPage } from "../page/solides/solides.page";
import { RemoteCommandSolides } from "../services/remote.service";
import { AppUtils } from "../app-utils";
import { ExerciseType, SolideSubjects } from "./exercices-solides";
import { AwardsType } from "./enums/awards";
import { AbstractMesh, Camera, Mesh, Nullable, PickingInfo, Plane, Quaternion, Ray, Space, SubMesh, Vector3 } from "babylon4.1";
import * as BABYLON from "babylon4.1";
import { exit } from "process";
declare var window: {
store: any;
document: any;
innerWidth: any;
innerHeight: any;
outerWidth: any;
outerHeight: any;
dispatchEvent: any;
Globals: any;
createCustomTube: any;
};
//declare var BABYLON ;
export class CabriIntegrationSolides extends CabriIntegration {
markVerticesDone: boolean;
markEdgesDone: boolean;
markFacetsDone: boolean;
patronDone = false;
divider = 0;
currentFPS: any;
grad1: any;
grad2: any;
grad3: any;
nbGradients: number;
numbersTextures = {};
isRenderForcedOn: boolean;
verticesDone = [];
constructor(
public cabriService: CabriDataService,
public globalService: GlobalService,
public _ngZone: NgZone,
public page: SolidesPage,
public renderer: Renderer2
) {
super(cabriService, globalService, _ngZone, page, renderer);
this.cabriRenderStarted = false;
this.page = page;
window.createCustomTube = this.createCustomTube.bind(this);
}
public pickWithBoundingInfo(
x: number,
y: number,
predicate?: (mesh: AbstractMesh) => boolean,
camera?: Nullable<Camera>
): Nullable<PickingInfo> {
const ray = Ray.Zero();
const nullPickInfo = new PickingInfo();
nullPickInfo.ray = ray;
let lastPickInfo: PickingInfo = null;
for (let meshIndex = 0; meshIndex < this.scene.meshes.length; meshIndex++) {
const mesh = this.scene.meshes[meshIndex];
//exclude all mesh who don't follow predicate rule
if (predicate) {
if (!predicate(mesh)) {
continue;
}
}
//exclude hidden not pickable or occlude mesh
if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable || mesh.isOccluded) {
continue;
}
//console.error(mesh);
const world = mesh.computeWorldMatrix(true);
//create a ray from camera
this.scene.createPickingRayToRef(x, y, world, ray, camera);
if ((mesh.metadata !== "facets" || this.markFacets) && ray.intersectsBox(mesh.getBoundingInfo().boundingBox, 0)) {
//for each mesh candidate see if her boundingbox intersect and create pickinginfo with distance(ray/interceptionPoint) and submesh result
//console.error("intersected", mesh);
let currentPickInfo = new PickingInfo();
currentPickInfo.hit = true;
currentPickInfo.pickedMesh = mesh;
let intersectionPoint = this.intersection(mesh.getBoundingInfo().boundingBox,ray);
// intersection is by default on localspace up to worldspace
intersectionPoint = BABYLON.Vector3.TransformCoordinates(intersectionPoint, world);
/*let sss = BABYLON.MeshBuilder.CreateSphere("grut", { diameter: 0.3 }, this.scene);
sss.position = intersectionPoint;
sss.layerMask = 0x10000000;
var mat1 = new BABYLON.StandardMaterial('mat1', this.scene);
mat1.diffuseColor = new BABYLON.Color3(0, 1, 0);
sss.material= mat1;
sss.renderingGroupId=1;*/
currentPickInfo.distance = Vector3.Distance(BABYLON.Vector3.TransformCoordinates(ray.origin, world), intersectionPoint);
//console.error("intersectedDistance ", currentPickInfo.distance);
if (mesh.subMeshes.length > 1) {
//search submesh who intersect with the lower distance and return her face id
let subMeshIndex = { index: 0, range: null };
for (let subMeshesIndex = 0; subMeshesIndex < mesh.subMeshes.length; subMeshesIndex++) {
const subMesh = mesh.subMeshes[subMeshesIndex];
if (ray.intersectsBox(subMesh.getBoundingInfo().boundingBox, 0)) {
let intersectionPointSm = this.intersection(subMesh.getBoundingInfo().boundingBox,ray);
intersectionPointSm = BABYLON.Vector3.TransformCoordinates(intersectionPointSm, world);
let currentSMRange = Vector3.Distance(BABYLON.Vector3.TransformCoordinates(ray.origin, world), intersectionPointSm);
if (!subMeshIndex.range || currentSMRange < subMeshIndex.range) {
subMeshIndex.index = subMeshesIndex;
subMeshIndex.range = currentSMRange;
}
}
}
currentPickInfo.subMeshId = subMeshIndex.index;
} else {
currentPickInfo.subMeshId = 0;
}
currentPickInfo.ray = ray;
if (!lastPickInfo || currentPickInfo.distance < lastPickInfo.distance) {
// search the closest range replace when a new candidate with lower distance is detected
lastPickInfo = currentPickInfo;
}
} else if (mesh.metadata === "facets" && !this.markFacets) {
// for facets boundingbox are badly generated use default picker not based on boundingbox
// the purpose it's to separate occlude part bt facet when we pick vertice or edges
let currentPickInfo = ray.intersectsMesh(mesh, false);
if (currentPickInfo.pickedMesh){
// pinckInfo is by default on localspace up to worldspace
currentPickInfo.pickedPoint= BABYLON.Vector3.TransformCoordinates(currentPickInfo.pickedPoint, world);
currentPickInfo.distance = Vector3.Distance(BABYLON.Vector3.TransformCoordinates(ray.origin, world), currentPickInfo.pickedPoint);
}
if (
(!lastPickInfo && currentPickInfo.pickedMesh) ||
(currentPickInfo.pickedMesh && currentPickInfo.distance < lastPickInfo.distance)
) {
/*
console.error("intersected", mesh);
console.error("intersectedDistance ", currentPickInfo.distance);
let sss = BABYLON.MeshBuilder.CreateSphere("grut", { diameter: 0.3 }, this.scene);
sss.position = currentPickInfo.pickedPoint;
var mat1 = new BABYLON.StandardMaterial('mat1', this.scene);
mat1.diffuseColor = new BABYLON.Color3(1, 0, 0);
sss.material= mat1;
sss.layerMask = 0x10000000;
sss.renderingGroupId=1;*/
lastPickInfo = currentPickInfo;
}
} else {
continue;
}
}
return lastPickInfo ? lastPickInfo : nullPickInfo;
}
intersection(boudindBox: BABYLON.BoundingBox, ray: BABYLON.Ray) {
var d = distance(ray, boudindBox);
let out : Vector3;
if (d === Infinity) {
out = null
} else {
out = new BABYLON.Vector3();
out.x = ray.origin.x +ray.direction.x * d;
out.y = ray.origin.y +ray.direction.y * d;
out.z = ray.origin.z +ray.direction.z * d;
}
return out
function distance (ray: BABYLON.Ray, boudindBox: BABYLON.BoundingBox) {
var lo = -Infinity
var hi = +Infinity
var dimLo = (boudindBox.minimum.x - ray.origin.x) / ray.direction.x;
var dimHi = (boudindBox.maximum.x - ray.origin.x) / ray.direction.x;
if (dimLo > dimHi) {
var tmp = dimLo
dimLo = dimHi
dimHi = tmp
}
if (dimHi < lo || dimLo > hi) {
return Infinity
}
if (dimLo > lo) lo = dimLo
if (dimHi < hi) hi = dimHi
var dimLo = (boudindBox.minimum.y - ray.origin.y) / ray.direction.y;
var dimHi = (boudindBox.maximum.y - ray.origin.y) / ray.direction.y;
if (dimLo > dimHi) {
var tmp = dimLo
dimLo = dimHi
dimHi = tmp
}
if (dimHi < lo || dimLo > hi) {
return Infinity
}
if (dimLo > lo) lo = dimLo
if (dimHi < hi) hi = dimHi
var dimLo = (boudindBox.minimum.z - ray.origin.z) / ray.direction.z;
var dimHi = (boudindBox.maximum.z - ray.origin.z) / ray.direction.z;
if (dimLo > dimHi) {
var tmp = dimLo
dimLo = dimHi
dimHi = tmp
}
if (dimHi < lo || dimLo > hi) {
return Infinity
}
if (dimLo > lo) lo = dimLo
if (dimHi < hi) hi = dimHi
return lo > hi ? Infinity : lo
}
}
createCustomTube(a: Vector3, b: Vector3, name: string, v: any) {
//if patron default CreateCustom tube
if (this.patron) {
return v.CreateTube(name, {
path: [a, b],
radius: 0.05,
tesselation: 8,
updatable: !0
});
} else {
//we use corrected boundingbox for edges and vertices
if (!this.verticesDone[JSON.stringify([b, a])]) {
const initialPath = new BABYLON.Vector3(a.x, a.y, a.z + BABYLON.Vector3.Distance(a, b));
const tube = v.CreateTube(name, {
path: [a, initialPath],
radius: 0.05,
updatable: !0
}) as Mesh;
var minimum = tube.getBoundingInfo().boundingBox.minimum.clone();
var maximum = tube.getBoundingInfo().boundingBox.maximum.clone();
const ratio = 0.2;
const ratio2 = -0.3;
var scaling = BABYLON.Matrix.Translation(-ratio, -ratio, -ratio2);
var scaling2 = BABYLON.Matrix.Translation(ratio, ratio, ratio2);
minimum = BABYLON.Vector3.TransformCoordinates(minimum, scaling);
maximum = BABYLON.Vector3.TransformCoordinates(maximum, scaling2);
tube.setBoundingInfo(new BABYLON.BoundingInfo(minimum, maximum));
tube.computeWorldMatrix(true);
//tube.showBoundingBox = true;
tube.setPivotPoint(a, BABYLON.Space.WORLD);
//calculate normal
const normal = BABYLON.Vector3.Cross(initialPath.subtract(a), b.subtract(a)).normalize();
const angle = BABYLON.Vector3.GetAngleBetweenVectors(initialPath.subtract(a), b.subtract(a), normal);
tube.rotate(normal, angle, BABYLON.Space.WORLD);
this.verticesDone[JSON.stringify([a, b])] = tube;
// tube.lookAt(b);
return tube;
} else {
return this.verticesDone[JSON.stringify([b, a])];
}
}
}
facetColoredCounter = 0;
edgeColoredCounter = 0;
verticeColoredCounter = 0;
public mathiaMesh;
public currentMeshId;
private rotationAngle = 0.02;
private rLeft = false;
private rRight = false;
private rUp = false;
private rDown = false;
private cabriEventsOff = false;
private saveEvents = { onPointerDown: null, onPointerUp: null, onPointerMove: null, onTouchMove: null };
private previousMouseMoveEvt;
public markFacets = false;
public colorSolid = false;
public markVertices = false;
public markEdges = false;
public patron = false;
public representation = false;
public _zoomToRadius: number;
public zoomToRadiusOptions = {
step: "1",
min: "125",
max: "185"
};
async onBabylonReady() {
await super.onBabylonReady();
//
// Gestion des pointers events pour remoteControl
//
if (this.page.remoteControl && !this.cabriService.mirrorMode && !window.store.getters.cps._pointerEventWithInfo) {
window.store.getters.cps._pointerEventWithInfo = window.store.getters.cps.pointerEventWithInfo;
window.store.getters.cps.mathia = this;
window.store.getters.cps.pointerEventWithInfo = function (x, y, z, element, n) {
element.pos = Object.keys(window.store.getters.cabri.SceneUpdate.CabriObjects).findIndex(
(id: any) => Number(id) === element.pickedObjectId
);
this.mathia.page.sendEvent(RemoteCommandSolides.patronPositionsParam, { type: "pewi", x, y, z, element, n });
this._pointerEventWithInfo(x, y, z, element, n);
};
window.store.getters.cps._pointerDown = window.store.getters.cps.pointerDown;
window.store.getters.cps.pointerDown = function (x, y, element, a) {
if (element) {
element.pos = Object.keys(window.store.getters.cabri.SceneUpdate.CabriObjects).findIndex(
(id: any) => Number(id) === element.id
);
}
this.mathia.page.sendEvent(RemoteCommandSolides.patronPositionsParam, { type: "down", x, y, element, a });
this._pointerDown(x, y, element, a);
};
window.store.getters.cps._pointerUp = window.store.getters.cps.pointerUp;
window.store.getters.cps.pointerUp = function (x, y, element, a) {
if (element) {
element.pos = Object.keys(window.store.getters.cabri.SceneUpdate.CabriObjects).findIndex(
(id: any) => Number(id) === element.id
);
}
this.mathia.page.sendEvent(RemoteCommandSolides.patronPositionsParam, { type: "up", x, y, element, a });
this._pointerUp(x, y, element, a);
};
}
this.removeCabriMouseEvents();
//
// Check patron finished + update remote
//
this.scene.onPointerUp = (evt, pickResult) => {
if (this.patron) {
if (this.page.remoteControl) {
setTimeout(() => {
const patronPositions = this.getPatronMeshesPositions();
this.page.sendEvent(RemoteCommandSolides.patronPositions, patronPositions);
}, 1000);
}
this.checkPatronOK();
}
this.stop();
};
//
// Gestion des clicks
//
this.scene.onPointerDown = (evt, pickResult) => {
let pickResult2;
// console.error("onPointerDown", this.scene.pointerX, this.scene._engine._gl.canvas.clientHeight - this.scene.pointerY);
const noMarked = !this.markEdges && !this.markVertices && !this.markFacets;
if (!noMarked) {
let pointerY = this.scene.pointerY;
if (this.cabriService.mirrorMode) {
//mirror pointer y is reversed
pointerY = (this.scene as any)._engine._gl.canvas.clientHeight - this.scene.pointerY;
}
if (this.markFacets) {
//facet basic pick work well
pickResult2 = this.scene.pick(
this.scene.pointerX,
pointerY,
mesh => {
return this.markFacets && mesh.metadata === "facets";
},
false,
this.camera
);
} else {
//vertices and edges use boundingbox with bigger size
pickResult2 = this.pickWithBoundingInfo(
this.scene.pointerX,
pointerY,
mesh => {
//edges and facets to avoid picking invisible part same for vertices
return (
(this.markEdges && (mesh.metadata === "edges" || mesh.metadata === "facets")) ||
(this.markVertices && (mesh.metadata === "vertices" || mesh.metadata === "facets")) ||
(this.markFacets && mesh.metadata === "facets")
);
},
this.camera
);
}
console.error("pickResult2 = ", pickResult2);
if (pickResult2.hit) {
// submesh picked
this.meshPicked(pickResult2.pickedMesh, pickResult2.subMeshId);
}
}
};
//
// Gestion des rotations
//
this.scene.onPointerMove = evt => {
// console.error(evt);
if (evt.buttons > 0) {
if (this.previousMouseMoveEvt) {
const deltaX = evt.x - this.previousMouseMoveEvt.x;
const deltaY = evt.y - this.previousMouseMoveEvt.y;
// console.error("deltas", deltaX, deltaY);
// console.error("event", evt);
// if (deltaX === 0) {
// this.rLeft = this.rRight = false;
// }
// if (deltaY === 0) {
// this.rUp = this.rDown = false;
// }
if (deltaX < -5) {
this.rotateMeshesLeft(this.getMeshTorotate(), 4);
this.previousMouseMoveEvt = evt;
}
if (deltaX > 5) {
this.rotateMeshesRight(this.getMeshTorotate(), 4);
this.previousMouseMoveEvt = evt;
}
if (deltaY < -5) {
this.rotateMeshesUp(this.getMeshTorotate(), 4);
this.previousMouseMoveEvt = evt;
}
if (deltaY > 5) {
this.rotateMeshesDown(this.getMeshTorotate(), 4);
this.previousMouseMoveEvt = evt;
}
} else {
this.previousMouseMoveEvt = evt;
}
if (this.patron) {
this.page.sendEvent(RemoteCommandSolides.camera, { alpha: this.camera.alpha, beta: this.camera.beta });
}
}
};
this.scene.registerAfterRender(this.afterRenderFunk);
// gradient for dynamic materials
this.grad1 = [
{ percent: 0.1007, r: 1, g: 0.48, b: 0 },
{ percent: 0.4655, r: 1, g: 0.76, b: 0 },
{ percent: 0.8161, r: 0.98, g: 1, b: 0.09 }
];
this.grad2 = [
{ percent: 0, r: 1, g: 0.478, b: 0.729 },
{ percent: 1, r: 0.933, g: 0, b: 0.447 }
];
this.grad3 = [
{ percent: 0, r: 0.514, g: 0.875, b: 1 },
{ percent: 0.46, r: 0, g: 0.686, b: 0.925 }
];
this.nbGradients = 3;
if (!this.globalService.lowPerformanceMode) {
// preload all number textures
this.textureArray("square", 12);
this.textureArray("triangle", 20);
this.textureArray("pyramide", 5);
this.textureArray("rectangleBig", 6);
this.textureArray("rectangleSmall", 6);
}
// custom loader
this.customLoadingScreen();
}
async getTexture(type: string, number, gradient) {
if (this.numbersTextures[type] && this.numbersTextures[type][number] && this.numbersTextures[type][number][gradient]) {
return this.numbersTextures[type][number][gradient];
} else {
let grad;
switch (gradient) {
case 0:
grad = this.grad1;
break;
case 1:
grad = this.grad2;
break;
case 2:
grad = this.grad3;
break;
}
const textureMaterial = await this.returnGeneratedCode(
grad,
"assets/babylon/textureNumbers/" + type + "/" + (number + 1) + ".png"
);
this.setTexture(type, number, gradient, textureMaterial);
return textureMaterial;
}
}
afterRenderFunk = () => {
if ((this.divider < 1000 && this.divider % 30 === 0) || this.divider % 600 === 0) {
this.currentFPS = (this.scene as any)._engine.getFps();
}
this.rotationFunction();
};
randomColor() {
return new BABYLON.Color3(0.2 + Math.random() * 0.8, 0.2 + Math.random() * 0.8, 0.2 + Math.random() * 0.8);
}
async meshPicked(mainMesh, subMeshId = null, randomColor = null, randomGradient = null) {
const submeshPicked = subMeshId !== null && mainMesh.subMeshes.length > 1 ? mainMesh.subMeshes[subMeshId] : mainMesh;
if (!randomColor) {
randomColor = this.randomColor();
} else {
randomColor = new BABYLON.Color3(randomColor.r, randomColor.g, randomColor.b);
}
if (!randomGradient) {
randomGradient = Math.floor(Math.random() * this.nbGradients);
}
this.page.sendEvent(RemoteCommandSolides.subMeshPicked, {
mainMeshId: mainMesh.id,
subMeshId,
color: randomColor,
gradient: randomGradient
});
if (this.markEdges && mainMesh.metadata === "edges") {
// edge clicked
if (!submeshPicked.clicked) {
submeshPicked.clicked = true;
this.edgeColoredCounter++;
if (this.page.remediationCountingMode) {
if (
this.edgeColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbEdges - 1
) {
this.page.scenario.readCustomText(this.edgeColoredCounter.toString() + "! " + $localize`Et enfin` + " ?");
} else if (
!(
this.edgeColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbEdges - 1
) ){
this.page.scenario.readCustomText(this.edgeColoredCounter.toString() + "! " + $localize`Et enfin`+" ?");
} else if (
!(
this.edgeColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbEdges
)
) {
this.page.scenario.readCustomText(this.edgeColoredCounter.toString());
}
}
this.page.checkEndMarkEdges();
}
mainMesh.material.diffuseColor = new BABYLON.Color3(0.08, 0.68, 0.11); // vert
} else if (this.markVertices && mainMesh.metadata === "vertices") {
// vertice clicked
if (!submeshPicked.clicked) {
submeshPicked.clicked = true;
this.verticeColoredCounter++;
if (this.page.remediationCountingMode) {
if (
this.verticeColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbVertices - 1
) {
this.page.scenario.readCustomText(this.verticeColoredCounter.toString() + "! " + $localize`Et enfin` + " ?");
} else if (
!(
this.verticeColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbVertices - 1
)) {
this.page.scenario.readCustomText(this.verticeColoredCounter.toString() + "! " + $localize`Et enfin`+" ?");
} else if (
!(
this.verticeColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbVertices
)
) {
this.page.scenario.readCustomText(this.verticeColoredCounter.toString());
}
}
this.page.checkEndMarkVertices();
}
mainMesh.material.diffuseColor = new BABYLON.Color3(1, 0, 0); // rouge
} else if (mainMesh.metadata === "facets") {
// facet clicked
if (this.markFacets) {
if (!submeshPicked.clicked) {
submeshPicked.clicked = true;
submeshPicked.faceNumber = this.facetColoredCounter;
//submeshPicked.faceNumber=subMeshId;
this.facetColoredCounter++;
if (this.page.remediationCountingMode) {
if (
this.facetColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbFacets - 1
) {
this.page.scenario.readCustomText(this.facetColoredCounter.toString() + "! " + $localize`Et enfin`+" ?");
} else if (
!(
this.facetColoredCounter ===
this.page.SOLIDES_DATA[this.page.currentSolid + "-" + this.page.currentRepresentation].nbFacets
)
) {
this.page.scenario.readCustomText(this.facetColoredCounter.toString());
}
}
this.page.checkEndMarkFacets();
}
// draw number on each face
if (
(mainMesh.id === "5-1" || mainMesh.id === "7-1" || submeshPicked.id === "7-5-0" || submeshPicked.id === "7-5-1") &&
submeshPicked.id !== "5-1-0"
) {
// pyramide base carrée (sauf base 5-1-0) et base triangle et faces supérieure et inférieure du prisme
mainMesh.material.subMaterials[subMeshId] = await this.getTexture("pyramide", submeshPicked.faceNumber, randomGradient);
} else if (mainMesh.id === "2-1" || mainMesh.id === "2-1-bis") {
// PAVÉ (bis = triangulated polygons)
if (submeshPicked.id === "2-1-1" || submeshPicked.id === "2-1-3") {
// Petites faces
mainMesh.material.subMaterials[subMeshId] = await this.getTexture(
"rectangleSmall",
submeshPicked.faceNumber,
randomGradient
);
} else {
// Grandes faces
mainMesh.material.subMaterials[subMeshId] = await this.getTexture(
"rectangleBig",
submeshPicked.faceNumber,
randomGradient
);
}
} else if (mainMesh.id === "7-4") {
// icosaèdre
mainMesh.material.subMaterials[subMeshId] = await this.getTexture("triangle", submeshPicked.faceNumber, randomGradient);
} else {
// les autres
mainMesh.material.subMaterials[subMeshId] = await this.getTexture("square", submeshPicked.faceNumber, randomGradient);
}
mainMesh.material.subMaterials[subMeshId].diffuseColor = randomColor;
}
}
this.page.detectChanges();
}
getMeshTorotate() {
let result = [];
const mesh = this.getMesh(this.currentMeshId);
const mesh2 = this.getMesh(this.currentMeshId + "-bis");
const edges = this.getMesh("edges-parent");
const vertices = this.getMesh(this.currentMeshId + "-vertices");
const models = this.getModels();
if (mesh) {
result.push(mesh);
}
if (mesh2) {
result.push(mesh2);
}
if (edges) {
result.push(edges);
}
if (vertices) {
result.push(vertices);
}
if (models) {
result = result.concat(models);
}
return result;
}
rotateMeshesLeft(meshes, ratio = 1) {
if (this.page.remoteControl) {
if (this.currentFPS < 30) {
ratio = ratio * 2;
}
if (this.currentFPS < 15) {
ratio = ratio * 2;
}
}
this.page.sendEvent(RemoteCommandSolides.rotate, { direction: "left", ratio });
meshes.forEach((mesh: Mesh) => {
mesh.rotate(BABYLON.Axis.Y, this.rotationAngle * ratio, BABYLON.Space.WORLD);
});
}
rotateMeshesRight(meshes, ratio = 1) {
if (this.page.remoteControl) {
if (this.currentFPS < 30) {
ratio = ratio * 2;
}
if (this.currentFPS < 15) {
ratio = ratio * 2;
}
}
this.page.sendEvent(RemoteCommandSolides.rotate, { direction: "right", ratio });
meshes.forEach(mesh => {
mesh.rotate(BABYLON.Axis.Y, -this.rotationAngle * ratio, BABYLON.Space.WORLD);
});
}
rotateMeshesUp(meshes, ratio = 1) {
if (this.page.remoteControl) {
if (this.currentFPS < 30) {
ratio = ratio * 2;
}
if (this.currentFPS < 15) {
ratio = ratio * 2;
}
}
this.page.sendEvent(RemoteCommandSolides.rotate, { direction: "up", ratio });
meshes.forEach(mesh => {
mesh.rotate(BABYLON.Axis.X, this.rotationAngle * ratio, BABYLON.Space.WORLD);
});
}
rotateMeshesDown(meshes, ratio = 1) {
if (this.page.remoteControl) {
if (this.currentFPS < 30) {
ratio = ratio * 2;
}
if (this.currentFPS < 15) {
ratio = ratio * 2;
}
}
this.page.sendEvent(RemoteCommandSolides.rotate, { direction: "down", ratio });
meshes.forEach(mesh => {
mesh.rotate(BABYLON.Axis.X, -this.rotationAngle * ratio, BABYLON.Space.WORLD);
});
}
rotationFunction() {
const meshes = this.getMeshTorotate();
if (meshes.length > 0) {
// SOLIDES
if (this.rLeft) {
this.rotateMeshesLeft(meshes);
}
if (this.rRight) {
this.rotateMeshesRight(meshes);
}
if (this.rUp) {
this.rotateMeshesUp(meshes);
}
if (this.rDown) {
this.rotateMeshesDown(meshes);
}
} else {
// PATRONS
if (this.rLeft) {
this.camera.alpha = this.camera.alpha + this.rotationAngle;
this.page.sendEvent(RemoteCommandSolides.camera, { alpha: this.camera.alpha, beta: this.camera.beta });
}
if (this.rRight) {
this.camera.alpha = this.camera.alpha - this.rotationAngle;
this.page.sendEvent(RemoteCommandSolides.camera, { alpha: this.camera.alpha, beta: this.camera.beta });
}
if (this.rUp) {
this.camera.beta = this.camera.beta + this.rotationAngle;
this.page.sendEvent(RemoteCommandSolides.camera, { alpha: this.camera.alpha, beta: this.camera.beta });
}
if (this.rDown) {
this.camera.beta = this.camera.beta - this.rotationAngle;
this.page.sendEvent(RemoteCommandSolides.camera, { alpha: this.camera.alpha, beta: this.camera.beta });
}
}
}
/**
* Update DOM Cabri elements
* @param holoMode Holo mode
* @param platform Platform
*/
updateCabriPosition(holoMode: string = null): Promise<void> {
return super.updateCabriPosition(holoMode, "solides");
}
async updateCabriBackground(renderCanvas, condition) {
window.store.getters.cabri.Scene?.meshes.forEach(async m => {
if (m.id === "background") {
if (this.page.remoteHostActivate && (this.cabriService.holoMode === "1" || this.cabriService.holoMode === "-1")) {
m.scaling.x = 1.6;
m.scaling.z = 1.41;
} else {
// background width proportion = 4096/3072 = 1.333333:
m.scaling.x = 1.5;
m.scaling.z = 1.5;
m.position.y = 1.1;
}
console.log("cabri background resized");
this.checkFlatHoloMode(m);
await this.switchBackgroundLauncher(m, renderCanvas.clientHeight, renderCanvas.clientWidth, false);
console.log("cabri switchBackgroundLauncher end");
}
});
}
get zoomToRadius() {
return this._zoomToRadius;
}
set zoomToRadius(value) {
this.forceRenderOn();
this.page.sendEvent(RemoteCommandSolides.zoom, value);
if (this._zoomToRadius !== value) {
this._zoomToRadius = value;
this.camera.radius = 195 - value;
// background scaling with zoom:
if (!this.page.firstTime) {
window.store.getters.cabri.Scene?.meshes.forEach(m => {
if (m.id === "background") {
if (this.page.remoteHostActivate && (this.cabriService.holoMode === "1" || this.cabriService.holoMode === "-1")) {
m.scaling.x = 1.7 * (value * 0.01);
m.scaling.z = 1.5 * (value * 0.01);
} else {
m.scaling.x = 1.5 * (value * 0.01);
m.scaling.z = 1.5 * (value * 0.01);
m.position.y = 1.1;
}
}
});
}
this.page.detectChanges();
}
AppUtils.timeOut(100).then(() => {
this.forceRenderOff();
});
}
resetZoomToRadius() {
// this.camera.radius = 50;
this.zoomToRadius = 140;
this.page.detectChanges();
}
checkActivityChange(): boolean {
return true;
const activityChange =
this.cabriService.currentSavedDom !== "solides" ||
this.cabriService.savedDomHoloMode !== this.cabriService.holoMode ||
this.cabriService.savedDomMirrorMode !== this.cabriService.mirrorMode;
// console.log("checkActivityChange = " + activityChange);
return activityChange;
}
saveDom() {
// temp fix for zoom on restoreDOM:
this.resetposition();
super.saveDom();
this.cabriService.currentSavedDom = "solides";
}
restoreDom(activityChange: boolean = false) {
window.Globals.HoloFaces = 4;
super.restoreDom();
if (window.document.querySelector("#page-div section")) {
window.document.querySelector("#page-div section").style.opacity = "1";
}
if (window.document.querySelector("#page-div")) {
window.document.querySelector("#page-div").style.height = window.innerHeight;
}
if (activityChange) {
// clean all custom elements in #page-div
if (
window.document.querySelector("#page-div #operationWrapper") &&
window.document.querySelector("#page-div #operationWrapper").length > 0
) {
window.document.querySelector("#page-div").removeChild(window.document.querySelector("#page-div #operationWrapper"));
}
if (
window.document.querySelector("#page-div #operationWrapperCordova") &&
window.document.querySelector("#page-div #operationWrapperCordova").length > 0
) {
window.document.querySelector("#page-div").removeChild(window.document.querySelector("#page-div #operationWrapperCordova"));
}
}
this.startRender();
}
getCurrentOperation(): string {
const str = "";
let solidName: string;
switch (this.page.solidsExercices.exoType) {
case ExerciseType.name:
solidName = this.page.solidsExercices.getCurrentSolidName();
return $localize`Nommer un solide : ${solidName}:solidName:`;
case ExerciseType.describe:
solidName = this.page.solidsExercices.getCurrentSolidName();
switch (this.page.solidsExercices.subject) {
case SolideSubjects.arete:
return $localize`Combien d’arêtes à ce solide : ${solidName}:solidName:`;
case SolideSubjects.faceForme:
return $localize`Quelle forme ont les faces de ce solide : ${solidName}:solidName:`;
case SolideSubjects.faceNombre:
return $localize`Combien de faces à ce solide : ${solidName}:solidName:`;
case SolideSubjects.sommet:
return $localize`Combien de sommets à ce solide : ${solidName}:solidName:`;
default:
throw new Error("subject not define");
}
case ExerciseType.pattern:
solidName = this.page.solidsExercices.getCurrentSolidName();
return $localize`Reconnaitre le patron d’un solide : ${solidName}:solidName:`;
case ExerciseType.recognize:
solidName = this.page.solidsExercices.getCurrentSolidName();
return $localize`Reconnaitre un solide : ${solidName}:solidName:`;
default:
return "";
}
return str;
}
clearResponse(mode: string, value: any): Promise<any> {
// selector
// #cabriText-34531 > div > div.editor-container > div.editor-content > div > p
// if(window.document.querySelector('.ZDR .svg-container')){
// window.document.querySelector('.ZDR .svg-container').innerHTML = '';
// }
// if(window.document.querySelector('.theZDR p')){
// window.document.querySelector('.theZDR p').innerHTML = '';
// window.document.querySelector('.theZDR').style.opacity = '0';
// }
return;
}
setResponse(mode: string, value: any) {
// display response
// window.document.querySelector('.theZDR p').innerHTML = value;
// window.document.querySelector('.theZDR').style.opacity = '1';
}
/***
*
* TEST 3D
*
*/
test3D() {
let distance = -1;
let minPoint = null;
for (const m in window.store.getters.cabri.Scene?.meshes) {
if (window.store.getters.cabri.Scene.meshes.hasOwnProperty(m)) {
const mesh = window.store.getters.cabri.Scene.meshes[m];
if (mesh.object && mesh.object.type === "facet") {
if (("" + mesh.name).indexOf("_") === -1) {
// console.log(m, mesh.name, mesh.object, mesh.object.params.pts3D);
if (distance < 0) {
distance = this.distance(mesh.object.params.pts3D[0], mesh.object.params.pts3D[1]);
}
if (!minPoint) {
minPoint = JSON.parse(JSON.stringify(mesh.position));
}
if (mesh.position.x < minPoint.x && mesh.position.y < minPoint.y && mesh.position.z < minPoint.z) {
minPoint = mesh.position;
}
}
} else {
// console.error(mesh.name, m);
}
}
}
const center = {
x: minPoint.x + distance / 2,
y: minPoint.y + distance / 2,
z: minPoint.z + distance / 2
};
// console.log(center);
const centerRotation = new BABYLON.Vector3(0, center.y, 0);
for (const m in window.store.getters.cabri.Scene?.meshes) {
if (window.store.getters.cabri.Scene.meshes.hasOwnProperty(m)) {
window.store.getters.cabri.Scene.meshes[m].setPivotPoint(centerRotation);
}
}
for (const m in window.store.getters.cabri.Scene?.meshes) {
if (window.store.getters.cabri.Scene.meshes.hasOwnProperty(m)) {
if (window.store.getters.cabri.Scene.meshes[m].id !== "sphere") {
// console.log(window.store.getters.cabri.Scene.meshes[m].name);
}
}
}
}
distance(pointA, pointB) {
const dx = pointB.x - pointA.x;
const dy = pointB.y - pointA.y;
const dz = pointB.z - pointA.z;
const dist = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2) + Math.pow(dz, 2));
return dist;
}
forceRenderOn() {
if (!this.page.cabri.cabriRenderStarted) {
this.isRenderForcedOn = true;
this.startRender();
}
}
forceRenderOff() {
if (this.page.cabri.cabriRenderStarted && this.isRenderForcedOn) {
this.isRenderForcedOn = false;
this.stopRender();
}
}
async rotateLeft($event = null) {
this.forceRenderOn();
if ($event) {
await this.globalService.waitButtonClick({ buttonClicked: $event.currentTarget }, true);
}
this.rLeft = true;
this.rRight = false;
}
async rotateRight($event = null) {
this.forceRenderOn();
if ($event) {
await this.globalService.waitButtonClick({ buttonClicked: $event.currentTarget }, true);
}
this.rRight = true;
this.rLeft = false;
}
async rotateUp($event = null) {
this.forceRenderOn();
if ($event) {
await this.globalService.waitButtonClick({ buttonClicked: $event.currentTarget }, true);
}
this.rUp = true;
this.rDown = false;
}
async rotateDown($event = null) {
this.forceRenderOn();
if ($event) {
await this.globalService.waitButtonClick({ buttonClicked: $event.currentTarget }, true);
}
this.rDown = true;
this.rUp = false;
}
async stop($event = null) {
this.forceRenderOff();
if ($event) {
await this.globalService.waitButtonClick({ buttonClicked: $event.currentTarget }, false);
}
this.rLeft = false;
this.rRight = false;
this.rUp = false;
this.rDown = false;
if (this.page.currentAction === "patron") {
window.store.getters.cps.setPageOrientation(this.camera.alpha, this.camera.beta);
await this.timeOut(100);
this.unlockRotation();
}
}
async resetposition($event = null) {
this.forceRenderOn();
let loaderOn = true;
if (!this.page.customLoader && !this.globalService.globalLoading) {
loaderOn = false;
// await this.page.startLoader();
}
if ($event) {
await this.globalService.waitButtonClick({ buttonClicked: $event.currentTarget });
}
this.page.sendEvent(RemoteCommandSolides.resetPosition);
const meshes = this.getMeshTorotate();
meshes.forEach(mesh => {
mesh.rotationQuaternion = null;
// mesh.rotationQuaternion = BABYLON.Quaternion.RotationAxis(new BABYLON.Vector3(0, 1, 0), 0);
});
this.resetZoomToRadius();
if ($event) {
await this.resetPatron();
}
if (!loaderOn) {
await this.page.stopLoader();
}
this.forceRenderOff();
}
async resetPatron() {
if (this.patron) {
const currentPatron = this.page.currentPatron + 0;
await this.page.patron();
await AppUtils.timeOut(100);
this.page.nextPatronButtonDisabled = false;
await this.page.patron(currentPatron);
await AppUtils.timeOut(100);
}
}
updateBabylonJSObject(id) {
this.facetColoredCounter = 0;
this.edgeColoredCounter = 0;
this.verticeColoredCounter = 0;
this.currentMeshId = id;
const mergedMeshes = [];
let mergedEdges = [];
let mergedVertices = [];
let modelIndex = 0;
(this.scene as any)?.meshes.forEach(m => {
if (m && m.name) {
// set default uvs for triangulated polygons
if (m.name === "triangulatedPolygon") {
m.setVerticesData(BABYLON.VertexBuffer.UVKind, [0, 0, 0, 1, 1, 1, 1, 0]);
}
//
// Identify meshes to merge and set custom UVS
//
// facets
if (m.object && m.object.type && m.object.type === "facet") {
m.material = m.material.clone();
const positions = m.getVerticesData(BABYLON.VertexBuffer.PositionKind);
const nbVertices = positions.length / 3;
if (nbVertices >= 5) {
// uvs pentagone
const uvs = [];
for (let i = 0; i < 5; i++) {
const x = 0.5 + Math.cos(-2 * Math.PI * 5 - (2 * Math.PI * i) / 5) / 2;
const y = 0.5 + Math.sin(-2 * Math.PI * 5 - (2 * Math.PI * i) / 5) / 2;
uvs.push(x);
uvs.push(y);
}
m.setVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
} else {
if (id === "7-4") {
m.setVerticesData(BABYLON.VertexBuffer.UVKind, [0, 0, 0.5, 0.87, 1, 0]);
}
if (id === "7-5") {
// inverse texture for prisme
if (nbVertices === 4) {
m.setVerticesData(BABYLON.VertexBuffer.UVKind, [1, 0, 1, 1, 0, 1, 0, 0]);
}
}
}
mergedMeshes.push(m);
}
// edges
if (this.isEdge(m)) {
m.isPickable = true;
m.material = m.material.clone();
// const info = m.getBoundingInfo().boundingBox.centerWorld;
// m.setPivotMatrix(BABYLON.Matrix.Translation(-info.x, -info.y, -info.z));
m.metadata = "edges";
mergedEdges.push(m);
}
// vertices
if (this.isVertice(m)) {
m.isPickable = true;
m.material = m.material.clone();
mergedVertices.push(m);
}
// model (3ds), cône et cylindre
if (
m &&
m.object &&
m.object.type &&
(m.object.type === "model" || m.object.type === "cone" || m.object.type === "cylinder") &&
(!m.name || String(m.name).indexOf("dumCube") === -1)
) {
if (m.parent === null) {
m.id = id + "-" + modelIndex;
const info = m.getBoundingInfo().boundingBox.centerWorld;
// const info = m.position;
this.camera.setTarget(info);
// this.camera.setTarget(new BABYLON.Vector3(0,20,0));
modelIndex++;
}
}
if (m.object && m.object.type && m.object.type === "model" && m.parent === null) {
const info = m.getBoundingInfo().boundingBox.centerWorld;
m.setPivotMatrix(BABYLON.Matrix.Translation(-info.x, -info.y, -info.z));
m.gabarit = "solides";
}
}
});
//
// Merge meshes and configure them
//
if (mergedMeshes.length > 0) {
// facets
// triangulated polygons can't be merged with facets
const mergedMeshes1 = mergedMeshes.filter(f => f.name !== "triangulatedPolygon");
const mergedMeshes2 = mergedMeshes.filter(f => f.name === "triangulatedPolygon");
// inverse UVS for triangulated polygon
if (mergedMeshes2.length > 0) {
mergedMeshes2[1].setVerticesData(BABYLON.VertexBuffer.UVKind, [1, 0, 1, 1, 0, 1, 0, 0]);
}
const newMesh = this.mergeMeshes(mergedMeshes1, id);
newMesh.refreshBoundingInfo();
newMesh.metadata = "facets";
(newMesh as any).gabarit = "solides";
if (mergedMeshes2 && mergedMeshes2.length > 0) {
const solidMesh = this.mergeMeshes(mergedMeshes2, id + "-bis");
//solidMesh.refreshBoundingInfo();
solidMesh.metadata = "facets";
(solidMesh as any).gabarit = "solides";
}
// edges
if (mergedEdges.length > 0) {
mergedEdges = this.deleteIntersectingMeshes(mergedEdges);
mergedEdges.forEach((m: Mesh) => {
m.parent = newMesh;
m.metadata = "edges";
(m as any).gabarit = "solides";
//add occlusion detection occluded are not rendered and status occluded is set
m.occlusionQueryAlgorithmType = BABYLON.AbstractMesh.OCCLUSION_ALGORITHM_TYPE_ACCURATE;
m.occlusionType = BABYLON.AbstractMesh.OCCLUSION_TYPE_STRICT;
});
}
// vertices
if (mergedVertices.length > 0) {
mergedVertices = this.deleteIntersectingMeshes(mergedVertices);
mergedVertices.forEach((m: Mesh) => {
m.parent = newMesh;
m.metadata = "vertices";
(m as any).gabarit = "solides";
var minimum = m.getBoundingInfo().boundingBox.minimum.clone();
var maximum = m.getBoundingInfo().boundingBox.maximum.clone();
const ratio = 0.8;
var scaling = BABYLON.Matrix.Translation(-ratio, -ratio, -ratio);
var scaling2 = BABYLON.Matrix.Translation(ratio, ratio, ratio);
minimum = BABYLON.Vector3.TransformCoordinates(minimum, scaling);
maximum = BABYLON.Vector3.TransformCoordinates(maximum, scaling2);
m._boundingInfo = new BABYLON.BoundingInfo(minimum, maximum);
m.computeWorldMatrix(true);
//m.showBoundingBox = true;
//add occlusion detection occluded are not rendered and status occluded is set
m.occlusionQueryAlgorithmType = BABYLON.AbstractMesh.OCCLUSION_ALGORITHM_TYPE_ACCURATE;
m.occlusionType = BABYLON.AbstractMesh.OCCLUSION_TYPE_STRICT;
});
}
}
}
deleteIntersectingMeshes(meshes) {
const sortedMeshes = this.sortMeshesByName(meshes);
meshes = [];
const disposedMeshes = [];
sortedMeshes.forEach(m => {
// on récupère le centre d'un object et on regarde s'il est "à l'intérieur" d'un autre objet
const center = m.getBoundingInfo().boundingBox.centerWorld;
if (disposedMeshes.indexOf(m.id) === -1) {
// s'il n'a pas déjà été supprimé
sortedMeshes.forEach((m2: Mesh) => {
if (m != null && m2 !== null && m.id !== m2.id) {
// ne pas comparé à lui même
if (m2.intersectsPoint(center)) {
// si intersection, on supprime le mesh et on stocke l'info pour filtrage ultérieur
disposedMeshes.push(m2.id);
m2.dispose();
}
}
});
}
});
return sortedMeshes.filter(m => disposedMeshes.indexOf(m.id) === -1);
}
mergeMeshes(meshes, id, info = null) {
const newMesh = BABYLON.Mesh.MergeMeshes(meshes, true, false, null, true, true);
newMesh.layerMask = 0x10000000;
if (!info) {
info = newMesh.getBoundingInfo().boundingBox.centerWorld;
}
newMesh.setPivotMatrix(BABYLON.Matrix.Translation(-info.x, -info.y, -info.z));
this.camera.setTarget(info);
newMesh.renderingGroupId = 1;
newMesh.id = id;
this.addToHoloCameras(newMesh);
let i = 0;
newMesh.subMeshes.forEach((submesh, index) => {
(submesh as any).id = newMesh.id + "-" + i;
(submesh as any).isPickable = true;
i++;
});
return newMesh;
}
isEdge(mesh) {
return (
String(mesh.name).indexOf("e0") === 0 ||
String(mesh.name).indexOf("e1") === 0 ||
String(mesh.name).indexOf("e2") === 0 ||
String(mesh.name).indexOf("e3") === 0 ||
String(mesh.name).indexOf("e4") === 0 ||
String(mesh.name).indexOf("e5") === 0
);
}
isVertice(mesh) {
return (
String(mesh.name).indexOf("v0") === 0 ||
String(mesh.name).indexOf("v1") === 0 ||
String(mesh.name).indexOf("v2") === 0 ||
String(mesh.name).indexOf("v3") === 0 ||
String(mesh.name).indexOf("v4") === 0 ||
String(mesh.name).indexOf("v5") === 0
);
}
deleteObject(id) {
const toDispose = (this.scene as any)?.meshes.filter(mesh => {
return mesh.id === id || mesh.id === id + "-bis" || mesh.id === id + "-edges" || mesh.id === id + "-vertices";
});
if (toDispose) {
toDispose.forEach(mesh => {
mesh.dispose(true);
});
} else {
console.error("no any mesh to remove");
}
}
lockRotation(): Promise<void> {
return new Promise(async (resolve, reject) => {
// window.store.getters.cps.updateOnscreen(true);
const cameraPositionUpdated =
this.camera.radius !== this.initialCameraPosition.radius ||
this.camera.alpha !== this.initialCameraPosition.alpha ||
this.camera.beta !== this.initialCameraPosition.beta;
this.camera.radius = this.initialCameraPosition.radius;
this.camera.alpha = this.initialCameraPosition.alpha;
this.camera.beta = this.initialCameraPosition.beta;
if (this.holoCameras) {
if (this.holoCameras.rtt_z) {
this.holoCameras.rtt_z.activeCamera.alpha = -Math.PI / 2;
this.holoCameras.rtt_z.activeCamera.beta = 1.396;
}
if (this.holoCameras.rtt_x && this.holoCameras.rtt_x.activeCamera) {
this.holoCameras.rtt_x.activeCamera.alpha = Math.PI;
this.holoCameras.rtt_x.activeCamera.beta = 1.396;
}
if (this.holoCameras.rttZ && this.holoCameras.rttZ.activeCamera) {
this.holoCameras.rttZ.activeCamera.alpha = Math.PI / 2;
this.holoCameras.rttZ.activeCamera.beta = 1.396;
}
if (this.holoCameras.rttX && this.holoCameras.rttX.activeCamera) {
this.holoCameras.rttX.activeCamera.alpha = 0;
this.holoCameras.rttX.activeCamera.beta = 1.396;
}
}
(this.scene as any)?.CABRI.lockOrientation();
if (cameraPositionUpdated) {
window.store.getters.cps.setPageOrientation(this.camera.alpha, this.camera.beta);
// keep for ios?
// if (this.globalService.isIos && this.globalService.isTablet) {
// this.updateCabriPosition();
// }
}
if (this.holoCameras) {
// console.error("HOLO CAMERAS");
await this.timeOut(500);
const bkgz = this.getLastMesh("bkgz");
if (bkgz) {
bkgz.rotation.y = 0;
}
const bkgZ = this.getLastMesh("bkgZ");
if (bkgZ) {
bkgZ.rotation.y = -Math.PI;
}
const bkgX = this.getLastMesh("bkgX");
if (bkgX) {
bkgX.rotation.y = -Math.PI / 2;
}
const bkgx = this.getLastMesh("bkgx");
if (bkgx) {
bkgx.rotation.y = Math.PI / 2;
}
} else {
const background = this.getMesh("background");
if (background) {
background.rotation.x = -Math.PI / 2;
background.rotation.y = 0;
} else {
console.error("no background");
}
}
resolve();
});
}
unlockRotation() {
(this.scene as any).CABRI.unlockOrientation();
this.camera.lowerAlphaLimit = null;
this.camera.upperAlphaLimit = null;
this.camera.lowerBetaLimit = null;
this.camera.upperBetaLimit = null;
}
showEdges() {
(this.scene as any).meshes.forEach(m => {
m.enableEdgesRendering(0.95, true);
m.edgesWidth = 4.0;
m.edgesColor = new BABYLON.Color4(1, 1, 1, 1);
});
}
getPatronMeshesPositions() {
const result = [];
// for (const k in this.cabriObjects) {
// if (this.cabriObjects.hasOwnProperty(k)) {
// const m = this.cabriObjects[k];
// if (m.type === "facet") {
// result.push({id: m.id, pts3D: m.params.pts3D});
// }
// }
// }
(this.scene as any).meshes.forEach(m => {
if (m && m.id) {
if (m.object && m.object.type && m.object.type === "facet") {
result.push({ id: m.id, positions: m.getVerticesData(BABYLON.VertexBuffer.PositionKind) });
}
if (this.isEdge(m)) {
// console.error(m);
}
if (this.isVertice(m)) {
// console.error(m);
}
}
});
return result;
}
setPatronMeshesPositions(positions) {
let counter = 0;
// for (const k in this.cabriObjects) {
// if (this.cabriObjects.hasOwnProperty(k)) {
// const m = this.cabriObjects[k];
// if (m.type === "facet") {
// m.params.pts3D = positions[counter].pts3D;
// counter++;
// }
// }
// }
(this.scene as any).meshes.forEach(m => {
if (m && m.id) {
if ((m.object && m.object.type && m.object.type === "facet") || this.isEdge(m) || this.isVertice(m)) {
m.setVerticesData(BABYLON.VertexBuffer.PositionKind, positions[counter].positions);
counter++;
}
}
});
}
checkPatronOK(next = true) {
if (!this.patronDone) {
this.patronDone = true;
const countCollisions = [];
(this.scene as any).meshes.forEach(m => {
if (m && m.name) {
if (m.object && m.object.type && m.object.type === "facet") {
(this.scene as any).meshes.forEach(m2 => {
if (m2 && m2.name && m.id !== m2.id) {
if (m2.object && m2.object.type && m2.object.type === "facet") {
if (!countCollisions[m.id]) {
countCollisions[m.id] = 0;
}
// let colide = false;
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
if (
this.check(m.object.params.pts3D[i].x, m2.object.params.pts3D[j].x) &&
this.check(m.object.params.pts3D[i].y, m2.object.params.pts3D[j].y) &&
this.check(m.object.params.pts3D[i].z, m2.object.params.pts3D[j].z)
) {
countCollisions[m.id]++;
}
}
}
}
}
});
}
}
});
let result = true;
if (this.page.currentSolid === 1 || this.page.currentSolid === 2) {
countCollisions.find(e => {
if (e < 8 || e > 8) {
result = false;
this.patronDone = false;
return false;
}
});
}
if (this.page.currentSolid === 5) {
let count16 = 0;
let count8 = 0;
countCollisions.find(e => {
if (e === 16) {
count16++;
}
if (e === 8) {
count8++;
}
});
if (count16 !== 4 || count8 !== 1) {
result = false;
this.patronDone = false;
return false;
}
}
if (countCollisions.length > 0 && result) {
this.patronDone = true;
this.page.scenario.endPatron();
this.page.patronsDone[this.page.currentSolid].push(this.page.currentPatron);
this.loadMathia(next);
// do not show starboard if in recognize pattern exercise remediation:
if (this.cabriService.getCurrentExercice().variables.type !== ExerciseType.pattern) {
setTimeout(async () => {
this.page.updatePlayerAndTeamStarboards(AwardsType.shooting);
await this.page.showHideAward();
}, 2000);
}
} else {
this.patronDone = false;
}
}
}
check(x, y) {
const delta = 0.1;
return x - delta < y && y < x + delta;
}
loadMathia(next = true) {
super.loadMathia(() => {
// end of animation => next patron
if (next) {
if (this.page.solidsExercices.remediationRunning) {
this.page.remediationEndSubscription.next();
} else {
this.page.patron();
}
}
});
// this.lockRotation();
// this.stopRender();
// change facets texture
const myMaterial = new BABYLON.StandardMaterial("grass", this.scene);
myMaterial.diffuseTexture = new BABYLON.Texture(
"assets/babylon/tex1" + (this.globalService.lowPerformanceMode ? "_ios" : "") + ".png",
this.scene
);
(this.scene as any).meshes.forEach(m => {
if (m && m.name) {
if (m.object && m.object.type && m.object.type === "facet") {
m.material = myMaterial;
m.object.params.facetmaterial = myMaterial;
}
}
});
const hl1 = new BABYLON.HighlightLayer("hl1", this.scene);
// change edges color
(this.scene as any).meshes.forEach(m => {
if (m && m.name && String(m.name).indexOf("e") === 0) {
m.material.diffuseColor = new BABYLON.Color3(99 / 255, 80 / 255, 17 / 255);
m.material.emissiveColor = new BABYLON.Color3(99 / 255, 80 / 255, 17 / 255);
hl1.addMesh(m, BABYLON.Color3.Black(), true);
}
});
}
sortMeshesByName(meshes) {
return meshes.sort((a, b) => {
const nameA = a.name.toUpperCase(); // ignore upper and lowercase
const nameB = b.name.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) {
return -1; // nameA comes first
}
if (nameA > nameB) {
return 1; // nameB comes first
}
return 0; // names must be equal
});
}
removeCabriMouseEvents() {
if (!this.cabriEventsOff && window.store.getters.cabri.Scene) {
this.saveEvents.onPointerDown = window.store.getters.cabri.Scene.CABRI.onPointerDown;
this.saveEvents.onPointerUp = window.store.getters.cabri.Scene.CABRI.onPointerUp;
this.saveEvents.onPointerMove = window.store.getters.cabri.Scene.CABRI.onPointerMove;
window.store.getters.cabri.Scene.CABRI.onPointerDown = () => {};
window.store.getters.cabri.Scene.CABRI.onPointerUp = () => {};
window.store.getters.cabri.Scene.CABRI.onPointerMove = () => {};
if (this.cabriService.mirrorMode && window.store.getters.cabri.Picker._pick3D) {
window.store.getters.cabri.Picker.pick3D = window.store.getters.cabri.Picker._pick3D;
window.store.getters.cabri.Picker._pick3D = null;
}
this.cabriEventsOff = true;
}
}
restoreCabriMouseEvents() {
if (this.cabriEventsOff && window.store.getters.cabri.Scene) {
window.store.getters.cabri.Scene.CABRI.onPointerDown = this.saveEvents.onPointerDown;
window.store.getters.cabri.Scene.CABRI.onPointerUp = this.saveEvents.onPointerUp;
window.store.getters.cabri.Scene.CABRI.onPointerMove = this.saveEvents.onPointerMove;
if (this.cabriService.mirrorMode) {
window.store.getters.cabri.Picker._pick3D = window.store.getters.cabri.Picker.pick3D;
window.store.getters.cabri.Picker.pick3D = (e, t, i) => {
t.y = window.store.getters.cabri.Scene._engine._gl.canvas.clientHeight - t.y;
return window.store.getters.cabri.Picker._pick3D(e, t, i);
};
}
this.saveEvents.onPointerDown = null;
this.saveEvents.onPointerUp = null;
this.saveEvents.onPointerMove = null;
this.cabriEventsOff = false;
}
}
getPickedElement() {
let element;
const xPIxels = window.store.getters.cabri.Scene.pointerX;
// (x + 10.5) / 21 * window.store.getters.cabri.Scene._engine._gl.canvas.clientWidth;
const yPIxels = window.store.getters.cabri.Scene._engine._gl.canvas.clientHeight - window.store.getters.cabri.Scene.pointerY;
// (y + (7.425-0.22)) / 14.85 * window.store.getters.cabri.Scene._engine._gl.canvas.clientHeight;
console.error(xPIxels, yPIxels);
const pickedResult = window.store.getters.cabri.Scene.pick(
xPIxels,
yPIxels,
null,
false,
window.store.getters.cabri.Scene.CABRI.Camera2D3D
);
console.error("pickedElement", pickedResult);
if (pickedResult.pickedMesh && pickedResult.pickedMesh.id !== "background") {
element = { id: pickedResult.pickedMesh.id };
}
return element;
}
async textureArray(folder: string, size: number) {
for (let i = 0; i < size; i++) {
const textureMaterial = await this.returnGeneratedCode(
this.grad1,
"assets/babylon/textureNumbers/" + folder + "/" + (i + 1) + ".png"
);
this.setTexture(folder, i, 0, textureMaterial);
const textureMaterial2 = await this.returnGeneratedCode(
this.grad2,
"assets/babylon/textureNumbers/" + folder + "/" + (i + 1) + ".png"
);
this.setTexture(folder, i, 1, textureMaterial2);
const textureMaterial3 = await this.returnGeneratedCode(
this.grad3,
"assets/babylon/textureNumbers/" + folder + "/" + (i + 1) + ".png"
);
this.setTexture(folder, i, 2, textureMaterial3);
}
}
setTexture(type, number, gradNumber, textureMaterial) {
if (!this.numbersTextures[type]) {
this.numbersTextures[type] = {};
}
if (!this.numbersTextures[type][number]) {
this.numbersTextures[type][number] = {};
}
this.numbersTextures[type][number][gradNumber] = textureMaterial;
}
restoreCameraTarget() {
const currentMesh = window.store.getters.cabri.Scene.meshes.find(mesh => {
return mesh.gabarit && mesh.gabarit === "solides";
});
if (currentMesh) {
const center = currentMesh.getBoundingInfo().boundingBox.centerWorld;
this.camera.setTarget(center);
}
}
setCameraDefaultPosition() {
if (!this.camera) {
this.camera = window.store.getters.cabri.Camera2D3D;
}
this.initialCameraPosition = { radius: 55, alpha: -Math.PI / 2, beta: (7 * Math.PI) / 18 };
this.restoreCamera();
}
}