react-planner
Version:
react-planner is a React Component for plans design. Draw a 2D floorplan and navigate it in 3D mode.
851 lines (694 loc) • 28.3 kB
JavaScript
import * as Three from 'three';
import createGrid from './grid-creator';
import { disposeObject } from './three-memory-cleaner';
export function parseData(sceneData, actions, catalog) {
let planData = {};
planData.sceneGraph = {
unit: sceneData.unit,
layers: {},
busyResources: { layers: {} },
width: sceneData.width,
height: sceneData.height,
LODs: {}
};
planData.plan = new Three.Object3D();
planData.plan.name = 'plan';
// Add a grid to the plan
planData.grid = createGrid(sceneData);
planData.grid.name = 'grid';
planData.boundingBox = new Three.Box3().setFromObject(planData.grid);
planData.boundingBox.name = 'boundingBox';
let promises = [];
sceneData.layers.forEach(layer => {
if (layer.id === sceneData.selectedLayer || layer.visible) {
promises = promises.concat(createLayerObjects(layer, planData, sceneData, actions, catalog));
}
});
Promise.all(promises).then(value => updateBoundingBox(planData));
return planData;
}
function createLayerObjects(layer, planData, sceneData, actions, catalog) {
let promises = [];
planData.sceneGraph.layers[layer.id] = {
id: layer.id,
lines: {},
holes: {},
areas: {},
items: {},
visible: layer.visible,
altitude: layer.altitude
};
planData.sceneGraph.busyResources.layers[layer.id] = {
id: layer.id,
lines: {},
holes: {},
areas: {},
items: {}
};
// Import lines
layer.lines.forEach(line => {
promises.push(addLine(sceneData, planData, layer, line.id, catalog, actions.linesActions));
line.holes.forEach(holeID => {
promises.push(addHole(sceneData, planData, layer, holeID, catalog, actions.holesActions));
});
});
// Import areas
layer.areas.forEach(area => {
promises.push(addArea(sceneData, planData, layer, area.id, catalog, actions.areaActions));
});
// Import items
layer.items.forEach(item => {
promises.push(addItem(sceneData, planData, layer, item.id, catalog, actions.itemsActions));
});
return promises;
}
export function updateScene(planData, sceneData, oldSceneData, diffArray, actions, catalog) {
let splitted = diffArray.map( el => { return { op: el.op, path: el.path.split('/'), value: el.value }; } );
let filteredDiffs = filterDiffs(splitted, sceneData, oldSceneData);
//***testing additional filter***
filteredDiffs = filteredDiffs.filter( ({path}) => path[3] !== 'selected' );
filteredDiffs = filteredDiffs.filter( ({path}) => path[1] !== 'groups' );
//*******************************
filteredDiffs.forEach(({op, path, value}) => {
/* First of all I need to find the object I need to update */
if (path[1] === 'layers') {
let layer = sceneData.getIn(['layers', path[2]]);
if (path.length === 3 && op === 'remove') {
removeLayer(path[2], planData);
} else if (path.length > 3) {
switch (op) {
case 'replace':
replaceObject(path, layer, planData, actions, sceneData, oldSceneData, catalog);
break;
case 'add':
addObject(path, layer, planData, actions, sceneData, oldSceneData, catalog);
break;
case 'remove':
removeObject(path, layer, planData, actions, sceneData, oldSceneData, catalog);
break;
}
}
} else if (path[1] === 'selectedLayer') {
let layerSelectedID = value;
let layerSelected = sceneData.getIn(['layers', layerSelectedID]);
// First of all I check if the new selected layer is not visible
if (!layerSelected.visible) {
// I need to create the objects for this layer
let promises = createLayerObjects(layerSelected, planData, sceneData, actions, catalog);
Promise.all(promises).then(() => updateBoundingBox(planData));
}
let layerGraph = planData.sceneGraph.layers[oldSceneData.selectedLayer];
if (layerGraph) {
if (!layerGraph.visible) {
// I need to remove the objects for this layer
for (let lineID in layerGraph.lines) removeLine(planData, layerGraph.id, lineID);
for (let areaID in layerGraph.areas) removeArea(planData, layerGraph.id, areaID);
for (let itemID in layerGraph.items) removeItem(planData, layerGraph.id, itemID);
for (let holeID in layerGraph.holes) removeHole(planData, layerGraph.id, holeID);
}
}
}
});
return planData;
}
function replaceObject(modifiedPath, layer, planData, actions, sceneData, oldSceneData, catalog) {
let promises = [];
switch (modifiedPath[3]) {
case 'vertices':
if (modifiedPath[5] !== 'selected') {
let vertex = layer.getIn(['vertices', modifiedPath[4]]);
if (modifiedPath[5] === 'x' || modifiedPath[5] === 'y') {
vertex.lines.forEach(lineID => {
let lineHoles = oldSceneData.getIn(['layers',layer.id, 'lines', lineID, 'holes' ]);
if( lineHoles ) lineHoles.forEach(holeID => { replaceObject([0, 0, 0, 'holes', holeID, 'selected'], layer, planData, actions, sceneData, oldSceneData, catalog); });
return replaceObject([0, 0, 0, 'lines', lineID], layer, planData, actions, sceneData, oldSceneData, catalog);
});
vertex.areas.forEach(areaID => replaceObject([0, 0, 0, 'areas', areaID], layer, planData, actions, sceneData, oldSceneData, catalog));
}
if (modifiedPath[5] === 'areas') {
let areaID = vertex.getIn(['areas', ~~modifiedPath[6]]);
replaceObject([0, 0, 0, 'areas', areaID], layer, planData, actions, sceneData, oldSceneData, catalog);
}
}
break;
case 'holes':
let newHoleData = layer.getIn(['holes', modifiedPath[4]]);
if (catalog.getElement(newHoleData.type).updateRender3D) {
promises.push(
updateHole(
sceneData,
oldSceneData,
planData,
layer,
modifiedPath[4],
modifiedPath.slice(5),
catalog,
actions.holesActions,
() => removeHole(planData, layer.id, newHoleData.id),
() => addHole(sceneData, planData, layer, newHoleData.id, catalog, actions.holesActions)
)
);
}
else {
let lineID = newHoleData.line;
if (modifiedPath[5] === 'selected') {
// I remove only the hole without removing the wall
removeHole(planData, layer.id, newHoleData.id);
promises.push(addHole(sceneData, planData, layer, newHoleData.id, catalog, actions.holesActions));
}
else {
layer.getIn(['lines', lineID, 'holes']).forEach(holeID => {
removeHole(planData, layer.id, holeID);
});
removeLine(planData, layer.id, lineID);
promises.push(addLine(sceneData, planData, layer, lineID, catalog, actions.linesActions));
layer.getIn(['lines', lineID, 'holes']).forEach(holeID => {
promises.push(addHole(sceneData, planData, layer, holeID, catalog, actions.holesActions));
});
}
}
break;
case 'lines':
let line = layer.getIn(['lines', modifiedPath[4]]);
if (catalog.getElement(line.type).updateRender3D) {
promises.push(
updateLine(
sceneData,
oldSceneData,
planData,
layer,
modifiedPath[4],
modifiedPath.slice(5),
catalog,
actions.linesActions,
() => removeLine(planData, layer.id, modifiedPath[4]),
() => addLine(sceneData, planData, layer, modifiedPath[4], catalog, actions.linesActions)
)
);
}
else {
removeLine(planData, layer.id, modifiedPath[4]);
promises.push(addLine(sceneData, planData, layer, modifiedPath[4], catalog, actions.linesActions));
}
break;
case 'areas':
let area = layer.getIn(['areas', modifiedPath[4]]);
if (catalog.getElement(area.type).updateRender3D) {
promises.push(
updateArea(
sceneData,
oldSceneData,
planData,
layer,
modifiedPath[4],
modifiedPath.slice(5),
catalog,
actions.areaActions,
() => removeArea(planData, layer.id, modifiedPath[4]),
() => addArea(sceneData, planData, layer, modifiedPath[4], catalog, actions.areaActions)
)
);
}
else {
if (planData.sceneGraph.layers[layer.id].areas[modifiedPath[4]]) {
removeArea(planData, layer.id, modifiedPath[4]);
}
promises.push(addArea(sceneData, planData, layer, modifiedPath[4], catalog, actions.areaActions));
}
break;
case 'items':
let item = layer.getIn(['items', modifiedPath[4]]);
if (catalog.getElement(item.type).updateRender3D) {
promises.push(
updateItem(
sceneData,
oldSceneData,
planData,
layer,
modifiedPath[4],
modifiedPath.slice(5),
catalog,
actions.itemsActions,
() => removeItem(planData, layer.id, modifiedPath[4]),
() => addItem(sceneData, planData, layer, modifiedPath[4], catalog, actions.itemsActions)
)
);
}
else {
removeItem(planData, layer.id, modifiedPath[4]);
promises.push(addItem(sceneData, planData, layer, modifiedPath[4], catalog, actions.itemsActions));
}
break;
case 'visible':
if (!layer.visible) {
let layerGraph = planData.sceneGraph.layers[layer.id];
for (let lineID in layerGraph.lines) removeLine(planData, layer.id, lineID);
for (let areaID in layerGraph.areas) removeArea(planData, layer.id, areaID);
for (let itemID in layerGraph.items) removeItem(planData, layer.id, itemID);
for (let holeID in layerGraph.holes) removeHole(planData, layer.id, holeID);
} else {
promises = promises.concat(createLayerObjects(layer, planData, sceneData, actions, catalog));
}
break;
case 'opacity':
case 'altitude':
let layerGraph = planData.sceneGraph.layers[layer.id];
for (let lineID in layerGraph.lines) removeLine(planData, layer.id, lineID);
for (let areaID in layerGraph.areas) removeArea(planData, layer.id, areaID);
for (let itemID in layerGraph.items) removeItem(planData, layer.id, itemID);
for (let holeID in layerGraph.holes) removeHole(planData, layer.id, holeID);
promises = promises.concat(createLayerObjects(layer, planData, sceneData, actions, catalog));
}
Promise.all(promises).then(values => updateBoundingBox(planData));
}
function removeObject(modifiedPath, layer, planData, actions, sceneData, oldSceneData, catalog) {
let promises = [];
switch (modifiedPath[3]) {
case 'lines':
// Here I remove the line with all its holes
let lineID = modifiedPath[4];
oldSceneData.getIn(['layers', layer.id, 'lines', lineID, 'holes']).forEach(holeID => {
removeHole(planData, layer.id, holeID);
});
removeLine(planData, layer.id, lineID);
if (modifiedPath.length > 5) {
// I removed an hole, so I should add the new line
promises.push(addLine(sceneData, planData, layer, lineID, catalog, actions.linesActions));
layer.getIn(['lines', lineID, 'holes']).forEach(holeID => {
promises.push(addHole(sceneData, planData, layer, holeID, catalog, actions.holesActions));
});
}
break;
case 'areas':
if (modifiedPath.length === 5) {
// I am removing an entire area
removeArea(planData, layer.id, modifiedPath[4]);
}
break;
case 'items':
if (modifiedPath.length === 5) {
// I am removing an item
removeItem(planData, layer.id, modifiedPath[4]);
}
break;
}
Promise.all(promises).then(values => updateBoundingBox(planData));
}
function removeLayer(layerId, planData) {
let layerGraph = planData.sceneGraph.layers[layerId];
for (let lineID in layerGraph.lines) removeLine(planData, layerId, lineID);
for (let areaID in layerGraph.areas) removeArea(planData, layerId, areaID);
for (let itemID in layerGraph.items) removeItem(planData, layerId, itemID);
for (let holeID in layerGraph.holes) removeHole(planData, layerId, holeID);
delete planData.sceneGraph.layers[layerId];
}
function removeHole(planData, layerId, holeID) {
if (planData.sceneGraph.busyResources.layers[layerId].holes[holeID]) {
setTimeout(() => removeHole(planData, layerId, holeID), 100);
return;
}
planData.sceneGraph.busyResources.layers[layerId].holes[holeID] = true;
let hole3D = planData.sceneGraph.layers[layerId].holes[holeID];
if (hole3D) {
planData.plan.remove(hole3D);
disposeObject(hole3D);
delete planData.sceneGraph.layers[layerId].holes[holeID];
delete planData.sceneGraph.LODs[holeID];
hole3D = null;
updateBoundingBox(planData);
}
planData.sceneGraph.busyResources.layers[layerId].holes[holeID] = false;
}
function removeLine(planData, layerId, lineID) {
if (planData.sceneGraph.busyResources.layers[layerId].lines[lineID]) {
setTimeout(() => removeLine(planData, layerId, lineID), 100);
return;
}
planData.sceneGraph.busyResources.layers[layerId].lines[lineID] = true;
let line3D = planData.sceneGraph.layers[layerId].lines[lineID];
if (line3D) {
planData.plan.remove(line3D);
disposeObject(line3D);
delete planData.sceneGraph.layers[layerId].lines[lineID];
delete planData.sceneGraph.LODs[lineID];
line3D = null;
updateBoundingBox(planData);
}
planData.sceneGraph.busyResources.layers[layerId].lines[lineID] = false;
}
function removeArea(planData, layerId, areaID) {
if (planData.sceneGraph.busyResources.layers[layerId].areas[areaID]) {
setTimeout(() => removeArea(planData, layerId, areaID), 100);
return;
}
planData.sceneGraph.busyResources.layers[layerId].areas[areaID] = true;
let area3D = planData.sceneGraph.layers[layerId].areas[areaID];
if (area3D) {
planData.plan.remove(area3D);
disposeObject(area3D);
delete planData.sceneGraph.layers[layerId].areas[areaID];
delete planData.sceneGraph.LODs[areaID];
area3D = null;
updateBoundingBox(planData);
}
planData.sceneGraph.busyResources.layers[layerId].areas[areaID] = false;
}
function removeItem(planData, layerId, itemID) {
if (planData.sceneGraph.busyResources.layers[layerId].items[itemID]) {
setTimeout(() => removeItem(planData, layerId, itemID), 100);
return;
}
planData.sceneGraph.busyResources.layers[layerId].items[itemID] = true;
let item3D = planData.sceneGraph.layers[layerId].items[itemID];
if (item3D) {
planData.plan.remove(item3D);
disposeObject(item3D);
delete planData.sceneGraph.layers[layerId].items[itemID];
delete planData.sceneGraph.LODs[itemID];
item3D = null;
updateBoundingBox(planData);
}
planData.sceneGraph.busyResources.layers[layerId].items[itemID] = false;
}
//TODO generate an area's replace if vertex has been changed
function addObject(modifiedPath, layer, planData, actions, sceneData, oldSceneData, catalog) {
if (modifiedPath.length === 5) {
let addPromise = null, addAction = null;
switch (modifiedPath[3]) {
case 'lines': addPromise = addLine; addAction = actions.linesActions; break;
case 'areas': addPromise = addArea; addAction = actions.areaActions; break;
case 'items': addPromise = addItem; addAction = actions.itemsActions; break;
case 'holes': addPromise = addHole; addAction = actions.holesActions; break;
}
if( addPromise ) addPromise( sceneData, planData, layer, modifiedPath[4], catalog, addAction ).then(() => updateBoundingBox(planData));
}
}
function addHole(sceneData, planData, layer, holeID, catalog, holesActions) {
let holeData = layer.getIn(['holes', holeID]);
// Create the hole object
return catalog.getElement(holeData.type).render3D(holeData, layer, sceneData).then(object => {
if (object instanceof Three.LOD) {
planData.sceneGraph.LODs[holeID] = object;
}
let pivot = new Three.Object3D();
pivot.name = 'pivot';
pivot.add(object);
let line = layer.getIn(['lines', holeData.line]);
// First of all I need to find the vertices of this line
let vertex0 = layer.vertices.get(line.vertices.get(0));
let vertex1 = layer.vertices.get(line.vertices.get(1));
let offset = holeData.offset;
if (vertex0.x > vertex1.x) {
let tmp = vertex0;
vertex0 = vertex1;
vertex1 = tmp;
offset = 1 - offset;
}
let distance = Math.sqrt(Math.pow(vertex0.x - vertex1.x, 2) + Math.pow(vertex0.y - vertex1.y, 2));
let alpha = Math.asin((vertex1.y - vertex0.y) / distance);
let boundingBox = new Three.Box3().setFromObject(pivot);
let center = [
(boundingBox.max.x - boundingBox.min.x) / 2 + boundingBox.min.x,
(boundingBox.max.y - boundingBox.min.y) / 2 + boundingBox.min.y,
(boundingBox.max.z - boundingBox.min.z) / 2 + boundingBox.min.z];
let holeAltitude = holeData.properties.getIn(['altitude', 'length']);
let holeHeight = holeData.properties.getIn(['height', 'length']);
pivot.rotation.y = alpha;
pivot.position.x = vertex0.x + distance * offset * Math.cos(alpha) - center[2] * Math.sin(alpha);
pivot.position.y = holeAltitude + holeHeight / 2 - center[1] + layer.altitude;
pivot.position.z = -vertex0.y - distance * offset * Math.sin(alpha) - center[2] * Math.cos(alpha);
planData.plan.add(pivot);
planData.sceneGraph.layers[layer.id].holes[holeData.id] = pivot;
applyInteract(pivot, () => {
return holesActions.selectHole(layer.id, holeData.id);
});
let opacity = layer.opacity;
if (holeData.selected) {
opacity = 1;
}
applyOpacity(pivot, opacity);
});
}
function updateHole(sceneData, oldSceneData, planData, layer, holeID, differences, catalog, holesActions, selfDestroy, selfBuild) {
let hole = layer.getIn(['holes', holeID]);
let oldHole = oldSceneData.getIn(['layers', layer.id, 'holes', holeID]);
let mesh = planData.sceneGraph.layers[layer.id].holes[holeID];
if (!mesh) return null;
return catalog.getElement(hole.type).updateRender3D(hole, layer, sceneData, mesh, oldHole, differences, selfDestroy, selfBuild);
}
function addLine(sceneData, planData, layer, lineID, catalog, linesActions) {
if (planData.sceneGraph.busyResources.layers[layer.id].lines[lineID]) {
setTimeout(() => addLine(sceneData, planData, layer, lineID, catalog, linesActions), 100);
return;
}
planData.sceneGraph.busyResources.layers[layer.id].lines[lineID] = true;
let line = layer.getIn(['lines', lineID]);
// First of all I need to find the vertices of this line
let vertex0 = layer.vertices.get(line.vertices.get(0));
let vertex1 = layer.vertices.get(line.vertices.get(1));
if (vertex0.x > vertex1.x) {
let tmp = vertex0;
vertex0 = vertex1;
vertex1 = tmp;
}
return catalog.getElement(line.type).render3D(line, layer, sceneData).then(line3D => {
if (line3D instanceof Three.LOD) {
planData.sceneGraph.LODs[line.id] = line3D;
}
let pivot = new Three.Object3D();
pivot.name = 'pivot';
pivot.add(line3D);
pivot.position.x = vertex0.x;
pivot.position.y = layer.altitude;
pivot.position.z = -vertex0.y;
planData.plan.add(pivot);
planData.sceneGraph.layers[layer.id].lines[lineID] = pivot;
applyInteract(pivot, () => {
return linesActions.selectLine(layer.id, line.id);
});
let opacity = layer.opacity;
if (line.selected) {
opacity = 1;
}
applyOpacity(pivot, opacity);
planData.sceneGraph.busyResources.layers[layer.id].lines[lineID] = false;
});
}
function updateLine(sceneData, oldSceneData, planData, layer, lineID, differences, catalog, linesActions, selfDestroy, selfBuild) {
let line = layer.getIn(['lines', lineID]);
let oldLine = oldSceneData.getIn(['layers', layer.id, 'lines', lineID]);
let mesh = planData.sceneGraph.layers[layer.id].lines[lineID];
if (!mesh) return null;
return catalog.getElement(line.type).updateRender3D(line, layer, sceneData, mesh, oldLine, differences, selfDestroy, selfBuild);
}
function addArea(sceneData, planData, layer, areaID, catalog, areaActions) {
if (planData.sceneGraph.busyResources.layers[layer.id].areas[areaID]) {
setTimeout(() => addArea(sceneData, planData, layer, areaID, catalog, areaActions), 100);
return;
}
planData.sceneGraph.busyResources.layers[layer.id].areas[areaID] = true;
let area = layer.getIn(['areas', areaID]);
let interactFunction = () => areaActions.selectArea(layer.id, areaID);
return catalog.getElement(area.type).render3D(area, layer, sceneData).then(area3D => {
if (area3D instanceof Three.LOD) {
planData.sceneGraph.LODs[areaID] = area3D;
}
let pivot = new Three.Object3D();
pivot.name = 'pivot';
pivot.add(area3D);
pivot.position.y = layer.altitude;
planData.plan.add(pivot);
planData.sceneGraph.layers[layer.id].areas[areaID] = pivot;
applyInteract(pivot, interactFunction);
let opacity = layer.opacity;
if (area.selected) {
opacity = 1;
}
applyOpacity(pivot, opacity);
planData.sceneGraph.busyResources.layers[layer.id].areas[areaID] = false;
});
}
function updateArea(sceneData, oldSceneData, planData, layer, areaID, differences, catalog, areaActions, selfDestroy, selfBuild) {
let area = layer.getIn(['areas', areaID]);
let oldArea = oldSceneData.getIn(['layers', layer.id, 'areas', areaID]);
let mesh = planData.sceneGraph.layers[layer.id].areas[areaID];
if (!mesh) return null;
return catalog.getElement(area.type).updateRender3D(area, layer, sceneData, mesh, oldArea, differences, selfDestroy, selfBuild);
}
function addItem(sceneData, planData, layer, itemID, catalog, itemsActions) {
let item = layer.getIn(['items', itemID]);
return catalog.getElement(item.type).render3D(item, layer, sceneData).then(item3D => {
if (item3D instanceof Three.LOD) {
planData.sceneGraph.LODs[itemID] = item3D;
}
let pivot = new Three.Object3D();
pivot.name = 'pivot';
pivot.add(item3D);
pivot.rotation.y = item.rotation * Math.PI / 180;
pivot.position.x = item.x;
pivot.position.y = layer.altitude;
pivot.position.z = -item.y;
applyInteract(item3D, () => {
itemsActions.selectItem(layer.id, item.id);
}
);
let opacity = layer.opacity;
if (item.selected) {
opacity = 1;
}
applyOpacity(pivot, opacity);
planData.plan.add(pivot);
planData.sceneGraph.layers[layer.id].items[item.id] = pivot;
});
}
function updateItem(sceneData, oldSceneData, planData, layer, itemID, differences, catalog, itemsActions, selfDestroy, selfBuild) {
let item = layer.getIn(['items', itemID]);
let oldItem = oldSceneData.getIn(['layers', layer.id, 'items', itemID]);
let mesh = planData.sceneGraph.layers[layer.id].items[itemID];
if (!mesh) return null;
return catalog.getElement(item.type).updateRender3D(item, layer, sceneData, mesh, oldItem, differences, selfDestroy, selfBuild);
}
// Apply interact function to children of an Object3D
function applyInteract(object, interactFunction) {
object.traverse((child) => {
if (child instanceof Three.Mesh) {
child.interact = interactFunction;
}
});
}
// Apply opacity to children of an Object3D
function applyOpacity(object, opacity) {
object.traverse((child) => {
if (child instanceof Three.Mesh) {
if (child.material instanceof Three.MultiMaterial) {
child.material.materials.forEach(materialChild => {
materialChild.transparent = true;
if (materialChild.maxOpacity) {
materialChild.opacity = Math.min(materialChild.maxOpacity, opacity);
} else if (materialChild.opacity && materialChild.opacity > opacity) {
materialChild.maxOpacity = materialChild.opacity;
materialChild.opacity = opacity;
}
});
} else if (child.material instanceof Array) {
child.material.forEach(material => {
material.transparent = true;
if (material.maxOpacity) {
material.opacity = Math.min(material.maxOpacity, opacity);
} else if (material.opacity && material.opacity > opacity) {
material.maxOpacity = material.opacity;
material.opacity = opacity;
}
});
} else {
child.material.transparent = true;
if (child.material.maxOpacity) {
child.material.opacity = Math.min(child.material.maxOpacity, opacity);
} else if (child.material.opacity && child.material.opacity > opacity) {
child.material.maxOpacity = child.material.opacity;
child.material.opacity = opacity;
}
}
}
});
}
function updateBoundingBox(planData) {
let newBoundingBox = new Three.Box3().setFromObject(planData.plan);
if (isFinite(newBoundingBox.max.x)
&& isFinite(newBoundingBox.min.x)
&& isFinite(newBoundingBox.max.y)
&& isFinite(newBoundingBox.min.y)
&& isFinite(newBoundingBox.max.z)
&& isFinite(newBoundingBox.min.z)) {
let newCenter = new Three.Vector3(
(newBoundingBox.max.x - newBoundingBox.min.x) / 2 + newBoundingBox.min.x,
(newBoundingBox.max.y - newBoundingBox.min.y) / 2 + newBoundingBox.min.y,
(newBoundingBox.max.z - newBoundingBox.min.z) / 2 + newBoundingBox.min.z
);
planData.plan.position.sub(newCenter);
planData.grid.position.sub(newCenter);
newBoundingBox.min.sub(newCenter);
newBoundingBox.max.sub(newCenter);
planData.boundingBox = newBoundingBox;
}
}
/**
* Filter the array of diffs
* @param diffArray
* @param sceneData
* @param oldSceneData
* @returns {Array}
*/
function filterDiffs(diffArray, sceneData, oldSceneData) {
return minimizeRemoveDiffsWhenSwitchingLayers(
minimizeChangePropertiesAfterSelectionsDiffs(
minimizeChangePropertiesDiffs(diffArray, sceneData, oldSceneData), sceneData, oldSceneData),
sceneData, oldSceneData);
}
/**
* Reduces the number of remove diffs when switching an hidden layer
* @param diffArray the array of the diffs
* @param sceneData
* @param oldSceneData
* @returns {Array}
*/
function minimizeRemoveDiffsWhenSwitchingLayers(diffArray, sceneData, oldSceneData) {
let foundDiff;
let i;
for (i = 0; i < diffArray.length && !foundDiff; i++) {
if (diffArray[i].path[1] === 'selectedLayer') {
foundDiff = diffArray[i];
}
}
if (foundDiff) {
if (!sceneData.getIn(['layers', oldSceneData.selectedLayer, 'visible'])) {
return diffArray.filter(({op, path}) => {
return (
!( path[ path.length - 1] === 'selected' && ( path[1] === 'layers' && path[2] === oldSceneData.selectedLayer )) &&
!(op === 'remove' && path.indexOf(oldSceneData.selectedLayer) !== -1)
);
});
}
}
return diffArray;
}
/**
* Reduces the number of change properties diffs for selected elements
* @param diffArray the array of the diffs
* @param sceneData
* @param oldSceneData
* @returns {Array}
*/
function minimizeChangePropertiesAfterSelectionsDiffs(diffArray, sceneData, oldSceneData) {
let idsFound = {};
diffArray.forEach( ({path}) => {
if (path[5] === 'selected') {
idsFound[path[4]] = path[4];
}
});
return diffArray.filter( ({path}) => {
if (path[5] === 'properties') {
return idsFound[path[4]] ? false : true;
}
return true;
});
}
/**
* Reduces the number of change properties diffs
* @param diffArray the array of the diffs
* @param sceneData
* @param oldSceneData
* @returns {Array}
*/
function minimizeChangePropertiesDiffs(diffArray, sceneData, oldSceneData) {
let idsFound = {};
return diffArray.filter( ({path}) => {
if (path[5] === 'properties') {
return idsFound[path[4]] ? false : (idsFound[path[4]] = true);
} else if (path[5] === 'misc') {
// Remove misc changes
return false;
}
return true;
});
}