2017-11-14 15:27:48 +01:00
|
|
|
import * as THREE from 'three';
|
2017-11-14 15:32:48 +01:00
|
|
|
import { shapeToPoints, getPointsBounds } from '../shape/DataUtils.js'
|
2017-11-14 15:27:48 +01:00
|
|
|
import { Vector } from 'cal';
|
|
|
|
import arrayMemoizer from './arrayMemoizer.js';
|
|
|
|
import memoize from 'memoizee';
|
|
|
|
// import createDebug from 'debug';
|
|
|
|
// const debug = createDebug('d3d:util:selection');
|
|
|
|
|
|
|
|
// Memoized selector that returns the same array of shapeSata's when
|
|
|
|
// - the selection array didn't change
|
|
|
|
// - the objects in the resulting array didn't change
|
|
|
|
// enables memoization of utils that use this array
|
|
|
|
export const getSelectedObjectsSelector = arrayMemoizer(getSelectedObjects);
|
|
|
|
// export const getSelectedObjectsSelector = getSelectedObjects;
|
|
|
|
function getSelectedObjects(selectedObjects, objectsById) {
|
|
|
|
return selectedObjects.map(({ id }) => objectsById[id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the boundingbox of (multiple) shape data's
|
|
|
|
* This generally can by two types of boundingboxes.
|
|
|
|
* 1) The boundingbox of the shapes without the selection transformations (rotation, scale etc).
|
|
|
|
* Requires a selectionTransform matrix.
|
|
|
|
* This is used to display the transformations that are applied to a selection,
|
|
|
|
* showing a for example rotated boundingbox.
|
|
|
|
* Views like the 2D SelectionView will place it over the selection
|
|
|
|
* by applying the selection transformations (translating it to Objects Container Space).
|
|
|
|
* 2) The boundingbox of the shapes with the selection transformations.
|
|
|
|
* This is used to get the axis-aligned bounding box of shapes, this is
|
|
|
|
* usually used to contain the shapes within the drawing area.
|
|
|
|
*/
|
|
|
|
export const getBoundingBox = memoize(getBoundingBoxRaw, { max: 1 });
|
|
|
|
// export const getBoundingBox = getBoundingBoxRaw;
|
|
|
|
function getBoundingBoxRaw(shapeDatas, selectionTransform) {
|
|
|
|
if (selectionTransform !== undefined) {
|
|
|
|
// To show a rectangle / box around the selection that has the
|
|
|
|
// selection transforms (rotation, scale) of the selection we first have to
|
|
|
|
// remove the selection transforms so we can get the boundingbox of
|
|
|
|
// all the selected shapes as if they where not transformed yet.
|
|
|
|
// We do this by multiplying it by the inverse of the selection transforms.
|
|
|
|
// In the case of one shape the selection transforms equals it's own
|
|
|
|
// transform, but in the case of multiple shapes this only contains the
|
|
|
|
// transformations since the last selection change.
|
|
|
|
const selectionTransformInverse = selectionTransform.inverseMatrix();
|
|
|
|
shapeDatas = shapeDatas.map(shapeData => ({
|
|
|
|
...shapeData,
|
|
|
|
transform: shapeData.transform.multiplyMatrix(selectionTransformInverse)
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
let minX = Infinity;
|
|
|
|
let minY = Infinity;
|
|
|
|
let maxX = -Infinity;
|
|
|
|
let maxY = -Infinity;
|
|
|
|
let minZ = Infinity;
|
|
|
|
let maxZ = -Infinity;
|
|
|
|
for (const shapeData of shapeDatas) {
|
|
|
|
const compoundPath = shapeToPoints(shapeData);
|
|
|
|
const { min, max } = getPointsBounds(compoundPath, shapeData.transform);
|
|
|
|
minX = (min.x < minX) ? min.x : minX;
|
|
|
|
minY = (min.y < minY) ? min.y : minY;
|
|
|
|
maxX = (max.x > maxX) ? max.x : maxX;
|
|
|
|
maxY = (max.y > maxY) ? max.y : maxY;
|
|
|
|
|
|
|
|
const { z, height } = shapeData;
|
|
|
|
minZ = (z < minZ) ? z : minZ;
|
|
|
|
maxZ = (z + height > maxZ) ? z + height : maxZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
const min = new THREE.Vector3(minX, minZ, minY);
|
|
|
|
const max = new THREE.Vector3(maxX, maxZ, maxY);
|
|
|
|
const center = new Vector(minX, minY).add(new Vector(maxX, maxY)).scale(0.5);
|
|
|
|
|
|
|
|
return { min, max, center };
|
|
|
|
}
|