diff --git a/B08_Quantity/B08_Quantity_Engine_HaulInputs.py b/B08_Quantity/B08_Quantity_Engine_HaulInputs.py index 5c8e3045..03e03d35 100644 --- a/B08_Quantity/B08_Quantity_Engine_HaulInputs.py +++ b/B08_Quantity/B08_Quantity_Engine_HaulInputs.py @@ -41,6 +41,23 @@ VOLUME_BASIS_KEY = "volume_basis" VOLUME_BASIS_NATURAL = "natural" SPOIL_COMPONENT = "잔토처리" +COLLECTED_STONE_COMPONENT = "채집석" + +#: 채집석 공제를 **갈래별로** 낸다 (2026-09-09 세 창 확정 — 축을 맞추기로). +#: ⚠ 이 값은 **벽 입적(제자리 완성 부피)**이다 — 자연·다짐 어느 축으로도 환산한 적 없다. +#: 굳이 가르면 자연 축 쪽이라 받는 쪽이 **×C 로 다짐 축에 맞춰** 뺀다. +#: ⚠⚠ **벽 입적과 원바닥 암 부피의 관계를 정한 원문이 없다** — 캐면 부풀고(L) 벽에 쌓으면 +#: 공극이 생기는데 그 값이 품셈·교본·지식DB 어디에도 없다. **실무 시트도 그냥 뺀다** +#: (울진 「채집석 −274.66」이 사토에서 바로 빠진다). 그 가정은 어느 쪽으로 가도 남으므로 +#: **가정은 그대로 두고 축만 맞춘다** — 축이 다른 값을 그냥 빼는 것은 우리가 만드는 어긋남이다. +#: ⚠ 갈래를 모르는 구조물 몫은 **환산하지 않는다**(계수가 없다) — 따로 낸다. +COLLECTED_STONE_BY_GROUND_KEY = "collected_stone_by_ground_m3" +COLLECTED_STONE_UNKNOWN_KEY = "collected_stone_ground_unknown_m3" +COLLECTED_STONE_BASIS_NOTE = ( + "벽 입적(제자리 부피) — 자연 축으로 보고 받는 쪽이 ×C 로 다짐 축에 맞춰 뺌." + " ⚠ 벽 입적과 원바닥 암 부피의 관계를 정한 원문이 없음(캐면 부풀고 쌓으면 공극이 생기나" + " 그 값이 어디에도 없음). 실무 시트는 그냥 뺌 — 우리는 축만 맞춤" +) def _center(structure: dict[str, Any]) -> float | None: @@ -59,18 +76,33 @@ def haul_inputs(unit_quantity_table: dict[str, Any] | None) -> dict[str, Any]: if not unit_quantity_table: return { COLLECTED_STONE_KEY: None, + COLLECTED_STONE_BY_GROUND_KEY: {}, + COLLECTED_STONE_UNKNOWN_KEY: None, STRUCTURE_SPOIL_KEY: None, STRUCTURE_SPOIL_POINTS_KEY: [], VOLUME_BASIS_KEY: VOLUME_BASIS_NATURAL, } total = 0.0 points: list[dict[str, Any]] = [] + stone_by_ground: dict[str, float] = {} + stone_unknown = 0.0 for structure in unit_quantity_table.get("structures") or []: amount = 0.0 + stone = 0.0 for component in structure.get("components") or []: - if str(component.get("name") or "") != SPOIL_COMPONENT: + name = str(component.get("name") or "") + if name == COLLECTED_STONE_COMPONENT: + stone += float(component.get("amount") or 0.0) + if name != SPOIL_COMPONENT: continue amount += float(component.get("amount") or 0.0) + # 채집석 — 그 구조물의 지반 갈래로 담는다. 갈래를 못 가른 구조물 몫은 따로 둔다. + if stone > 0: + ground = str(structure.get("ground_type") or "") + if ground: + stone_by_ground[ground] = stone_by_ground.get(ground, 0.0) + stone + else: + stone_unknown += stone if amount <= 0: continue total += amount @@ -92,6 +124,11 @@ def haul_inputs(unit_quantity_table: dict[str, Any] | None) -> dict[str, Any]: collected = unit_quantity_table.get(COLLECTED_STONE_KEY) return { COLLECTED_STONE_KEY: collected, + COLLECTED_STONE_BY_GROUND_KEY: { + key: round(value, 3) for key, value in sorted(stone_by_ground.items()) + }, + COLLECTED_STONE_UNKNOWN_KEY: round(stone_unknown, 3) if stone_unknown else 0.0, + "collected_stone_basis": COLLECTED_STONE_BASIS_NOTE, STRUCTURE_SPOIL_KEY: round(total, 3) if points or total else None, STRUCTURE_SPOIL_POINTS_KEY: sorted(points, key=lambda row: row["chainage_m"]), # 총량에도 상태를 적는다 — 측점값을 안 쓰는 쪽도 상태를 알아야 한다.