import memoize from 'memoizee'; import { Vector } from '@doodle3d/cal'; import { SHAPE_CACHE_LIMIT } from '../constants/general.js'; import ImageShape from '../d2/ImageShape.js'; import Shape from '../d2/Shape.js'; import { applyMatrixOnPath } from '../utils/vectorUtils.js'; export function shapeChanged(oldShapeData, newShapeData) { const pointsChanged = oldShapeData.points !== newShapeData.points; const holesChanged = oldShapeData.holes !== newShapeData.holes; const rectSizeChanged = oldShapeData.rectSize !== newShapeData.rectSize; const triangleSizeChanged = oldShapeData.triangleSize !== newShapeData.triangleSize; const circleChanged = oldShapeData.circle !== newShapeData.circle; const starChanged = oldShapeData.star !== newShapeData.star; const textChanged = oldShapeData.text !== newShapeData.text; const polyPoints = oldShapeData.polyPoints !== newShapeData.polyPoints; const fillChanged = oldShapeData.fill !== newShapeData.fill; const heartChanged = oldShapeData.heart !== newShapeData.heart; return pointsChanged || holesChanged || rectSizeChanged || triangleSizeChanged || circleChanged || starChanged || textChanged || polyPoints || fillChanged || heartChanged; } export const getPointsBounds = memoize(getPointsBoundsRaw, { max: SHAPE_CACHE_LIMIT }); export function getPointsBoundsRaw(compoundPaths, transform) { let points = compoundPaths.reduce((a, { points: b }) => a.concat(b), []); if (transform !== undefined) { points = applyMatrixOnPath(points, transform); } const min = new Vector( Math.min(...points.map((point) => point.x)), Math.min(...points.map((point) => point.y)) ); const max = new Vector( Math.max(...points.map((point) => point.x)), Math.max(...points.map((point) => point.y)) ); return { min, max }; } export function getPointsCenter(points) { const { min, max } = getPointsBounds(points); return min.add(max).scale(0.5); } export function isClosed(shapeData) { switch (shapeData.type) { case 'RECT': case 'TRIANGLE': case 'STAR': case 'CIRCLE': case 'CIRCLE_SEGMENT': case 'COMPOUND_PATH': return true; default: return false; } } export const shapeDataToShape = memoize(shapeDataToShapeRaw, { max: SHAPE_CACHE_LIMIT }); // export const shapeDataToShape = shapeDataToShapeRaw; function shapeDataToShapeRaw(shapeData) { if (shapeData.type === 'IMAGE_GUIDE') { return new ImageShape(shapeData); } else { return new Shape(shapeData); } } // TODO can maybe be memoized export const determineActiveShape = (state) => { const selectedObjects = state.selection.objects.map(({ id }) => id); const activeShapes = {}; for (const id in state.objectsById) { if (state.d2.activeShape === id) { activeShapes[id] = true; continue; } activeShapes[id] = state.d2.transform.active && selectedObjects.includes(id); } return activeShapes; };