React实现多块玻璃大板上小片最优排布的方法
多板材玻璃排样跨板自动放置实现问题
现有功能基础
- 已实现单块大板材上的小玻璃零件最优排布:所有待排布玻璃小片按高度从大到小排序后,从左到右依次放置
- 多块大板材场景下,已完成所有大板的状态统一维护
需求说明
需要实现逻辑:当第一块大板上没有适合放置待新增小片的位置时,自动在第二块(及后续)大板上查询匹配可用区域完成放置。当前编写的实现代码如下(文件index.js):
import React, { useContext, useEffect, useRef, useState } from 'react' import data from '../data' import Graph from './graph/graph' import SmallAreaGraph from './graph/small-area-graph'; import { IndexContext } from './IndexContext'; function Index() { var height = 50; var width = 50; const [defaultHeight, setDefaultHeight] = useState(50); const [defaultWidth, setDefaultWidth] = useState(50); const [planes, setPlanes] = useState(); const [testState, setTestState] = useState([]); const [bigBoard, setBigBoard] = useState(new Array(defaultWidth).fill(0).map(() => new Array(defaultHeight).fill(0))); const [smallPlanes, setSmallPlanes] = useState([]); const [smallPlanesArea, setSmallPlanesArea] = useState([]); const [freeSpaceAreas, setFreeSpaceAreas] = useState([]); const [bigPlanes, setBigPlanes] = useState([{ bigBoard: bigBoard, planes: [], height: defaultHeight, width: defaultWidth, color: "pink" }]); var totalWidth; const heightRef = useRef(); const widthRef = useRef(); var smallPlane, totalArea = 0; function Placement() { let total = 0; let totalHeight = 0; let allArea = []; for (let i = 0; i < smallPlanes.length; i++) { if (i === 0) { smallPlanes[i].x = 1; } else { if (allArea !== []) { } else { total = total + smallPlanes[i - 1].width + 2; totalHeight = totalHeight + smallPlanes[i - 1].height + 2; allArea.push(smallPlanes[i - 1]); } if (total + smallPlanes[i].width > Number(width)) { total = 0; allArea.push(smallPlanes[i]); smallPlanes[i].x = 1; smallPlanes[i].y = allArea[0].height + 2; return total } else { smallPlanes[i].x = total; } } } } function Sort() { let gecici; for (let i = 0; i <= testState.length - 1; i++) { for (let j = i; j <= testState.length; j++) { // 注:将比较符号从>(大于)改为<(小于)即可实现从大到小排序 if (testState[i]?.height < testState[j]?.height) { gecici = testState[j]; testState[j] = testState[i]; testState[i] = gecici; setTestState(testState); } } } // Placement(); } useEffect(() => { if (testState !== [] || testState !== undefined) { Sort(); } }, [testState]); function AddBigPlane() { setBigPlanes([...bigPlanes, { bigBoard: bigBoard, planes: [], height: defaultHeight, width: defaultWidth, color: "pink" }]) } function Revaluation(w, h, row, col, k) { totalWidth = totalWidth + Number(w); if (Number(col + w) <= bigPlanes[k].bigBoard.length) { if (Number(row + h) <= bigPlanes[k].bigBoard[row].length) { for (let i = row; i < Number(row + h); i++) { for (let j = col; j < Number(col + w); j++) { let bashData = bigPlanes[k]; bashData.bigBoard[i][j] = 1 setBigPlanes(bashData); } } } } } function test(w, h, row, col, index) { if (Number(row + w) <= bigPlanes[index].width && Number(col + h) <= bigPlanes[index].height) { for (let i = row; i < Number(row + w); i++) { for (let j = col; j < Number(col + h); j++) { if (bigPlanes[index].bigBoard[i][j] === 0) { if (i === (Number(row + w) - 1) && j === (Number(col + h) - 1)) { freeSpaceAreas[index] = freeSpaceAreas[index] - smallPlane; setFreeSpaceAreas([...freeSpaceAreas]); setTestState([...testState, { height: Number(heightRef?.current?.value), width: Number(widthRef?.current?.value) }]) } } } } } } function Control(index) { // 查找第一个值为0的单元格对应行列坐标 console.log(index); for (let row = 0; row < bigPlanes[index].bigBoard.length; row++) { for (let col = 0; col < bigPlanes[index].bigBoard[row].length; col++) { if (bigPlanes[index].bigBoard[row][col] === 0) { // 找到坐标后传入空间校验函数 return test(Number(widthRef.current.value), Number(heightRef.current.value), row, col, index); } } } } useEffect(() => { if (bigPlanes.length !== freeSpaceAreas.length) { for (let i = 0; i < bigPlanes.length; i++) { console.log(bigPlanes); setFreeSpaceAreas([...freeSpaceAreas, bigPlanes[i].width * bigPlanes[i].height]) } } }, [bigPlanes]); function AreaControl() { console.log("空间校验启动"); for (let i = 0; i < freeSpaceAreas.length; i++) { if (smallPlane <= freeSpaceAreas[i]) { console.log(i); return Control(i); } } heightRef.current.value = ""; widthRef.current.value = ""; } function handleKeyDown(e) { if (e.key === "Enter") { if (heightRef?.current.value !== "") { if (widthRef.current.value !== "") { smallPlane = Number(heightRef?.current.value) * Number(widthRef?.current.value); AreaControl(); } else { alert("请输入宽度值"); } } else { alert("请输入高度值"); } } } useEffect(() => { console.log(freeSpaceAreas); }, [freeSpaceAreas]); function AddAreas() { // 实时更新数组状态 setPlanes([...smallPlanes]); ResetSmallPlane(); ResetBigPlane(); for (let i = 0; i < testState.length; i++) { findCoords(testState[i]) } } var totalWidth = 0, totalHeight = 0, totW = 0, totH = 0; function ResetBigPlane() { for (let k = 0; k < bigPlanes.length; k++) { for (let row = 0; row < bigPlanes[k].bigBoard.length; row++) { for (let col = 0; col < bigPlanes[k].bigBoard[row].length; col++) { if (bigPlanes[k].bigBoard[row][col] === 1) { let bashData = bigPlanes; bashData[k].bigBoard[row][col] = 0 setBigPlanes(bashData); } } } } } function bigPlanesControl() { for (let i = 0; i < bigPlanes.length; i++) { } } function ResetSmallPlane() { let arrAttributes = []; for (let i = 0; i < bigPlanes.length; i++) { var arr = bigPlanes[i].planes; arr.length = 0; arrAttributes.push(arr); } setBigPlanes([...arrAttributes]); } function createCoords(w, h, row, col, i) { let bashData = []; totW = totW + Number(w); if (Number(col + w) <= bigPlanes[i].width) { if (Number(row + h) <= bigPlanes[i].height) { bashData = bigPlanes; bashData[i].planes.push({ height: h, width: w, x: col + 1, y: row + 1 }); setBigPlanes([...bashData]); } else { return; } } else { return; } } function findCoords(test) { console.log(test); for (let k = 0; k < bigPlanes.length; k++) { for (let row = 0; row < bigPlanes[k].bigBoard.length; row++) { for (let col = 0; col < bigPlanes[k].bigBoard[row].length; col++) { if (bigPlanes[k].bigBoard[row][col] === 0) { Revaluation(test.width, test.height, row, col, k); if (Number(bigPlanes[k].bigBoard[row].length - col) >= test.width) { return createCoords(test.width, test.height, row, col, k); } else return; } } } } } function Approve() { ResetSmallPlane(); ResetBigPlane(); for (let i = 0; i < testState.length; i++) { findCoords(testState[i]) } } return ( <div className='container mt-5'> <div className='big-plane'> </div> <div className='d-flex justify-content-between '> <div></div> <div className='d-flex'> <div className='me-4'> <input className='input form-control ' type="text" ref={heightRef} placeholder="输入高度.." onKeyUp={handleKeyDown} /> </div> <div className='me-4'> <input className='input form-control ' type="text" ref={widthRef} placeholder="输入宽度.." onKeyUp={handleKeyDown} /> </div> <div className='btn btn-success' onClick={() => Approve()}> 确认 </div> <div className='btn btn-success' onClick={() => AddAreas()}> 添加 </div> </div> <div className='btn btn-danger d-flex align-items-center'> <div onClick={() => AddBigPlane()}>添加玻璃板材</div> <b style={{ fontWeight: "bolder", fontSize: "20px", marginLeft: "5px" }}>+</b> </div> </div> { testState?.length ? testState.map((plane, i) => { return <SmallAreaGraph color="purple" key={i} data={data} height={Number(plane.height)} width={Number(plane.width)} /> }) : "" } <div className='mt-5'> {/* 大板渲染区域 */} { bigPlanes.length ? bigPlanes.map((plane, i) => { totalWidth = totalWidth + bigPlanes[i].width; return <Graph smallPlanesProps={plane.planes} data={plane.bigBoard} key={i} color={plane.color} height={plane.height} width={plane.width} x={0} y={0} position="absolute" zIndex="-10" left={totalWidth} /> } ) : "" } </div> </div> ) } export default Index
内容的提问来源于stack exchange,提问作者sumeyyeyeg
相关产品推荐
相关产品推荐

