|
|
@@ -17,20 +17,21 @@ interface RowScopedRule {
|
|
|
rowRange?: RowRange
|
|
|
}
|
|
|
|
|
|
+interface ColumnScopedRule {
|
|
|
+ startColumn: number
|
|
|
+ endColumn?: number
|
|
|
+}
|
|
|
+
|
|
|
interface LocalColumnAisleRule extends RowScopedRule {
|
|
|
afterColumn: number
|
|
|
gapCols: number
|
|
|
}
|
|
|
|
|
|
-interface LocalColumnShiftRule extends RowScopedRule {
|
|
|
- startColumn: number
|
|
|
- endColumn?: number
|
|
|
+interface LocalColumnShiftRule extends RowScopedRule, ColumnScopedRule {
|
|
|
shiftCols: number
|
|
|
}
|
|
|
|
|
|
-interface ManualColumnOffsetRule extends RowScopedRule {
|
|
|
- startColumn: number
|
|
|
- endColumn?: number
|
|
|
+interface ManualColumnOffsetRule extends RowScopedRule, ColumnScopedRule {
|
|
|
offsetCols: number
|
|
|
}
|
|
|
|
|
|
@@ -67,6 +68,52 @@ const scopedRowRange = <T extends object>(
|
|
|
rowRange: [start, end]
|
|
|
})
|
|
|
|
|
|
+const localColumnAisleRows = (rows: readonly number[], afterColumn: number, gapCols: number) =>
|
|
|
+ scopedRows(rows, {
|
|
|
+ afterColumn,
|
|
|
+ gapCols
|
|
|
+ })
|
|
|
+
|
|
|
+const localColumnAisleRange = (
|
|
|
+ startRow: number,
|
|
|
+ endRow: number,
|
|
|
+ afterColumn: number,
|
|
|
+ gapCols: number
|
|
|
+) =>
|
|
|
+ scopedRowRange(startRow, endRow, {
|
|
|
+ afterColumn,
|
|
|
+ gapCols
|
|
|
+ })
|
|
|
+
|
|
|
+const localColumnShiftRows = (
|
|
|
+ rows: readonly number[],
|
|
|
+ startColumn: number,
|
|
|
+ shiftCols: number,
|
|
|
+ endColumn?: number
|
|
|
+) =>
|
|
|
+ scopedRows(rows, {
|
|
|
+ startColumn,
|
|
|
+ endColumn,
|
|
|
+ shiftCols
|
|
|
+ })
|
|
|
+
|
|
|
+const manualColumnOffsetRows = (
|
|
|
+ rows: readonly number[],
|
|
|
+ startColumn: number,
|
|
|
+ offsetCols: number,
|
|
|
+ endColumn?: number
|
|
|
+) =>
|
|
|
+ scopedRows(rows, {
|
|
|
+ startColumn,
|
|
|
+ endColumn,
|
|
|
+ offsetCols
|
|
|
+ })
|
|
|
+
|
|
|
+const columnCompactionRows = (rows: readonly number[], startColumn: number) =>
|
|
|
+ scopedRows(rows, {
|
|
|
+ startColumn
|
|
|
+ })
|
|
|
+
|
|
|
const globalColumnAisle = (
|
|
|
breakpoint: number,
|
|
|
options: Omit<GlobalColumnAisleRule, 'breakpoint'> = {}
|
|
|
@@ -75,6 +122,11 @@ const globalColumnAisle = (
|
|
|
...options
|
|
|
})
|
|
|
|
|
|
+const FIRST_FLOOR_ROWS_6_AND_13 = [6, 13] as const
|
|
|
+const FIRST_FLOOR_ROWS_8_AND_11 = [8, 11] as const
|
|
|
+const FIRST_FLOOR_ROWS_9_AND_10 = [9, 10] as const
|
|
|
+const FIRST_FLOOR_ROWS_7 = [7] as const
|
|
|
+
|
|
|
const FIRST_FLOOR_ROW_AISLE_BREAKPOINTS = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22] as const
|
|
|
|
|
|
const FIRST_FLOOR_GLOBAL_COLUMN_AISLES = [
|
|
|
@@ -88,84 +140,32 @@ const FIRST_FLOOR_GLOBAL_COLUMN_AISLES = [
|
|
|
] as const
|
|
|
|
|
|
const FIRST_FLOOR_LOCAL_COLUMN_AISLES = [
|
|
|
- scopedRowRange(0, 7, {
|
|
|
- afterColumn: 7,
|
|
|
- gapCols: 1
|
|
|
- }),
|
|
|
- scopedRowRange(12, 22, {
|
|
|
- afterColumn: 7,
|
|
|
- gapCols: 1
|
|
|
- }),
|
|
|
- scopedRows([9, 10], {
|
|
|
- afterColumn: 6,
|
|
|
- gapCols: 3
|
|
|
- }),
|
|
|
- scopedRows([9, 10], {
|
|
|
- afterColumn: 10,
|
|
|
- gapCols: 1
|
|
|
- }),
|
|
|
- scopedRows([8, 11], {
|
|
|
- afterColumn: 13,
|
|
|
- gapCols: 1
|
|
|
- }),
|
|
|
- scopedRows([9, 10], {
|
|
|
- afterColumn: 20,
|
|
|
- gapCols: 1
|
|
|
- }),
|
|
|
- scopedRows([8, 11], {
|
|
|
- afterColumn: 26,
|
|
|
- gapCols: 1
|
|
|
- }),
|
|
|
- scopedRows([9, 10], {
|
|
|
- afterColumn: 14,
|
|
|
- gapCols: 3
|
|
|
- })
|
|
|
+ localColumnAisleRange(0, 7, 7, 1),
|
|
|
+ localColumnAisleRange(12, 22, 7, 1),
|
|
|
+ localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 6, 3),
|
|
|
+ localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 10, 1),
|
|
|
+ localColumnAisleRows(FIRST_FLOOR_ROWS_8_AND_11, 13, 1),
|
|
|
+ localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 20, 1),
|
|
|
+ localColumnAisleRows(FIRST_FLOOR_ROWS_8_AND_11, 26, 1),
|
|
|
+ localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 14, 3)
|
|
|
] as const
|
|
|
|
|
|
const FIRST_FLOOR_LOCAL_COLUMN_SHIFTS = [
|
|
|
- scopedRows([6, 13], {
|
|
|
- startColumn: 0,
|
|
|
- shiftCols: 1
|
|
|
- }),
|
|
|
- scopedRows([8, 11], {
|
|
|
- startColumn: 8,
|
|
|
- shiftCols: 1
|
|
|
- }),
|
|
|
- scopedRows([6, 13], {
|
|
|
- startColumn: 5,
|
|
|
- shiftCols: 1
|
|
|
- }),
|
|
|
- scopedRows([6, 13], {
|
|
|
- startColumn: 11,
|
|
|
- shiftCols: 1
|
|
|
- }),
|
|
|
- scopedRows([6, 13], {
|
|
|
- startColumn: 17,
|
|
|
- shiftCols: 1
|
|
|
- }),
|
|
|
- scopedRows([7], {
|
|
|
- startColumn: 20,
|
|
|
- shiftCols: 1
|
|
|
- })
|
|
|
+ localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 0, 1),
|
|
|
+ localColumnShiftRows(FIRST_FLOOR_ROWS_8_AND_11, 8, 1),
|
|
|
+ localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 5, 1),
|
|
|
+ localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 11, 1),
|
|
|
+ localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 17, 1),
|
|
|
+ localColumnShiftRows(FIRST_FLOOR_ROWS_7, 20, 1)
|
|
|
] as const
|
|
|
|
|
|
const FIRST_FLOOR_MANUAL_COLUMN_OFFSETS = [
|
|
|
- scopedRows([8, 11], {
|
|
|
- startColumn: 13,
|
|
|
- endColumn: 17,
|
|
|
- offsetCols: -1
|
|
|
- }),
|
|
|
- scopedRows([8, 11], {
|
|
|
- startColumn: 18,
|
|
|
- endColumn: 18,
|
|
|
- offsetCols: -1
|
|
|
- })
|
|
|
+ manualColumnOffsetRows(FIRST_FLOOR_ROWS_8_AND_11, 13, -1, 17),
|
|
|
+ manualColumnOffsetRows(FIRST_FLOOR_ROWS_8_AND_11, 18, -1, 18)
|
|
|
] as const
|
|
|
|
|
|
const FIRST_FLOOR_COLUMN_COMPACTIONS = [
|
|
|
- scopedRows([9, 10], {
|
|
|
- startColumn: 11
|
|
|
- })
|
|
|
+ columnCompactionRows(FIRST_FLOOR_ROWS_9_AND_10, 11)
|
|
|
] as const
|
|
|
|
|
|
const FIRST_FLOOR_RULE_SET: WarehouseLayoutRuleSet = {
|
|
|
@@ -230,27 +230,26 @@ const sumLocalColumnShiftOffsets = (
|
|
|
parsedLocation: WarehouseLayoutParsedLocation,
|
|
|
rules: readonly LocalColumnShiftRule[]
|
|
|
) =>
|
|
|
- rules.reduce((total, rule) => {
|
|
|
- const matchedColumn = parsedLocation.x >= rule.startColumn
|
|
|
- && (rule.endColumn === undefined || parsedLocation.x <= rule.endColumn)
|
|
|
-
|
|
|
- if (matchesRowScope(parsedLocation.y, rule) && matchedColumn) {
|
|
|
- return total + rule.shiftCols
|
|
|
- }
|
|
|
-
|
|
|
- return total
|
|
|
- }, 0)
|
|
|
+ sumColumnScopedRuleValues(parsedLocation, rules, (rule) => rule.shiftCols)
|
|
|
|
|
|
const sumManualColumnOffsets = (
|
|
|
parsedLocation: WarehouseLayoutParsedLocation,
|
|
|
rules: readonly ManualColumnOffsetRule[]
|
|
|
) =>
|
|
|
- rules.reduce((total, rule) => {
|
|
|
- const matchedColumn = parsedLocation.x >= rule.startColumn
|
|
|
- && (rule.endColumn === undefined || parsedLocation.x <= rule.endColumn)
|
|
|
+ sumColumnScopedRuleValues(parsedLocation, rules, (rule) => rule.offsetCols)
|
|
|
+
|
|
|
+const matchesColumnScope = (column: number, rule: ColumnScopedRule) => {
|
|
|
+ return column >= rule.startColumn && (rule.endColumn === undefined || column <= rule.endColumn)
|
|
|
+}
|
|
|
|
|
|
- if (matchesRowScope(parsedLocation.y, rule) && matchedColumn) {
|
|
|
- return total + rule.offsetCols
|
|
|
+const sumColumnScopedRuleValues = <TRule extends RowScopedRule & ColumnScopedRule>(
|
|
|
+ parsedLocation: WarehouseLayoutParsedLocation,
|
|
|
+ rules: readonly TRule[],
|
|
|
+ getValue: (rule: TRule) => number
|
|
|
+) =>
|
|
|
+ rules.reduce((total, rule) => {
|
|
|
+ if (matchesRowScope(parsedLocation.y, rule) && matchesColumnScope(parsedLocation.x, rule)) {
|
|
|
+ return total + getValue(rule)
|
|
|
}
|
|
|
|
|
|
return total
|
|
|
@@ -302,6 +301,7 @@ const applyRuleSet = (
|
|
|
parsedLocation: WarehouseLayoutParsedLocation,
|
|
|
ruleSet: WarehouseLayoutRuleSet
|
|
|
) => {
|
|
|
+ // 保持现有语义顺序:先结构性位移与过道,再单点修正,最后做链式补位。
|
|
|
const gridColOffset =
|
|
|
getBaseGridColOffset(parsedLocation, ruleSet) +
|
|
|
sumManualColumnOffsets(parsedLocation, ruleSet.manualColumnOffsets) +
|