fix(b06): 묻힌 관 유출 흙막이 벽 모서리 절토 · 3도 끝 연결선 겹침 제거 — 설계선 접힘 해소(186-1)
- 검증_랩탑메인 No.14+12.22 관 유출 흙막이가 원지반 아래 → 91-4 벽 모서리 절토와 139-4 끝 연결선이 함께 이어져 설계선이 되접힘 - 유출 끝 연결선이 있으면 벽 모서리 절토를 잇지 않음(카드 · 서버 면적 · B07 · 3D 같은 기하) - 사본 재현 시험 test_186_1 · 픽스처 b06_186_1_pipe_292 · 91 헬퍼 시작점 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
This commit is contained in:
@@ -601,8 +601,11 @@ export function computeCulvertLayout(
|
||||
// 접점을 다시 깨뜨리지 않는다 — 종전 어긋남의 직접 원인이 이 순서였다.
|
||||
const slopeOf = (wall: WallLayout): FillSlopeSegment =>
|
||||
fillSlopeOf(wall, wall.role === "inlet" ? inletInfo.edge : outletInfo.edge);
|
||||
// 유출 끝 연결선(139-4)이 있으면 벽 모서리 절토(91-4)를 또 잇지 않음 — 설계선이 접힘(186-1)
|
||||
const outletTail = drawnFillPoints(extrasForArea, true).length > 0;
|
||||
for (const wall of walls) {
|
||||
const slope = withBackCut(slopeOf(wall), wall, section.design, groundAt, !culvert.hidden_pipe);
|
||||
const backCut = !culvert.hidden_pipe && !outletTail;
|
||||
const slope = withBackCut(slopeOf(wall), wall, section.design, groundAt, backCut);
|
||||
// 사면선은 노견부터 우리가 그림 — 트림을 노견까지 당겨 백엔드 설계선 성토 구간을 통째로 덮음
|
||||
if (wall.outward > 0) {
|
||||
trimMax = slope.points[0].offset;
|
||||
|
||||
@@ -0,0 +1,917 @@
|
||||
{
|
||||
"source": "검증_랩탑메인(226fc805) route 282 · No.14+12.22 관(파형강관 D800 · 유입 L형 집수정 · 유출 흙막이 돌쌓기(찰) H1.3) · 저장 design 그대로(유출 d 9.0)",
|
||||
"cross_sections": [
|
||||
{
|
||||
"station_id": "station_000000292220",
|
||||
"chainage_m": 292.22,
|
||||
"label": "STA.0+292.220",
|
||||
"kind": "irregular",
|
||||
"center_x": 208535.186869,
|
||||
"center_y": 367765.719131,
|
||||
"center_z": 860.254154,
|
||||
"azimuth_deg": 134.945611,
|
||||
"plan_radius_m": null,
|
||||
"curve_outer_side": "left",
|
||||
"curve_widening_m": 2.033,
|
||||
"uphill_side": "right",
|
||||
"structure": "파형강관 D800",
|
||||
"samples": [
|
||||
{
|
||||
"offset_m": -20.0,
|
||||
"elevation_m": 875.942681,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -19.5,
|
||||
"elevation_m": 875.563445,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -19.0,
|
||||
"elevation_m": 875.223804,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -18.5,
|
||||
"elevation_m": 874.839366,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -18.0,
|
||||
"elevation_m": 874.373517,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -17.5,
|
||||
"elevation_m": 873.834699,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -17.0,
|
||||
"elevation_m": 873.328076,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -16.5,
|
||||
"elevation_m": 873.003181,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -16.0,
|
||||
"elevation_m": 872.868685,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -15.5,
|
||||
"elevation_m": 872.700062,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -15.0,
|
||||
"elevation_m": 872.492793,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -14.5,
|
||||
"elevation_m": 872.264882,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -14.0,
|
||||
"elevation_m": 871.921377,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -13.5,
|
||||
"elevation_m": 871.449263,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -13.0,
|
||||
"elevation_m": 871.050131,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -12.5,
|
||||
"elevation_m": 870.664549,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -12.0,
|
||||
"elevation_m": 870.348929,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -11.5,
|
||||
"elevation_m": 869.897268,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -11.0,
|
||||
"elevation_m": 869.481532,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -10.5,
|
||||
"elevation_m": 869.031119,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -10.0,
|
||||
"elevation_m": 868.558707,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -9.5,
|
||||
"elevation_m": 868.123739,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -9.0,
|
||||
"elevation_m": 867.798147,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -8.5,
|
||||
"elevation_m": 867.489499,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -8.0,
|
||||
"elevation_m": 867.256843,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -7.5,
|
||||
"elevation_m": 867.081439,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -7.0,
|
||||
"elevation_m": 866.940587,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -6.5,
|
||||
"elevation_m": 866.550692,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -6.0,
|
||||
"elevation_m": 865.812117,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -5.5,
|
||||
"elevation_m": 864.812694,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -5.0,
|
||||
"elevation_m": 864.211627,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -4.5,
|
||||
"elevation_m": 863.993389,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -4.0,
|
||||
"elevation_m": 863.791331,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -3.5,
|
||||
"elevation_m": 863.6089,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -3.0,
|
||||
"elevation_m": 863.47762,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -2.5,
|
||||
"elevation_m": 863.178131,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -2.0,
|
||||
"elevation_m": 862.70616,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -1.5,
|
||||
"elevation_m": 862.084857,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -1.0,
|
||||
"elevation_m": 861.397999,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": -0.5,
|
||||
"elevation_m": 860.781491,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 0.0,
|
||||
"elevation_m": 860.254154,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 0.5,
|
||||
"elevation_m": 860.008424,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 1.0,
|
||||
"elevation_m": 859.743024,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 1.5,
|
||||
"elevation_m": 859.431951,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 2.0,
|
||||
"elevation_m": 859.169405,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 2.5,
|
||||
"elevation_m": 858.865535,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 3.0,
|
||||
"elevation_m": 858.524512,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 3.5,
|
||||
"elevation_m": 858.164126,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 4.0,
|
||||
"elevation_m": 857.818061,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 4.5,
|
||||
"elevation_m": 857.442262,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 5.0,
|
||||
"elevation_m": 857.021062,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 5.5,
|
||||
"elevation_m": 856.664537,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 6.0,
|
||||
"elevation_m": 856.388529,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 6.5,
|
||||
"elevation_m": 856.164636,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 7.0,
|
||||
"elevation_m": 855.840671,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 7.5,
|
||||
"elevation_m": 855.415507,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 8.0,
|
||||
"elevation_m": 855.15202,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 8.5,
|
||||
"elevation_m": 854.88336,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 9.0,
|
||||
"elevation_m": 854.52968,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 9.5,
|
||||
"elevation_m": 854.210706,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 10.0,
|
||||
"elevation_m": 853.936088,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 10.5,
|
||||
"elevation_m": 853.667609,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 11.0,
|
||||
"elevation_m": 853.315257,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 11.5,
|
||||
"elevation_m": 852.962466,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 12.0,
|
||||
"elevation_m": 852.592563,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 12.5,
|
||||
"elevation_m": 852.365461,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 13.0,
|
||||
"elevation_m": 852.241766,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 13.5,
|
||||
"elevation_m": 852.168603,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 14.0,
|
||||
"elevation_m": 852.137894,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 14.5,
|
||||
"elevation_m": 852.122192,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 15.0,
|
||||
"elevation_m": 852.082728,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 15.5,
|
||||
"elevation_m": 851.581695,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 16.0,
|
||||
"elevation_m": 850.702327,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 16.5,
|
||||
"elevation_m": 849.751282,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 17.0,
|
||||
"elevation_m": 849.271151,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 17.5,
|
||||
"elevation_m": 849.023418,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 18.0,
|
||||
"elevation_m": 848.775996,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 18.5,
|
||||
"elevation_m": 848.584444,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 19.0,
|
||||
"elevation_m": 848.552501,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 19.5,
|
||||
"elevation_m": 848.524788,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"offset_m": 20.0,
|
||||
"elevation_m": 848.338541,
|
||||
"valid": true
|
||||
}
|
||||
],
|
||||
"culvert": {
|
||||
"type": "pipe",
|
||||
"pipe_kind": "파형강관",
|
||||
"diameter_m": 0.8,
|
||||
"min_cover_m": 0.5,
|
||||
"foundation": null,
|
||||
"inlet": {
|
||||
"role": "inlet",
|
||||
"structure": "집수정",
|
||||
"basin_length_m": 2.0,
|
||||
"basin_before_m": 1.0,
|
||||
"basin_after_m": 1.0,
|
||||
"basin_height_m": 1.3,
|
||||
"basin_form": "L"
|
||||
},
|
||||
"outlet": {
|
||||
"role": "outlet",
|
||||
"structure": "기슭막이",
|
||||
"revet_form": "돌쌓기(찰)",
|
||||
"revet_height_m": 1.3,
|
||||
"revet_length_m": 10.0,
|
||||
"revet_before_m": 5.0,
|
||||
"revet_after_m": 5.0,
|
||||
"face_slope": 0.3
|
||||
},
|
||||
"chainage_m": 292.22
|
||||
},
|
||||
"design": {
|
||||
"ground_type": "ripping_rock",
|
||||
"geometry_preset": "rock",
|
||||
"section_mode": "both_cut",
|
||||
"ditch_side": "right",
|
||||
"ditch_type": "standard",
|
||||
"cut_slope_ratio": 0.4,
|
||||
"soil_cut_slope_ratio": 1.0,
|
||||
"two_stage_slope": true,
|
||||
"fill_slope_ratio": 1.2,
|
||||
"roadbed_width_m": 6.0,
|
||||
"carriageway_width_m": 5.0,
|
||||
"carriageway_standard_width_m": 3.0,
|
||||
"widening_left_m": 2.0,
|
||||
"widening_right_m": 0.0,
|
||||
"cross_slope_pct": 3.0,
|
||||
"ditch": {
|
||||
"type": "standard",
|
||||
"top_width_m": 0.9,
|
||||
"bottom_width_m": 0.3,
|
||||
"depth_m": 0.3
|
||||
},
|
||||
"ditch_enabled": true,
|
||||
"ditch_choice": null,
|
||||
"paved": false,
|
||||
"road_edges": {
|
||||
"left": {
|
||||
"offset_m": 4.0,
|
||||
"elevation_m": 857.4906
|
||||
},
|
||||
"right": {
|
||||
"offset_m": -2.0,
|
||||
"elevation_m": 857.3106
|
||||
}
|
||||
},
|
||||
"carriageway_edges": {
|
||||
"left": {
|
||||
"offset_m": 3.5,
|
||||
"elevation_m": 857.4756
|
||||
},
|
||||
"right": {
|
||||
"offset_m": -1.5,
|
||||
"elevation_m": 857.3256
|
||||
}
|
||||
},
|
||||
"design_elevation_m": 857.3706,
|
||||
"cut_area_m2": 27.9382,
|
||||
"cut_soil_area_m2": 8.3598,
|
||||
"cut_rock_area_m2": 19.5784,
|
||||
"cut_rock_kind": "ripping_rock",
|
||||
"fill_area_m2": 0.3364,
|
||||
"spoil_fill_area_m2": 0.0,
|
||||
"spoil_fill_side": null,
|
||||
"spoil_fill_width_m": 0.0,
|
||||
"spoil_fill_max_width_m": 0.0,
|
||||
"spoil_fill_line": [],
|
||||
"spoil_fill_unclosed": false,
|
||||
"spoil_fill_replaced_fill_m2": 0.0,
|
||||
"bench_cut_length_m": 0.0,
|
||||
"slope_unclosed": false,
|
||||
"fill_ground_slope": null,
|
||||
"ditch_area_m2": 0.18,
|
||||
"ditch_soil_area_m2": 0.0,
|
||||
"ditch_rock_area_m2": 0.18,
|
||||
"ditch_split_basis": "rock_boundary",
|
||||
"design_line": [
|
||||
{
|
||||
"offset_m": -20.0,
|
||||
"elevation_m": 875.9427
|
||||
},
|
||||
{
|
||||
"offset_m": -19.5,
|
||||
"elevation_m": 875.5634
|
||||
},
|
||||
{
|
||||
"offset_m": -19.0,
|
||||
"elevation_m": 875.2238
|
||||
},
|
||||
{
|
||||
"offset_m": -18.5,
|
||||
"elevation_m": 874.8394
|
||||
},
|
||||
{
|
||||
"offset_m": -18.0,
|
||||
"elevation_m": 874.3735
|
||||
},
|
||||
{
|
||||
"offset_m": -17.5,
|
||||
"elevation_m": 873.8347
|
||||
},
|
||||
{
|
||||
"offset_m": -17.0,
|
||||
"elevation_m": 873.3281
|
||||
},
|
||||
{
|
||||
"offset_m": -16.5,
|
||||
"elevation_m": 873.0032
|
||||
},
|
||||
{
|
||||
"offset_m": -16.0,
|
||||
"elevation_m": 872.8687
|
||||
},
|
||||
{
|
||||
"offset_m": -15.5,
|
||||
"elevation_m": 872.7001
|
||||
},
|
||||
{
|
||||
"offset_m": -15.0,
|
||||
"elevation_m": 872.4928
|
||||
},
|
||||
{
|
||||
"offset_m": -14.5,
|
||||
"elevation_m": 872.2649
|
||||
},
|
||||
{
|
||||
"offset_m": -14.0,
|
||||
"elevation_m": 871.9214
|
||||
},
|
||||
{
|
||||
"offset_m": -13.5,
|
||||
"elevation_m": 871.4493
|
||||
},
|
||||
{
|
||||
"offset_m": -13.0,
|
||||
"elevation_m": 871.0501
|
||||
},
|
||||
{
|
||||
"offset_m": -12.5,
|
||||
"elevation_m": 870.6645
|
||||
},
|
||||
{
|
||||
"offset_m": -12.0,
|
||||
"elevation_m": 870.3489
|
||||
},
|
||||
{
|
||||
"offset_m": -11.5,
|
||||
"elevation_m": 869.8973
|
||||
},
|
||||
{
|
||||
"offset_m": -11.0,
|
||||
"elevation_m": 869.4815
|
||||
},
|
||||
{
|
||||
"offset_m": -10.5,
|
||||
"elevation_m": 869.0311
|
||||
},
|
||||
{
|
||||
"offset_m": -10.0,
|
||||
"elevation_m": 868.5587
|
||||
},
|
||||
{
|
||||
"offset_m": -9.5,
|
||||
"elevation_m": 868.1237
|
||||
},
|
||||
{
|
||||
"offset_m": -9.0,
|
||||
"elevation_m": 867.7981
|
||||
},
|
||||
{
|
||||
"offset_m": -8.5,
|
||||
"elevation_m": 867.4895
|
||||
},
|
||||
{
|
||||
"offset_m": -8.0,
|
||||
"elevation_m": 867.2568
|
||||
},
|
||||
{
|
||||
"offset_m": -7.75,
|
||||
"elevation_m": 867.1691
|
||||
},
|
||||
{
|
||||
"offset_m": -7.5,
|
||||
"elevation_m": 866.9294
|
||||
},
|
||||
{
|
||||
"offset_m": -7.0,
|
||||
"elevation_m": 866.4294
|
||||
},
|
||||
{
|
||||
"offset_m": -6.5,
|
||||
"elevation_m": 865.9294
|
||||
},
|
||||
{
|
||||
"offset_m": -6.2459,
|
||||
"elevation_m": 865.6753
|
||||
},
|
||||
{
|
||||
"offset_m": -6.0,
|
||||
"elevation_m": 865.0606
|
||||
},
|
||||
{
|
||||
"offset_m": -5.5,
|
||||
"elevation_m": 863.8106
|
||||
},
|
||||
{
|
||||
"offset_m": -5.0,
|
||||
"elevation_m": 862.5606
|
||||
},
|
||||
{
|
||||
"offset_m": -4.5,
|
||||
"elevation_m": 861.3106
|
||||
},
|
||||
{
|
||||
"offset_m": -4.0,
|
||||
"elevation_m": 860.0606
|
||||
},
|
||||
{
|
||||
"offset_m": -3.5,
|
||||
"elevation_m": 858.8106
|
||||
},
|
||||
{
|
||||
"offset_m": -3.0,
|
||||
"elevation_m": 857.5606
|
||||
},
|
||||
{
|
||||
"offset_m": -2.9,
|
||||
"elevation_m": 857.3106
|
||||
},
|
||||
{
|
||||
"offset_m": -2.6,
|
||||
"elevation_m": 857.0106
|
||||
},
|
||||
{
|
||||
"offset_m": -2.5,
|
||||
"elevation_m": 857.0106
|
||||
},
|
||||
{
|
||||
"offset_m": -2.3,
|
||||
"elevation_m": 857.0106
|
||||
},
|
||||
{
|
||||
"offset_m": -2.0,
|
||||
"elevation_m": 857.3106
|
||||
},
|
||||
{
|
||||
"offset_m": -1.5,
|
||||
"elevation_m": 857.3256
|
||||
},
|
||||
{
|
||||
"offset_m": -1.0,
|
||||
"elevation_m": 857.3406
|
||||
},
|
||||
{
|
||||
"offset_m": -0.5,
|
||||
"elevation_m": 857.3556
|
||||
},
|
||||
{
|
||||
"offset_m": 0.0,
|
||||
"elevation_m": 857.3706
|
||||
},
|
||||
{
|
||||
"offset_m": 0.5,
|
||||
"elevation_m": 857.3856
|
||||
},
|
||||
{
|
||||
"offset_m": 1.0,
|
||||
"elevation_m": 857.4006
|
||||
},
|
||||
{
|
||||
"offset_m": 1.5,
|
||||
"elevation_m": 857.4156
|
||||
},
|
||||
{
|
||||
"offset_m": 2.0,
|
||||
"elevation_m": 857.4306
|
||||
},
|
||||
{
|
||||
"offset_m": 2.5,
|
||||
"elevation_m": 857.4456
|
||||
},
|
||||
{
|
||||
"offset_m": 3.0,
|
||||
"elevation_m": 857.4606
|
||||
},
|
||||
{
|
||||
"offset_m": 3.5,
|
||||
"elevation_m": 857.4756
|
||||
},
|
||||
{
|
||||
"offset_m": 4.0,
|
||||
"elevation_m": 857.4906
|
||||
},
|
||||
{
|
||||
"offset_m": 4.2,
|
||||
"elevation_m": 857.6677
|
||||
},
|
||||
{
|
||||
"offset_m": 4.5,
|
||||
"elevation_m": 857.4423
|
||||
},
|
||||
{
|
||||
"offset_m": 5.0,
|
||||
"elevation_m": 857.0211
|
||||
},
|
||||
{
|
||||
"offset_m": 5.5,
|
||||
"elevation_m": 856.6645
|
||||
},
|
||||
{
|
||||
"offset_m": 6.0,
|
||||
"elevation_m": 856.3885
|
||||
},
|
||||
{
|
||||
"offset_m": 6.5,
|
||||
"elevation_m": 856.1646
|
||||
},
|
||||
{
|
||||
"offset_m": 7.0,
|
||||
"elevation_m": 855.8407
|
||||
},
|
||||
{
|
||||
"offset_m": 7.5,
|
||||
"elevation_m": 855.4155
|
||||
},
|
||||
{
|
||||
"offset_m": 8.0,
|
||||
"elevation_m": 855.152
|
||||
},
|
||||
{
|
||||
"offset_m": 8.5,
|
||||
"elevation_m": 854.8834
|
||||
},
|
||||
{
|
||||
"offset_m": 9.0,
|
||||
"elevation_m": 854.5297
|
||||
},
|
||||
{
|
||||
"offset_m": 9.5,
|
||||
"elevation_m": 854.2107
|
||||
},
|
||||
{
|
||||
"offset_m": 10.0,
|
||||
"elevation_m": 853.9361
|
||||
},
|
||||
{
|
||||
"offset_m": 10.5,
|
||||
"elevation_m": 853.6676
|
||||
},
|
||||
{
|
||||
"offset_m": 11.0,
|
||||
"elevation_m": 853.3153
|
||||
},
|
||||
{
|
||||
"offset_m": 11.5,
|
||||
"elevation_m": 852.9625
|
||||
},
|
||||
{
|
||||
"offset_m": 12.0,
|
||||
"elevation_m": 852.5926
|
||||
},
|
||||
{
|
||||
"offset_m": 12.5,
|
||||
"elevation_m": 852.3655
|
||||
},
|
||||
{
|
||||
"offset_m": 13.0,
|
||||
"elevation_m": 852.2418
|
||||
},
|
||||
{
|
||||
"offset_m": 13.5,
|
||||
"elevation_m": 852.1686
|
||||
},
|
||||
{
|
||||
"offset_m": 14.0,
|
||||
"elevation_m": 852.1379
|
||||
},
|
||||
{
|
||||
"offset_m": 14.5,
|
||||
"elevation_m": 852.1222
|
||||
},
|
||||
{
|
||||
"offset_m": 15.0,
|
||||
"elevation_m": 852.0827
|
||||
},
|
||||
{
|
||||
"offset_m": 15.5,
|
||||
"elevation_m": 851.5817
|
||||
},
|
||||
{
|
||||
"offset_m": 16.0,
|
||||
"elevation_m": 850.7023
|
||||
},
|
||||
{
|
||||
"offset_m": 16.5,
|
||||
"elevation_m": 849.7513
|
||||
},
|
||||
{
|
||||
"offset_m": 17.0,
|
||||
"elevation_m": 849.2712
|
||||
},
|
||||
{
|
||||
"offset_m": 17.5,
|
||||
"elevation_m": 849.0234
|
||||
},
|
||||
{
|
||||
"offset_m": 18.0,
|
||||
"elevation_m": 848.776
|
||||
},
|
||||
{
|
||||
"offset_m": 18.5,
|
||||
"elevation_m": 848.5844
|
||||
},
|
||||
{
|
||||
"offset_m": 19.0,
|
||||
"elevation_m": 848.5525
|
||||
},
|
||||
{
|
||||
"offset_m": 19.5,
|
||||
"elevation_m": 848.5248
|
||||
},
|
||||
{
|
||||
"offset_m": 20.0,
|
||||
"elevation_m": 848.3385
|
||||
}
|
||||
],
|
||||
"cut_slope_segments": [
|
||||
{
|
||||
"side": "left",
|
||||
"ratio": 1.0,
|
||||
"rise_m": 0.2,
|
||||
"run_m": 0.2,
|
||||
"start_offset_m": 4.0,
|
||||
"end_offset_m": 4.2,
|
||||
"material": "soil"
|
||||
},
|
||||
{
|
||||
"side": "right",
|
||||
"ratio": 0.4,
|
||||
"rise_m": 8.3647,
|
||||
"run_m": 3.3459,
|
||||
"start_offset_m": -2.9,
|
||||
"end_offset_m": -6.2459,
|
||||
"material": "rock"
|
||||
},
|
||||
{
|
||||
"side": "right",
|
||||
"ratio": 1.0,
|
||||
"rise_m": 1.5041,
|
||||
"run_m": 1.5041,
|
||||
"start_offset_m": -6.2459,
|
||||
"end_offset_m": -7.75,
|
||||
"material": "soil"
|
||||
}
|
||||
],
|
||||
"rock_boundary_offset_m": -0.5,
|
||||
"status": "provisional",
|
||||
"pavement_suggested": false,
|
||||
"revet_adjust": {
|
||||
"outlet": {
|
||||
"x": 0.0,
|
||||
"d": 9.0,
|
||||
"h": null,
|
||||
"m": null
|
||||
}
|
||||
},
|
||||
"pipe_length_m": 18.0,
|
||||
"pipe_slope_pct": 42.0261,
|
||||
"extra_walls": [],
|
||||
"wall_fill_overlap": {
|
||||
"outlet": 0
|
||||
},
|
||||
"inlet_basin": "L"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/* 186-1 묻힌 관 유출 벽 설계선 접힘 헬퍼 — 화면 TS 를 그 자리에서 트랜스파일해 Node 로 돌림.
|
||||
* 입력 = 검증_랩탑메인 No.14+12.22 사본(`fixtures/b06_186_1_pipe_292.json`) · 73-4 픽스처 관 340(절토 쪽 유출).
|
||||
* 결과 = 표준출력 JSON 한 벌. 짝 = `test_186_1_outlet_fold.py`.
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
const cache = new Map();
|
||||
// 화면 전용 모듈(토스트) — 기하 계산엔 안 쓰임
|
||||
const STUBS = {
|
||||
"@ui/ui_template_toast": { showToast: () => undefined },
|
||||
};
|
||||
|
||||
function loadTs(file) {
|
||||
const full = path.resolve(file);
|
||||
if (cache.has(full)) return cache.get(full);
|
||||
if (full.endsWith(".json")) {
|
||||
const data = JSON.parse(fs.readFileSync(full, "utf8"));
|
||||
cache.set(full, data);
|
||||
return data;
|
||||
}
|
||||
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
||||
compilerOptions: {
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
target: ts.ScriptTarget.ES2020,
|
||||
esModuleInterop: true,
|
||||
},
|
||||
}).outputText;
|
||||
const box = { exports: {} };
|
||||
cache.set(full, box.exports);
|
||||
const localRequire = (request) => {
|
||||
if (STUBS[request]) return STUBS[request];
|
||||
const alias = { "@util/": "common_util", "@ui/": "ui_template", "@config/": "config" };
|
||||
for (const [prefix, dir] of Object.entries(alias))
|
||||
if (request.startsWith(prefix))
|
||||
return loadTs(resolve(path.join(ROOT, dir, request.slice(prefix.length))));
|
||||
return loadTs(resolve(path.join(path.dirname(full), request)));
|
||||
};
|
||||
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
||||
cache.set(full, box.exports);
|
||||
return box.exports;
|
||||
}
|
||||
const resolve = (base) =>
|
||||
[base, `${base}.ts`, path.join(base, "index.ts")].find(
|
||||
(p) => fs.existsSync(p) && fs.statSync(p).isFile(),
|
||||
) ?? `${base}.ts`;
|
||||
|
||||
const B06 = (f) => path.join(ROOT, "B06_Section", f);
|
||||
const { computeStoredLayouts, structureAreaRows } = loadTs(B06("B06_Section_Structure_Layouts.ts"));
|
||||
const { computeCulvertLayout } = loadTs(B06("B06_Section_UI_Cross_Culvert_Geom.ts"));
|
||||
const read = (name) =>
|
||||
JSON.parse(fs.readFileSync(path.join(__dirname, "fixtures", name), "utf8")).cross_sections;
|
||||
const clone = (v) => JSON.parse(JSON.stringify(v));
|
||||
const r2 = (v) => Math.round(v * 100) / 100;
|
||||
|
||||
/** 유출 쪽 설계선(트림 사면) 점열 · 유출 벽 · 면적 행. */
|
||||
function study(sections, target) {
|
||||
const section = sections.find((s) => Math.abs(s.chainage_m - target) < 0.01);
|
||||
const { culvert } = computeStoredLayouts(section, sections);
|
||||
const wall = culvert.walls.find((w) => w.role === "outlet");
|
||||
const trim = culvert.designTrim;
|
||||
const slope = (wall.outward > 0 ? trim.maxSlope : trim.minSlope).points;
|
||||
const row = structureAreaRows(sections).find((r) => Math.abs(r.chainage_m - target) < 0.01);
|
||||
return {
|
||||
outward: wall.outward,
|
||||
wallTop: r2(wall.topJoint.elevation),
|
||||
groundAtWall: r2(groundOf(section, wall.topJoint.offset)),
|
||||
offsets: slope.map((p) => r2(p.offset)),
|
||||
elevations: slope.map((p) => r2(p.elevation)),
|
||||
cut: row ? row.cut_area_m2 : null,
|
||||
fill: row ? row.fill_area_m2 : null,
|
||||
};
|
||||
}
|
||||
function groundOf(section, offset) {
|
||||
const s = section.samples;
|
||||
for (let i = 1; i < s.length; i += 1)
|
||||
if (s[i].offset_m >= offset) {
|
||||
const t = (offset - s[i - 1].offset_m) / (s[i].offset_m - s[i - 1].offset_m);
|
||||
return s[i - 1].elevation_m + (s[i].elevation_m - s[i - 1].elevation_m) * t;
|
||||
}
|
||||
return NaN;
|
||||
}
|
||||
|
||||
const out = {};
|
||||
// ① 저장값 그대로(유출 d 9.0) · ② 자동 자리(조작값 없음)
|
||||
const stored = read("b06_186_1_pipe_292.json");
|
||||
out.stored = study(stored, 292.22);
|
||||
const auto = clone(stored);
|
||||
auto[0].design.revet_adjust = null;
|
||||
out.auto = study(auto, 292.22);
|
||||
// ③ 91-4 절토 쪽 배관 유출(73-4 픽스처 관 340 · 유출 = 우측 절토)
|
||||
const base = read("b06_73_4_body_guard_sections.json");
|
||||
const s340 = clone(base.find((s) => Math.abs(s.chainage_m - 340) < 0.6));
|
||||
s340.uphill_side = "left";
|
||||
s340.culvert = {
|
||||
type: "pipe",
|
||||
chainage_m: 340,
|
||||
pipe_kind: "흄관",
|
||||
diameter_m: 1.0,
|
||||
min_cover_m: 0.5,
|
||||
inlet: { role: "inlet", structure: "기슭막이", revet_form: "돌쌓기(찰)" },
|
||||
outlet: { role: "outlet", structure: "기슭막이", revet_form: "돌쌓기(찰)" },
|
||||
};
|
||||
s340.design.inlet_structure = "revet";
|
||||
const layout = computeCulvertLayout(s340, s340.samples, undefined, "revet");
|
||||
const wall340 = layout.walls.find((w) => w.role === "outlet");
|
||||
const slope340 = (wall340.outward > 0 ? layout.designTrim.maxSlope : layout.designTrim.minSlope)
|
||||
.points;
|
||||
out.cut340 = {
|
||||
outward: wall340.outward,
|
||||
offsets: slope340.map((p) => r2(p.offset)),
|
||||
elevations: slope340.map((p) => r2(p.elevation)),
|
||||
};
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
@@ -185,9 +185,10 @@ function cutOutlet(edit = () => undefined) {
|
||||
s.design.inlet_structure = "revet";
|
||||
edit(s);
|
||||
const layout = computeCulvertLayout(s, s.samples, undefined, "revet");
|
||||
const wall = layout.walls.find((w) => w.role === "outlet");
|
||||
// 벽 뒤 절토 = 유출 끝 연결선(139-4) — 벽 모서리 절토는 또 잇지 않음(186-1)
|
||||
const start = layout.outletFill.segments.at(-1).points[0];
|
||||
const pts = layout.designTrim.minSlope.points;
|
||||
const from = pts.findIndex((p) => Math.abs(p.offset - wall.points[2].offset) < 1e-9);
|
||||
const from = pts.findIndex((p) => Math.abs(p.offset - start.offset) < 1e-9);
|
||||
return profile(pts.slice(from), s.samples);
|
||||
}
|
||||
out.cutOutlet = cutOutlet();
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
"""PLAN 186-1 — 흙막이류 횡단 형상(랩탑 메인 프로젝트 No.14+12) 사본 재현.
|
||||
|
||||
자료: 검증_랩탑메인(226fc805) No.14+12.22 = 관(파형강관 D800) · 유입 L형 집수정 · 유출 흙막이
|
||||
(돌쌓기(찰) H1.3) · 유출 쪽 원지반이 노견보다 높아 벽이 묻힘(벽 윗면 849.99 · 원지반 852.24).
|
||||
|
||||
흠: 묻힌 유출 벽에 절토선이 둘 — 벽 바깥 윗모서리 절토(91-4 `withBackCut`)와 관 끝 3도 절토선
|
||||
(139-4). 둘 다 설계선(트림 사면)에 이어 붙어 선이 원지반까지 올랐다가 벽 앞으로 되내려 접힘
|
||||
(오프셋 13.45 → 14.59 → 13.69) → 카드 · B07 · 3D 모양이 꺾이고 서버 면적도 접힌 폐회로로 셈.
|
||||
|
||||
고침: 유출 끝 연결선(139-4)이 있으면 벽 모서리 절토를 잇지 않음(`_Culvert_Geom.ts`).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
HERE = os.path.dirname(__file__)
|
||||
ROOT = os.path.join(HERE, "..", "..")
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not os.path.isdir(os.path.join(ROOT, "config", "node_modules")),
|
||||
reason="프론트엔드 의존성 미설치",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def out() -> dict:
|
||||
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||||
["node", os.path.join(HERE, "helper_186_1_outlet_fold.cjs")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=60,
|
||||
)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
return json.loads(proc.stdout)
|
||||
|
||||
|
||||
def _one_way(offsets: list[float], outward: int) -> bool:
|
||||
"""설계선이 바깥으로만 나아감 — 되돌아가면 접힌 것."""
|
||||
return all((b - a) * outward >= -1e-9 for a, b in zip(offsets, offsets[1:]))
|
||||
|
||||
|
||||
def _no_peak(elevations: list[float]) -> bool:
|
||||
"""원지반까지 올랐다 되내리는 뾰족 봉우리 없음."""
|
||||
return not any(b > a and b > c for a, b, c in zip(elevations, elevations[1:], elevations[2:]))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", ["stored", "auto"])
|
||||
def test_묻힌_유출_벽_설계선이_안_접힘(out: dict, case: str) -> None:
|
||||
"""저장값(d 9.0)도 자동 자리도 — 벽은 묻혀 있고 설계선은 한 방향."""
|
||||
study = out[case]
|
||||
assert study["wallTop"] < study["groundAtWall"] # 사본이 묻힌 벽을 재현
|
||||
assert _one_way(study["offsets"], study["outward"]), study["offsets"]
|
||||
assert _no_peak(study["elevations"]), study["elevations"]
|
||||
|
||||
|
||||
def test_저장값_사본_면적(out: dict) -> None:
|
||||
"""접힌 폐회로(절토 27.94 · 성토 0.34 ㎡) → 노견~벽~3도 선 절토만."""
|
||||
assert out["stored"]["cut"] == pytest.approx(34.0391, abs=1e-3)
|
||||
assert out["stored"]["fill"] == 0
|
||||
assert out["auto"]["cut"] == pytest.approx(16.8211, abs=1e-3)
|
||||
|
||||
|
||||
def test_절토_쪽_배관_유출도_안_접힘(out: dict) -> None:
|
||||
"""91-4 자료(관 340 · 유출 = 절토 쪽) — 3도 선이 못 만나 복합경사 하나로 원지반까지."""
|
||||
study = out["cut340"]
|
||||
assert _one_way(study["offsets"], study["outward"]), study["offsets"]
|
||||
assert _no_peak(study["elevations"]), study["elevations"]
|
||||
Reference in New Issue
Block a user