You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:39:18