import { PPTElement } from '@/types/slides' // 获取矩形旋转后在画布中的位置范围 interface RotatedElementData { left: number; top: number; width: number; height: number; rotate: number; } export const getRectRotatedRange = (element: RotatedElementData) => { const { left, top, width, height, rotate = 0 } = element const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2 const auxiliaryAngle = Math.atan(height / width) * 180 / Math.PI const tlbraRadian = (180 - rotate - auxiliaryAngle) * Math.PI / 180 const trblaRadian = (auxiliaryAngle - rotate) * Math.PI / 180 const halfWidth = width / 2 const halfHeight = height / 2 const middleLeft = left + halfWidth const middleTop = top + halfHeight const xAxis = [ middleLeft + radius * Math.cos(tlbraRadian), middleLeft + radius * Math.cos(trblaRadian), middleLeft - radius * Math.cos(tlbraRadian), middleLeft - radius * Math.cos(trblaRadian), ] const yAxis = [ middleTop - radius * Math.sin(tlbraRadian), middleTop - radius * Math.sin(trblaRadian), middleTop + radius * Math.sin(tlbraRadian), middleTop + radius * Math.sin(trblaRadian), ] return { xRange: [Math.min(...xAxis), Math.max(...xAxis)], yRange: [Math.min(...yAxis), Math.max(...yAxis)], } } // 获取元素在画布中的位置范围 export const getElementRange = (element: PPTElement) => { let minX, maxX, minY, maxY if (element.type === 'line') { minX = element.left maxX = element.left + Math.max(element.start[0], element.end[0]) minY = element.top maxY = element.top + Math.max(element.start[1], element.end[1]) } else if ('rotate' in element && element.rotate) { const { left, top, width, height, rotate } = element const { xRange, yRange } = getRectRotatedRange({ left, top, width, height, rotate }) minX = xRange[0] maxX = xRange[1] minY = yRange[0] maxY = yRange[1] } else { minX = element.left maxX = element.left + element.width minY = element.top maxY = element.top + element.height } return { minX, maxX, minY, maxY } } // 获取元素集合在画布中的位置范围 export const getElementListRange = (elementList: PPTElement[]) => { const leftValues: number[] = [] const topValues: number[] = [] const rightValues: number[] = [] const bottomValues: number[] = [] elementList.forEach(element => { const { minX, maxX, minY, maxY } = getElementRange(element) leftValues.push(minX) topValues.push(minY) rightValues.push(maxX) bottomValues.push(maxY) }) const minX = Math.min(...leftValues) const maxX = Math.max(...rightValues) const minY = Math.min(...topValues) const maxY = Math.max(...bottomValues) return { minX, maxX, minY, maxY } } export interface AlignLine { value: number; range: [number, number]; } // 对齐参考线去重,对于相同位置的多条参考线,取长度范围的最小值和最大值,并基于此范围将多条参考线合并为一条 export const uniqAlignLines = (lines: AlignLine[]) => { const uniqLines: AlignLine[] = [] lines.forEach(line => { const index = uniqLines.findIndex(_line => _line.value === line.value) if (index === -1) uniqLines.push(line) else { const uniqLine = uniqLines[index] const rangeMin = Math.min(uniqLine.range[0], line.range[0]) const rangeMax = Math.max(uniqLine.range[1], line.range[1]) const range: [number, number] = [rangeMin, rangeMax] const _line = { value: line.value, range } uniqLines[index] = _line } }) return uniqLines }