于杰
2025-08-13 91e1d5b820bd39b6d6c97349facda304ec317606
完善余料计算代码,修复余料部分重叠计算的问题
1个文件已修改
227 ■■■■■ 已修改文件
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue
@@ -648,11 +648,11 @@
  adjustGrayRectangles(layoutIndex);
};
const mergeAdjacentGrayRects = (glassDetails,totalWidth,totalHeight) => {
const mergeAdjacentGrayRects = (glassDetails, totalWidth, totalHeight) => {
  const grayRects = glassDetails.filter(r => r.isRemain);
  const grayRects2 = glassDetails.filter(r => r.isRemain);
  let merged = [];
  const nonGrayRects = glassDetails.filter(r => !r.isRemain);
  // 按坐标排序,优先按x坐标,其次按y坐标
  grayRects.sort((a, b) => {
    if (a.x !== b.x) return a.x - b.x;
    return a.y - b.y;
@@ -660,30 +660,31 @@
  if (grayRects.length === 0) return;
  merged.push({ ...grayRects[0] });
  const merged = [];
  // 从第一个矩形开始
  let current = { ...grayRects[0] };
  // 遍历所有余料矩形进行合并
  for (let i = 1; i < grayRects.length; i++) {
      const last = merged[merged.length-1];
      const current = grayRects[i];
    const next = grayRects[i];
    if (current.x === last.x + last.width &&
        current.y === last.y &&
        current.height === last.height) {
      last.width += current.width;
      last.x = Math.round(last.x);
      last.y = Math.round(last.y);
      last.width = Math.round(last.width);
      last.height = Math.round(last.height);
    } else if (current.y === last.y + last.height &&
               current.x === last.x &&
               current.width === last.width) {
      last.height += current.height;
      last.x = Math.round(last.x);
      last.y = Math.round(last.y);
      last.width = Math.round(last.width);
      last.height = Math.round(last.height);
    } else {
    // 检查是否可以水平合并(同一行,高度相同,相邻)
    if (current.y === next.y &&
        current.height === next.height &&
        current.x + current.width === next.x) {
      // 水平合并
      current.width += next.width;
    }
    // 检查是否可以垂直合并(同一列,宽度相同,相邻)
    else if (current.x === next.x &&
        current.width === next.width &&
        current.y + current.height === next.y) {
      // 垂直合并
      current.height += next.height;
    }
    else {
      // 无法合并,保存当前矩形,开始新的合并
      merged.push({
        x: Math.round(current.x),
        y: Math.round(current.y),
@@ -691,54 +692,100 @@
        height: Math.round(current.height),
        isRemain: true
      });
      current = { ...next };
    }
  }
  const nonGray = glassDetails.filter(r => !r.isRemain);
  //删除原数组拼接新的小片跟余料
  glassDetails.splice(0, glassDetails.length, ...nonGray, ...merged);
  // 重新构建数组:非余料 + 合并后的余料
  glassDetails.splice(0, glassDetails.length, ...nonGrayRects, ...merged);
};
// 确保返回的区域不重叠
const calculateRemainingAreas = (totalWidth, totalHeight, obstacles) => {
  // 从整个原片开始
  let remaining = [{ x: 0, y: 0, width: totalWidth, height: totalHeight }];
  // 逐个处理障碍物(已放置的玻璃片)
  obstacles.forEach(obstacle => {
    remaining = cutRemainingAreas(remaining, obstacle, totalWidth, totalHeight);
  });
  // 对结果进行排序,确保一致性
  remaining.sort((a, b) => {
    if (a.x !== b.x) return a.x - b.x;
    return a.y - b.y;
  });
  return remaining;
};
// 调整后重新计算灰色余料
const adjustGrayRectangles = (layoutIndex) => {
  const layout = layouts.value[layoutIndex];
  const glassDetails = layout.glassDetails;
  //小片的数据
  // 1. 筛选出非余料的玻璃片(即实际要切割的玻璃片)
  const nonGrayRects = glassDetails.filter(glassDetail => !glassDetail.isRemain);
  //所有的小片余料坐标跟尺寸
  // 2. 计算剩余可用区域
  let remainingAreas = calculateRemainingAreas(layout.width, layout.height, nonGrayRects);
  const uniqueArr = Array.from(
      new Set(remainingAreas.map(item => JSON.stringify(item)))
  ).map(item => JSON.parse(item));
  //余料的数据
  // 3. 去重处理 - 更严格的去重逻辑
  const uniqueArr = removeDuplicateAreas(remainingAreas);
  // 4. 获取当前已存在的余料矩形(需要保留引用以便更新)
  const currentGrayRects = glassDetails.filter(r => r.isRemain);
  //循环余料数据跟全部的对比
  currentGrayRects.forEach((_, index) => {
    if (index >= remainingAreas.length) {
      glassDetails.splice(index, 1);
    }
  // 5. 清除所有现有的余料矩形
  // 先收集非余料矩形
  const nonRemainRects = glassDetails.filter(r => !r.isRemain);
  // 6. 重新构建玻璃详情数组
  // 保留非余料矩形
  const newGlassDetails = [...nonRemainRects];
  // 添加新的余料矩形
  uniqueArr.forEach((area) => {
    newGlassDetails.push({
      x: Math.round(area.x),
      y: Math.round(area.y),
      width: Math.round(area.width),
      height: Math.round(area.height),
      isRemain: true
    });
  });
  uniqueArr.forEach((area, index) => {
    if (index < currentGrayRects.length) {
      currentGrayRects[index].x = Math.round(area.x);
      currentGrayRects[index].y = Math.round(area.y);
      currentGrayRects[index].width = Math.round(area.width);
      currentGrayRects[index].height = Math.round(area.height);
    } else {
      glassDetails.push({
        x: Math.round(area.x),
        y: Math.round(area.y),
        width: Math.round(area.width),
        height: Math.round(area.height),
        isRemain: true
      });
    }
  });
  // 7. 更新布局的玻璃详情
  layout.glassDetails = newGlassDetails;
  mergeAdjacentGrayRects(glassDetails,layout.width, layout.height);
  // 8. 合并相邻的余料矩形
  mergeAdjacentGrayRects(layout.glassDetails, layout.width, layout.height);
};
const removeDuplicateAreas = (areas) => {
  const result = [];
  areas.forEach(area => {
    // 检查是否与已存在的区域重叠或相等
    const isDuplicate = result.some(existingArea => {
      return (
          existingArea.x === area.x &&
          existingArea.y === area.y &&
          existingArea.width === area.width &&
          existingArea.height === area.height
      );
    });
    if (!isDuplicate) {
      result.push(area);
    }
  });
  return result;
};
//旋转方法
const rotateRect = (layoutIndex, rectIndex) => {
@@ -882,19 +929,24 @@
};
//重新计算余料坐标以及尺寸1
const calculateRemainingAreas = (totalWidth, totalHeight, obstacles) => {
  let remaining = [{ x: 0, y: 0, width: totalWidth, height: totalHeight }];
  obstacles.forEach(glassDetail => {
    remaining = cutRemainingAreas(remaining, glassDetail,totalWidth,totalHeight);
  });
  return remaining;
};
// const calculateRemainingAreas = (totalWidth, totalHeight, obstacles) => {
//   let remaining = [{ x: 0, y: 0, width: totalWidth, height: totalHeight }];
//   obstacles.forEach(glassDetail => {
//     remaining = cutRemainingAreas(remaining, glassDetail,totalWidth,totalHeight);
//   });
//   return remaining;
// };
//重新计算余料坐标以及尺寸2
const cutRemainingAreas = (remainingAreas, obstacle,totalWidth,totalHeight) => {
const cutRemainingAreas = (remainingAreas, obstacle, totalWidth, totalHeight) => {
  const newRemaining = [];
  remainingAreas.forEach(area => {
    // 如果障碍物与当前区域有重叠
    if (checkOverlap(area, obstacle)) {
      // 切分当前区域为最多4个新区域
      // 左侧区域
      if (obstacle.x > area.x) {
        newRemaining.push({
          x: area.x,
@@ -903,35 +955,50 @@
          height: area.height
        });
      }
      // 右侧区域
      if (obstacle.x + obstacle.width < area.x + area.width) {
        newRemaining.push({
          x: obstacle.x + obstacle.width,
          y: area.y,
          width: area.width - (obstacle.x + obstacle.width - area.x),
          width: area.x + area.width - (obstacle.x + obstacle.width),
          height: area.height
        });
      }
      if (obstacle.y > area.y) {
        newRemaining.push({
          x: area.x,
          y: area.y,
          width: area.width,
          height: obstacle.y - area.y
        });
      }
      if (obstacle.y + obstacle.height < area.y + area.height ) {
          newRemaining.push({
            x: area.x,
            y: obstacle.y + obstacle.height,
            width: area.width,
            height: area.height - (obstacle.y + obstacle.height - area.y)
          });
      // 上方区域(仅在障碍物左右边界之间的区域)
      if (obstacle.y > area.y) {
        const startX = Math.max(area.x, obstacle.x);
        const endX = Math.min(area.x + area.width, obstacle.x + obstacle.width);
        if (endX > startX) {
          newRemaining.push({
            x: startX,
            y: area.y,
            width: endX - startX,
            height: obstacle.y - area.y
          });
        }
      }
      // 下方区域(仅在障碍物左右边界之间的区域)
      if (obstacle.y + obstacle.height < area.y + area.height) {
        const startX = Math.max(area.x, obstacle.x);
        const endX = Math.min(area.x + area.width, obstacle.x + obstacle.width);
        if (endX > startX) {
          newRemaining.push({
            x: startX,
            y: obstacle.y + obstacle.height,
            width: endX - startX,
            height: area.y + area.height - (obstacle.y + obstacle.height)
          });
        }
      }
    } else {
      // 没有重叠,保留原区域
      newRemaining.push(area);
    }
  });
  return newRemaining;
};